diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index 22340548028..9da94706493 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -68,6 +68,7 @@ public enum SpellApiToAi { .put(ApiType.Encode, EncodeAi.class) .put(ApiType.EndTurn, EndTurnAi.class) .put(ApiType.ExchangeLife, LifeExchangeAi.class) + .put(ApiType.ExchangeLifeVariant, LifeExchangeVariantAi.class) .put(ApiType.ExchangeControl, ControlExchangeAi.class) .put(ApiType.ExchangeControlVariant, CannotPlayAi.class) .put(ApiType.ExchangePower, PowerExchangeAi.class) diff --git a/forge-ai/src/main/java/forge/ai/ability/LifeExchangeVariantAi.java b/forge-ai/src/main/java/forge/ai/ability/LifeExchangeVariantAi.java new file mode 100644 index 00000000000..a34f5e0d801 --- /dev/null +++ b/forge-ai/src/main/java/forge/ai/ability/LifeExchangeVariantAi.java @@ -0,0 +1,122 @@ +package forge.ai.ability; + +import forge.ai.ComputerUtil; +import forge.ai.ComputerUtilAbility; +import forge.ai.ComputerUtilCombat; +import forge.ai.SpellAbilityAi; +import forge.game.Game; +import forge.game.card.Card; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; +import forge.game.spellability.TargetRestrictions; + +public class LifeExchangeVariantAi extends SpellAbilityAi { + + /* + * (non-Javadoc) + * + * @see + * forge.card.abilityfactory.AbilityFactoryAlterLife.SpellAiLogic#canPlayAI + * (forge.game.player.Player, java.util.Map, + * forge.card.spellability.SpellAbility) + */ + @Override + protected boolean canPlayAI(Player ai, SpellAbility sa) { + final Card source = sa.getHostCard(); + final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa); + final Game game = ai.getGame(); + + if ("Tree of Redemption".equals(sourceName)) { + if (!ai.canGainLife()) + return false; + + // someone controls "Rain of Gore" or "Sulfuric Vortex", lifegain is bad in that case + if (game.isCardInPlay("Rain of Gore") || game.isCardInPlay("Sulfuric Vortex")) + return false; + + // an opponent controls "Tainted Remedy", lifegain is bad in that case + for (Player op : ai.getOpponents()) { + if (op.isCardInPlay("Tainted Remedy")) + return false; + } + + if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetToughness() + || (ai.getLife() > 5 && !ComputerUtilCombat.lifeInSeriousDanger(ai, ai.getGame().getCombat()))) { + return false; + } + } + else if ("Tree of Perdition".equals(sourceName)) { + boolean shouldDo = false; + + if (ComputerUtil.waitForBlocking(sa)) + return false; + + for (Player op : ai.getOpponents()) { + // if oppoent can't be targeted, or it can't lose life, try another one + if (!op.canBeTargetedBy(sa) || !op.canLoseLife()) + continue; + // an opponent has more live than this toughness + if (op.getLife() + 1 >= source.getNetToughness()) { + shouldDo = true; + } else { + // opponent can't gain life, so "Tainted Remedy" should not work. + if (!op.canGainLife()) { + continue; + } else if (ai.isCardInPlay("Tainted Remedy")) { // or AI has Tainted Remedy + shouldDo = true; + } else { + for (Player ally : ai.getAllies()) { + // if an Ally has Tainted Remedy and opponent is also opponent of ally + if (ally.isCardInPlay("Tainted Remedy") && op.isOpponentOf(ally)) + shouldDo = true; + } + } + + } + + if (shouldDo) { + sa.getTargets().add(op); + break; + } + } + + return shouldDo; + } + else if ("Evra, Halcyon Witness".equals(sourceName)) { + // TODO add logic + } + return false; + + } + + /** + *
+ * exchangeLifeDoTriggerAINoCost. + *
+ * @param sa + * a {@link forge.game.spellability.SpellAbility} object. + * @param mandatory + * a boolean. + * @param af + * a {@link forge.game.ability.AbilityFactory} object. + * + * @return a boolean. + */ + @Override + protected boolean doTriggerAINoCost(final Player ai, final SpellAbility sa, + final boolean mandatory) { + + final TargetRestrictions tgt = sa.getTargetRestrictions(); + Player opp = ComputerUtil.getOpponentFor(ai); + if (tgt != null) { + sa.resetTargets(); + if (sa.canTarget(opp) && (mandatory || ai.getLife() < opp.getLife())) { + sa.getTargets().add(opp); + } else { + return false; + } + } + return true; + } + +} diff --git a/forge-ai/src/main/java/forge/ai/ability/StoreSVarAi.java b/forge-ai/src/main/java/forge/ai/ability/StoreSVarAi.java index 6df57af7807..f5dc2c0282e 100644 --- a/forge-ai/src/main/java/forge/ai/ability/StoreSVarAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/StoreSVarAi.java @@ -1,6 +1,5 @@ package forge.ai.ability; -import forge.ai.ComputerUtil; import forge.ai.ComputerUtilAbility; import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilMana; @@ -25,7 +24,6 @@ public class StoreSVarAi extends SpellAbilityAi { @Override protected boolean canPlayAI(Player ai, SpellAbility sa) { final Card source = sa.getHostCard(); - final String sourceName = ComputerUtilAbility.getAbilitySourceName(sa); final Game game = ai.getGame(); final Combat combat = game.getCombat(); final PhaseHandler ph = game.getPhaseHandler(); @@ -69,62 +67,7 @@ public class StoreSVarAi extends SpellAbilityAi { } return false; } - else if ("Tree of Redemption".equals(sourceName)) { - if (!ai.canGainLife()) - return false; - // someone controls "Rain of Gore" or "Sulfuric Vortex", lifegain is bad in that case - if (game.isCardInPlay("Rain of Gore") || game.isCardInPlay("Sulfuric Vortex")) - return false; - - // an opponent controls "Tainted Remedy", lifegain is bad in that case - for (Player op : ai.getOpponents()) { - if (op.isCardInPlay("Tainted Remedy")) - return false; - } - - if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetToughness() - || (ai.getLife() > 5 && !ComputerUtilCombat.lifeInSeriousDanger(ai, ai.getGame().getCombat()))) { - return false; - } - } - else if ("Tree of Perdition".equals(sourceName)) { - boolean shouldDo = false; - - if (ComputerUtil.waitForBlocking(sa)) - return false; - - for (Player op : ai.getOpponents()) { - // if oppoent can't be targeted, or it can't lose life, try another one - if (!op.canBeTargetedBy(sa) || !op.canLoseLife()) - continue; - // an opponent has more live than this toughness - if (op.getLife() + 1 >= source.getNetToughness()) { - shouldDo = true; - } else { - // opponent can't gain life, so "Tainted Remedy" should not work. - if (!op.canGainLife()) { - continue; - } else if (ai.isCardInPlay("Tainted Remedy")) { // or AI has Tainted Remedy - shouldDo = true; - } else { - for (Player ally : ai.getAllies()) { - // if an Ally has Tainted Remedy and opponent is also opponent of ally - if (ally.isCardInPlay("Tainted Remedy") && op.isOpponentOf(ally)) - shouldDo = true; - } - } - - } - - if (shouldDo) { - sa.getTargets().add(op); - break; - } - } - - return shouldDo; - } return true; } diff --git a/forge-game/src/main/java/forge/game/ability/ApiType.java b/forge-game/src/main/java/forge/game/ability/ApiType.java index 7c0a63d1ceb..8605e2453fd 100644 --- a/forge-game/src/main/java/forge/game/ability/ApiType.java +++ b/forge-game/src/main/java/forge/game/ability/ApiType.java @@ -65,6 +65,7 @@ public enum ApiType { Encode (EncodeEffect.class), EndTurn (EndTurnEffect.class), ExchangeLife (LifeExchangeEffect.class), + ExchangeLifeVariant (LifeExchangeVariantEffect.class), ExchangeControl (ControlExchangeEffect.class), ExchangeControlVariant (ControlExchangeVariantEffect.class), ExchangePower (PowerExchangeEffect.class), diff --git a/forge-game/src/main/java/forge/game/ability/effects/LifeExchangeVariantEffect.java b/forge-game/src/main/java/forge/game/ability/effects/LifeExchangeVariantEffect.java new file mode 100644 index 00000000000..c0836c66c06 --- /dev/null +++ b/forge-game/src/main/java/forge/game/ability/effects/LifeExchangeVariantEffect.java @@ -0,0 +1,95 @@ +package forge.game.ability.effects; + +import forge.game.Game; +import forge.game.ability.SpellAbilityEffect; +import forge.game.card.Card; +import forge.game.event.GameEventCardStatsChanged; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; +import forge.game.zone.ZoneType; + +import java.util.List; + +public class LifeExchangeVariantEffect extends SpellAbilityEffect { + + // ************************************************************************* + // ************************ EXCHANGE LIFE ********************************** + // ************************************************************************* + + + + // ************************************************************************* + // ************************* LOSE LIFE ************************************* + // ************************************************************************* + + /* (non-Javadoc) + * @see forge.card.abilityfactory.AbilityFactoryAlterLife.SpellEffect#getStackDescription(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + protected String getStackDescription(SpellAbility sa) { + final StringBuilder sb = new StringBuilder(); + final Player activatingPlayer = sa.getActivatingPlayer(); + final String mode = sa.getParam("Mode"); + + sb.append(activatingPlayer).append(" exchanges life totals with "); + sb.append(sa.getHostCard()); + sb.append("'s "); + sb.append(mode.toLowerCase()); + + return sb.toString(); + } + + /* (non-Javadoc) + * @see forge.card.abilityfactory.AbilityFactoryAlterLife.SpellEffect#resolve(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + public void resolve(SpellAbility sa) { + final Card source = sa.getHostCard(); + final String mode = sa.getParam("Mode"); + final List