diff --git a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java index 3c38cfd40fa..1ea361bd9fa 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CountersPutAi.java @@ -1,6 +1,7 @@ package forge.ai.ability; import com.google.common.base.Predicate; +import com.google.common.base.Predicates; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import forge.ai.*; @@ -125,6 +126,8 @@ public class CountersPutAi extends SpellAbilityAi { final String type = sa.getParam("CounterType"); final String amountStr = sa.getParam("CounterNum"); final boolean divided = sa.hasParam("DividedAsYouChoose"); + final String logic = sa.getParamOrDefault("AILogic", ""); + PhaseHandler ph = ai.getGame().getPhaseHandler(); final boolean isClockwork = "True".equals(sa.getParam("UpTo")) && "Self".equals(sa.getParam("Defined")) && "P1P0".equals(sa.getParam("CounterType")) && "Count$xPaid".equals(source.getSVar("X")) @@ -214,15 +217,15 @@ public class CountersPutAi extends SpellAbilityAi { return false; } - if ("Never".equals(sa.getParam("AILogic"))) { + if ("Never".equals(logic)) { return false; } - if ("PayEnergy".equals(sa.getParam("AILogic"))) { + if ("PayEnergy".equals(logic)) { return true; } - if ("PayEnergyConservatively".equals(sa.getParam("AILogic"))) { + if ("PayEnergyConservatively".equals(logic)) { boolean onlyInCombat = ai.getController().isAI() && ((PlayerControllerAi) ai.getController()).getAi().getBooleanProperty(AiProps.CONSERVATIVE_ENERGY_PAYMENT_ONLY_IN_COMBAT); boolean onlyDefensive = ai.getController().isAI() @@ -264,6 +267,22 @@ public class CountersPutAi extends SpellAbilityAi { } } + if (logic.equals("MarkOppCreature")) { + if (!ph.is(PhaseType.END_OF_TURN)) { + return false; + } + + CardCollection oppCreats = CardLists.filter(ai.getOpponents().getCreaturesInPlay(), + Predicates.not(CardPredicates.hasCounter(CounterType.getType(type)))); + + if (!oppCreats.isEmpty()) { + Card bestCreat = ComputerUtilCard.getBestCreatureAI(oppCreats); + sa.resetTargets(); + sa.getTargets().add(bestCreat); + return true; + } + } + if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) { return false; } @@ -292,7 +311,7 @@ public class CountersPutAi extends SpellAbilityAi { // TODO handle proper calculation of X values based on Cost int amount = AbilityUtils.calculateAmount(source, amountStr, sa); - if ("Fight".equals(sa.getParam("AILogic"))) { + if ("Fight".equals(logic)) { int nPump = 0; if (type.equals("P1P1")) { nPump = amount; @@ -323,7 +342,7 @@ public class CountersPutAi extends SpellAbilityAi { } source.setSVar("PayX", Integer.toString(amount)); - } else if ("ExiledCreatureFromGraveCMC".equals(sa.getParam("AILogic"))) { + } else if ("ExiledCreatureFromGraveCMC".equals(logic)) { // e.g. Necropolis amount = Aggregates.max(CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), CardPredicates.Presets.CREATURES), CardPredicates.Accessors.fnGetCmc); if (amount > 0 && ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)) { @@ -337,7 +356,7 @@ public class CountersPutAi extends SpellAbilityAi { return false; } - if ("Polukranos".equals(sa.getParam("AILogic"))) { + if ("Polukranos".equals(logic)) { CardCollection humCreatures = CardLists.getTargetableCards(ai.getOpponents().getCreaturesInPlay(), sa); @@ -360,9 +379,7 @@ public class CountersPutAi extends SpellAbilityAi { } } - PhaseHandler ph = ai.getGame().getPhaseHandler(); - - if ("AlwaysAtOppEOT".equals(sa.getParam("AILogic"))) { + if ("AlwaysAtOppEOT".equals(logic)) { if (ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn().equals(ai)) { return true; } @@ -566,6 +583,7 @@ public class CountersPutAi extends SpellAbilityAi { final Game game = ai.getGame(); Card choice = null; final String type = sa.getParam("CounterType"); + final String logic = sa.getParamOrDefault("AILogic", ""); final String amountStr = sa.getParam("CounterNum"); final boolean divided = sa.hasParam("DividedAsYouChoose"); @@ -611,7 +629,7 @@ public class CountersPutAi extends SpellAbilityAi { SpellAbility animate = sa.findSubAbilityByType(ApiType.Animate); if (!lands.isEmpty() && animate != null) { choice = ComputerUtilCard.getWorstLand(lands); - } else if ("BoonCounterOnOppCreature".equals(sa.getParam("AILogic"))) { + } else if ("BoonCounterOnOppCreature".equals(logic)) { choice = ComputerUtilCard.getWorstCreatureAI(list); } else { choice = CountersAi.chooseBoonTarget(list, type); diff --git a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java index 81e26eb32d4..7a8e7343b61 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DestroyAllAi.java @@ -64,10 +64,15 @@ public class DestroyAllAi extends SpellAbilityAi { public boolean doMassRemovalLogic(Player ai, SpellAbility sa) { final Card source = sa.getHostCard(); + final String logic = sa.getParamOrDefault("AILogic", ""); Player opponent = ComputerUtil.getOpponentFor(ai); // TODO: how should this AI logic work for multiplayer and getOpponents()? final int CREATURE_EVAL_THRESHOLD = 200; + if (logic.equals("Always")) { + return true; // e.g. Tetzimoc, Primal Death, where we want to cast the permanent even if the removal trigger does nothing + } + String valid = ""; if (sa.hasParam("ValidCards")) { valid = sa.getParam("ValidCards"); diff --git a/forge-gui/res/cardsfolder/t/tetzimoc_primal_death.txt b/forge-gui/res/cardsfolder/t/tetzimoc_primal_death.txt index 4306a8ced1b..61c39e5b0fd 100644 --- a/forge-gui/res/cardsfolder/t/tetzimoc_primal_death.txt +++ b/forge-gui/res/cardsfolder/t/tetzimoc_primal_death.txt @@ -3,8 +3,8 @@ ManaCost:4 B B Types:Legendary Creature Elder Dinosaur PT:6/6 K:Deathtouch -A:AB$ PutCounter | Cost$ B | ActivationZone$ Hand | CostDesc$ {B}, Reveal CARDNAME from your hand: | PlayerTurn$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ PREY | CounterNum$ 1 | IsCurse$ True | SpellDescription$ Put a prey counter on target creature. Activate this ability only during your turn. +A:AB$ PutCounter | Cost$ B | ActivationZone$ Hand | CostDesc$ {B}, Reveal CARDNAME from your hand: | PlayerTurn$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ PREY | CounterNum$ 1 | IsCurse$ True | AILogic$ MarkOppCreature | SpellDescription$ Put a prey counter on target creature. Activate this ability only during your turn. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroyAll | TriggerDescription$ When CARDNAME enters the battlefield, destroy each creature your opponents control with a prey counter on it. -SVar:TrigDestroyAll:DB$ DestroyAll | ValidCards$ Creature.OppCtrl+counters_GE1_PREY +SVar:TrigDestroyAll:DB$ DestroyAll | ValidCards$ Creature.OppCtrl+counters_GE1_PREY | AILogic$ Always SVar:Picture:http://www.wizards.com/global/images/magic/general/tetzimoc_primal_death.jpg Oracle:Deathtouch\n{B}, Reveal Tetzimoc, Primal Death from your hand: Put a prey counter on target creature. Activate this ability only during your turn.\nWhen Tetzimoc enters the battlefield, destroy each creature your opponents control with a prey counter on it. \ No newline at end of file