From f652bd5f298099e70d18a41a0910b3deaa415d79 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Mon, 8 Nov 2021 18:11:26 +0100 Subject: [PATCH] Fix attacking self with Kaalia trigger --- .../src/main/java/forge/ai/AiController.java | 1 + .../java/forge/ai/ComputerUtilCombat.java | 23 +++++++++++ .../main/java/forge/ai/ability/AttachAi.java | 26 +++++++------ .../java/forge/ai/ability/ChangeZoneAi.java | 19 ++++++++-- .../forge/ai/ability/CopyPermanentAi.java | 17 ++++++++- .../src/main/java/forge/ai/ability/DigAi.java | 15 ++++++++ .../main/java/forge/ai/ability/TokenAi.java | 38 ++++--------------- .../src/main/java/forge/game/GameAction.java | 2 +- .../game/ability/SpellAbilityEffect.java | 9 ++--- .../game/ability/effects/DigUntilEffect.java | 1 - .../game/ability/effects/DrawEffect.java | 2 +- .../main/java/forge/game/cost/CostReturn.java | 1 - .../spellability/SpellAbilityCondition.java | 20 +++++----- .../a/adeline_resplendent_cathar.txt | 6 +-- forge-gui/res/cardsfolder/c/conflagrate.txt | 2 +- .../cardsfolder/e/elaborate_firecannon.txt | 2 +- .../res/cardsfolder/f/felidar_sovereign.txt | 2 +- forge-gui/res/cardsfolder/g/gigapede.txt | 2 +- 18 files changed, 116 insertions(+), 72 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index b48114b9022..94d3d425adc 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -770,6 +770,7 @@ public class AiController { // one is warded and can't be paid for. if (sa.usesTargeting()) { for (Card tgt : sa.getTargets().getTargetCards()) { + // TODO some older cards don't use the keyword, so check for trigger instead if (tgt.hasKeyword(Keyword.WARD) && tgt.isInPlay() && tgt.getController().isOpponentOf(sa.getHostCard().getController())) { int amount = 0; Cost wardCost = ComputerUtilCard.getTotalWardCost(tgt); diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java index be637b22855..8e55739b45c 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java @@ -2497,4 +2497,27 @@ public class ComputerUtilCombat { } return poison; } + + public static GameEntity addAttackerToCombat(SpellAbility sa, Card attacker, FCollection defenders) { + Combat combat = sa.getHostCard().getGame().getCombat(); + if (combat != null) { + // 1. If the card that spawned the attacker was sent at a planeswalker, attack the same. Consider improving. + GameEntity def = combat.getDefenderByAttacker(sa.getHostCard()); + if (def != null && def instanceof Card) { + if (((Card)def).isPlaneswalker()) { + return def; + } + } + // 2. Otherwise, go through the list of options one by one, choose the first one that can't be blocked profitably. + for (GameEntity p : defenders) { + if (p instanceof Player && !ComputerUtilCard.canBeBlockedProfitably((Player)p, attacker)) { + return p; + } + if (p instanceof Card && !ComputerUtilCard.canBeBlockedProfitably(((Card)p).getController(), attacker)) { + return p; + } + } + } + return Iterables.getFirst(defenders, null); + } } 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 5540f3fec3b..e08152d3abd 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java @@ -452,21 +452,15 @@ public class AttachAi extends SpellAbilityAi { /** * Attach to player ai preferences. - * * @param sa * the sa * @param mandatory * the mandatory + * @param newParam TODO + * * @return the player */ - public static Player attachToPlayerAIPreferences(final Player aiPlayer, final SpellAbility sa, final boolean mandatory) { - List targetable = new ArrayList<>(); - for (final Player player : aiPlayer.getGame().getPlayers()) { - if (sa.canTarget(player)) { - targetable.add(player); - } - } - + public static Player attachToPlayerAIPreferences(final Player aiPlayer, final SpellAbility sa, final boolean mandatory, List targetable) { if ("Curse".equals(sa.getParam("AILogic"))) { if (!mandatory) { targetable.removeAll(aiPlayer.getAllies()); @@ -1020,7 +1014,13 @@ public class AttachAi extends SpellAbilityAi { private static boolean attachPreference(final SpellAbility sa, final TargetRestrictions tgt, final boolean mandatory) { GameObject o; if (tgt.canTgtPlayer()) { - o = attachToPlayerAIPreferences(sa.getActivatingPlayer(), sa, mandatory); + List targetable = new ArrayList<>(); + for (final Player player : sa.getHostCard().getGame().getPlayers()) { + if (sa.canTarget(player)) { + targetable.add(player); + } + } + o = attachToPlayerAIPreferences(sa.getActivatingPlayer(), sa, mandatory, targetable); } else { o = attachToCardAIPreferences(sa.getActivatingPlayer(), sa, mandatory); } @@ -1459,10 +1459,12 @@ public class AttachAi extends SpellAbilityAi { */ public static Card attachGeneralAI(final Player ai, final SpellAbility sa, final List list, final boolean mandatory, final Card attachSource, final String logic) { - Player prefPlayer = AiAttackController.choosePreferredDefenderPlayer(ai); + Player prefPlayer; if ("Pump".equals(logic) || "Animate".equals(logic) || "Curiosity".equals(logic) || "MoveTgtAura".equals(logic) || "MoveAllAuras".equals(logic)) { prefPlayer = ai; + } else { + prefPlayer = AiAttackController.choosePreferredDefenderPlayer(ai); } // Some ChangeType cards are beneficial, and PrefPlayer should be // changed to represent that @@ -1765,6 +1767,6 @@ public class AttachAi extends SpellAbilityAi { @Override protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) { - return attachToPlayerAIPreferences(ai, sa, true); + return attachToPlayerAIPreferences(ai, sa, true, (List)options); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java index 9eb152ca4a0..f9c97cf30f5 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -29,6 +29,7 @@ import forge.ai.SpellAbilityAi; import forge.ai.SpellApiToAi; import forge.card.MagicColor; import forge.game.Game; +import forge.game.GameEntity; import forge.game.GameObject; import forge.game.GlobalRuleChange; import forge.game.ability.AbilityKey; @@ -50,6 +51,7 @@ import forge.game.spellability.TargetRestrictions; import forge.game.staticability.StaticAbilityMustTarget; import forge.game.zone.ZoneType; import forge.util.MyRandom; +import forge.util.collect.FCollection; public class ChangeZoneAi extends SpellAbilityAi { /* @@ -423,7 +425,6 @@ public class ChangeZoneAi extends SpellAbilityAi { } return canBouncePermanent(ai, sa, list) != null; } - } if (ComputerUtil.playImmediately(ai, sa)) { @@ -1784,8 +1785,20 @@ public class ChangeZoneAi extends SpellAbilityAi { */ @Override public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) { - // Called when attaching Aura to player - return AttachAi.attachToPlayerAIPreferences(ai, sa, true); + // Called when attaching Aura to player or adding creature to combat + if (params.containsKey("Attacker")) { + return (Player) ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), new FCollection(options)); + } + return AttachAi.attachToPlayerAIPreferences(ai, sa, true, (List)options); + } + + @Override + protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) { + if (params.containsKey("Attacker")) { + return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), new FCollection(options)); + } + // should not be reached + return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params); } private boolean doSacAndReturnFromGraveLogic(final Player ai, final SpellAbility sa) { diff --git a/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java b/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java index 5c56ff9ddae..e17bdd279ec 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CopyPermanentAi.java @@ -12,10 +12,12 @@ import forge.ai.AiPlayDecision; import forge.ai.ComputerUtil; import forge.ai.ComputerUtilAbility; import forge.ai.ComputerUtilCard; +import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilCost; import forge.ai.SpecialCardAi; import forge.ai.SpellAbilityAi; import forge.game.Game; +import forge.game.GameEntity; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.card.Card; @@ -32,6 +34,7 @@ import forge.game.player.PlayerActionConfirmMode; import forge.game.player.PlayerCollection; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; +import forge.util.collect.FCollection; public class CopyPermanentAi extends SpellAbilityAi { @Override @@ -232,7 +235,7 @@ public class CopyPermanentAi extends SpellAbilityAi { } return ComputerUtilCard.getBestAI(options); } - + private CardCollection getBetterOptions(Player ai, SpellAbility sa, Iterable options, boolean isOptional) { final Card host = sa.getHostCard(); final Player ctrl = host.getController(); @@ -244,9 +247,21 @@ public class CopyPermanentAi extends SpellAbilityAi { @Override protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) { + if (params.containsKey("Attacker")) { + return (Player) ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), new FCollection(options)); + } final List cards = new PlayerCollection(options).getCreaturesInPlay(); Card chosen = ComputerUtilCard.getBestCreatureAI(cards); return chosen != null ? chosen.getController() : Iterables.getFirst(options, null); } + @Override + protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) { + if (params.containsKey("Attacker")) { + return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), new FCollection(options)); + } + // should not be reached + return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params); + } + } diff --git a/forge-ai/src/main/java/forge/ai/ability/DigAi.java b/forge-ai/src/main/java/forge/ai/ability/DigAi.java index 5ba76682eb8..25602dc9d98 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DigAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DigAi.java @@ -8,10 +8,12 @@ import forge.ai.AiAttackController; import forge.ai.ComputerUtil; import forge.ai.ComputerUtilAbility; import forge.ai.ComputerUtilCard; +import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilCost; import forge.ai.SpecialCardAi; import forge.ai.SpellAbilityAi; import forge.game.Game; +import forge.game.GameEntity; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardCollection; @@ -25,6 +27,7 @@ import forge.game.player.PlayerPredicates; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; import forge.util.TextUtil; +import forge.util.collect.FCollection; public class DigAi extends SpellAbilityAi { @@ -180,10 +183,22 @@ public class DigAi extends SpellAbilityAi { */ @Override public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) { + if (params.containsKey("Attacker")) { + return (Player) ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), new FCollection(options)); + } // an opponent choose a card from return Iterables.getFirst(options, null); } + @Override + protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) { + if (params.containsKey("Attacker")) { + return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), new FCollection(options)); + } + // should not be reached + return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params); + } + /* (non-Javadoc) * @see forge.card.ability.SpellAbilityAi#confirmAction(forge.card.spellability.SpellAbility, forge.game.player.PlayerActionConfirmMode, java.lang.String) */ diff --git a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java index 4c26284fea4..5451a516580 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java @@ -9,6 +9,7 @@ import forge.ai.AiController; import forge.ai.AiProps; import forge.ai.ComputerUtil; import forge.ai.ComputerUtilCard; +import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilCost; import forge.ai.ComputerUtilMana; import forge.ai.PlayerControllerAi; @@ -37,6 +38,7 @@ import forge.game.spellability.SpellAbility; import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; import forge.util.MyRandom; +import forge.util.collect.FCollection; /** *

@@ -312,15 +314,8 @@ public class TokenAi extends SpellAbilityAi { */ @Override protected Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable options, Map params) { - Combat combat = ai.getGame().getCombat(); - // TokenAttacking - if (combat != null && sa.hasParam("TokenAttacking")) { - Card attacker = spawnToken(ai, sa); - for (Player p : options) { - if (!ComputerUtilCard.canBeBlockedProfitably(p, attacker)) { - return p; - } - } + if (params.containsKey("Attacker")) { + return (Player) ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), new FCollection(options)); } return Iterables.getFirst(options, null); } @@ -330,28 +325,11 @@ public class TokenAi extends SpellAbilityAi { */ @Override protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable options, Map params) { - Combat combat = ai.getGame().getCombat(); - // TokenAttacking - if (combat != null && sa.hasParam("TokenAttacking")) { - // 1. If the card that spawned the token was sent at a planeswalker, attack the same planeswalker with the token. Consider improving. - GameEntity def = combat.getDefenderByAttacker(sa.getHostCard()); - if (def != null && def instanceof Card) { - if (((Card)def).isPlaneswalker()) { - return def; - } - } - // 2. Otherwise, go through the list of options one by one, choose the first one that can't be blocked profitably. - Card attacker = spawnToken(ai, sa); - for (GameEntity p : options) { - if (p instanceof Player && !ComputerUtilCard.canBeBlockedProfitably((Player)p, attacker)) { - return p; - } - if (p instanceof Card && !ComputerUtilCard.canBeBlockedProfitably(((Card)p).getController(), attacker)) { - return p; - } - } + if (params.containsKey("Attacker")) { + return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), new FCollection(options)); } - return Iterables.getFirst(options, null); + // should not be reached + return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params); } /** diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 9d3a3454e2d..f158cfcb9be 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -412,7 +412,7 @@ public class GameAction { CardCollection cards = new CardCollection(c.getMergedCards()); // replace top card with copied card for correct name for human to choose. cards.set(cards.indexOf(c), copied); - // 721.3b + // 723.3b if (cause != null && zoneTo.getZoneType() == ZoneType.Exile) { cards = (CardCollection) cause.getHostCard().getController().getController().orderMoveToZoneList(cards, zoneTo.getZoneType(), cause); } else { diff --git a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java index 367123c77ff..17d541ee3be 100644 --- a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java +++ b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java @@ -575,14 +575,14 @@ public abstract class SpellAbilityEffect { FCollection defs = null; // important to update defenders here, maybe some PW got removed combat.initConstraints(); - if ("True".equalsIgnoreCase(attacking)) { - defs = (FCollection) combat.getDefenders(); - } else if (sa.hasParam("ChoosePlayerOrPlaneswalker")) { + if (sa.hasParam("ChoosePlayerOrPlaneswalker")) { PlayerCollection defendingPlayers = AbilityUtils.getDefinedPlayers(host, attacking, sa); defs = new FCollection<>(); for (Player p : defendingPlayers) { defs.addAll(game.getCombat().getDefendersControlledBy(p)); } + } else if ("True".equalsIgnoreCase(attacking)) { + defs = (FCollection) combat.getDefenders(); } else { defs = AbilityUtils.getDefinedEntities(host, attacking, sa); } @@ -593,8 +593,7 @@ public abstract class SpellAbilityEffect { Player chooser; if (sa.hasParam("Chooser")) { chooser = Iterables.getFirst(AbilityUtils.getDefinedPlayers(host, sa.getParam("Chooser"), sa), null); - } - else { + } else { chooser = controller; } defender = chooser.getController().chooseSingleEntityForEffect(defs, sa, diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java index 81f41238da0..2c853f6afa9 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DigUntilEffect.java @@ -164,7 +164,6 @@ public class DigUntilEffect extends SpellAbilityEffect { game.getAction().reveal(revealed, p, false); } - if (foundDest != null) { // Allow ordering of found cards if ((foundDest.isKnown()) && found.size() >= 2 && !foundDest.equals(ZoneType.Exile)) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java index 772e44c3168..7e6d66e5bd4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DrawEffect.java @@ -52,7 +52,7 @@ public class DrawEffect extends SpellAbilityEffect { int actualNum = numCards; if (upto) { - actualNum = p.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblHowManyCardDoYouWantDraw"),0, numCards); + actualNum = p.getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblHowManyCardDoYouWantDraw"), 0, numCards); } final CardCollectionView drawn = p.drawCards(actualNum, sa); diff --git a/forge-game/src/main/java/forge/game/cost/CostReturn.java b/forge-game/src/main/java/forge/game/cost/CostReturn.java index 4b6b4091370..7cceba28bc5 100644 --- a/forge-game/src/main/java/forge/game/cost/CostReturn.java +++ b/forge-game/src/main/java/forge/game/cost/CostReturn.java @@ -132,7 +132,6 @@ public class CostReturn extends CostPartWithList { return "ReturnedCards"; } - public T accept(ICostVisitor visitor) { return visitor.visit(this); } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java b/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java index 71e87b7e556..698066c157f 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java @@ -294,7 +294,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables { } if (this.getShareAllColors() != null) { - List tgts = AbilityUtils.getDefinedCards(sa.getHostCard(), this.getShareAllColors(), sa); + List tgts = AbilityUtils.getDefinedCards(host, this.getShareAllColors(), sa); Card first = Iterables.getFirst(tgts, null); if (first == null) { return false; @@ -324,11 +324,11 @@ public class SpellAbilityCondition extends SpellAbilityVariables { return false; } - if ((this.getActivationLimit() != -1) && (sa.getActivationsThisTurn() >= this.getActivationLimit())) { + if (this.getActivationLimit() != -1 && sa.getActivationsThisTurn() >= this.getActivationLimit()) { return false; } - if ((this.getGameActivationLimit() != -1) && (sa.getActivationsThisGame() >= this.getGameActivationLimit())) { + if (this.getGameActivationLimit() != -1 && sa.getActivationsThisGame() >= this.getGameActivationLimit()) { return false; } @@ -352,7 +352,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables { } if (this.getColorToCheck() != null) { - if (!sa.getHostCard().hasChosenColor(this.getColorToCheck())) { + if (!host.hasChosenColor(this.getColorToCheck())) { return false; } } @@ -365,7 +365,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables { list = new FCollection(game.getCardsIn(getPresentZone())); } - final int left = Iterables.size(Iterables.filter(list, GameObjectPredicates.restriction(getIsPresent().split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa))); + final int left = Iterables.size(Iterables.filter(list, GameObjectPredicates.restriction(getIsPresent().split(","), sa.getActivatingPlayer(), host, sa))); final String rightString = this.getPresentCompare().substring(2); int right = AbilityUtils.calculateAmount(host, rightString, sa); @@ -378,9 +378,9 @@ public class SpellAbilityCondition extends SpellAbilityVariables { if (this.getPlayerContains() != null) { List list = new ArrayList<>(); if (this.getPlayerDefined() != null) { - list.addAll(AbilityUtils.getDefinedPlayers(sa.getHostCard(), this.getPlayerDefined(), sa)); + list.addAll(AbilityUtils.getDefinedPlayers(host, this.getPlayerDefined(), sa)); } - List contains = AbilityUtils.getDefinedPlayers(sa.getHostCard(), this.getPlayerContains(), sa); + List contains = AbilityUtils.getDefinedPlayers(host, this.getPlayerContains(), sa); if (contains.isEmpty() || !list.containsAll(contains)) { return false; } @@ -417,7 +417,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables { boolean result = false; for (final GameObject o : matchTgt.getFirstTargetedSpell().getTargets()) { - if (o.isValid(this.getTargetValidTargeting().split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa)) { + if (o.isValid(this.getTargetValidTargeting().split(","), sa.getActivatingPlayer(), host, sa)) { result = true; break; } @@ -448,7 +448,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables { } if (StringUtils.isNotEmpty(getManaSpent())) { - SpellAbility castSa = sa.getHostCard().getCastSA(); + SpellAbility castSa = host.getCastSA(); if (castSa == null) { return false; } @@ -457,7 +457,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables { } } if (StringUtils.isNotEmpty(getManaNotSpent())) { - SpellAbility castSa = sa.getHostCard().getCastSA(); + SpellAbility castSa = host.getCastSA(); if (castSa != null && castSa.getPayingColors().hasAllColors(ColorSet.fromNames(getManaNotSpent().split(" ")).getColor())) { return false; } diff --git a/forge-gui/res/cardsfolder/a/adeline_resplendent_cathar.txt b/forge-gui/res/cardsfolder/a/adeline_resplendent_cathar.txt index caf8200d7ff..55e8eb7cb1c 100644 --- a/forge-gui/res/cardsfolder/a/adeline_resplendent_cathar.txt +++ b/forge-gui/res/cardsfolder/a/adeline_resplendent_cathar.txt @@ -5,8 +5,8 @@ PT:*/4 K:Vigilance S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | Description$ CARDNAME's power is equal to the number of creatures you control. SVar:X:Count$Valid Creature.YouCtrl -T:Mode$ AttackersDeclared | AttackingPlayer$ You | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever you attack, for each opponent, create a 1/1 white Human creature token that's tapped and attacking that player or a planeswalker they control. -SVar:TrigToken:DB$ Token | TokenAmount$ Y | TokenScript$ w_1_1_human | TokenTapped$ True | TokenAttacking$ True | ChoosePlayerOrPlaneswalker$ True | TokenOwner$ You -SVar:Y:PlayerCountOpponents$Amount +T:Mode$ AttackersDeclared | AttackingPlayer$ You | Execute$ DBRepeat | TriggerZones$ Battlefield | TriggerDescription$ Whenever you attack, for each opponent, create a 1/1 white Human creature token that's tapped and attacking that player or a planeswalker they control. +SVar:DBRepeat:DB$ RepeatEach | RepeatPlayers$ Opponent | ChangeZoneTable$ True | RepeatSubAbility$ DBToken +SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_human | TokenTapped$ True | TokenAttacking$ Remembered | ChoosePlayerOrPlaneswalker$ True | TokenOwner$ You DeckHas:Ability$Token Oracle:Vigilance\nAdeline, Resplendent Cathar's power is equal to the number of creatures you control.\nWhenever you attack, for each opponent, create a 1/1 white Human creature token that's tapped and attacking that player or a planeswalker they control. diff --git a/forge-gui/res/cardsfolder/c/conflagrate.txt b/forge-gui/res/cardsfolder/c/conflagrate.txt index c137e495ebd..1be51079fd0 100644 --- a/forge-gui/res/cardsfolder/c/conflagrate.txt +++ b/forge-gui/res/cardsfolder/c/conflagrate.txt @@ -5,5 +5,5 @@ A:SP$ DealDamage | Cost$ X X R | ValidTgts$ Creature,Player,Planeswalker | TgtPr SVar:MaxTgts:PlayerCountPlayers$Amount/Plus.NumCreatures SVar:NumCreatures:Count$Valid Creature,Planeswalker SVar:X:Count$xPaid -K:Flashback:R R Discard +K:Flashback:R R Discard Oracle:Conflagrate deals X damage divided as you choose among any number of targets.\nFlashback—{R}{R}, Discard X cards. (You may cast this card from your graveyard for its flashback cost. Then exile it.) diff --git a/forge-gui/res/cardsfolder/e/elaborate_firecannon.txt b/forge-gui/res/cardsfolder/e/elaborate_firecannon.txt index f1d645f3b74..e6169949b0c 100644 --- a/forge-gui/res/cardsfolder/e/elaborate_firecannon.txt +++ b/forge-gui/res/cardsfolder/e/elaborate_firecannon.txt @@ -4,6 +4,6 @@ Types:Artifact K:CARDNAME doesn't untap during your untap step. A:AB$ DealDamage | Cost$ 4 T | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 2 | SpellDescription$ CARDNAME deals 2 damage to any target. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigUntap | TriggerDescription$ At the beginning of your upkeep, you may discard a card. If you do, untap CARDNAME. -SVar:TrigUntap:AB$Untap | Cost$ Discard<1/Card> | Defined$ Self +SVar:TrigUntap:AB$ Untap | Cost$ Discard<1/Card> | Defined$ Self SVar:Picture:http://www.wizards.com/global/images/magic/general/elaborate_firecannon.jpg Oracle:Elaborate Firecannon doesn't untap during your untap step.\n{4}, {T}: Elaborate Firecannon deals 2 damage to any target.\nAt the beginning of your upkeep, you may discard a card. If you do, untap Elaborate Firecannon. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/f/felidar_sovereign.txt b/forge-gui/res/cardsfolder/f/felidar_sovereign.txt index 96f01bb833b..ce06505d067 100644 --- a/forge-gui/res/cardsfolder/f/felidar_sovereign.txt +++ b/forge-gui/res/cardsfolder/f/felidar_sovereign.txt @@ -4,7 +4,7 @@ Types:Creature Cat Beast PT:4/6 K:Vigilance K:Lifelink -T:Mode$Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | LifeTotal$ You | LifeAmount$ GE40 | Execute$ TrigWin | TriggerDescription$ At the beginning of your upkeep, if you have 40 or more life, you win the game. +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | LifeTotal$ You | LifeAmount$ GE40 | Execute$ TrigWin | TriggerDescription$ At the beginning of your upkeep, if you have 40 or more life, you win the game. SVar:TrigWin:DB$ WinsGame | Defined$ You DeckHints:Ability$LifeGain SVar:Picture:http://www.wizards.com/global/images/magic/general/felidar_sovereign.jpg diff --git a/forge-gui/res/cardsfolder/g/gigapede.txt b/forge-gui/res/cardsfolder/g/gigapede.txt index 3d9debf3b35..ee79e0eaec6 100644 --- a/forge-gui/res/cardsfolder/g/gigapede.txt +++ b/forge-gui/res/cardsfolder/g/gigapede.txt @@ -3,7 +3,7 @@ ManaCost:3 G G Types:Creature Insect PT:6/1 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Graveyard | IsPresent$ Card.StrictlySelf | PresentZone$ Graveyard | PresentPlayer$ You | OptionalDecider$ You | Execute$ TrigChange | TriggerDescription$ At the beginning of your upkeep, if CARDNAME is in your graveyard, you may discard a card. If you do, return CARDNAME to your hand. -SVar:TrigChange:AB$ChangeZone | Cost$ Discard<1/Card> | Origin$ Graveyard | Destination$ Hand | Defined$ Self +SVar:TrigChange:AB$ ChangeZone | Cost$ Discard<1/Card> | Origin$ Graveyard | Destination$ Hand | Defined$ Self K:Shroud SVar:Picture:http://www.wizards.com/global/images/magic/general/gigapede.jpg Oracle:Shroud (This creature can't be the target of spells or abilities.)\nAt the beginning of your upkeep, if Gigapede is in your graveyard, you may discard a card. If you do, return Gigapede to your hand.