diff --git a/forge-ai/src/main/java/forge/ai/AiAttackController.java b/forge-ai/src/main/java/forge/ai/AiAttackController.java index 7ed6cdc9..4760c121 100644 --- a/forge-ai/src/main/java/forge/ai/AiAttackController.java +++ b/forge-ai/src/main/java/forge/ai/AiAttackController.java @@ -17,19 +17,13 @@ */ package forge.ai; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Lists; - import forge.ai.ability.AnimateAi; import forge.card.CardTypeView; import forge.game.GameEntity; import forge.game.ability.AbilityFactory; -import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.ability.effects.ProtectEffect; import forge.game.card.*; @@ -45,6 +39,10 @@ import forge.util.Expressions; import forge.util.MyRandom; import forge.util.collect.FCollectionView; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + //doesHumanAttackAndWin() uses the global variable AllZone.getComputerPlayer() /** @@ -377,8 +375,12 @@ public class AiAttackController { blockersLeft--; continue; } - totalAttack += ComputerUtilCombat.damageIfUnblocked(attacker, ai, null, false); - totalPoison += ComputerUtilCombat.poisonIfUnblocked(attacker, ai); + + // Test for some special triggers that can change the creature in combat + Card effectiveAttacker = ComputerUtilCombat.applyPotentialAttackCloneTriggers(attacker); + + totalAttack += ComputerUtilCombat.damageIfUnblocked(effectiveAttacker, ai, null, false); + totalPoison += ComputerUtilCombat.poisonIfUnblocked(effectiveAttacker, ai); } if (totalAttack > 0 && ai.getLife() <= totalAttack && !ai.cantLoseForZeroOrLessLife()) { diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java index a9d55624..06d71b03 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java @@ -2527,6 +2527,38 @@ public class ComputerUtilCombat { return categorizedAttackers; } + + public static Card applyPotentialAttackCloneTriggers(Card attacker) { + // This method returns the potentially cloned card if the creature turns into something else during the attack + // (currently looks for the creature with maximum raw power since that's what the AI usually judges by when + // deciding whether the creature is worth blocking). + // If the creature doesn't change into anything, returns the original creature. + Card attackerAfterTrigs = attacker; + + // Test for some special triggers that can change the creature in combat + for (Trigger t : attacker.getTriggers()) { + if (t.getMode() == TriggerType.Attacks && t.hasParam("Execute")) { + SpellAbility exec = AbilityFactory.getAbility(attacker, t.getParam("Execute")); + if (exec != null) { + if (exec.getApi() == ApiType.Clone && "Self".equals(exec.getParam("CloneTarget")) + && exec.hasParam("ValidTgts") && exec.getParam("ValidTgts").contains("Creature") + && exec.getParam("ValidTgts").contains("+attacking")) { + // Tilonalli's Skinshifter and potentially other similar cards that can clone other stuff + // while attacking + int maxPwr = 0; + for (Card c : attacker.getController().getCreaturesInPlay()) { + if (c.getNetPower() > maxPwr) { + maxPwr = c.getNetPower(); + attackerAfterTrigs = c; + } + } + } + } + } + } + + return attackerAfterTrigs; + } }