diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index 764793295b7..ac8c1ceeeef 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -129,11 +129,11 @@ public class Game { private IdentityHashMap, Pair> damageThisTurnLKI = new IdentityHashMap<>(); private Map topLibsCast = Maps.newHashMap(); - private Map facedownWhileCasting = Maps.newHashMap(); + private Map facedownWhileCasting = Maps.newHashMap(); - private Player monarch = null; - private Player initiative = null; - private Player monarchBeginTurn = null; + private Player monarch; + private Player initiative; + private Player monarchBeginTurn; private Player startingPlayer; private Direction turnOrder = Direction.getDefaultDirection(); 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 29682398b19..88e5ff549da 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -665,13 +665,6 @@ public class AbilityUtils { for (final SpellAbility s : saList) { tgtList.addAll(getDefinedCards(s.getHostCard(), "Targeted", s)); - // Check sub-abilities, so that modal cards like Abzan Charm are correctly handled. - // TODO: Should this be done in a more general place, like in getDefinedCards()? - AbilitySub abSub = s.getSubAbility(); - while (abSub != null) { - tgtList.addAll(getDefinedCards(abSub.getHostCard(), "Targeted", abSub)); - abSub = abSub.getSubAbility(); - } } val = handlePaid(tgtList, calcX[1], card, ability); } 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 61aa696a247..fc6e1b89f8c 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 @@ -261,6 +261,6 @@ public class DigUntilEffect extends SpellAbilityEffect { game.fireEvent(new GameEventCombatChanged()); } table.triggerChangesZoneAll(game, sa); - } // end resolve + } } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 4c6e602f870..d25747abd6f 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -6744,6 +6744,10 @@ public class Card extends GameEntity implements Comparable, IHasSVars { return new PlayerCollection(goad.values()); // 701.38d } + public final Map getGoadMap() { + return goad; + } + /** * Returns the last known zone information for the card. If the card is a LKI copy of another card, * then it stores the relevant information in savedLastKnownZone, which is returned. If the card is diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index c99ec287ff7..738eeabf985 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1792,7 +1792,7 @@ public class CardFactoryUtil { //upkeep trigger StringBuilder upkeepTrig = new StringBuilder(); - upkeepTrig.append("Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Exile "); + upkeepTrig.append("Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Exile"); upkeepTrig.append(" | IsPresent$ Card.Self+suspended | PresentZone$ Exile"); // Mark this trigger as Secondary, so it's not displayed twice upkeepTrig.append(" | Secondary$ True | TriggerDescription$ At the beginning of your upkeep, if this card is suspended, remove a time counter from it"); @@ -1805,7 +1805,7 @@ public class CardFactoryUtil { //play trigger StringBuilder playTrig = new StringBuilder(); - playTrig.append("Mode$ CounterRemoved | TriggerZones$ Exile | ValidCard$ Card.Self | CounterType$ TIME | NewCounterAmount$ 0 | Secondary$ True "); + playTrig.append("Mode$ CounterRemoved | TriggerZones$ Exile | ValidCard$ Card.Self | CounterType$ TIME | NewCounterAmount$ 0 | Secondary$ True"); playTrig.append(" | TriggerDescription$ When the last time counter is removed from this card, if it's exiled, play it without paying its mana cost if able. "); playTrig.append("If you can't, it remains exiled. If you cast a creature spell this way, it gains haste until you lose control of the spell or the permanent it becomes."); diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java index 7699689d798..c0ae01befe5 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -321,6 +321,8 @@ public final class CardUtil { newCopy.setCombatLKI(in.getGame().getCombat().saveLKI(newCopy)); } + newCopy.getGoadMap().putAll(in.getGoadMap()); + return newCopy; } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index e12a551dae3..1f12c72bd4b 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -1919,39 +1919,22 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit if (splitTargetRestrictions != null) { // TODO Ensure that spells with subabilities are processed correctly - TargetChoices matchTgt = topSA.getTargets(); - - if (matchTgt == null) { - return false; - } - boolean result = false; - - for (final GameObject o : matchTgt) { - if (o.isValid(splitTargetRestrictions.split(","), getActivatingPlayer(), getHostCard(), this)) { - result = true; - break; - } - } - - // spells with subabilities - if (!result) { - AbilitySub subAb = topSA.getSubAbility(); - while (subAb != null) { - if (subAb.getTargetRestrictions() != null) { - matchTgt = subAb.getTargets(); - if (matchTgt == null) { - continue; - } - for (final GameObject o : matchTgt) { - if (o.isValid(splitTargetRestrictions.split(","), getActivatingPlayer(), getHostCard(), this)) { - result = true; - break; - } + SpellAbility subAb = topSA; + while (subAb != null && !result) { + if (subAb.usesTargeting()) { + TargetChoices matchTgt = subAb.getTargets(); + if (matchTgt == null) { + continue; + } + for (final GameObject o : matchTgt) { + if (o.isValid(splitTargetRestrictions.split(","), getActivatingPlayer(), getHostCard(), this)) { + result = true; + break; } } - subAb = subAb.getSubAbility(); } + subAb = subAb.getSubAbility(); } if (!result) { diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityActivateAbilityAsIfHaste.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityActivateAbilityAsIfHaste.java index c6781262d4f..64249cd9b82 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityActivateAbilityAsIfHaste.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityActivateAbilityAsIfHaste.java @@ -44,7 +44,6 @@ public class StaticAbilityActivateAbilityAsIfHaste { } public static boolean applyCanActivateAbility(final StaticAbility stAb, final Card card) { - if (!stAb.matchesValidParam("ValidCard", card)) { return false; } diff --git a/forge-gui/res/cardsfolder/a/archelos_lagoon_mystic.txt b/forge-gui/res/cardsfolder/a/archelos_lagoon_mystic.txt index cee61e3ea9b..d3fdd4d5b59 100644 --- a/forge-gui/res/cardsfolder/a/archelos_lagoon_mystic.txt +++ b/forge-gui/res/cardsfolder/a/archelos_lagoon_mystic.txt @@ -2,8 +2,8 @@ Name:Archelos, Lagoon Mystic ManaCost:1 B G U Types:Legendary Creature Turtle Shaman PT:2/4 -R:Event$ Moved | ValidCard$ Permanent | Destination$ Battlefield | IsPresent$ Card.Self+tapped | ReplaceWith$ ETBTapped | ActiveZones$ Battlefield | Description$ As long as CARDNAME is tapped, other permanents enter the battlefield tapped. -SVar:ETBTapped:DB$ ChangeZone | Origin$ All | Destination$ Battlefield | Tapped$ True | Defined$ ReplacedCard -R:Event$ Moved | ValidCard$ Permanent | Destination$ Battlefield | IsPresent$ Card.Self+untapped | ReplaceWith$ ETBUntapped | ActiveZones$ Battlefield | Description$ As long as NICKNAME is untapped, other permanents enter the battlefield untapped. -SVar:ETBUntapped:DB$ ChangeZone | Origin$ All | Destination$ Battlefield | Untapped$ True | Defined$ ReplacedCard +R:Event$ Moved | ValidCard$ Permanent | Destination$ Battlefield | IsPresent$ Card.Self+tapped | ReplaceWith$ ETBTapped | ReplacementResult$ Updated | ActiveZones$ Battlefield | Description$ As long as CARDNAME is tapped, other permanents enter the battlefield tapped. +SVar:ETBTapped:DB$ Tap | ETB$ True | Defined$ ReplacedCard +R:Event$ Moved | ValidCard$ Permanent | Destination$ Battlefield | IsPresent$ Card.Self+untapped | ReplaceWith$ ETBUntapped | ReplacementResult$ Updated | ActiveZones$ Battlefield | Description$ As long as NICKNAME is untapped, other permanents enter the battlefield untapped. +SVar:ETBUntapped:DB$ Untap | ETB$ True | Defined$ ReplacedCard Oracle:As long as Archelos, Lagoon Mystic is tapped, other permanents enter the battlefield tapped.\nAs long as Archelos is untapped, other permanents enter the battlefield untapped. diff --git a/forge-gui/res/cardsfolder/e/esior_wardwing_familiar.txt b/forge-gui/res/cardsfolder/e/esior_wardwing_familiar.txt index 661b90bffab..daf7ed436ac 100644 --- a/forge-gui/res/cardsfolder/e/esior_wardwing_familiar.txt +++ b/forge-gui/res/cardsfolder/e/esior_wardwing_familiar.txt @@ -4,6 +4,6 @@ Types:Legendary Creature Bird PT:1/3 K:Flying K:Partner -S:Mode$ RaiseCost | ValidTarget$ Card.IsCommander+YouCtrl | Activator$ Opponent | Type$ Spell | Amount$ 3 | Description$ Spells your opponents cast that target one or more commanders you control cost {3} more to cast. +S:Mode$ RaiseCost | ValidTarget$ Card.IsCommander+YouCtrl+inZoneBattlefield | Activator$ Opponent | Type$ Spell | Amount$ 3 | Description$ Spells your opponents cast that target one or more commanders you control cost {3} more to cast. AI:RemoveDeck:NonCommander Oracle:Flying\nSpells your opponents cast that target one or more commanders you control cost {3} more to cast.\nPartner (You can have two commanders if both have partner.) diff --git a/forge-gui/res/cardsfolder/k/kasmina_enigmatic_mentor.txt b/forge-gui/res/cardsfolder/k/kasmina_enigmatic_mentor.txt index c0c871b7be2..87ea3dd6c3d 100644 --- a/forge-gui/res/cardsfolder/k/kasmina_enigmatic_mentor.txt +++ b/forge-gui/res/cardsfolder/k/kasmina_enigmatic_mentor.txt @@ -2,7 +2,7 @@ Name:Kasmina, Enigmatic Mentor ManaCost:3 U Types:Legendary Planeswalker Kasmina Loyalty:5 -S:Mode$ RaiseCost | ValidTarget$ Creature.YouOwn+inZoneBattlefield | Activator$ Player.Opponent | Type$ Spell | Amount$ 2 | Description$ Spells your opponents cast that target a creature or planeswalker you control cost {2} more to cast. +S:Mode$ RaiseCost | ValidTarget$ Creature.YouCtrl+inZoneBattlefield,Planeswalker.YouCtrl+inZoneBattlefield | Activator$ Player.Opponent | Type$ Spell | Amount$ 2 | Description$ Spells your opponents cast that target a creature or planeswalker you control cost {2} more to cast. A:AB$ Token | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenScript$ u_2_2_wizard | TokenOwner$ You | SubAbility$ DBDraw | SpellDescription$ Create a 2/2 blue Wizard creature token. Draw a card, then discard a card. SVar:DBDraw:DB$ Draw | NumCards$ 1 | SubAbility$ DBDiscard SVar:DBDiscard:DB$ Discard | Defined$ You | Mode$ TgtChoose | NumCards$ 1 diff --git a/forge-gui/res/cardsfolder/k/kopala_warden_of_waves.txt b/forge-gui/res/cardsfolder/k/kopala_warden_of_waves.txt index 5d6da5d67f0..89adf878196 100644 --- a/forge-gui/res/cardsfolder/k/kopala_warden_of_waves.txt +++ b/forge-gui/res/cardsfolder/k/kopala_warden_of_waves.txt @@ -2,6 +2,6 @@ Name:Kopala, Warden of Waves ManaCost:1 U U Types:Legendary Creature Merfolk Wizard PT:2/2 -S:Mode$ RaiseCost | ValidTarget$ Creature.Merfolk+YouCtrl | Activator$ Player.Opponent | Type$ Spell | Amount$ 2 | Description$ Spells your opponents cast that target a Merfolk you control cost {2} more to cast. -S:Mode$ RaiseCost | ValidTarget$ Creature.Merfolk+YouCtrl | Activator$ Player.Opponent | Type$ Ability | Amount$ 2 | Description$ Abilities your opponents activate that target a Merfolk you control cost {2} more to activate. +S:Mode$ RaiseCost | ValidTarget$ Creature.Merfolk+YouCtrl+inZoneBattlefield | Activator$ Player.Opponent | Type$ Spell | Amount$ 2 | Description$ Spells your opponents cast that target a Merfolk you control cost {2} more to cast. +S:Mode$ RaiseCost | ValidTarget$ Creature.Merfolk+YouCtrl+inZoneBattlefield | Activator$ Player.Opponent | Type$ Ability | Amount$ 2 | Description$ Abilities your opponents activate that target a Merfolk you control cost {2} more to activate. Oracle:Spells your opponents cast that target a Merfolk you control cost {2} more to cast.\nAbilities your opponents activate that target a Merfolk you control cost {2} more to activate. diff --git a/forge-gui/res/cardsfolder/m/mavinda_students_advocate.txt b/forge-gui/res/cardsfolder/m/mavinda_students_advocate.txt index 715cb4e4058..665b53b5e4f 100644 --- a/forge-gui/res/cardsfolder/m/mavinda_students_advocate.txt +++ b/forge-gui/res/cardsfolder/m/mavinda_students_advocate.txt @@ -5,7 +5,7 @@ PT:2/3 K:Flying A:AB$ Effect | Cost$ 0 | ValidTgts$ Instant.YouOwn,Sorcery.YouOwn | TgtZone$ Graveyard | TgtPrompt$ Select target instant or sorcery card in your graveyard | ActivationLimit$ 1 | RememberObjects$ Targeted | StaticAbilities$ MayPlay,RaiseCost | ReplacementEffects$ ReplaceGraveyard | SubAbility$ DBCleanup | SpellDescription$ You may cast target instant or sorcery card from your graveyard this turn. If that spell doesn't target a creature you control, it costs {8} more to cast this way. If that spell would be put into your graveyard, exile it instead. Activate only once each turn. (You still pay the spell's costs. Timing rules for the spell still apply.) SVar:MayPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Graveyard | Description$ You may cast target instant or sorcery card from your graveyard this turn. (You still pay the spell's costs. Timing rules for the spell still apply.) -SVar:RaiseCost:Mode$ RaiseCost | ValidCard$ Card.IsRemembered | ValidTarget$ Creature.YouCtrl | UnlessValidTarget$ True | Activator$ You | Type$ Spell | Amount$ 8 | EffectZone$ Command | Description$ If that spell doesn't target a creature you control, it costs {8} more to cast this way. +SVar:RaiseCost:Mode$ RaiseCost | ValidCard$ Card.IsRemembered | ValidTarget$ Creature.YouCtrl+inZoneBattlefield | UnlessValidTarget$ True | Activator$ You | Type$ Spell | Amount$ 8 | EffectZone$ Command | Description$ If that spell doesn't target a creature you control, it costs {8} more to cast this way. SVar:ReplaceGraveyard:Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Graveyard | ReplaceWith$ MoveExile | Description$ If that spell would be put into your graveyard, exile it instead. SVar:MoveExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ All | Destination$ Exile | SubAbility$ ExileSelf SVar:ExileSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile diff --git a/forge-gui/res/cardsfolder/m/monastery_siege.txt b/forge-gui/res/cardsfolder/m/monastery_siege.txt index fe3e70f5526..d5580a32758 100644 --- a/forge-gui/res/cardsfolder/m/monastery_siege.txt +++ b/forge-gui/res/cardsfolder/m/monastery_siege.txt @@ -8,5 +8,5 @@ SVar:KhansTrigger:Mode$ Phase | Phase$ Draw | TriggerZones$ Battlefield | ValidP SVar:Filter:DB$ Draw | Defined$ You | NumCards$ 1 | SubAbility$ DBDiscard SVar:DBDiscard:DB$ Discard | Defined$ You | Mode$ TgtChoose | NumCards$ 1 SVar:Dragons:DB$ Animate | Defined$ Self | staticAbilities$ DragonsST | Duration$ Permanent | SpellDescription$ Dragons -SVar:DragonsST:Mode$ RaiseCost | ValidTarget$ You,Card.YouCtrl | Activator$ Opponent | Type$ Spell | Amount$ 2 | Description$ Spells your opponents cast that target you or a permanent you control cost {2} more to cast. +SVar:DragonsST:Mode$ RaiseCost | ValidTarget$ You,Card.YouCtrl+inZoneBattlefield | Activator$ Opponent | Type$ Spell | Amount$ 2 | Description$ Spells your opponents cast that target you or a permanent you control cost {2} more to cast. Oracle:As Monastery Siege enters the battlefield, choose Khans or Dragons.\n• Khans — At the beginning of your draw step, draw an additional card, then discard a card.\n• Dragons — Spells your opponents cast that target you or a permanent you control cost {2} more to cast. diff --git a/forge-gui/res/cardsfolder/upcoming/baeloth_barrityl_entertainer.txt b/forge-gui/res/cardsfolder/upcoming/baeloth_barrityl_entertainer.txt index 065e6fe446d..900f53468ef 100644 --- a/forge-gui/res/cardsfolder/upcoming/baeloth_barrityl_entertainer.txt +++ b/forge-gui/res/cardsfolder/upcoming/baeloth_barrityl_entertainer.txt @@ -3,10 +3,10 @@ ManaCost:4 R Types:Legendary Creature Elf Shaman PT:2/5 K:Choose a Background -S:Mode$ Continuous | Affected$ Creature.powerLTY+OppCtrl | Goad$ True | SubAbility$ TrigChangesZone | Description$ Creatures your opponents control with power less than CARDNAME power are goaded. (They attacks each combat if able and attack a player other than you if able.) +S:Mode$ Continuous | Affected$ Creature.powerLTY+OppCtrl | Goad$ True | Description$ Creatures your opponents control with power less than CARDNAME power are goaded. (They attack each combat if able and attack a player other than you if able.) SVar:Y:Count$CardPower -SVar:TrigChangesZone:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.attacking+IsGoaded,Creature.blocking+IsGoaded | Execute$ TrigToken | TriggerZones$ Battlefield | SubAbility$ TrigToken | TriggerDescription$ Whenever a goaded attacking or blocking creature dies, you create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.") +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.attacking+IsGoaded,Creature.blocking+IsGoaded | Execute$ TrigToken | TriggerZones$ Battlefield | SubAbility$ TrigToken | TriggerDescription$ Whenever a goaded attacking or blocking creature dies, you create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.") SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_treasure_sac | TokenOwner$ You SVar:HasAttackEffect:TRUE DeckHas:Ability$Token|Sacrifice & Type$Artifact|Treasure -Oracle:Creatures your opponents control with power less than Baeloth Barrityl's power are goaded. (They attacks each combat if able and attack a player other than you if able.)\nWhenever a goaded attacking or blocking creature dies, you create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")\nChoose a Background (You can have a Background as a second commander.) +Oracle:Creatures your opponents control with power less than Baeloth Barrityl's power are goaded. (They attack each combat if able and attack a player other than you if able.)\nWhenever a goaded attacking or blocking creature dies, you create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")\nChoose a Background (You can have a Background as a second commander.) diff --git a/forge-gui/res/cardsfolder/upcoming/gond_gate.txt b/forge-gui/res/cardsfolder/upcoming/gond_gate.txt index d55587805b5..1c8cd840332 100644 --- a/forge-gui/res/cardsfolder/upcoming/gond_gate.txt +++ b/forge-gui/res/cardsfolder/upcoming/gond_gate.txt @@ -1,8 +1,8 @@ Name:Gond Gate ManaCost:no cost Types:Land Gate -R:Event$ Moved | ValidCard$ Gate.YouCtrl | Destination$ Battlefield | ReplaceWith$ ETBUntapped | ActiveZones$ Battlefield | Description$ Gates you control enter the battlefield untapped. -SVar:ETBUntapped:DB$ ChangeZone | Origin$ All | Destination$ Battlefield | Untapped$ True | Defined$ ReplacedCard +R:Event$ Moved | ValidCard$ Gate.YouCtrl | Destination$ Battlefield | ReplaceWith$ ETBUntapped | ReplacementResult$ Updated | ActiveZones$ Battlefield | Description$ Gates you control enter the battlefield untapped. +SVar:ETBUntapped:DB$ Untap | ETB$ True | Defined$ ReplacedCard A:AB$ Mana | Cost$ T | Produced$ C | Amount$ 1 | SpellDescription$ Add {C}. A:AB$ ManaReflected | Cost$ T | ColorOrType$ Color | Valid$ Gate.YouCtrl | ReflectProperty$ Produce | SpellDescription$ Add one mana of any color that a Gate you control could produce. DeckNeeds:Type$Gate