diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index 15955be71d6..dad45f1042c 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -668,7 +668,7 @@ public class ComputerUtil { return returnList; } - public static CardCollection choosePermanentsToSacrifice(final Player ai, final CardCollectionView cardlist, final int amount, SpellAbility source, + public static CardCollection choosePermanentsToSacrifice(final Player ai, final CardCollectionView cardlist, final int amount, final SpellAbility source, final boolean destroy, final boolean isOptional) { CardCollection remaining = new CardCollection(cardlist); final CardCollection sacrificed = new CardCollection(); @@ -680,6 +680,10 @@ public class ComputerUtil { if(!source.getActivatingPlayer().isOpponentOf(ai)) { return sacrificed; // sacrifice none } + } else if ("DesecrationDemon".equals(source.getParam("AILogic"))) { + if (!SpecialCardAi.DesecrationDemon.considerSacrificingCreature(ai, source)) { + return sacrificed; // don't sacrifice unless in special conditions specified by DesecrationDemon AI + } } else if (isOptional && source.getActivatingPlayer().isOpponentOf(ai)) { if ("Pillar Tombs of Aku".equals(host.getName())) { if (!ai.canLoseLife() || ai.cantLose()) { @@ -715,7 +719,15 @@ public class ComputerUtil { remaining = CardLists.filter(remaining, new Predicate() { @Override public boolean apply(final Card c) { - if (c.hasSVar("SacMe") || ComputerUtilCard.evaluateCreature(c) < (considerSacThreshold != -1 ? considerSacThreshold : 190)) { + int sacThreshold = 190; + + if ("DesecrationDemon".equals(source.getParam("AILogic"))) { + sacThreshold = SpecialCardAi.DesecrationDemon.getSacThreshold(); + } else if (considerSacLogic) { + sacThreshold = considerSacThreshold; + } + + if (c.hasSVar("SacMe") || ComputerUtilCard.evaluateCreature(c) < sacThreshold) { return true; } diff --git a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java index 45b922f8d2f..8be07ea2417 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java +++ b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java @@ -17,6 +17,7 @@ */ package forge.ai; +import com.google.common.base.Predicates; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import forge.card.MagicColor; @@ -107,6 +108,32 @@ public class SpecialCardAi { } } + // Desecration Demon + public static class DesecrationDemon { + private static final int demonSacThreshold = Integer.MAX_VALUE; // if we're in dire conditions, sac everything from worst to best hoping to find an answer + + public static boolean considerSacrificingCreature(Player ai, SpellAbility sa) { + CardCollection flyingCreatures = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), Predicates.and(CardPredicates.Presets.UNTAPPED, Predicates.or(CardPredicates.hasKeyword("Flying"), CardPredicates.hasKeyword("Reach")))); + boolean hasUsefulBlocker = false; + + for (Card c : flyingCreatures) { + if (!ComputerUtilCard.isUselessCreature(ai, c)) { + hasUsefulBlocker = true; + } + } + + if (ai.getLife() <= sa.getHostCard().getNetPower() && !hasUsefulBlocker) { + return true; + } else { + return false; + } + } + + public static int getSacThreshold() { + return demonSacThreshold; + } + } + // Donate public static class Donate { public static boolean considerTargetingOpponent(Player ai, SpellAbility sa) { diff --git a/forge-gui/res/cardsfolder/d/desecration_demon.txt b/forge-gui/res/cardsfolder/d/desecration_demon.txt index 19017d6b386..f43dd323071 100644 --- a/forge-gui/res/cardsfolder/d/desecration_demon.txt +++ b/forge-gui/res/cardsfolder/d/desecration_demon.txt @@ -4,11 +4,10 @@ Types:Creature Demon PT:6/6 K:Flying T:Mode$ Phase | Phase$ BeginCombat | TriggerZones$ Battlefield | Execute$ TrigSac | TriggerDescription$ At the beginning of each combat, any opponent may sacrifice a creature. If a player does, tap CARDNAME and put a +1/+1 counter on it. -SVar:TrigSac:AB$ Sacrifice | Cost$ 0 | Defined$ Opponent | Amount$ 1 | SacValid$ Creature | RememberSacrificed$ True | Optional$ True | AILogic$ ConsiderSac | SubAbility$ DBSacSelf +SVar:TrigSac:AB$ Sacrifice | Cost$ 0 | Defined$ Opponent | Amount$ 1 | SacValid$ Creature | RememberSacrificed$ True | Optional$ True | AILogic$ DesecrationDemon | SubAbility$ DBSacSelf SVar:DBSacSelf:DB$ Tap | Cost$ 0 | Defined$ Self | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | References$ X | SubAbility$ DBPutCounter SVar:DBPutCounter:DB$ PutCounter | Cost$ 0 | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | References$ X | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Remembered$Amount -SVar:AIPreferenceParams:CreatureEvalThreshold$ 150 SVar:Picture:http://www.wizards.com/global/images/magic/general/desecration_demon.jpg Oracle:Flying\nAt the beginning of each combat, any opponent may sacrifice a creature. If a player does, tap Desecration Demon and put a +1/+1 counter on it.