From eae566a83c710f9ff0e34760002b673565f266ef Mon Sep 17 00:00:00 2001 From: tool4ever Date: Sun, 18 Jun 2023 10:06:00 +0200 Subject: [PATCH] Fix full replacement not reaching caller if chain contains update result (#3281) --- .../src/main/java/forge/game/card/CardProperty.java | 9 ++++++++- .../java/forge/game/replacement/ReplacementHandler.java | 8 +++----- .../ai/simulation/SpellAbilityPickerSimulationTest.java | 3 --- forge-gui/res/cardsfolder/b/balor.txt | 2 +- forge-gui/res/cardsfolder/p/prophetic_titan.txt | 2 +- forge-gui/res/cardsfolder/s/sakashimas_will.txt | 2 +- forge-gui/res/cardsfolder/s/szats_will.txt | 2 +- .../cardsfolder/upcoming/witch_king_bringer_of_ruin.txt | 2 +- 8 files changed, 16 insertions(+), 14 deletions(-) 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 4ad8b439eb0..6f99a4ba06f 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -1309,7 +1309,14 @@ public class CardProperty { } } } else if (property.startsWith("leastPower")) { - final CardCollectionView cards = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES); + CardCollectionView cards = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES); + if (property.contains("ControlledBy")) { + FCollectionView p = AbilityUtils.getDefinedPlayers(source, property.split("ControlledBy")[1], spellAbility); + cards = CardLists.filterControlledBy(cards, p); + if (!cards.contains(card)) { + return false; + } + } for (final Card crd : cards) { if (crd.getNetPower() < card.getNetPower()) { return false; diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java index 8d4a120d6ca..37ccfd8ed42 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java @@ -29,7 +29,6 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.google.common.collect.Sets; import forge.game.CardTraitBase; @@ -251,7 +250,7 @@ public class ReplacementHandler { // if its updated, try to call event again if (res == ReplacementResult.Updated) { - Map params = Maps.newHashMap(runParams); + Map params = AbilityKey.newMap(runParams); if (params.containsKey(AbilityKey.EffectOnly)) { params.put(AbilityKey.EffectOnly, true); @@ -260,15 +259,14 @@ public class ReplacementHandler { switch (result) { case NotReplaced: case Updated: { - for (Map.Entry e : params.entrySet()) { - runParams.put(e.getKey(), e.getValue()); - } + runParams.putAll(params); // effect was updated runParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); break; } default: // effect was replaced with something else + res = result; runParams.put(AbilityKey.ReplacementResult, result); break; } diff --git a/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java b/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java index 50131064c3b..99a9b65cc33 100644 --- a/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java +++ b/forge-gui-desktop/src/test/java/forge/ai/simulation/SpellAbilityPickerSimulationTest.java @@ -418,8 +418,6 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest { continue; } -// System.out.println(c.getName()); - // Skip glacial chasm, it's really weird. if (c.getName().equals("Glacial Chasm")) { System.out.println("Skipping " + c.getName()); @@ -478,7 +476,6 @@ public class SpellAbilityPickerSimulationTest extends SimulationTest { AssertJUnit.assertEquals(0, funky.size()); } - @Test public void testPlayRememberedCardsLand() { Game game = initAndCreateGame(); diff --git a/forge-gui/res/cardsfolder/b/balor.txt b/forge-gui/res/cardsfolder/b/balor.txt index ea8c46b73fd..ed54a30823a 100644 --- a/forge-gui/res/cardsfolder/b/balor.txt +++ b/forge-gui/res/cardsfolder/b/balor.txt @@ -5,7 +5,7 @@ PT:5/5 K:Flying T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigChoose | TriggerDescription$ Whenever CARDNAME attacks or dies, ABILITY T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChoose | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks or dies, ABILITY -SVar:TrigChoose:DB$ Charm | MinCharmNum$ 1 | CharmNum$ MaxUniqueOpponents | Choices$ TrigDrawDiscard,TrigSacrifice,TrigDmg | AdditionalDescription$ choose one or more. Each mode must target a different player. +SVar:TrigChoose:DB$ Charm | MinCharmNum$ 1 | CharmNum$ MaxUniqueOpponents | Choices$ TrigDrawDiscard,TrigSacrifice,TrigDmg | AdditionalDescription$ or more. Each mode must target a different player. SVar:TrigDrawDiscard:DB$ Draw | ValidTgts$ Opponent | TargetUnique$ True | NumCards$ 3 | SubAbility$ Discard3 | SpellDescription$ Target opponent draws three cards, then discards three cards at random. SVar:Discard3:DB$ Discard | Defined$ ParentTarget | Mode$ Random | NumCards$ 3 SVar:TrigSacrifice:DB$ Sacrifice | ValidTgts$ Opponent | TargetUnique$ True | SacValid$ Artifact.nonToken | SpellDescription$ Target opponent sacrifices a nontoken artifact. | SacMessage$ nontoken artifact diff --git a/forge-gui/res/cardsfolder/p/prophetic_titan.txt b/forge-gui/res/cardsfolder/p/prophetic_titan.txt index 36e3b3f22ca..1a1b09e4f59 100644 --- a/forge-gui/res/cardsfolder/p/prophetic_titan.txt +++ b/forge-gui/res/cardsfolder/p/prophetic_titan.txt @@ -3,7 +3,7 @@ ManaCost:4 U R Types:Creature Giant Wizard PT:4/4 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerDescription$ Delirium — When CARDNAME enters the battlefield, ABILITY -SVar:TrigCharm:DB$ Charm | CharmNum$ X | Choices$ DBDealDamage,DBDig | AdditionalDescription$ If there are four or more card types in your graveyard, choose both. +SVar:TrigCharm:DB$ Charm | CharmNum$ X | Choices$ DBDealDamage,DBDig | AdditionalDescription$ . If there are four or more card types in your graveyard, choose both. SVar:DBDealDamage:DB$ DealDamage | ValidTgts$ Any | NumDmg$ 4 | SpellDescription$ CARDNAME deals 4 damage to any target. SVar:DBDig:DB$ Dig | DigNum$ 4 | RestRandomOrder$ True | NoReveal$ True | SpellDescription$ Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in a random order. SVar:X:Count$Compare Y GE4.2.1 diff --git a/forge-gui/res/cardsfolder/s/sakashimas_will.txt b/forge-gui/res/cardsfolder/s/sakashimas_will.txt index 7d976373fd2..3e1c2b68f2e 100644 --- a/forge-gui/res/cardsfolder/s/sakashimas_will.txt +++ b/forge-gui/res/cardsfolder/s/sakashimas_will.txt @@ -1,7 +1,7 @@ Name:Sakashima's Will ManaCost:3 U Types:Sorcery -A:SP$ Charm | Cost$ 3 U | MinCharmNum$ 1 | CharmNum$ X | Choices$ DBControl,DBImprint | AdditionalDescription$ If you control a commander as you cast this spell, you may choose both. +A:SP$ Charm | Cost$ 3 U | MinCharmNum$ 1 | CharmNum$ X | Choices$ DBControl,DBImprint | AdditionalDescription$ . If you control a commander as you cast this spell, you may choose both. SVar:DBControl:DB$ ChooseCard | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | Mandatory$ True | Choices$ Creature.TargetedPlayerCtrl | ChoiceTitle$ Choose a creature you control | SubAbility$ DBGainControl | AILogic$ WorstCard | SpellDescription$ Target opponent chooses a creature they control. You gain control of it. SVar:DBGainControl:DB$ GainControl | Defined$ ChosenCard | NewController$ You | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True diff --git a/forge-gui/res/cardsfolder/s/szats_will.txt b/forge-gui/res/cardsfolder/s/szats_will.txt index 9134cfc882b..4229a6a56ec 100644 --- a/forge-gui/res/cardsfolder/s/szats_will.txt +++ b/forge-gui/res/cardsfolder/s/szats_will.txt @@ -1,7 +1,7 @@ Name:Szat's Will ManaCost:4 B Types:Instant -A:SP$ Charm | Cost$ 4 B | MinCharmNum$ 1 | CharmNum$ X | Choices$ DBOppSac,DBExile | AdditionalDescription$ If you control a commander as you cast this spell, you may choose both. +A:SP$ Charm | Cost$ 4 B | MinCharmNum$ 1 | CharmNum$ X | Choices$ DBOppSac,DBExile | AdditionalDescription$ . If you control a commander as you cast this spell, you may choose both. SVar:DBOppSac:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | RepeatSubAbility$ DBChooseCard | SubAbility$ DBSac | SpellDescription$ Each opponent sacrifices a creature they control with the greatest power. SVar:DBChooseCard:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.greatestPowerControlledByRemembered | ChoiceTitle$ Choose a creature you control with the greatest power | Mandatory$ True | RememberChosen$ True SVar:DBSac:DB$ SacrificeAll | ValidCards$ Card.IsRemembered | SubAbility$ DBCleanup | StackDescription$ None diff --git a/forge-gui/res/cardsfolder/upcoming/witch_king_bringer_of_ruin.txt b/forge-gui/res/cardsfolder/upcoming/witch_king_bringer_of_ruin.txt index 02243aeb62d..d65420afcee 100644 --- a/forge-gui/res/cardsfolder/upcoming/witch_king_bringer_of_ruin.txt +++ b/forge-gui/res/cardsfolder/upcoming/witch_king_bringer_of_ruin.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Wraith Noble PT:5/3 K:Flying T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigSac | TriggerDescription$ Whenever CARDNAME attacks, defending player sacrifices a creature with the least power among creatures they control. -SVar:TrigSac:DB$ Sacrifice | Defined$ TriggeredDefendingPlayer | SacValid$ Creature.leastPowerControlledBy TriggeredDefendingPlayer +SVar:TrigSac:DB$ Sacrifice | Defined$ TriggeredDefendingPlayer | SacValid$ Creature.leastPowerControlledByTriggeredDefendingPlayer SVar:HasAttackEffect:True DeckHas:Ability$Sacrifice Oracle:Flying\nWhenever Witch-king, Bringer of Ruin attacks, defending player sacrifices a creature with the least power among creatures they control. \ No newline at end of file