diff --git a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java index 6366da9e194..7fabfae3974 100644 --- a/forge-ai/src/main/java/forge/ai/SpecialCardAi.java +++ b/forge-ai/src/main/java/forge/ai/SpecialCardAi.java @@ -738,12 +738,11 @@ public class SpecialCardAi { // Grothama, All-Devouring public static class GrothamaAllDevouring { public static boolean consider(final Player ai, final SpellAbility sa) { - final Card source = sa.getHostCard(); - final Card devourer = AbilityUtils.getDefinedCards(source, sa.getParam("ExtraDefined"), sa).getFirst(); // maybe just getOriginalHost()? + final Card fighter = sa.getHostCard(); + final Card devourer = sa.getOriginalHost(); if (ai.getTeamMates(true).contains(devourer.getController())) { return false; // TODO: Currently, the AI doesn't ever fight its own (or allied) Grothama for card draw. This can be improved. } - final Card fighter = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa).getFirst(); boolean goodTradeOrNoTrade = devourer.canBeDestroyed() && (devourer.getNetPower() < fighter.getNetToughness() || !fighter.canBeDestroyed() || ComputerUtilCard.evaluateCreature(devourer) > ComputerUtilCard.evaluateCreature(fighter)); return goodTradeOrNoTrade && fighter.getNetPower() >= devourer.getNetToughness(); 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 be7cd298c57..1949e29fa60 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -825,8 +825,8 @@ public class AbilityUtils { return objects; } - public static FCollection getDefinedEntities(final Card card, final String[] def, final CardTraitBase sa) { - final FCollection objects = new FCollection<>(); + public static List getDefinedEntities(final Card card, final String[] def, final CardTraitBase sa) { + final List objects = new ArrayList<>(); for (String d : def) { objects.addAll(AbilityUtils.getDefinedEntities(card, d, sa)); } 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 c3e4c26ba42..261f59cf419 100644 --- a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java +++ b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java @@ -206,16 +206,44 @@ public abstract class SpellAbilityEffect { protected final static CardCollection getDefinedCardsOrTargeted(final SpellAbility sa) { return getCards(true, "Defined", sa); } protected final static CardCollection getDefinedCardsOrTargeted(final SpellAbility sa, final String definedParam) { return getCards(true, definedParam, sa); } + protected static List getTargetCardsWithDuplicates(final boolean definedFirst, final String definedParam, final SpellAbility sa) { + List result = Lists.newArrayList(); + getCards(definedFirst, definedParam, sa, result); + return result; + } + + // overloaded variant that returns the unique objects instead of filling a result list private static CardCollection getCards(final boolean definedFirst, final String definedParam, final SpellAbility sa) { + return getCards(definedFirst, definedParam, sa, null); + } + private static CardCollection getCards(final boolean definedFirst, final String definedParam, final SpellAbility sa, List resultDuplicate) { if (sa.hasParam("ThisDefinedAndTgts")) { - CardCollection cards = - AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("ThisDefinedAndTgts"), sa); + CardCollection cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("ThisDefinedAndTgts"), sa); cards.addAll(sa.getTargets().getTargetCards()); return cards; } + + CardCollection resultUnique = null; final boolean useTargets = sa.usesTargeting() && (!definedFirst || !sa.hasParam(definedParam)); - return useTargets ? new CardCollection(sa.getTargets().getTargetCards()) - : AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam(definedParam), sa); + if (useTargets) { + if (resultDuplicate == null) { + resultUnique = new CardCollection(); + resultDuplicate = resultUnique; + } + Iterables.addAll(resultDuplicate, sa.getTargets().getTargetCards()); + } else { + String[] def = sa.getParamOrDefault(definedParam, "Self").split(" & "); + for (String d : def) { + CardCollection defResult = AbilityUtils.getDefinedCards(sa.getHostCard(), d, sa); + if (resultDuplicate == null) { + resultUnique = defResult; + resultDuplicate = resultUnique; + } else { + resultDuplicate.addAll(defResult); + } + } + } + return resultUnique; } // Players @@ -224,16 +252,44 @@ public abstract class SpellAbilityEffect { protected final static PlayerCollection getDefinedPlayersOrTargeted(final SpellAbility sa) { return getPlayers(true, "Defined", sa); } protected final static PlayerCollection getDefinedPlayersOrTargeted(final SpellAbility sa, final String definedParam) { return getPlayers(true, definedParam, sa); } + protected static List getTargetPlayersWithDuplicates(final boolean definedFirst, final String definedParam, final SpellAbility sa) { + List result = Lists.newArrayList(); + getPlayers(definedFirst, definedParam, sa, result); + return result; + } + + // overloaded variant that returns the unique objects instead of filling a result list private static PlayerCollection getPlayers(final boolean definedFirst, final String definedParam, final SpellAbility sa) { + return getPlayers(definedFirst, definedParam, sa, null); + } + private static PlayerCollection getPlayers(final boolean definedFirst, final String definedParam, final SpellAbility sa, List resultDuplicate) { + PlayerCollection resultUnique = null; final boolean useTargets = sa.usesTargeting() && (!definedFirst || !sa.hasParam(definedParam)); - PlayerCollection players = useTargets ? new PlayerCollection(sa.getTargets().getTargetPlayers()) - : AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam(definedParam), sa); - // try sort in APNAP order - int indexAP = players.indexOf(sa.getHostCard().getGame().getPhaseHandler().getPlayerTurn()); - if (indexAP != -1) { - Collections.rotate(players, - indexAP); + if (useTargets) { + if (resultDuplicate == null) { + resultUnique = new PlayerCollection(); + resultDuplicate = resultUnique; + } + Iterables.addAll(resultDuplicate, sa.getTargets().getTargetPlayers()); + } else { + String[] def = sa.getParamOrDefault(definedParam, "You").split(" & "); + for (String d : def) { + PlayerCollection defResult = AbilityUtils.getDefinedPlayers(sa.getHostCard(), d, sa); + if (resultDuplicate == null) { + resultUnique = defResult; + resultDuplicate = resultUnique; + } else { + resultDuplicate.addAll(defResult); + } + } } - return players; + + // try sort in APNAP order + int indexAP = resultDuplicate.indexOf(sa.getHostCard().getGame().getPhaseHandler().getPlayerTurn()); + if (indexAP != -1) { + Collections.rotate(resultDuplicate, - indexAP); + } + return resultUnique; } // Spells @@ -624,21 +680,19 @@ public abstract class SpellAbilityEffect { String attacking = sa.getParam(attackingParam); GameEntity defender = null; - FCollection defs = null; + FCollection defs = new FCollection<>(); // important to update defenders here, maybe some PW got removed combat.initConstraints(); if ("True".equalsIgnoreCase(attacking)) { - defs = (FCollection) combat.getDefenders(); + defs.addAll(combat.getDefenders()); } else { - defs = AbilityUtils.getDefinedEntities(sa.hasParam("ForEach") ? c : host, attacking.split(","), sa); + defs.addAll(AbilityUtils.getDefinedEntities(sa.hasParam("ForEach") ? c : host, attacking.split("&"), sa)); } - if (defs != null) { - Map params = Maps.newHashMap(); - params.put("Attacker", c); - defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(defs, sa, - Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), false, params); - } + Map params = Maps.newHashMap(); + params.put("Attacker", c); + defender = sa.getActivatingPlayer().getController().chooseSingleEntityForEffect(defs, sa, + Localizer.getInstance().getMessage("lblChooseDefenderToAttackWithCard", CardTranslation.getTranslatedName(c.getName())), false, params); final GameEntity originalDefender = combat.getDefenderByAttacker(c); if (defender != null && 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 d67830d3895..79c8163e45f 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 @@ -1,8 +1,11 @@ package forge.game.ability.effects; +import java.util.Collections; import java.util.List; import java.util.Map; +import com.google.common.collect.Sets; + import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; @@ -53,7 +56,6 @@ public class DrawEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { final Card source = sa.getHostCard(); - final int numCards = sa.hasParam("NumCards") ? AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumCards"), sa) : 1; final boolean upto = sa.hasParam("Upto"); final boolean optional = sa.hasParam("OptionalDecider") || upto; @@ -61,11 +63,16 @@ public class DrawEffect extends SpellAbilityEffect { moveParams.put(AbilityKey.LastStateBattlefield, sa.getLastStateBattlefield()); moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); - for (final Player p : getDefinedPlayersOrTargeted(sa)) { + final List tgts = getTargetPlayersWithDuplicates(true, "Defined", sa); + + for (final Player p : Sets.newHashSet(tgts)) { if (!p.isInGame()) { continue; } + int numCards = sa.hasParam("NumCards") ? AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("NumCards"), sa) : 1; + numCards *= Collections.frequency(tgts, p); + // it is optional, not upto and player can't choose to draw that many cards if (optional && !upto && !p.canDrawAmount(numCards)) { continue; diff --git a/forge-game/src/main/java/forge/game/ability/effects/FightEffect.java b/forge-game/src/main/java/forge/game/ability/effects/FightEffect.java index b4ab672fa2f..4e27d42bfe4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/FightEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/FightEffect.java @@ -98,11 +98,8 @@ public class FightEffect extends DamageBaseEffect { } } if (sa.hasParam("Defined")) { - List defined = AbilityUtils.getDefinedCards(host, sa.getParam("Defined"), sa); + List defined = getTargetCardsWithDuplicates(true, "Defined", sa); // Allow both fighters to come from defined list if first fighter not already found - if (sa.hasParam("ExtraDefined")) { - defined.addAll(AbilityUtils.getDefinedCards(host, sa.getParam("ExtraDefined"), sa)); - } List newDefined = Lists.newArrayList(); for (final Card d : defined) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/LifeGainEffect.java b/forge-game/src/main/java/forge/game/ability/effects/LifeGainEffect.java index e89d1025d0b..4cd41608298 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/LifeGainEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/LifeGainEffect.java @@ -5,8 +5,14 @@ import forge.game.ability.SpellAbilityEffect; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.util.Lang; + +import java.util.Collections; +import java.util.List; + import org.apache.commons.lang3.StringUtils; +import com.google.common.collect.Sets; + public class LifeGainEffect extends SpellAbilityEffect { /* (non-Javadoc) @@ -44,21 +50,20 @@ public class LifeGainEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { String amount = sa.getParam("LifeAmount"); boolean variableAmount = amount.equals("AFNotDrawnNum"); - int lifeAmount = 0; if (variableAmount) { amount = "X"; - } else { - lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amount, sa); } + final List tgts = getTargetPlayersWithDuplicates(false, "Defined", sa); - for (final Player p : getDefinedPlayersOrTargeted(sa)) { + for (final Player p : Sets.newHashSet(tgts)) { if (!p.isInGame()) { continue; } if (variableAmount) { sa.setSVar("AFNotDrawnNum", sa.getSVar("AFNotDrawnNum_" + p.getId())); - lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amount, sa); } + int lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), amount, sa); + lifeAmount *= Collections.frequency(tgts, p); p.gainLife(lifeAmount, sa.getHostCard(), sa); } } diff --git a/forge-gui/res/cardsfolder/a/adeline_resplendent_cathar.txt b/forge-gui/res/cardsfolder/a/adeline_resplendent_cathar.txt index 3f987c0ba42..e05adab9bee 100644 --- a/forge-gui/res/cardsfolder/a/adeline_resplendent_cathar.txt +++ b/forge-gui/res/cardsfolder/a/adeline_resplendent_cathar.txt @@ -7,6 +7,6 @@ S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ SVar:X:Count$Valid Creature.YouCtrl 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$ Player.IsRemembered,Valid Planeswalker.ControlledBy Remembered | TokenOwner$ You +SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_human | TokenTapped$ True | TokenAttacking$ Player.IsRemembered & Valid Planeswalker.ControlledBy Remembered | 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/a/angel_of_destiny.txt b/forge-gui/res/cardsfolder/a/angel_of_destiny.txt index 848208c7c19..f9f47a7eaf8 100644 --- a/forge-gui/res/cardsfolder/a/angel_of_destiny.txt +++ b/forge-gui/res/cardsfolder/a/angel_of_destiny.txt @@ -5,8 +5,7 @@ PT:2/6 K:Flying K:Double Strike T:Mode$ DamageDone | ValidSource$ Creature.YouCtrl | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigGain | TriggerZones$ Battlefield | TriggerDescription$ Whenever a creature you control deals combat damage to a player, you and that player each gain that much life. -SVar:TrigGain:DB$ GainLife | Defined$ You | LifeAmount$ X | SubAbility$ DBGain -SVar:DBGain:DB$ GainLife | Defined$ TriggeredTarget | LifeAmount$ X +SVar:TrigGain:DB$ GainLife | Defined$ You & TriggeredTarget | LifeAmount$ X SVar:X:TriggerCount$DamageAmount T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | CheckSVar$ Z | SVarCompare$ GEY | Execute$ TrigLose | TriggerDescription$ At the beginning of your end step, if you have at least 15 life more than your starting life total, each player CARDNAME attacked this turn loses the game. SVar:TrigLose:DB$ LosesGame | Defined$ Player.attackedBySourceThisTurn diff --git a/forge-gui/res/cardsfolder/c/conjured_currency.txt b/forge-gui/res/cardsfolder/c/conjured_currency.txt index 5955d36d6e1..4eb303e797d 100644 --- a/forge-gui/res/cardsfolder/c/conjured_currency.txt +++ b/forge-gui/res/cardsfolder/c/conjured_currency.txt @@ -2,6 +2,6 @@ Name:Conjured Currency ManaCost:5 U Types:Enchantment T:Mode$ Phase | Phase$ Upkeep | TriggerZones$ Battlefield | ValidPlayer$ You | Execute$ ExchangeCards | OptionalDecider$ You | TriggerDescription$ At the beginning of your upkeep, you may exchange control of CARDNAME and target permanent you neither own nor control. -SVar:ExchangeCards:DB$ ExchangeControl | Defined$ Self | ValidTgts$ Permanent.YouDontCtrl+YouDontOwn | TgtPrompt$ Select target permanent you neither own nor control | SpellDescription$ Exchange control of CARDNAME and target permanent you neither own nor control. +SVar:ExchangeCards:DB$ ExchangeControl | Defined$ Self | ValidTgts$ Permanent.YouDontCtrl+YouDontOwn | TgtPrompt$ Select target permanent you neither own nor control AI:RemoveDeck:All Oracle:At the beginning of your upkeep, you may exchange control of Conjured Currency and target permanent you neither own nor control. diff --git a/forge-gui/res/cardsfolder/c/cunning_strike.txt b/forge-gui/res/cardsfolder/c/cunning_strike.txt index c799ebb773f..c1af5d2111b 100644 --- a/forge-gui/res/cardsfolder/c/cunning_strike.txt +++ b/forge-gui/res/cardsfolder/c/cunning_strike.txt @@ -1,7 +1,8 @@ Name:Cunning Strike ManaCost:3 U R Types:Instant -A:SP$ DealDamage | Cost$ 3 U R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 2 | SubAbility$ DB1 | SpellDescription$ CARDNAME deals 2 damage to target creature and 2 damage to target player or planeswalker. Draw a card. -SVar:DB1:DB$ DealDamage | NumDmg$ 2 | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | SubAbility$ DBDraw +A:SP$ DealDamage | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 2 | DamageMap$ True | SubAbility$ DB1 | SpellDescription$ CARDNAME deals 2 damage to target creature and 2 damage to target player or planeswalker. Draw a card. +SVar:DB1:DB$ DealDamage | NumDmg$ 2 | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | SubAbility$ DBDamageResolve +SVar:DBDamageResolve:DB$ DamageResolve | SubAbility$ DBDraw SVar:DBDraw:DB$ Draw | NumCards$ 1 Oracle:Cunning Strike deals 2 damage to target creature and 2 damage to target player or planeswalker.\nDraw a card. diff --git a/forge-gui/res/cardsfolder/d/diviner_spirit.txt b/forge-gui/res/cardsfolder/d/diviner_spirit.txt index 4f7d968d2bb..01d99a0610f 100644 --- a/forge-gui/res/cardsfolder/d/diviner_spirit.txt +++ b/forge-gui/res/cardsfolder/d/diviner_spirit.txt @@ -3,7 +3,6 @@ ManaCost:4 U Types:Creature Spirit PT:2/4 T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDraw | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you and that player each draw that many cards. -SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ X | SubAbility$ DBDraw -SVar:DBDraw:DB$ Draw | Defined$ TriggeredTarget | NumCards$ X +SVar:TrigDraw:DB$ Draw | Defined$ You & TriggeredTarget | NumCards$ X SVar:X:TriggerCount$DamageAmount Oracle:Whenever Diviner Spirit deals combat damage to a player, you and that player each draw that many cards. diff --git a/forge-gui/res/cardsfolder/e/ezuris_predation.txt b/forge-gui/res/cardsfolder/e/ezuris_predation.txt index 7565fb1038f..28dd75055f7 100644 --- a/forge-gui/res/cardsfolder/e/ezuris_predation.txt +++ b/forge-gui/res/cardsfolder/e/ezuris_predation.txt @@ -1,9 +1,9 @@ Name:Ezuri's Predation ManaCost:5 G G G Types:Sorcery -A:SP$ RepeatEach | Cost$ 5 G G G | RepeatCards$ Creature.OppCtrl | ChooseOrder$ True | UseImprinted$ True | RepeatSubAbility$ DBToken | ChangeZoneTable$ True | SpellDescription$ For each creature your opponents control, create a 4/4 green Phyrexian Beast creature token. Each of those Beasts fights a different one of those creatures. +A:SP$ RepeatEach | RepeatCards$ Creature.OppCtrl | ChooseOrder$ True | UseImprinted$ True | RepeatSubAbility$ DBToken | ChangeZoneTable$ True | SpellDescription$ For each creature your opponents control, create a 4/4 green Phyrexian Beast creature token. Each of those Beasts fights a different one of those creatures. SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_4_4_phyrexian_beast | TokenOwner$ You | RememberTokens$ True | SubAbility$ DBFight -SVar:DBFight:DB$ Fight | Defined$ Imprinted | ExtraDefined$ Remembered | SubAbility$ DBCleanup +SVar:DBFight:DB$ Fight | Defined$ Imprinted & Remembered | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:NeedsToPlay:Creature.OppCtrl+powerLE3 Oracle:For each creature your opponents control, create a 4/4 green Phyrexian Beast creature token. Each of those Beasts fights a different one of those creatures. diff --git a/forge-gui/res/cardsfolder/f/first_volley.txt b/forge-gui/res/cardsfolder/f/first_volley.txt index 280ecc91002..a1bc3ec8229 100644 --- a/forge-gui/res/cardsfolder/f/first_volley.txt +++ b/forge-gui/res/cardsfolder/f/first_volley.txt @@ -1,6 +1,7 @@ Name:First Volley ManaCost:1 R Types:Instant Arcane -A:SP$ DealDamage | Cost$ 1 R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 1 | SubAbility$ DBDealDamage | SpellDescription$ CARDNAME deals 1 damage to target creature and 1 damage to that creature's controller. -SVar:DBDealDamage:DB$ DealDamage | NumDmg$ 1 | Defined$ TargetedController +A:SP$ DealDamage | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 1 | DamageMap$ True | SubAbility$ DBDealDamage | SpellDescription$ CARDNAME deals 1 damage to target creature and 1 damage to that creature's controller. +SVar:DBDealDamage:DB$ DealDamage | NumDmg$ 1 | Defined$ TargetedController | SubAbility$ DBDamageResolve +SVar:DBDamageResolve:DB$ DamageResolve Oracle:First Volley deals 1 damage to target creature and 1 damage to that creature's controller. diff --git a/forge-gui/res/cardsfolder/g/grothama_all_devouring.txt b/forge-gui/res/cardsfolder/g/grothama_all_devouring.txt index c4d0d4ff244..4432f21b13d 100644 --- a/forge-gui/res/cardsfolder/g/grothama_all_devouring.txt +++ b/forge-gui/res/cardsfolder/g/grothama_all_devouring.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Wurm PT:10/8 S:Mode$ Continuous | Affected$ Creature.Other | AddTrigger$ GrothamaAttack | AddSVar$ HasAttackEffect | Description$ Other creatures have "Whenever this creature attacks, you may have it fight CARDNAME." SVar:GrothamaAttack:Mode$ Attacks | ValidCard$ Card.Self | Execute$ GrothamaFight | OptionalDecider$ You | TriggerDescription$ Whenever this creature attacks, ABILITY. -SVar:GrothamaFight:DB$ Fight | Defined$ TriggeredAttackerLKICopy | ExtraDefined$ OriginalHost | AILogic$ Grothama | SpellDescription$ You may have it fight ORIGINALHOST +SVar:GrothamaFight:DB$ Fight | Defined$ TriggeredAttackerLKICopy & OriginalHost | AILogic$ Grothama | SpellDescription$ You may have it fight ORIGINALHOST T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigRepeat | TriggerDescription$ When NICKNAME leaves the battlefield, each player draws cards equal to the amount of damage dealt to NICKNAME this turn by sources they controlled. SVar:TrigRepeat:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ TrigDraw SVar:TrigDraw:DB$ Draw | Defined$ Remembered | NumCards$ X diff --git a/forge-gui/res/cardsfolder/h/hans_eriksson.txt b/forge-gui/res/cardsfolder/h/hans_eriksson.txt index 3179942414c..e18dcc66396 100644 --- a/forge-gui/res/cardsfolder/h/hans_eriksson.txt +++ b/forge-gui/res/cardsfolder/h/hans_eriksson.txt @@ -3,9 +3,9 @@ ManaCost:2 R G Types:Legendary Creature Human Scout PT:1/4 T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDig | TriggerDescription$ Whenever CARDNAME attacks, reveal the top card of your library. If it's a creature card, put it onto the battlefield tapped and attacking defending player or a planeswalker they control. Otherwise, put that card into your hand. When you put a creature card onto the battlefield this way, it fights CARDNAME. -SVar:TrigDig:DB$ Dig | DigNum$ 1 | ChangeNum$ All | Optional$ True | Reveal$ True | ChangeValid$ Creature | DestinationZone$ Battlefield | DestinationZone2$ Hand | Tapped$ True | Attacking$ DefendingPlayer,Valid Planeswalker.ControlledBy DefendingPlayer | RememberChanged$ True | SubAbility$ DBImmediateTriggerCheck +SVar:TrigDig:DB$ Dig | DigNum$ 1 | ChangeNum$ All | Optional$ True | Reveal$ True | ChangeValid$ Creature | DestinationZone$ Battlefield | DestinationZone2$ Hand | Tapped$ True | Attacking$ DefendingPlayer & Valid Planeswalker.ControlledBy DefendingPlayer | RememberChanged$ True | SubAbility$ DBImmediateTriggerCheck SVar:DBImmediateTriggerCheck:DB$ ImmediateTrigger | Execute$ DBFight | ConditionDefined$ Remembered | ConditionPresent$ Creature | ConditionCompare$ GE1 | TriggerDescription$ When you put a creature card onto the battlefield this way, it fights Hans Eriksson. -SVar:DBFight:DB$ Fight | Defined$ Remembered | ExtraDefined$ Self | SubAbility$ DBCleanup +SVar:DBFight:DB$ Fight | Defined$ Remembered & Self | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:HasAttackEffect:TRUE Oracle:Whenever Hans Eriksson attacks, reveal the top card of your library. If it's a creature card, put it onto the battlefield tapped and attacking defending player or a planeswalker they control. Otherwise, put that card into your hand. When you put a creature card onto the battlefield this way, it fights Hans Eriksson. diff --git a/forge-gui/res/cardsfolder/h/hungry_flames.txt b/forge-gui/res/cardsfolder/h/hungry_flames.txt index f0f0eef09d9..7de60a3c433 100644 --- a/forge-gui/res/cardsfolder/h/hungry_flames.txt +++ b/forge-gui/res/cardsfolder/h/hungry_flames.txt @@ -1,6 +1,7 @@ Name:Hungry Flames ManaCost:2 R Types:Instant -A:SP$ DealDamage | Cost$ 2 R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 3 | SubAbility$ DBDealDamage | SpellDescription$ CARDNAME deals 3 damage to target creature and 2 damage to target player or planeswalker. -SVar:DBDealDamage:DB$ DealDamage | NumDmg$ 2 | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker +A:SP$ DealDamage | ValidTgts$ Creature | NumDmg$ 3 | DamageMap$ True | SubAbility$ DBDealDamage | SpellDescription$ CARDNAME deals 3 damage to target creature and 2 damage to target player or planeswalker. +SVar:DBDealDamage:DB$ DealDamage | NumDmg$ 2 | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | SubAbility$ DBDamageResolve +SVar:DBDamageResolve:DB$ DamageResolve Oracle:Hungry Flames deals 3 damage to target creature and 2 damage to target player or planeswalker. diff --git a/forge-gui/res/cardsfolder/l/lunge.txt b/forge-gui/res/cardsfolder/l/lunge.txt index 5b750a99f71..34f8b94f4dc 100644 --- a/forge-gui/res/cardsfolder/l/lunge.txt +++ b/forge-gui/res/cardsfolder/l/lunge.txt @@ -1,6 +1,7 @@ Name:Lunge ManaCost:2 R Types:Instant -A:SP$ DealDamage | Cost$ 2 R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 2 | SubAbility$ DB1 | SpellDescription$ CARDNAME deals 2 damage to target creature and 2 damage to target player or planeswalker. -SVar:DB1:DB$ DealDamage | NumDmg$ 2 | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker +A:SP$ DealDamage | ValidTgts$ Creature | NumDmg$ 2 | DamageMap$ True | SubAbility$ DB1 | SpellDescription$ CARDNAME deals 2 damage to target creature and 2 damage to target player or planeswalker. +SVar:DB1:DB$ DealDamage | NumDmg$ 2 | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | SubAbility$ DBDamageResolve +SVar:DBDamageResolve:DB$ DamageResolve Oracle:Lunge deals 2 damage to target creature and 2 damage to target player or planeswalker. diff --git a/forge-gui/res/cardsfolder/n/neonates_rush.txt b/forge-gui/res/cardsfolder/n/neonates_rush.txt index 082f7e597f9..b5b2a499cbe 100644 --- a/forge-gui/res/cardsfolder/n/neonates_rush.txt +++ b/forge-gui/res/cardsfolder/n/neonates_rush.txt @@ -2,8 +2,9 @@ Name:Neonate's Rush ManaCost:2 R Types:Instant S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ 1 | EffectZone$ All | IsPresent$ Vampire.YouCtrl | Description$ This spell costs {1} less to cast if you control a Vampire. -A:SP$ DealDamage | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 1 | SubAbility$ DBDealDamage | SpellDescription$ CARDNAME deals 1 damage to target creature and 1 damage to its controller. Draw a card. -SVar:DBDealDamage:DB$ DealDamage | Defined$ TargetedController | NumDmg$ 1 | SubAbility$ DBDraw +A:SP$ DealDamage | ValidTgts$ Creature | NumDmg$ 1 | DamageMap$ True | SubAbility$ DBDealDamage | SpellDescription$ CARDNAME deals 1 damage to target creature and 1 damage to its controller. Draw a card. +SVar:DBDealDamage:DB$ DealDamage | Defined$ TargetedController | NumDmg$ 1 | SubAbility$ DBDamageResolve +SVar:DBDamageResolve:DB$ DamageResolve | SubAbility$ DBDraw SVar:DBDraw:DB$ Draw | NumCards$ 1 SVar:BuffedBy:Vampire DeckHints:Type$Vampire diff --git a/forge-gui/res/cardsfolder/p/psionic_entity.txt b/forge-gui/res/cardsfolder/p/psionic_entity.txt index 23cfdd770dd..0950c616034 100644 --- a/forge-gui/res/cardsfolder/p/psionic_entity.txt +++ b/forge-gui/res/cardsfolder/p/psionic_entity.txt @@ -2,7 +2,8 @@ Name:Psionic Entity ManaCost:4 U Types:Creature Illusion PT:2/2 -A:AB$ DealDamage | Cost$ T | ValidTgts$ Any | NumDmg$ 2 | SubAbility$ DB1 | SpellDescription$ CARDNAME deals 2 damage to any target and 3 damage to itself. -SVar:DB1:DB$ DealDamage | NumDmg$ 3 | Defined$ Self +A:AB$ DealDamage | Cost$ T | ValidTgts$ Any | NumDmg$ 2 | DamageMap$ True | SubAbility$ DB1 | SpellDescription$ CARDNAME deals 2 damage to any target and 3 damage to itself. +SVar:DB1:DB$ DealDamage | NumDmg$ 3 | Defined$ Self | SubAbility$ DBDamageResolve +SVar:DBDamageResolve:DB$ DamageResolve AI:RemoveDeck:All Oracle:{T}: Psionic Entity deals 2 damage to any target and 3 damage to itself. diff --git a/forge-gui/res/cardsfolder/s/sergeant_john_benton.txt b/forge-gui/res/cardsfolder/s/sergeant_john_benton.txt index c50af9359de..21da33b28bd 100644 --- a/forge-gui/res/cardsfolder/s/sergeant_john_benton.txt +++ b/forge-gui/res/cardsfolder/s/sergeant_john_benton.txt @@ -5,7 +5,6 @@ PT:2/4 K:Trample K:Haste T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDraw | CombatDamage$ True | TriggerDescription$ Share Intelligence — Whenever CARDNAME deals combat damage to a player, you and that player each draw that many cards. -SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ X | SubAbility$ DBDraw -SVar:DBDraw:DB$ Draw | Defined$ TriggeredTarget | NumCards$ X +SVar:TrigDraw:DB$ Draw | Defined$ You & TriggeredTarget | NumCards$ X SVar:X:TriggerCount$DamageAmount Oracle:Trample, haste\nShare Intelligence — Whenever Sergeant John Benton deals combat damage to a player, you and that player each draw that many cards. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/s/shauku_endbringer.txt b/forge-gui/res/cardsfolder/s/shauku_endbringer.txt index e32632a6528..82009098baa 100644 --- a/forge-gui/res/cardsfolder/s/shauku_endbringer.txt +++ b/forge-gui/res/cardsfolder/s/shauku_endbringer.txt @@ -5,7 +5,7 @@ PT:5/5 K:Flying S:Mode$ Continuous | Affected$ Card.Self | AddHiddenKeyword$ CARDNAME can't attack. | IsPresent$ Creature | PresentCompare$ GT1 | Description$ CARDNAME can't attack if another creature is on the battlefield. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigLoseLife | TriggerDescription$ At the beginning of your upkeep, you lose 3 life. -A:AB$ ChangeZone | Cost$ T | ValidTgts$ Creature | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature | SubAbility$ DBCounter | SpellDescription$ Exile target creature and put a +1/+1 counter on CARDNAME. +A:AB$ ChangeZone | Cost$ T | ValidTgts$ Creature | Origin$ Battlefield | Destination$ Exile | TgtPrompt$ Select target creature | SubAbility$ DBCounter | SpellDescription$ Exile target creature and put a +1/+1 counter on NICKNAME. SVar:TrigLoseLife:DB$ LoseLife | Defined$ You | LifeAmount$ 3 SVar:DBCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 1 | Defined$ Self #TODO: This creature seems almost AI playable, except the AI won't play around it and will cast other creatures, which may not even be a necessarily bad thing. Maybe RemRandomDeck would suffice here. diff --git a/forge-gui/res/cardsfolder/s/shower_of_sparks.txt b/forge-gui/res/cardsfolder/s/shower_of_sparks.txt index 8c3e01ae4cc..64dab0556e0 100644 --- a/forge-gui/res/cardsfolder/s/shower_of_sparks.txt +++ b/forge-gui/res/cardsfolder/s/shower_of_sparks.txt @@ -1,6 +1,7 @@ Name:Shower of Sparks ManaCost:R Types:Instant -A:SP$ DealDamage | Cost$ R | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 1 | SubAbility$ DBDamage | SpellDescription$ CARDNAME deals 1 damage to target creature -SVar:DBDamage:DB$ DealDamage | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | NumDmg$ 1 | SpellDescription$ and 1 damage to target player or planeswalker. +A:SP$ DealDamage | ValidTgts$ Creature | NumDmg$ 1 | DamageMap$ True | SubAbility$ DBDamage | SpellDescription$ CARDNAME deals 1 damage to target creature +SVar:DBDamage:DB$ DealDamage | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | NumDmg$ 1 | SubAbility$ DBDamageResolve | SpellDescription$ and 1 damage to target player or planeswalker. +SVar:DBDamageResolve:DB$ DamageResolve Oracle:Shower of Sparks deals 1 damage to target creature and 1 damage to target player or planeswalker. diff --git a/forge-gui/res/cardsfolder/s/skophos_maze_warden.txt b/forge-gui/res/cardsfolder/s/skophos_maze_warden.txt index 64d3468b6de..ef0a05ba1de 100644 --- a/forge-gui/res/cardsfolder/s/skophos_maze_warden.txt +++ b/forge-gui/res/cardsfolder/s/skophos_maze_warden.txt @@ -4,6 +4,6 @@ Types:Creature Minotaur Warrior PT:3/4 A:AB$ Pump | Cost$ 1 | NumAtt$ +1 | NumDef$ -1 | SpellDescription$ CARDNAME gets +1/-1 until end of turn. T:Mode$ BecomesTarget | ValidSource$ Ability.Land+namedLabyrinth of Skophos+YouCtrl | ValidTarget$ Creature.Other | TriggerZones$ Battlefield | Execute$ TrigFight | OptionalDecider$ You | TriggerDescription$ Whenever another creature becomes the target of an ability of a land you control named Labyrinth of Skophos, you may have CARDNAME fight that creature. (Each deals damage equal to its power to the other.) -SVar:TrigFight:DB$ Fight | Defined$ Self | ExtraDefined$ TriggeredTarget +SVar:TrigFight:DB$ Fight | Defined$ Self & TriggeredTarget DeckNeeds:Name$Labyrinth of Skophos Oracle:{1}: Skophos Maze-Warden gets +1/-1 until end of turn.\nWhenever another creature becomes the target of an ability of a land you control named Labyrinth of Skophos, you may have Skophos Maze-Warden fight that creature. (Each deals damage equal to its power to the other.) diff --git a/forge-gui/res/cardsfolder/t/tahngarth_first_mate.txt b/forge-gui/res/cardsfolder/t/tahngarth_first_mate.txt index f34c576423d..45d0b68645a 100644 --- a/forge-gui/res/cardsfolder/t/tahngarth_first_mate.txt +++ b/forge-gui/res/cardsfolder/t/tahngarth_first_mate.txt @@ -5,7 +5,7 @@ PT:5/5 S:Mode$ MinMaxBlocker | ValidCard$ Card.Self | Max$ 1 | Description$ CARDNAME can't be blocked by more than one creature. T:Mode$ AttackersDeclared | AttackingPlayer$ Player.Opponent | Execute$ TrigGainControl | TriggerZones$ Battlefield | OptionalDecider$ You | IsPresent$ Card.Self+tapped | TriggerDescription$ Whenever an opponent attacks with one or more creatures, if NICKNAME is tapped, you may have that opponent gain control of NICKNAME until end of combat. If you do, choose a player or planeswalker that opponent is attacking. NICKNAME is attacking that player or planeswalker. SVar:TrigGainControl:DB$ GainControl | Defined$ Self | NewController$ TriggeredAttackingPlayer | LoseControl$ EndOfCombat | RememberControlled$ True | SubAbility$ DBAttack -SVar:DBAttack:DB$ ChangeCombatants | Defined$ Remembered | Attacking$ Player.Defending,Valid Planeswalker.Defending | SubAbility$ DBCleanup +SVar:DBAttack:DB$ ChangeCombatants | Defined$ Remembered | Attacking$ Player.Defending & Valid Planeswalker.Defending | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True AI:RemoveDeck:All Oracle:Tahngarth, First Mate can't be blocked by more than one creature.\nWhenever an opponent attacks with one or more creatures, if Tahngarth is tapped, you may have that opponent gain control of Tahngarth until end of combat. If you do, choose a player or planeswalker that opponent is attacking. Tahngarth is attacking that player or planeswalker. diff --git a/forge-gui/res/cardsfolder/x/xyris_the_writhing_storm.txt b/forge-gui/res/cardsfolder/x/xyris_the_writhing_storm.txt index eb0e7e597d6..29b95abc989 100644 --- a/forge-gui/res/cardsfolder/x/xyris_the_writhing_storm.txt +++ b/forge-gui/res/cardsfolder/x/xyris_the_writhing_storm.txt @@ -6,8 +6,7 @@ K:Flying T:Mode$ Drawn | ValidCard$ Card.OppOwn | FirstCardInDrawStep$ False | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever an opponent draws a card except the first one they draw in each of their draw steps, create a 1/1 green Snake creature token. SVar:TrigToken:DB$ Token | TokenScript$ g_1_1_snake T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDraw | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you and that player each draw that many cards. -SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ X | SubAbility$ DBDraw -SVar:DBDraw:DB$ Draw | Defined$ TriggeredTarget | NumCards$ X +SVar:TrigDraw:DB$ Draw | Defined$ You & TriggeredTarget | NumCards$ X SVar:X:TriggerCount$DamageAmount DeckHas:Ability$Token Oracle:Flying\nWhenever an opponent draws a card except the first one they draw in each of their draw steps, create a 1/1 green Snake creature token.\nWhenever Xyris, the Writhing Storm deals combat damage to a player, you and that player each draw that many cards. diff --git a/forge-gui/res/cardsfolder/z/zara_renegade_recruiter.txt b/forge-gui/res/cardsfolder/z/zara_renegade_recruiter.txt index 91a7566d30e..d4b9623d072 100644 --- a/forge-gui/res/cardsfolder/z/zara_renegade_recruiter.txt +++ b/forge-gui/res/cardsfolder/z/zara_renegade_recruiter.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Human Pirate PT:4/3 K:Flying T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigBorrow | TriggerDescription$ Whenever CARDNAME attacks, look at defending player's hand. You may put a creature card from it onto the battlefield under your control tapped and attacking that player or a planeswalker they control. Return that creature to its owner's hand at the beginning of the next end step. -SVar:TrigBorrow:DB$ ChangeZone | ChangeNum$ 1 | DefinedPlayer$ TriggeredDefendingPlayer | Chooser$ You | ChangeType$ Creature | Origin$ Hand | Destination$ Battlefield | GainControl$ True | Tapped$ True | Attacking$ DefendingPlayer,Valid Planeswalker.ControlledBy DefendingPlayer | RememberChanged$ True | SubAbility$ DBDelayTrig +SVar:TrigBorrow:DB$ ChangeZone | ChangeNum$ 1 | DefinedPlayer$ TriggeredDefendingPlayer | Chooser$ You | ChangeType$ Creature | Origin$ Hand | Destination$ Battlefield | GainControl$ True | Tapped$ True | Attacking$ DefendingPlayer & Valid Planeswalker.ControlledBy DefendingPlayer | RememberChanged$ True | SubAbility$ DBDelayTrig SVar:DBDelayTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | ValidPlayer$ Player | RememberObjects$ RememberedLKI | Execute$ DBChange | StackDescription$ None | SubAbility$ DBCleanup | TriggerDescription$ Return that creature to its owner's hand at the beginning of the next end step. SVar:DBChange:DB$ ChangeZone | Defined$ DelayTriggerRememberedLKI | Origin$ Battlefield | Destination$ Hand SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True