From e1f784211f8e64b3074cd636d60e109ff15ad2e9 Mon Sep 17 00:00:00 2001 From: Bug Hunter Date: Fri, 14 Jan 2022 04:43:47 +0000 Subject: [PATCH] CR 603.6b: cardsAddedThisTurn should not use LKI with unmodified characteristics for battlefield --- .../src/main/java/forge/ai/ability/CloneAi.java | 2 +- .../java/forge/ai/simulation/GameCopier.java | 1 + .../java/forge/util/maps/EnumMapOfLists.java | 2 -- .../src/main/java/forge/game/GameAction.java | 10 ++++++++-- .../java/forge/game/ability/AbilityUtils.java | 6 ------ .../main/java/forge/game/card/CardProperty.java | 16 ++++++++++++---- .../src/main/java/forge/game/zone/Zone.java | 13 ++++++++++++- forge-gui/res/cardsfolder/e/emissarys_ploy.txt | 3 +-- forge-gui/res/cardsfolder/s/sanctum_prelate.txt | 3 +-- forge-gui/res/cardsfolder/s/sorins_guide.txt | 2 +- 10 files changed, 37 insertions(+), 21 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/CloneAi.java b/forge-ai/src/main/java/forge/ai/ability/CloneAi.java index f0cfe7c4a87..d9a7070f29c 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CloneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CloneAi.java @@ -53,7 +53,7 @@ public class CloneAi extends SpellAbilityAi { boolean bFlag = false; for (final Card c : defined) { - bFlag |= (!c.isCreature() && !c.isTapped() && !(c.getTurnInZone() == phase.getTurn())); + bFlag |= !c.isCreature() && !c.isTapped() && !(c.getTurnInZone() == phase.getTurn()); // for creatures that could be improved (like Figure of Destiny) if (c.isCreature() && (!sa.hasParam("Duration") || (!c.isTapped() && !c.isSick()))) { diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java index 92f75da9be2..103b50a5736 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java @@ -89,6 +89,7 @@ public class GameCopier { newPlayer.setCounters(Maps.newHashMap(origPlayer.getCounters())); newPlayer.setLifeLostLastTurn(origPlayer.getLifeLostLastTurn()); newPlayer.setLifeLostThisTurn(origPlayer.getLifeLostThisTurn()); + newPlayer.setLifeGainedThisTurn(origPlayer.getLifeGainedThisTurn()); newPlayer.getManaPool().add(origPlayer.getManaPool()); newPlayer.setCommanders(origPlayer.getCommanders()); // will be fixed up below playerMap.put(origPlayer, newPlayer); diff --git a/forge-core/src/main/java/forge/util/maps/EnumMapOfLists.java b/forge-core/src/main/java/forge/util/maps/EnumMapOfLists.java index 2d025e331de..19b0293a506 100644 --- a/forge-core/src/main/java/forge/util/maps/EnumMapOfLists.java +++ b/forge-core/src/main/java/forge/util/maps/EnumMapOfLists.java @@ -17,7 +17,6 @@ public class EnumMapOfLists, V> extends EnumMap> m, Supplier> factory) { super(m); this.factory = factory; @@ -42,7 +41,6 @@ public class EnumMapOfLists, V> extends EnumMap elements) { ensureCollectionFor(key).addAll(elements); diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index ca30df21f42..4416787a829 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -528,7 +528,7 @@ public class GameAction { if (repres != ReplacementResult.NotReplaced) continue; } if (card == c) { - zoneTo.add(copied, position, lastKnownInfo); // the modified state of the card is also reported here (e.g. for Morbid + Awaken) + zoneTo.add(copied, position, toBattlefield ? null : lastKnownInfo); // the modified state of the card is also reported here (e.g. for Morbid + Awaken) } else { zoneTo.add(card, position, CardUtil.getLKICopy(card)); } @@ -537,7 +537,7 @@ public class GameAction { } else { // "enter the battlefield as a copy" - apply code here // but how to query for input here and continue later while the callers assume synchronous result? - zoneTo.add(copied, position, lastKnownInfo); // the modified state of the card is also reported here (e.g. for Morbid + Awaken) + zoneTo.add(copied, position, toBattlefield ? null : lastKnownInfo); // the modified state of the card is also reported here (e.g. for Morbid + Awaken) c.setZone(zoneTo); } @@ -568,6 +568,12 @@ public class GameAction { // Need to apply any static effects to produce correct triggers checkStaticAbilities(); + + // CR 603.6b + if (toBattlefield) { + zoneTo.saveLKI(copied, lastKnownInfo); + } + game.getTriggerHandler().clearActiveTriggers(copied, null); game.getTriggerHandler().registerActiveLTBTrigger(lastKnownInfo); game.getTriggerHandler().registerActiveTrigger(copied, false); 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 4ff465ae098..ab333dede5b 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -2706,9 +2706,6 @@ public class AbilityUtils { String validFilter = workingCopy[hasFrom ? 4 : 2] ; final List res = CardUtil.getThisTurnEntered(destination, origin, validFilter, c, ctb); - if (origin == null) { // Remove cards on the battlefield that changed controller - res.removeAll(CardUtil.getThisTurnEntered(destination, destination, validFilter, c, ctb)); - } return doXMath(res.size(), expr, c, ctb); } @@ -2722,9 +2719,6 @@ public class AbilityUtils { String validFilter = workingCopy[hasFrom ? 4 : 2] ; final List res = CardUtil.getLastTurnEntered(destination, origin, validFilter, c, ctb); - if (origin == null) { // Remove cards on the battlefield that changed controller - res.removeAll(CardUtil.getLastTurnEntered(destination, destination, validFilter, c, ctb)); - } return doXMath(res.size(), expr, c, ctb); } diff --git a/forge-game/src/main/java/forge/game/card/CardProperty.java b/forge-game/src/main/java/forge/game/card/CardProperty.java index 5dc629bab2c..6240b39d65d 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -1397,10 +1397,18 @@ public class CardProperty { return false; } } else if (property.equals("cmcNotChosenEvenOdd")) { - if (source.hasChosenEvenOdd()) { - if ((card.getCMC() % 2 == 0) == (source.getChosenEvenOdd() == EvenOdd.Even)) { - return false; - } + if (!source.hasChosenEvenOdd()) { + return false; + } + if ((card.getCMC() % 2 == 0) == (source.getChosenEvenOdd() == EvenOdd.Even)) { + return false; + } + } else if (property.equals("cmcChosen")) { + if (!source.hasChosenNumber()) { + return false; + } + if (card.getCMC() != source.getChosenNumber()) { + return false; } } else if (property.startsWith("power") || property.startsWith("toughness") || property.startsWith("cmc") || property.startsWith("totalPT")) { diff --git a/forge-game/src/main/java/forge/game/zone/Zone.java b/forge-game/src/main/java/forge/game/zone/Zone.java index b60850a018d..12f6e1c4b52 100644 --- a/forge-game/src/main/java/forge/game/zone/Zone.java +++ b/forge-game/src/main/java/forge/game/zone/Zone.java @@ -111,7 +111,9 @@ public class Zone implements java.io.Serializable, Iterable { if (zt != zoneType) { c.setTurnInController(getPlayer()); c.setTurnInZone(game.getPhaseHandler().getTurn()); - cardsAddedThisTurn.add(zt, latestState != null ? latestState : c); + if (latestState != null) { + cardsAddedThisTurn.add(zt, latestState); + } } } @@ -265,4 +267,13 @@ public class Zone implements java.io.Serializable, Iterable { return result; } + + public void saveLKI(Card c, Card old) { + final Zone oldZone = game.getZoneOf(old); + final ZoneType zt = oldZone == null ? ZoneType.Stack : oldZone.getZoneType(); + if (zt == zoneType) { + return; + } + cardsAddedThisTurn.add(zt, CardUtil.getLKICopy(c)); + } } diff --git a/forge-gui/res/cardsfolder/e/emissarys_ploy.txt b/forge-gui/res/cardsfolder/e/emissarys_ploy.txt index 22140e0306d..baee8f6368b 100644 --- a/forge-gui/res/cardsfolder/e/emissarys_ploy.txt +++ b/forge-gui/res/cardsfolder/e/emissarys_ploy.txt @@ -2,6 +2,5 @@ Name:Emissary's Ploy Types:Conspiracy Text:(Start the game with this conspiracy face up in the command zone.) K:Before drawing your opening hand, choose 1, 2, or 3. -S:Mode$ Continuous | Affected$ Creature.YouCtrl+cmcEQX | AffectedZone$ Stack | AddHiddenKeyword$ May spend mana as though it were mana of any color to cast CARDNAME | Description$ You may spend mana as though it were mana of any color to cast creature spells with mana value equal to the chosen number. -SVar:X:Count$ChosenNumber +S:Mode$ Continuous | Affected$ Creature.YouCtrl+cmcChosen | AffectedZone$ Stack | AddHiddenKeyword$ May spend mana as though it were mana of any color to cast CARDNAME | Description$ You may spend mana as though it were mana of any color to cast creature spells with mana value equal to the chosen number. Oracle:(Start the game with this conspiracy face up in the command zone.)\nBefore drawing your opening hand, choose 1, 2, or 3.\nYou may spend mana as though it were mana of any color to cast creature spells with mana value equal to the chosen number. diff --git a/forge-gui/res/cardsfolder/s/sanctum_prelate.txt b/forge-gui/res/cardsfolder/s/sanctum_prelate.txt index f6790b0a40d..6ca5138a823 100644 --- a/forge-gui/res/cardsfolder/s/sanctum_prelate.txt +++ b/forge-gui/res/cardsfolder/s/sanctum_prelate.txt @@ -4,8 +4,7 @@ Types:Creature Human Cleric PT:2/2 K:ETBReplacement:Other:ChooseNumber SVar:ChooseNumber:DB$ ChooseNumber | Defined$ You | SpellDescription$ As CARDNAME enters the battlefield, choose a number. -S:Mode$ CantBeCast | ValidCard$ Card.nonCreature+cmcEQX | Description$ Noncreature spells with mana value equal to the chosen number can't be cast. -SVar:X:Count$ChosenNumber +S:Mode$ CantBeCast | ValidCard$ Card.nonCreature+cmcChosen | Description$ Noncreature spells with mana value equal to the chosen number can't be cast. AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/sanctum_prelate.jpg Oracle:As Sanctum Prelate enters the battlefield, choose a number.\nNoncreature spells with mana value equal to the chosen number can't be cast. diff --git a/forge-gui/res/cardsfolder/s/sorins_guide.txt b/forge-gui/res/cardsfolder/s/sorins_guide.txt index 5cc58b4490b..e8c0b7e631e 100644 --- a/forge-gui/res/cardsfolder/s/sorins_guide.txt +++ b/forge-gui/res/cardsfolder/s/sorins_guide.txt @@ -2,7 +2,7 @@ Name:Sorin's Guide ManaCost:3 B B Types:Creature Vampire PT:4/2 -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearch | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library and/or graveyard for a card named flying, Vampire CARDNAME, and put it into your hand. If you search your library this way, shuffle it. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearch | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may search your library and/or graveyard for a card named Sorin, Vampire Lord, and put it into your hand. If you search your library this way, shuffle it. SVar:TrigSearch:DB$ ChangeZone | Origin$ Library | OriginChoice$ True | OriginAlternative$ Graveyard | AlternativeMessage$ Would you like to search your library with this ability? If you do, your library will be shuffled. | Destination$ Hand | ChangeType$ Card.namedSorin; Vampire Lord | ChangeNum$ 1 | Optional$ True DeckHints:Name$Sorin, Vampire Lord Oracle:When Sorin's Guide enters the battlefield, you may search your library and/or graveyard for a card named Sorin, Vampire Lord, reveal it, and put it into your hand. If you search your library this way, shuffle.