- AI: Now knows how to instantly reequip Cranial Plating to an unblocked attacker who would deal lethal damage.

This commit is contained in:
Agetian
2017-09-30 13:50:26 +00:00
parent 3f3f2f2c18
commit 7459f7a9fa
2 changed files with 55 additions and 4 deletions

View File

@@ -2,13 +2,13 @@ package forge.ai.ability;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import forge.ai.*; import forge.ai.*;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.*; import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.cost.CostPart; import forge.game.cost.CostPart;
@@ -24,7 +24,10 @@ import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType; 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 { public class AttachAi extends SpellAbilityAi {
@@ -502,6 +505,44 @@ public class AttachAi extends SpellAbilityAi {
return chosen; 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 // Should generalize this code a bit since they all have similar structures
/** /**
* Attach ai control preference. * Attach ai control preference.
@@ -1049,6 +1090,10 @@ public class AttachAi extends SpellAbilityAi {
return null; return null;
} }
if ("InstantReequipPowerBuff".equals(sa.getParam("AILogic"))) {
return c;
}
boolean uselessCreature = ComputerUtilCard.isUselessCreature(aiPlayer, attachSource.getEquipping()); boolean uselessCreature = ComputerUtilCard.isUselessCreature(aiPlayer, attachSource.getEquipping());
if (aic.getProperty(AiProps.MOVE_EQUIPMENT_TO_BETTER_CREATURES).equals("never")) { 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); 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 there are no preferred cards, and not mandatory bail out
if (prefList.isEmpty()) { if (prefList.isEmpty()) {
return chooseUnpreferred(mandatory, list); return chooseUnpreferred(mandatory, list);

View File

@@ -2,8 +2,8 @@ Name:Cranial Plating
ManaCost:2 ManaCost:2
Types:Artifact Equipment Types:Artifact Equipment
K:Equip 1 K:Equip 1
S:Mode$ Continuous | Affected$ Card.EquippedBy | AddPower$ X | Description$ Equipped creature gets +1/+0 for each artifact 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 | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | SpellDescription$ Attach CARDNAME to target creature 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:X:Count$Valid Artifact.YouCtrl
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE
SVar:BuffedBy:Artifact SVar:BuffedBy:Artifact