From 4683e5c05ade2a3fc697ffa7ff95722e94d36851 Mon Sep 17 00:00:00 2001 From: ssk97 Date: Sun, 6 Jul 2025 22:49:51 -0700 Subject: [PATCH 1/2] Fix saga first chapter zcc (#13710) * Enable disabled tests * Enable zcc Saga fix * Remove existing zcc hacks (cherry picked from commit 19f980c2ce4ce4eef345c141c16dba55aaed6e44) --- .../src/mage/cards/g/GenesisOfTheDaleks.java | 41 +------------------ .../src/mage/cards/l/LongListOfTheEnts.java | 13 +++--- .../mage/cards/s/SummonEsperValigarmanda.java | 2 +- .../mage/cards/t/TheAesirEscapeValhalla.java | 8 ++-- .../src/mage/cards/t/TheCreationOfAvacyn.java | 2 +- .../single/cmm/BattleAtTheHelvaultTest.java | 2 - .../cards/single/fic/SummonIxionTest.java | 2 - .../pip/Vault13DwellersJourneyTest.java | 4 -- .../cards/single/who/DayOfTheMoonTest.java | 2 - .../cards/single/who/TheWarGamesTest.java | 3 -- .../single/who/TrialOfATimeLordTest.java | 2 - .../woe/ThePrincessTakesFlightTest.java | 3 -- .../main/java/mage/abilities/AbilityImpl.java | 5 +-- 13 files changed, 15 insertions(+), 74 deletions(-) diff --git a/Mage.Sets/src/mage/cards/g/GenesisOfTheDaleks.java b/Mage.Sets/src/mage/cards/g/GenesisOfTheDaleks.java index daef4301cea9..6807307ac586 100644 --- a/Mage.Sets/src/mage/cards/g/GenesisOfTheDaleks.java +++ b/Mage.Sets/src/mage/cards/g/GenesisOfTheDaleks.java @@ -2,8 +2,7 @@ import mage.abilities.Ability; import mage.abilities.common.SagaAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.Effect; +import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyAllEffect; @@ -19,7 +18,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; import mage.game.permanent.token.DalekToken; import mage.players.Player; import mage.target.common.TargetOpponent; @@ -44,7 +42,7 @@ public GenesisOfTheDaleks(UUID ownerId, CardSetInfo setInfo) { // I, II, III -- Create a 3/3 black Dalek artifact creature token with menace for each lore counter on Genesis of the Daleks. sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_III, - new CreateTokenEffect(new DalekToken(), GenesisOfTheDaleksValue.instance) + new CreateTokenEffect(new DalekToken(), new CountersSourceCount(CounterType.LORE)) ); // IV -- Target opponent faces a villainous choice -- Destroy all Dalek creatures and each of your opponents loses life equal to the total power of Daleks that died this turn, or destroy all non-Dalek creatures. @@ -65,41 +63,6 @@ public GenesisOfTheDaleks copy() { } } -enum GenesisOfTheDaleksValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - Permanent permanent = sourceAbility.getSourcePermanentOrLKI(game); - if (permanent != null) { - return permanent - .getCounters(game) - .getCount(CounterType.LORE); - } - return Optional - .ofNullable(sourceAbility) - .map(Ability::getSourceId) - .map(game::getPermanentOrLKIBattlefield) - .map(p -> p.getCounters(game).getCount(CounterType.LORE)) - .orElse(0); - } - - @Override - public GenesisOfTheDaleksValue copy() { - return this; - } - - @Override - public String getMessage() { - return "lore counter on {this}"; - } - - @Override - public String toString() { - return "1"; - } -} - class GenesisOfTheDaleksEffect extends OneShotEffect { private static final FaceVillainousChoice choice = new FaceVillainousChoice( diff --git a/Mage.Sets/src/mage/cards/l/LongListOfTheEnts.java b/Mage.Sets/src/mage/cards/l/LongListOfTheEnts.java index 95abf6d63d5e..0bb6414a7a71 100644 --- a/Mage.Sets/src/mage/cards/l/LongListOfTheEnts.java +++ b/Mage.Sets/src/mage/cards/l/LongListOfTheEnts.java @@ -53,8 +53,8 @@ public LongListOfTheEnts copy() { return new LongListOfTheEnts(this); } - static String getKey(Game game, Ability source, int offset) { - return "EntList_" + source.getSourceId() + "_" + (offset + CardUtil.getActualSourceObjectZoneChangeCounter(game, source)); + static String getKey(Game game, Ability source) { + return "EntList_" + source.getSourceId() + "_" + CardUtil.getActualSourceObjectZoneChangeCounter(game, source); } } @@ -67,7 +67,7 @@ public String getText(Game game, Ability ability) { if (ability.getSourcePermanentIfItStillExists(game) == null) { return null; } - Set subTypes = (Set) game.getState().getValue(LongListOfTheEnts.getKey(game, ability, 0)); + Set subTypes = (Set) game.getState().getValue(LongListOfTheEnts.getKey(game, ability)); if (subTypes == null || subTypes.isEmpty()) { return "No creature types have been noted yet."; } @@ -109,14 +109,11 @@ public boolean apply(Game game, Ability source) { return false; } - Object existingEntList = game.getState().getValue(LongListOfTheEnts.getKey(game, source, 0)); - int offset; + Object existingEntList = game.getState().getValue(LongListOfTheEnts.getKey(game, source)); Set newEntList; if (existingEntList == null) { - offset = 1; // zcc is off-by-one due to still entering battlefield newEntList = new LinkedHashSet<>(); } else { - offset = 0; newEntList = new LinkedHashSet<>((Set) existingEntList); } Set chosenTypes = newEntList @@ -132,7 +129,7 @@ public boolean apply(Game game, Ability source) { SubType subType = SubType.byDescription(choice.getChoiceKey()); game.informPlayers(player.getLogName() + " notes the creature type " + subType); newEntList.add(subType); - game.getState().setValue(LongListOfTheEnts.getKey(game, source, offset), newEntList); + game.getState().setValue(LongListOfTheEnts.getKey(game, source), newEntList); FilterSpell filter = new FilterCreatureSpell("a creature spell of that type"); filter.add(subType.getPredicate()); game.addDelayedTriggeredAbility(new AddCounterNextSpellDelayedTriggeredAbility(filter), source); diff --git a/Mage.Sets/src/mage/cards/s/SummonEsperValigarmanda.java b/Mage.Sets/src/mage/cards/s/SummonEsperValigarmanda.java index 3a2c1b4614ad..3fcc14c2c8ec 100644 --- a/Mage.Sets/src/mage/cards/s/SummonEsperValigarmanda.java +++ b/Mage.Sets/src/mage/cards/s/SummonEsperValigarmanda.java @@ -107,7 +107,7 @@ public boolean apply(Game game, Ability source) { return !cards.isEmpty() && controller.moveCardsToExile( cards.getCards(game), source, game, true, - CardUtil.getExileZoneId(game, source, 1), + CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source) ); } diff --git a/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java b/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java index 0095d30b9ae5..aed85868cd23 100644 --- a/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java +++ b/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java @@ -1,15 +1,13 @@ package mage.cards.t; -import java.util.UUID; - import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.ExileZone; @@ -20,6 +18,8 @@ import mage.target.common.TargetControlledCreaturePermanent; import mage.util.CardUtil; +import java.util.UUID; + /** * * @author Grath @@ -83,7 +83,7 @@ public boolean apply(Game game, Ability source) { controller.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { - UUID exileId = CardUtil.getExileZoneId(game, source, 1); + UUID exileId = CardUtil.getExileZoneId(game, source); MageObject sourceObject = source.getSourceObject(game); String exileName = sourceObject != null ? sourceObject.getName() : ""; controller.moveCardsToExile(card, source, game, false, exileId, exileName); diff --git a/Mage.Sets/src/mage/cards/t/TheCreationOfAvacyn.java b/Mage.Sets/src/mage/cards/t/TheCreationOfAvacyn.java index 17b28d397541..b1cdb9ab4688 100644 --- a/Mage.Sets/src/mage/cards/t/TheCreationOfAvacyn.java +++ b/Mage.Sets/src/mage/cards/t/TheCreationOfAvacyn.java @@ -81,7 +81,7 @@ public boolean apply(Game game, Ability source) { if (card != null) { // exile it face down card.setFaceDown(true, game); - UUID exileId = CardUtil.getExileZoneId(game, source, 1); + UUID exileId = CardUtil.getExileZoneId(game, source); MageObject sourceObject = source.getSourceObject(game); String exileName = sourceObject != null ? sourceObject.getName() : ""; controller.moveCardsToExile(card, source, game, false, exileId, exileName); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmm/BattleAtTheHelvaultTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmm/BattleAtTheHelvaultTest.java index 033278783613..858946e21287 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmm/BattleAtTheHelvaultTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmm/BattleAtTheHelvaultTest.java @@ -2,7 +2,6 @@ import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -19,7 +18,6 @@ public class BattleAtTheHelvaultTest extends CardTestPlayerBase { */ private static final String battle = "Battle at the Helvault"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, battle, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/SummonIxionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/SummonIxionTest.java index 82fb895ccce8..527cba0941b1 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/SummonIxionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/SummonIxionTest.java @@ -3,7 +3,6 @@ import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -23,7 +22,6 @@ public class SummonIxionTest extends CardTestPlayerBase { */ private static final String ixion = "Summon: Ixion"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, ixion, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/Vault13DwellersJourneyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/Vault13DwellersJourneyTest.java index 16b0a3f9ae9d..b5ddd69b9125 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/Vault13DwellersJourneyTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/Vault13DwellersJourneyTest.java @@ -2,7 +2,6 @@ import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -21,7 +20,6 @@ public class Vault13DwellersJourneyTest extends CardTestPlayerBase { */ private static final String vault = "Vault 13: Dweller's Journey"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_ReturnOne() { addCard(Zone.HAND, playerA, vault, 1); @@ -49,7 +47,6 @@ public void test_SimplePlay_ReturnOne() { assertPermanentCount(playerA, "Memnite", 1); assertLife(playerA, 20 + 2); } - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_Return() { addCard(Zone.HAND, playerA, vault, 1); @@ -81,7 +78,6 @@ public void test_SimplePlay_Return() { assertLife(playerA, 20 + 2); } - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_NoReturn() { addCard(Zone.HAND, playerA, vault, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/DayOfTheMoonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/DayOfTheMoonTest.java index bd0c49f72d17..97d1072d424b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/DayOfTheMoonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/DayOfTheMoonTest.java @@ -2,7 +2,6 @@ import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -18,7 +17,6 @@ public class DayOfTheMoonTest extends CardTestPlayerBase { */ private static final String day = "Day of the Moon"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, day, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TheWarGamesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TheWarGamesTest.java index 7bddf646de16..8f5d72293c6a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TheWarGamesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TheWarGamesTest.java @@ -2,7 +2,6 @@ import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -20,7 +19,6 @@ public class TheWarGamesTest extends CardTestPlayerBase { */ private static final String war = "The War Games"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_NoExile() { addCard(Zone.HAND, playerA, war, 1); @@ -63,7 +61,6 @@ public void test_SimplePlay_NoExile() { assertLife(playerB, 20 - 6 - 9); } - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_Exile() { addCard(Zone.HAND, playerA, war, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TrialOfATimeLordTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TrialOfATimeLordTest.java index 09ae8e86c72f..7653a1e1a339 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TrialOfATimeLordTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TrialOfATimeLordTest.java @@ -2,7 +2,6 @@ import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -20,7 +19,6 @@ public class TrialOfATimeLordTest extends CardTestPlayerBase { */ private static final String trial = "Trial of a Time Lord"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, trial, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java index e7b9d1975902..5fe5879fa963 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java @@ -3,7 +3,6 @@ import mage.abilities.keyword.FlyingAbility; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -21,7 +20,6 @@ public class ThePrincessTakesFlightTest extends CardTestPlayerBase { */ private static final String flight = "The Princess Takes Flight"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, flight, 1); @@ -54,7 +52,6 @@ public void test_SimplePlay() { assertExileCount(playerB, "Memnite", 0); assertPermanentCount(playerB, "Memnite", 1); } - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void testFlicker() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 503401775264..dd566fe48343 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -1707,15 +1707,14 @@ public void initSourceObjectZoneChangeCounter(Game game, boolean force) { private int getCurrentSourceObjectZoneChangeCounter(Game game){ int zcc = game.getState().getZoneChangeCounter(getSourceId()); - // TODO: Enable this, #13710 - /*if (game.getPermanentEntering(getSourceId()) != null){ + if (game.getPermanentEntering(getSourceId()) != null){ // If the triggered ability triggered while the permanent is entering the battlefield // then add 1 zcc so that it triggers as if the permanent was already on the battlefield // So "Enters with counters" causes "Whenever counters are placed" to trigger with battlefield zcc // Particularly relevant for Sagas, which always involve both // Note that this does NOT apply to "As ~ ETB" effects, those still use the stack zcc zcc += 1; - }*/ + } return zcc; } From 2552dcf63313f3d7f893efd02d4ffd6ab7aea897 Mon Sep 17 00:00:00 2001 From: Steven Knipe Date: Sun, 10 Aug 2025 18:19:41 -0700 Subject: [PATCH 2/2] Fix and test token saga zcc tracking --- .../woe/ThePrincessTakesFlightTest.java | 69 +++++++++++++++++++ .../main/java/mage/abilities/AbilityImpl.java | 5 +- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java index 5fe5879fa963..8ff3950a316f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java @@ -79,4 +79,73 @@ public void testFlicker() { assertPermanentCount(playerA, "Memnite", 1); assertGraveyardCount(playerA, flight, 1); } + + @Test + public void test_TokenCopy() { + addCard(Zone.HAND, playerA, flight, 1); + addCard(Zone.HAND, playerA, "Swords to Plowshares", 1); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerA, "Ondu Spiritdancer", 1); + addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, flight); + setChoice(playerA, "I - "); + addTarget(playerA, "Memnite"); + setChoice(playerA, true); + addTarget(playerA, "Grizzly Bears"); + + checkExileCount("after I, exiled Memnite", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Memnite", 1); + checkExileCount("after I, exiled Grizzly Bears", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Grizzly Bears", 1); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Swords to Plowshares", "Ondu Spiritdancer"); + + // turn 3 + setChoice(playerA, "II - "); + // No targets available + + // turn 5 + setChoice(playerA, "III - "); + setStrictChooseMode(true); + setStopAt(5, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertExileCount(playerA, "Grizzly Bears", 0); + assertExileCount(playerB, "Memnite", 0); + assertPermanentCount(playerA, "Grizzly Bears", 1); + assertPermanentCount(playerB, "Memnite", 1); + } + @Test + public void test_SpellCopy() { + addCard(Zone.HAND, playerA, flight, 1); + addCard(Zone.HAND, playerA, "Swords to Plowshares", 1); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerA, "The Sixth Doctor", 1); + addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, flight); + addTarget(playerA, "Memnite"); + addTarget(playerA, "Grizzly Bears"); + + checkExileCount("after I, exiled Memnite", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Memnite", 1); + checkExileCount("after I, exiled Grizzly Bears", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Grizzly Bears", 1); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Swords to Plowshares", "The Sixth Doctor"); + + // turn 3 + setChoice(playerA, "II - "); + // No targets available + + // turn 5 + setChoice(playerA, "III - "); + setStrictChooseMode(true); + setStopAt(5, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertExileCount(playerA, "Grizzly Bears", 0); + assertExileCount(playerB, "Memnite", 0); + assertPermanentCount(playerA, "Grizzly Bears", 1); + assertPermanentCount(playerB, "Memnite", 1); + } } diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index dd566fe48343..8b16d1a20787 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -33,6 +33,7 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; import mage.game.stack.Spell; import mage.game.stack.StackAbility; import mage.players.Player; @@ -1707,13 +1708,15 @@ public void initSourceObjectZoneChangeCounter(Game game, boolean force) { private int getCurrentSourceObjectZoneChangeCounter(Game game){ int zcc = game.getState().getZoneChangeCounter(getSourceId()); - if (game.getPermanentEntering(getSourceId()) != null){ + Permanent p = game.getPermanentEntering(getSourceId()); + if (p != null && !(p instanceof PermanentToken)){ // If the triggered ability triggered while the permanent is entering the battlefield // then add 1 zcc so that it triggers as if the permanent was already on the battlefield // So "Enters with counters" causes "Whenever counters are placed" to trigger with battlefield zcc // Particularly relevant for Sagas, which always involve both // Note that this does NOT apply to "As ~ ETB" effects, those still use the stack zcc zcc += 1; + // However, tokens don't change their zcc upon entering the battlefield, so don't add for them } return zcc; }