diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 437618ecf5e..ab1b0f333e9 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -992,12 +992,17 @@ public class AbilityUtils { */ public static PlayerCollection getDefinedPlayers(final Card card, final String def, final CardTraitBase sa) { final PlayerCollection players = new PlayerCollection(); - final String defined = (def == null) ? "You" : applyAbilityTextChangeEffects(def, sa); + String changedDef = (def == null) ? "You" : applyAbilityTextChangeEffects(def, sa); // default to Self + final String[] incR = changedDef.split("\\.", 2); + String defined = incR[0]; + final Game game = card == null ? null : card.getGame(); final Player player = sa instanceof SpellAbility ? ((SpellAbility)sa).getActivatingPlayer() : card.getController(); - if (defined.equals("TargetedOrController")) { + if (defined.equals("Self")) { + // do nothing, Self is for Cards, not Players + } else if (defined.equals("TargetedOrController")) { players.addAll(getDefinedPlayers(card, "Targeted", sa)); players.addAll(getDefinedPlayers(card, "TargetedController", sa)); } @@ -1056,6 +1061,15 @@ public class AbilityUtils { else if (defined.startsWith("Remembered")) { addPlayer(card.getRemembered(), defined, players); } + else if (defined.startsWith("Imprinted")) { + addPlayer(Lists.newArrayList(card.getImprintedCards()), defined, players); + } + else if (defined.startsWith("EffectSource")) { + Card root = findEffectRoot(card); + if (root != null) { + addPlayer(Lists.newArrayList(root), defined, players); + } + } else if (defined.startsWith("DelayTriggerRemembered") && sa instanceof SpellAbility) { SpellAbility root = ((SpellAbility)sa).getRootAbility(); if (root != null) { @@ -1064,16 +1078,6 @@ public class AbilityUtils { System.err.println("Warning: couldn't find trigger SA in the chain of SpellAbility " + sa); } } - else if (defined.equals("ImprintedController")) { - for (final Card rem : card.getImprintedCards()) { - players.add(rem.getController()); - } - } - else if (defined.equals("ImprintedOwner")) { - for (final Card rem : card.getImprintedCards()) { - players.add(rem.getOwner()); - } - } else if (defined.startsWith("Triggered") && sa instanceof SpellAbility) { String defParsed = defined.endsWith("AndYou") ? defined.substring(0, defined.indexOf("AndYou")) : defined; if (defined.endsWith("AndYou")) { @@ -1096,7 +1100,7 @@ public class AbilityUtils { o = ((CardCollection) c).get(0).getController(); } } - else if (defParsed.endsWith("Opponent") && !defParsed.endsWith("IfOpponent")) { + else if (defParsed.endsWith("Opponent")) { String triggeringType = defParsed.substring(9); triggeringType = triggeringType.substring(0, triggeringType.length() - 8); final Object c = root.getTriggeringObject(AbilityKey.fromString(triggeringType)); @@ -1125,21 +1129,7 @@ public class AbilityUtils { } else { String triggeringType = defParsed.substring(9); - String filter = null; - if (triggeringType.contains("=")) { - filter = triggeringType.split("If")[1]; - triggeringType = triggeringType.split("If")[0]; - } o = root.getTriggeringObject(AbilityKey.fromString(triggeringType)); - if (filter != null) { - if (filter.equals("Opponent")) { - if (!((Player)o).isOpponentOf(((SpellAbility) sa).getActivatingPlayer())) { - o = null; - } - } else { - System.err.println("getDefinedPlayers needs additional code for =Filter"); - } - } } if (o != null) { if (o instanceof Player) { @@ -1190,29 +1180,26 @@ public class AbilityUtils { players.addAll(game.getPlayersInTurnOrder()); players.removeAll((FCollectionView)getDefinedPlayers(card, defined.substring(3), sa)); } - else if (defined.equals("EnchantedController")) { - if (card.getEnchantingCard() == null) { - return players; - } - players.add(card.getEnchantingCard().getController()); - } - else if (defined.equals("EnchantedOwner")) { - if (card.getEnchantingCard() == null) { - return players; - } - players.add(card.getEnchantingCard().getOwner()); - } else if (defined.equals("EnchantedPlayer")) { final Object o = sa.getHostCard().getEntityAttachedTo(); if (o instanceof Player) { players.add((Player) o); } } - else if (defined.equals("AttackingPlayer")) { - if (!game.getPhaseHandler().inCombat()) { - return players; + else if (defined.startsWith("Enchanted")) { + if (card.getEntityAttachedTo() != null) { + addPlayer(Lists.newArrayList(card.getEntityAttachedTo()), defined, players); + } + } + else if (defined.startsWith("Equipped")) { + if (card.getEquipping() != null) { + addPlayer(Lists.newArrayList(card.getEquipping()), defined, players); + } + } + else if (defined.equals("AttackingPlayer")) { + if (game.getPhaseHandler().inCombat()) { + players.add(game.getCombat().getAttackingPlayer()); } - players.add(game.getCombat().getAttackingPlayer()); } else if (defined.equals("DefendingPlayer")) { players.add(game.getCombat().getDefendingPlayerRelatedTo(card)); @@ -1264,8 +1251,10 @@ public class AbilityUtils { } } } - else if (defined.equals("Caster") && sa.getHostCard().wasCast()) { - players.add((sa.getHostCard().getCastSA().getActivatingPlayer())); + else if (defined.equals("Caster")) { + if (sa.getHostCard().wasCast()) { + players.add((sa.getHostCard().getCastSA().getActivatingPlayer())); + } } else if (defined.equals("ActivePlayer")) { players.add(game.getPhaseHandler().getPlayerTurn()); @@ -1281,11 +1270,17 @@ public class AbilityUtils { players.add(game.getNextPlayerAfter(player, dir)); } else { - for (Player p : game.getPlayersInTurnOrder()) { - if (p.isValid(defined, player, card, sa)) { - players.add(p); - } + // will be filtered below + players.addAll(game.getPlayersInTurnOrder()); + } + + if (incR.length > 1 && !players.isEmpty()) { + String[] valids = incR[1].split(","); + // need to add valids onto all of them + for (int i = 0; i < valids.length; i++) { + valids[i] = "Player." + valids[i]; } + return players.filter(PlayerPredicates.restriction(valids, player, card, sa)); } return players; } diff --git a/forge-game/src/main/java/forge/game/player/PlayerPredicates.java b/forge-game/src/main/java/forge/game/player/PlayerPredicates.java index 021a6ce959f..049550ddf55 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerPredicates.java +++ b/forge-game/src/main/java/forge/game/player/PlayerPredicates.java @@ -5,6 +5,7 @@ import java.util.Comparator; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import forge.game.CardTraitBase; import forge.game.card.Card; import forge.game.card.CardLists; import forge.game.card.CounterEnumType; @@ -129,6 +130,15 @@ public final class PlayerPredicates { }; } + public static final Predicate restriction(final String[] restrictions, final Player sourceController, final Card source, final CardTraitBase spellAbility) { + return new Predicate() { + @Override + public boolean apply(final Player c) { + return c != null && c.isValid(restrictions, sourceController, source, spellAbility); + } + }; + } + public static final Comparator compareByZoneSize(final ZoneType zone) { return new Comparator() { @Override diff --git a/forge-gui/res/cardsfolder/c/curse_of_bounty.txt b/forge-gui/res/cardsfolder/c/curse_of_bounty.txt index e64645f2ff4..84a46100c00 100644 --- a/forge-gui/res/cardsfolder/c/curse_of_bounty.txt +++ b/forge-gui/res/cardsfolder/c/curse_of_bounty.txt @@ -5,5 +5,5 @@ K:Enchant player A:SP$ Attach | ValidTgts$ Player | AILogic$ Curse T:Mode$ AttackersDeclared | ValidCard$ Creature | AttackedTarget$ Player.EnchantedBy | Execute$ TrigUntap | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted player is attacked, untap all nonland permanents you control. Each opponent attacking that player untaps all nonland permanents they control. SVar:TrigUntap:DB$ UntapAll | Defined$ You | ValidCards$ Permanent.nonLand | SubAbility$ DBUntap -SVar:DBUntap:DB$ UntapAll | Defined$ TriggeredAttackingPlayerIfOpponent | ValidCards$ Permanent.nonLand +SVar:DBUntap:DB$ UntapAll | Defined$ TriggeredAttackingPlayer.Opponent | ValidCards$ Permanent.nonLand Oracle:Enchant player\nWhenever enchanted player is attacked, untap all nonland permanents you control. Each opponent attacking that player untaps all nonland permanents they control. diff --git a/forge-gui/res/cardsfolder/c/curse_of_disturbance.txt b/forge-gui/res/cardsfolder/c/curse_of_disturbance.txt index df53532df34..993e35964ec 100644 --- a/forge-gui/res/cardsfolder/c/curse_of_disturbance.txt +++ b/forge-gui/res/cardsfolder/c/curse_of_disturbance.txt @@ -5,5 +5,5 @@ K:Enchant player A:SP$ Attach | ValidTgts$ Player | AILogic$ Curse T:Mode$ AttackersDeclared | ValidCard$ Creature | AttackedTarget$ Player.EnchantedBy | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted player is attacked, create a 2/2 black Zombie creature token. Each opponent attacking that player does the same. SVar:TrigToken:DB$ Token | TokenScript$ b_2_2_zombie | SubAbility$ DBToken -SVar:DBToken:DB$ Token | TokenOwner$ TriggeredAttackingPlayerIfOpponent | TokenScript$ b_2_2_zombie +SVar:DBToken:DB$ Token | TokenOwner$ TriggeredAttackingPlayer.Opponent | TokenScript$ b_2_2_zombie Oracle:Enchant player\nWhenever enchanted player is attacked, create a 2/2 black Zombie creature token. Each opponent attacking that player does the same. diff --git a/forge-gui/res/cardsfolder/c/curse_of_opulence.txt b/forge-gui/res/cardsfolder/c/curse_of_opulence.txt index 5a073423ab2..14880a5cd66 100644 --- a/forge-gui/res/cardsfolder/c/curse_of_opulence.txt +++ b/forge-gui/res/cardsfolder/c/curse_of_opulence.txt @@ -5,5 +5,5 @@ K:Enchant player A:SP$ Attach | ValidTgts$ Player | AILogic$ Curse T:Mode$ AttackersDeclared | ValidCard$ Creature | AttackedTarget$ Player.EnchantedBy | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted player is attacked, create a Gold token. Each opponent attacking that player does the same. (A Gold token is an artifact with "Sacrifice this artifact: Add one mana of any color.") SVar:TrigToken:DB$ Token | TokenScript$ c_a_gold_draw | SubAbility$ DBToken -SVar:DBToken:DB$ Token | TokenOwner$ TriggeredAttackingPlayerIfOpponent | TokenScript$ c_a_gold_draw +SVar:DBToken:DB$ Token | TokenOwner$ TriggeredAttackingPlayer.Opponent | TokenScript$ c_a_gold_draw Oracle:Enchant player\nWhenever enchanted player is attacked, create a Gold token. Each opponent attacking that player does the same. (A Gold token is an artifact with "Sacrifice this artifact: Add one mana of any color.") diff --git a/forge-gui/res/cardsfolder/c/curse_of_verbosity.txt b/forge-gui/res/cardsfolder/c/curse_of_verbosity.txt index c9503bf4ca1..af3c937184b 100644 --- a/forge-gui/res/cardsfolder/c/curse_of_verbosity.txt +++ b/forge-gui/res/cardsfolder/c/curse_of_verbosity.txt @@ -5,5 +5,5 @@ K:Enchant player A:SP$ Attach | ValidTgts$ Player | AILogic$ Curse T:Mode$ AttackersDeclared | ValidCard$ Creature | AttackedTarget$ Player.EnchantedBy | Execute$ TrigRepeat | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted player is attacked, draw a card. Each opponent attacking that player does the same. SVar:TrigDraw:DB$ Draw | NumCards$ 1 | Defined$ You -SVar:DBDraw:DB$ Draw | NumCards$ 1 | Defined$ TriggeredAttackingPlayerIfOpponent +SVar:DBDraw:DB$ Draw | NumCards$ 1 | Defined$ TriggeredAttackingPlayer.Opponent Oracle:Enchant player\nWhenever enchanted player is attacked, you draw a card. Each opponent attacking that player does the same. diff --git a/forge-gui/res/cardsfolder/c/curse_of_vitality.txt b/forge-gui/res/cardsfolder/c/curse_of_vitality.txt index acb55715ac5..8a5b73f6b5b 100644 --- a/forge-gui/res/cardsfolder/c/curse_of_vitality.txt +++ b/forge-gui/res/cardsfolder/c/curse_of_vitality.txt @@ -5,6 +5,6 @@ K:Enchant player A:SP$ Attach | ValidTgts$ Player | AILogic$ Curse T:Mode$ AttackersDeclared | ValidCard$ Creature | AttackedTarget$ Player.EnchantedBy | Execute$ TrigGainLife | TriggerZones$ Battlefield | TriggerDescription$ Whenever enchanted player is attacked, you gain 2 life. Each opponent attacking that player does the same. SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SubAbility$ DBGainLife -SVar:DBGainLife:DB$ GainLife | Defined$ TriggeredAttackingPlayerIfOpponent | LifeAmount$ 2 +SVar:DBGainLife:DB$ GainLife | Defined$ TriggeredAttackingPlayer.Opponent | LifeAmount$ 2 DeckHas:Ability$LifeGain Oracle:Enchant player\nWhenever enchanted player is attacked, you gain 2 life. Each opponent attacking that player does the same.