From 4a11157019d872bb23f51a86760a5ff5c7431e96 Mon Sep 17 00:00:00 2001 From: Hans Mackowiak Date: Tue, 7 Jul 2020 09:58:08 +0000 Subject: [PATCH] Resolve "Morph X costs - X is not being remembered" --- .../java/forge/ai/ability/SetStateAi.java | 2 +- .../src/main/java/forge/game/GameAction.java | 8 ++--- .../java/forge/game/ability/AbilityUtils.java | 6 ++++ .../ability/effects/ChangeZoneEffect.java | 4 +-- .../game/ability/effects/DiscardEffect.java | 5 +--- .../game/ability/effects/PlayEffect.java | 2 +- .../game/ability/effects/SetStateEffect.java | 8 ++--- .../src/main/java/forge/game/card/Card.java | 19 +++++++----- .../main/java/forge/game/player/Player.java | 2 +- .../java/forge/game/spellability/Spell.java | 2 +- .../forge/game/trigger/TriggerTurnFaceUp.java | 2 +- .../main/java/forge/game/zone/MagicStack.java | 2 +- .../quest/precons/Basri, Devoted Paladin.dck | 29 ++++++++++++++++++ .../precons/Chandra, Flames Catalyst.dck | 30 +++++++++++++++++++ .../quest/precons/Garruk, Savage Herald.dck | 29 ++++++++++++++++++ .../res/quest/precons/Liliana, Death Mage.dck | 29 ++++++++++++++++++ .../precons/Teferi, Timeless Voyager.dck | 30 +++++++++++++++++++ .../src/main/java/forge/player/HumanPlay.java | 2 +- .../forge/player/HumanPlaySpellAbility.java | 2 +- 19 files changed, 183 insertions(+), 30 deletions(-) create mode 100644 forge-gui/res/quest/precons/Basri, Devoted Paladin.dck create mode 100644 forge-gui/res/quest/precons/Chandra, Flames Catalyst.dck create mode 100644 forge-gui/res/quest/precons/Garruk, Savage Herald.dck create mode 100644 forge-gui/res/quest/precons/Liliana, Death Mage.dck create mode 100644 forge-gui/res/quest/precons/Teferi, Timeless Voyager.dck diff --git a/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java b/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java index ca7404dee76..60f2b1e7f51 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java @@ -174,7 +174,7 @@ public class SetStateAi extends SpellAbilityAi { if (!card.isFaceDown()) { transformed.turnFaceDown(true); } else { - transformed.turnFaceUp(false, false); + transformed.forceTurnFaceUp(); } transformed.updateStateForView(); return compareCards(card, transformed, ai, ph); diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 6456b345b3d..16b2d97728e 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -202,7 +202,7 @@ public class GameAction { // all sort of funky shenanigans may happen later (e.g. their ETB replacement effects are set // up on the wrong card state etc.). if (wasFacedown && (fromBattlefield || (toHand && zoneFrom.is(ZoneType.Exile)))) { - c.turnFaceUp(false, false); + c.forceTurnFaceUp(); } if (!c.isToken()) { @@ -264,7 +264,7 @@ public class GameAction { if (repres != ReplacementResult.NotReplaced) { // reset failed manifested Cards back to original if (c.isManifested() && !c.isInZone(ZoneType.Battlefield)) { - c.turnFaceUp(false, false); + c.forceTurnFaceUp(); } copied.getOwner().removeInboundToken(copied); @@ -431,7 +431,7 @@ public class GameAction { // rule 504.6: reveal a face-down card leaving the stack if (zoneFrom != null && zoneTo != null && zoneFrom.is(ZoneType.Stack) && !zoneTo.is(ZoneType.Battlefield) && wasFacedown) { Card revealLKI = CardUtil.getLKICopy(c); - revealLKI.turnFaceUp(true, false); + revealLKI.forceTurnFaceUp(); reveal(new CardCollection(revealLKI), revealLKI.getOwner(), true, "Face-down card moves from the stack: "); } @@ -462,7 +462,7 @@ public class GameAction { // Reveal if face-down if (wasFacedown) { Card revealLKI = CardUtil.getLKICopy(c); - revealLKI.turnFaceUp(true, false); + revealLKI.forceTurnFaceUp(); reveal(new CardCollection(revealLKI), revealLKI.getOwner(), true, "Face-down card leaves the battlefield: "); 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 cc160872bf6..828e9becae4 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -1650,6 +1650,12 @@ public class AbilityUtils { return CardFactoryUtil.doXMath(0, expr, c); } return CardFactoryUtil.doXMath(cycleSA.getXManaCostPaid(), expr, c); + } else if (TriggerType.TurnFaceUp.equals(t.getMode())) { + SpellAbility turnupSA = (SpellAbility) sa.getTriggeringObject(AbilityKey.Cause); + if (turnupSA == null || turnupSA.getXManaCostPaid() == null) { + return CardFactoryUtil.doXMath(0, expr, c); + } + return CardFactoryUtil.doXMath(turnupSA.getXManaCostPaid(), expr, c); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index 8711a63ad8e..79fab604916 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -483,7 +483,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } if (sa.hasParam("Transformed")) { if (tgtC.isDoubleFaced()) { - tgtC.changeCardState("Transform", null); + tgtC.changeCardState("Transform", null, sa); } else { // If it can't Transform, don't change zones. continue; @@ -1031,7 +1031,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } if (sa.hasParam("Transformed")) { if (c.isDoubleFaced()) { - c.changeCardState("Transform", null); + c.changeCardState("Transform", null, sa); } else { // If it can't Transform, don't change zones. continue; diff --git a/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java index dcc351e65fc..62a02bd2e60 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DiscardEffect.java @@ -19,8 +19,6 @@ import forge.util.Aggregates; import forge.util.TextUtil; import forge.util.Localizer; -import org.apache.commons.lang3.StringUtils; - import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -294,8 +292,7 @@ public class DiscardEffect extends SpellAbilityEffect { continue; // for loop over players if (sa.hasParam("RevealNumber")) { - String amountString = sa.getParam("RevealNumber"); - int amount = StringUtils.isNumeric(amountString) ? Integer.parseInt(amountString) : CardFactoryUtil.xCount(source, source.getSVar(amountString)); + int amount = AbilityUtils.calculateAmount(source, sa.getParam("RevealNumber"), sa); dPHand = p.getController().chooseCardsToRevealFromHand(amount, amount, dPHand); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java index 17a633afa6a..780d6b8697e 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -153,7 +153,7 @@ public class PlayEffect extends SpellAbilityEffect { final boolean wasFaceDown; if (tgtCard.isFaceDown()) { - tgtCard.turnFaceUp(false, false); + tgtCard.forceTurnFaceUp(); wasFaceDown = true; } else { wasFaceDown = false; diff --git a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java index 56d064457b8..2ab35c6b1dd 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java @@ -76,7 +76,7 @@ public class SetStateEffect extends SpellAbilityEffect { if ("TurnFace".equals(mode) && tgt.isFaceDown() && tgt.isInZone(ZoneType.Battlefield) && !tgt.getState(CardStateName.Original).getType().isPermanent()) { Card lki = CardUtil.getLKICopy(tgt); - lki.turnFaceUp(true, false); + lki.forceTurnFaceUp(); game.getAction().reveal(new CardCollection(lki), lki.getOwner(), true, Localizer.getInstance().getMessage("lblFaceDownCardCantTurnFaceUp")); continue; @@ -106,11 +106,11 @@ public class SetStateEffect extends SpellAbilityEffect { boolean hasTransformed = false; if (morphUp) { - hasTransformed = tgt.turnFaceUp(); + hasTransformed = tgt.turnFaceUp(sa); } else if (manifestUp) { - hasTransformed = tgt.turnFaceUp(true, true); + hasTransformed = tgt.turnFaceUp(true, true, sa); } else { - hasTransformed = tgt.changeCardState(mode, sa.getParam("NewState")); + hasTransformed = tgt.changeCardState(mode, sa.getParam("NewState"), sa); } if ( hasTransformed ) { if (morphUp) { 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 753b99333cf..91aeeef211b 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -549,7 +549,7 @@ public class Card extends GameEntity implements Comparable { currentState.getView().updateType(currentState); } - public boolean changeCardState(final String mode, final String customState) { + public boolean changeCardState(final String mode, final String customState, final SpellAbility cause) { if (mode == null) return changeToState(CardStateName.smartValueOf(customState)); @@ -597,7 +597,7 @@ public class Card extends GameEntity implements Comparable { if (oldState == CardStateName.Original || oldState == CardStateName.Flipped) { return turnFaceDown(); } else if (isFaceDown()) { - return turnFaceUp(); + return turnFaceUp(cause); } } else if (mode.equals("Meld") && isMeldable()) { return changeToState(CardStateName.Meld); @@ -656,11 +656,11 @@ public class Card extends GameEntity implements Comparable { return setState(CardStateName.FaceDown, false); } - public boolean turnFaceUp() { - return turnFaceUp(false, true); + public boolean turnFaceUp(SpellAbility cause) { + return turnFaceUp(false, true, cause); } - public boolean turnFaceUp(boolean manifestPaid, boolean runTriggers) { + public boolean turnFaceUp(boolean manifestPaid, boolean runTriggers, SpellAbility cause) { if (isFaceDown()) { if (manifestPaid && isManifested() && !getRules().getType().isCreature()) { // If we've manifested a non-creature and we're demanifesting disallow it @@ -688,8 +688,11 @@ public class Card extends GameEntity implements Comparable { getGame().getReplacementHandler().run(ReplacementType.TurnFaceUp, AbilityKey.mapFromAffected(this)); // Run triggers + final Map runParams = AbilityKey.mapFromCard(this); + runParams.put(AbilityKey.Cause, cause); + getGame().getTriggerHandler().registerActiveTrigger(this, false); - getGame().getTriggerHandler().runTrigger(TriggerType.TurnFaceUp, AbilityKey.mapFromCard(this), false); + getGame().getTriggerHandler().runTrigger(TriggerType.TurnFaceUp, runParams, false); } return result; } @@ -6102,7 +6105,7 @@ public class Card extends GameEntity implements Comparable { if (isFaceDown()) { lkicheck = true; source = CardUtil.getLKICopy(source); - source.turnFaceUp(false, false); + source.forceTurnFaceUp(); } if (lkicheck) { @@ -6315,7 +6318,7 @@ public class Card extends GameEntity implements Comparable { public void forceTurnFaceUp() { getGame().getTriggerHandler().suppressMode(TriggerType.TurnFaceUp); - turnFaceUp(false, false); + turnFaceUp(false, false, null); getGame().getTriggerHandler().clearSuppression(TriggerType.TurnFaceUp); } 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 a9514ed4a12..bf7b1156cfe 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -1772,7 +1772,7 @@ public class Player extends GameEntity implements Comparable { public final void playLandNoCheck(final Card land) { land.setController(this, 0); if (land.isFaceDown()) { - land.turnFaceUp(); + land.turnFaceUp(null); } final Card c = game.getAction().moveTo(getZone(ZoneType.Battlefield), land, null); game.updateLastStateForCard(c); diff --git a/forge-game/src/main/java/forge/game/spellability/Spell.java b/forge-game/src/main/java/forge/game/spellability/Spell.java index 7901469e500..2de48e94e87 100644 --- a/forge-game/src/main/java/forge/game/spellability/Spell.java +++ b/forge-game/src/main/java/forge/game/spellability/Spell.java @@ -209,7 +209,7 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable source = CardUtil.getLKICopy(source); } - source.turnFaceUp(false, false); + source.forceTurnFaceUp(); lkicheck = true; } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTurnFaceUp.java b/forge-game/src/main/java/forge/game/trigger/TriggerTurnFaceUp.java index 0ca7689734d..f79a8ba5a18 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerTurnFaceUp.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTurnFaceUp.java @@ -65,7 +65,7 @@ public class TriggerTurnFaceUp extends Trigger { /** {@inheritDoc} */ @Override public final void setTriggeringObjects(final SpellAbility sa, Map runParams) { - sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card); + sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card, AbilityKey.Cause); } @Override diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index ee805d953e5..17933b95a88 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -242,7 +242,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable