From aee2bb3ffe0d1c5974ee3d763131d5b997c211d3 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Sun, 22 Nov 2020 23:01:29 +0100 Subject: [PATCH] DelayedTriggerEffect: make the trigger remember the spawning Ability --- forge-game/src/main/java/forge/game/Game.java | 2 +- .../java/forge/game/ability/AbilityUtils.java | 6 +++ .../ability/effects/DelayedTriggerEffect.java | 1 + .../effects/ImmediateTriggerEffect.java | 6 +-- .../java/forge/game/card/CardFactoryUtil.java | 2 +- .../main/java/forge/game/player/Player.java | 4 ++ .../forge/game/player/PlayerProperty.java | 6 ++- .../main/java/forge/game/trigger/Trigger.java | 38 ++++++++++++------- .../cardsfolder/i/isareth_the_awakener.txt | 9 ++--- .../upcoming/halana_kessig_ranger.txt | 7 ++-- .../upcoming/numa_joraga_chieftain.txt | 5 +-- .../res/cardsfolder/w/wildborn_preserver.txt | 5 +-- 12 files changed, 53 insertions(+), 38 deletions(-) diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index f1c89930705..96c5c5d8d69 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -719,7 +719,7 @@ public class Game { getNextPlayerAfter(p).initPlane(); } - if (p != null && p.equals(getMonarch())) { + if (p != null && p.isMonarch()) { // if the player who lost was the Monarch, someone else will be the monarch if(p.equals(getPhaseHandler().getPlayerTurn())) { getAction().becomeMonarch(getNextPlayerAfter(p)); 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 1dfaf2a1c94..1a7e7005736 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -1642,6 +1642,12 @@ public class AbilityUtils { return CardFactoryUtil.doXMath(0, expr, c); } + // ImmediateTrigger should check for the Ability which created the trigger + if (t.getSpawningAbility() != null) { + root = t.getSpawningAbility().getRootAbility(); + return CardFactoryUtil.doXMath(root.getXManaCostPaid(), expr, c); + } + // 107.3k If an object’s enters-the-battlefield triggered ability or replacement effect refers to X, // and the spell that became that object as it resolved had a value of X chosen for any of its costs, // the value of X for that ability is the same as the value of X for that spell, although the value of X for that permanent is 0. diff --git a/forge-game/src/main/java/forge/game/ability/effects/DelayedTriggerEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DelayedTriggerEffect.java index 3017b3fac51..6a33e44b278 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DelayedTriggerEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DelayedTriggerEffect.java @@ -58,6 +58,7 @@ public class DelayedTriggerEffect extends SpellAbilityEffect { Card lki = CardUtil.getLKICopy(gameCard); lki.setOwner(sa.getActivatingPlayer()); final Trigger delTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic()); + delTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true)); if (triggerRemembered != null) { for (final String rem : triggerRemembered.split(",")) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java index 0308f85ae4d..499239ef39f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java @@ -57,6 +57,7 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect { Card lki = CardUtil.getLKICopy(gameCard); lki.setOwner(sa.getActivatingPlayer()); final Trigger immediateTrig = TriggerHandler.parseTrigger(mapParams, lki, sa.isIntrinsic()); + immediateTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true)); // Need to copy paid costs @@ -72,11 +73,6 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect { } } - if (sa.hasParam("RememberDefinedNumber")) { - immediateTrig.addRemembered((Integer) AbilityUtils.calculateAmount(sa.getHostCard(), - sa.getParam("RememberDefinedNumber"), sa)); - } - if (mapParams.containsKey("Execute") || sa.hasAdditionalAbility("Execute")) { AbilitySub overridingSA = (AbilitySub)sa.getAdditionalAbility("Execute").copy(lki, sa.getActivatingPlayer(), false); // need to set Parent to null, otherwise it might have wrong root ability 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 8683bde53bb..fcebf2c75eb 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1167,7 +1167,7 @@ public class CardFactoryUtil { return doXMath(Integer.parseInt(sq[cc.hasLandfall() ? 1 : 2]), m, c); } if (sq[0].contains("Monarch")) { - return doXMath(Integer.parseInt(sq[cc.equals(game.getMonarch()) ? 1 : 2]), m, c); + return doXMath(Integer.parseInt(sq[cc.isMonarch() ? 1 : 2]), m, c); } if (sq[0].contains("Blessing")) { return doXMath(Integer.parseInt(sq[cc.hasBlessing() ? 1 : 2]), m, c); diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index f2d4259816b..a8d7d7aad00 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -3113,6 +3113,10 @@ public class Player extends GameEntity implements Comparable { return view; } + public boolean isMonarch() { + return equals(game.getMonarch()); + } + public void createMonarchEffect() { final PlayerZone com = getZone(ZoneType.Command); if (monarchEffect == null) { diff --git a/forge-game/src/main/java/forge/game/player/PlayerProperty.java b/forge-game/src/main/java/forge/game/player/PlayerProperty.java index be408467898..ea0327e4cdf 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerProperty.java +++ b/forge-game/src/main/java/forge/game/player/PlayerProperty.java @@ -70,7 +70,11 @@ public class PlayerProperty { return false; } } else if (property.equals("isMonarch")) { - if (!player.equals(game.getMonarch())) { + if (!player.isMonarch()) { + return false; + } + } else if (property.equals("isNotMonarch")) { + if (player.isMonarch()) { return false; } } else if (property.equals("hasBlessing")) { diff --git a/forge-game/src/main/java/forge/game/trigger/Trigger.java b/forge-game/src/main/java/forge/game/trigger/Trigger.java index 48dc95df0cf..6c0617eb00e 100644 --- a/forge-game/src/main/java/forge/game/trigger/Trigger.java +++ b/forge-game/src/main/java/forge/game/trigger/Trigger.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -44,7 +44,7 @@ import forge.util.TextUtil; *

* Abstract Trigger class. Constructed by reflection only *

- * + * * @author Forge * @version $Id$ */ @@ -74,11 +74,13 @@ public abstract class Trigger extends TriggerReplacementBase { private Set validPhases; + private SpellAbility spawningAbility = null; + /** *

* Constructor for Trigger. *

- * + * * @param params * a {@link java.util.HashMap} object. * @param host @@ -109,14 +111,14 @@ public abstract class Trigger extends TriggerReplacementBase { *

* toString. *

- * + * * @return a {@link java.lang.String} object. */ @Override public final String toString() { return toString(false); } - + public String toString(boolean active) { if (hasParam("TriggerDescription") && !this.isSuppressed()) { @@ -148,9 +150,9 @@ public abstract class Trigger extends TriggerReplacementBase { SpellAbility sa = ensureAbility(); return replaceAbilityText(desc, sa); - + } - + public final String replaceAbilityText(final String desc, SpellAbility sa) { String result = desc; @@ -204,7 +206,7 @@ public abstract class Trigger extends TriggerReplacementBase { *

* phasesCheck. *

- * + * * @return a boolean. */ public final boolean phasesCheck(final Game game) { @@ -270,7 +272,7 @@ public abstract class Trigger extends TriggerReplacementBase { *

* requirementsCheck. *

- * @param game + * @param game * * @return a boolean. */ @@ -398,7 +400,7 @@ public abstract class Trigger extends TriggerReplacementBase { *

* performTest. *

- * + * * @param runParams * a {@link HashMap} object. * @return a boolean. @@ -409,7 +411,7 @@ public abstract class Trigger extends TriggerReplacementBase { *

* setTriggeringObjects. *

- * + * * @param sa * a {@link forge.game.spellability.SpellAbility} object. */ @@ -439,7 +441,7 @@ public abstract class Trigger extends TriggerReplacementBase { public void addRemembered(Object o) { this.triggerRemembered.add(o); } - + public List getTriggerRemembered() { return this.triggerRemembered; } @@ -453,7 +455,7 @@ public abstract class Trigger extends TriggerReplacementBase { } /** - * + * * @param triggerType * the triggerType to set * @param triggerType @@ -493,6 +495,14 @@ public abstract class Trigger extends TriggerReplacementBase { //public String getImportantStackObjects(SpellAbility sa) { return ""; }; abstract public String getImportantStackObjects(SpellAbility sa); + public SpellAbility getSpawningAbility() { + return spawningAbility; + } + + public void setSpawningAbility(SpellAbility ability) { + spawningAbility = ability; + } + public int getActivationsThisTurn() { return this.numberTurnActivations; } diff --git a/forge-gui/res/cardsfolder/i/isareth_the_awakener.txt b/forge-gui/res/cardsfolder/i/isareth_the_awakener.txt index 8fa288f013e..9a8e8ef27cd 100644 --- a/forge-gui/res/cardsfolder/i/isareth_the_awakener.txt +++ b/forge-gui/res/cardsfolder/i/isareth_the_awakener.txt @@ -4,11 +4,8 @@ Types:Legendary Creature Human Wizard K:Deathtouch PT:3/3 T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigImmediateTrig | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, you may pay {X}. When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else. -SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ X | Execute$ TrigChange | RememberDefinedNumber$ X | References$ X | TriggerDescription$ When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else. +SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ X | Execute$ TrigChange | References$ X | SpellDescription$ When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else. SVar:X:Count$xPaid -SVar:TrigChange:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouOwn+cmcEQY | TgtPrompt$ Choose target creature card with converted mana cost X | References$ Y | RememberTargets$ True | AILogic$ BeforeCombat | SubAbility$ DBPutCounter | SpellDescription$ Return target creature card with converted mana cost X from your graveyard to the battlefield. -SVar:DBPutCounter:DB$ PutCounter | Defined$ Targeted | CounterType$ CORPSE | CounterNum$ 1 | SubAbility$ DBPump -SVar:DBPump:DB$ Pump | Defined$ Remembered | LeaveBattlefield$ Exile -SVar:Y:Count$TriggerRememberAmount +SVar:TrigChange:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouOwn+cmcEQX | TgtPrompt$ Choose target creature card with converted mana cost X | References$ X | WithCounters$ CORPSE_1 | AILogic$ BeforeCombat | LeaveBattlefield$ Exile | SpellDescription$ Return target creature card with converted mana cost X from your graveyard to the battlefield. SVar:HasAttackEffect:TRUE -Oracle:Deathtouch\nWhenever Isareth the Awakener attacks, you may pay {X}. When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else. \ No newline at end of file +Oracle:Deathtouch\nWhenever Isareth the Awakener attacks, you may pay {X}. When you do, return target creature card with converted mana cost X from your graveyard to the battlefield with a corpse counter on it. If that creature would leave the battlefield, exile it instead of putting it anywhere else. diff --git a/forge-gui/res/cardsfolder/upcoming/halana_kessig_ranger.txt b/forge-gui/res/cardsfolder/upcoming/halana_kessig_ranger.txt index 7b3b08bcdab..a1a0ddd42f9 100644 --- a/forge-gui/res/cardsfolder/upcoming/halana_kessig_ranger.txt +++ b/forge-gui/res/cardsfolder/upcoming/halana_kessig_ranger.txt @@ -5,9 +5,8 @@ PT:3/4 K:Reach K:Partner T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | Execute$ TrigPayCost | TriggerZones$ Battlefield | TriggerDescription$ Whenever another creature enters the battlefield under your control, you may pay {2}. When you do, that creature deals damage equal to its power to target creature. -SVar:TrigPayCost:AB$ ImmediateTrigger | Cost$ 2 | Execute$ TrigDealDamage | RememberObjects$ TriggeredCard | SubAbility$ DBCleanup | TriggerDescription$ When you pay {2}, that creature deals damage equal to its power to target creature. -SVar:TrigDealDamage:DB$ DealDamage | DamageSource$ DelayTriggerRememberedLKI | NumDmg$ XPower | References$ XPower | ValidTgts$ Creature -SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:XPower:TriggerRememberedLKI$CardPower +SVar:TrigPayCost:AB$ ImmediateTrigger | Cost$ 2 | Execute$ TrigDealDamage | CopyTriggeringObjects$ True | TriggerDescription$ When you pay {2}, that creature deals damage equal to its power to target creature. +SVar:TrigDealDamage:DB$ DealDamage | DamageSource$ TriggeredCardLKICopy | NumDmg$ X | References$ X | ValidTgts$ Creature +SVar:X:TriggeredCard$CardPower DeckNeeds:Type$Creature Oracle:Reach\nWhenever another creature enters the battlefield under your control, you may pay {2}. When you do, that creature deals damage equal to its power to target creature.\nPartner (You can have two commanders if both have partner.) diff --git a/forge-gui/res/cardsfolder/upcoming/numa_joraga_chieftain.txt b/forge-gui/res/cardsfolder/upcoming/numa_joraga_chieftain.txt index 64157784e3e..0c4f0f9abdb 100755 --- a/forge-gui/res/cardsfolder/upcoming/numa_joraga_chieftain.txt +++ b/forge-gui/res/cardsfolder/upcoming/numa_joraga_chieftain.txt @@ -3,10 +3,9 @@ ManaCost:2 G Types:Legendary Creature Elf Warrior PT:2/2 T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigPayCost | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of combat on your turn, you may pay {X}{X}. When you do, distribute X +1/+1 counters among any number of target Elf creatures you control. -SVar:TrigPayCost:AB$ ImmediateTrigger | Cost$ X X | RememberDefinedNumber$ X | References$ X | Execute$ TrigPutCounters | TriggerDescription$ When you pay {X}{X}, distribute X +1/+1 counters among any number of target Elf creatures you control. -SVar:TrigPutCounters:DB$ PutCounter | ValidTgts$ Creature.Elf+YouCtrl | TgtPrompt$ Select any number of target Elf creatures you control to distribute counters to | CounterType$ P1P1 | CounterNum$ Y | TargetMin$ 1 | TargetMax$ Y | DividedAsYouChoose$ Y | References$ Y +SVar:TrigPayCost:AB$ ImmediateTrigger | Cost$ X X | References$ X | Execute$ TrigPutCounters | TriggerDescription$ When you pay {X}{X}, distribute X +1/+1 counters among any number of target Elf creatures you control. +SVar:TrigPutCounters:DB$ PutCounter | ValidTgts$ Creature.Elf+YouCtrl | TgtPrompt$ Select any number of target Elf creatures you control to distribute counters to | CounterType$ P1P1 | CounterNum$ Y | TargetMin$ 1 | TargetMax$ X | DividedAsYouChoose$ X | References$ X SVar:X:Count$xPaid -SVar:Y:Count$TriggerRememberAmount K:Partner DeckHas:Ability$Counters DeckHints:Type$Elf diff --git a/forge-gui/res/cardsfolder/w/wildborn_preserver.txt b/forge-gui/res/cardsfolder/w/wildborn_preserver.txt index 91032be0fab..c046468cd20 100644 --- a/forge-gui/res/cardsfolder/w/wildborn_preserver.txt +++ b/forge-gui/res/cardsfolder/w/wildborn_preserver.txt @@ -5,9 +5,8 @@ PT:2/2 K:Flash K:Reach T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.nonHuman+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigImmediateTrig | TriggerDescription$ Whenever another non-Human creature enters the battlefield under your control, you may pay {X}. When you do, put X +1/+1 counters on CARDNAME. -SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ X | Execute$ TrigPutCounter | RememberDefinedNumber$ X | References$ X | TriggerDescription$ When you do, put X +1/+1 counters on CARDNAME. +SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ X | Execute$ TrigPutCounter | References$ X | TriggerDescription$ When you do, put X +1/+1 counters on CARDNAME. SVar:X:Count$xPaid -SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ Y | References$ Y -SVar:Y:Count$TriggerRememberAmount +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | References$ X DeckHas:Ability$Counters Oracle:Flash\nReach\nWhenever another non-Human creature enters the battlefield under your control, you may pay {X}. When you do, put X +1/+1 counters on Wildborn Preserver.