From 7459f7a9faf7020a3e575ce176e7000d6c46e8c0 Mon Sep 17 00:00:00 2001 From: Agetian Date: Sat, 30 Sep 2017 13:50:26 +0000 Subject: [PATCH] - AI: Now knows how to instantly reequip Cranial Plating to an unblocked attacker who would deal lethal damage. --- .../main/java/forge/ai/ability/AttachAi.java | 55 ++++++++++++++++++- .../res/cardsfolder/c/cranial_plating.txt | 4 +- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java index ad13fc53ca1..67ca93a33e4 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java @@ -2,13 +2,13 @@ package forge.ai.ability; import com.google.common.base.Predicate; import com.google.common.base.Predicates; - import forge.ai.*; import forge.game.GameObject; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.*; +import forge.game.combat.Combat; import forge.game.combat.CombatUtil; import forge.game.cost.Cost; import forge.game.cost.CostPart; @@ -24,7 +24,10 @@ import forge.game.trigger.Trigger; import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; public class AttachAi extends SpellAbilityAi { @@ -502,6 +505,44 @@ public class AttachAi extends SpellAbilityAi { return chosen; } + private static Card attachAIInstantReequipPreference(final SpellAbility sa, final Card attachSource) { + // e.g. Cranial Plating + PhaseHandler ph = attachSource.getGame().getPhaseHandler(); + Combat combat = attachSource.getGame().getCombat(); + Card equipped = sa.getHostCard().getEquipping(); + if (equipped == null) { + return null; + } + + int powerBuff = 0; + for (StaticAbility stAb : sa.getHostCard().getStaticAbilities()) { + if ("Card.EquippedBy".equals(stAb.getParam("Affected")) && stAb.hasParam("AddPower")) { + powerBuff = AbilityUtils.calculateAmount(sa.getHostCard(), stAb.getParam("AddPower"), null); + } + } + if (combat != null && combat.isAttacking(equipped) && ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS, sa.getActivatingPlayer())) { + int damage = 0; + for (Card c : combat.getUnblockedAttackers()) { + damage += ComputerUtilCombat.predictDamageTo(combat.getDefenderPlayerByAttacker(equipped), c.getNetCombatDamage(), c, true); + } + if (combat.isBlocked(equipped)) { + for (Card atk : combat.getAttackers()) { + if (!combat.isBlocked(atk) && !ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), null).contains(atk)) { + if (ComputerUtilCombat.predictDamageTo(combat.getDefenderPlayerByAttacker(atk), + atk.getNetCombatDamage(), atk, true) > 0) { + if (damage + powerBuff >= combat.getDefenderPlayerByAttacker(atk).getLife()) { + sa.resetTargets(); // this is needed to avoid bugs with adding two targets to a single SA + return atk; // lethal damage, we can win right now, so why not? + } + } + } + } + } + } + + return null; + } + // Should generalize this code a bit since they all have similar structures /** * Attach ai control preference. @@ -1049,6 +1090,10 @@ public class AttachAi extends SpellAbilityAi { return null; } + if ("InstantReequipPowerBuff".equals(sa.getParam("AILogic"))) { + return c; + } + boolean uselessCreature = ComputerUtilCard.isUselessCreature(aiPlayer, attachSource.getEquipping()); if (aic.getProperty(AiProps.MOVE_EQUIPMENT_TO_BETTER_CREATURES).equals("never")) { @@ -1125,6 +1170,12 @@ public class AttachAi extends SpellAbilityAi { prefList = CardLists.filterControlledBy(list, prefPlayer); } + // AI logic types that do not require a prefList and that evaluate the + // usefulness of attach action autonomously + if ("InstantReequipPowerBuff".equals(logic)) { + return attachAIInstantReequipPreference(sa, attachSource); + } + // If there are no preferred cards, and not mandatory bail out if (prefList.isEmpty()) { return chooseUnpreferred(mandatory, list); diff --git a/forge-gui/res/cardsfolder/c/cranial_plating.txt b/forge-gui/res/cardsfolder/c/cranial_plating.txt index 8ecf80061e9..c8027e52055 100644 --- a/forge-gui/res/cardsfolder/c/cranial_plating.txt +++ b/forge-gui/res/cardsfolder/c/cranial_plating.txt @@ -2,8 +2,8 @@ Name:Cranial Plating ManaCost:2 Types:Artifact Equipment K:Equip 1 -S:Mode$ Continuous | Affected$ Card.EquippedBy | AddPower$ X | Description$ Equipped creature gets +1/+0 for each artifact you control. -A:AB$ Attach | Cost$ B B | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | SpellDescription$ Attach CARDNAME to target creature you control. +S:Mode$ Continuous | Affected$ Card.EquippedBy | AddPower$ X | References$ X | Description$ Equipped creature gets +1/+0 for each artifact you control. +A:AB$ Attach | Cost$ B B | AILogic$ InstantReequipPowerBuff | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | SpellDescription$ Attach CARDNAME to target creature you control. SVar:X:Count$Valid Artifact.YouCtrl SVar:PlayMain1:TRUE SVar:BuffedBy:Artifact