diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/RielleTheEverwiseTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/RielleTheEverwiseTest.java new file mode 100644 index 00000000000..aba4494e4c5 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/RielleTheEverwiseTest.java @@ -0,0 +1,83 @@ +package org.mage.test.cards.single.iko; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author Susucr + */ +public class RielleTheEverwiseTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.r.RielleTheEverwise} Rielle, the Everwise {1}{U}{R} + * Legendary Creature — Human Wizard + * Rielle, the Everwise gets +1/+0 for each instant and sorcery card in your graveyard. + * Whenever you discard one or more cards for the first time each turn, draw that many cards. + * 0/3 + */ + private static final String rielle = "Rielle, the Everwise"; + + private static void checkMidExecute(String info, Player player, Game game, int stack, int hand, int life) { + Assert.assertEquals(info + " - stack size", stack, game.getStack().size()); + Assert.assertEquals(info + " - hand size", hand, player.getHand().size()); + Assert.assertEquals(info + " - life", life, player.getLife()); + } + + // Bug: you had no play priority to respond to Rielle's trigger at end step. + @Test + public void test_CleanupDiscard_Opp_Response() { + setStrictChooseMode(true); + skipInitShuffling(); + + addCard(Zone.BATTLEFIELD, playerA, rielle); + addCard(Zone.HAND, playerA, "Island", 10); + addCard(Zone.LIBRARY, playerA, "Island", 3); + addCard(Zone.HAND, playerB, "Lightning Bolt"); + addCard(Zone.HAND, playerB, "Shock"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); + + // Choose to discard Islands on first cleanup + setChoice(playerA, "Island", 3); + + // Rielle's Trigger on the stack. + runCode("Trigger on the stack", 1, PhaseStep.CLEANUP, playerB, + (i, p, g) -> checkMidExecute(i, playerA, g, 1, 7, 20)); + + // Cast Bolt in response of Rielle's trigger. + castSpell(1, PhaseStep.CLEANUP, playerB, "Lightning Bolt", playerA); + runCode("Trigger+Bolt on the stack", 1, PhaseStep.CLEANUP, playerB, + (i, p, g) -> checkMidExecute(i, playerA, g, 2, 7, 20)); + + waitStackResolved(1, PhaseStep.CLEANUP, 1); // resolves first bolt + runCode("Trigger+Bolt on the stack", 1, PhaseStep.CLEANUP, playerB, + (i, p, g) -> checkMidExecute(i, playerA, g, 1, 7, 20 - 3)); + + waitStackResolved(1, PhaseStep.CLEANUP, 1); // resolves rielle trigger + runCode("Trigger+Bolt on the stack", 1, PhaseStep.CLEANUP, playerB, + (i, p, g) -> checkMidExecute(i, playerA, g, 0, 10, 20 - 3)); + + // Cast Shock after Rielle's trigger resolved. + castSpell(1, PhaseStep.CLEANUP, playerB, "Shock", playerA); + runCode("Trigger+Bolt on the stack", 1, PhaseStep.CLEANUP, playerB, + (i, p, g) -> checkMidExecute(i, playerA, g, 1, 10, 20 - 3)); + + waitStackResolved(1, PhaseStep.CLEANUP, 1); + runCode("Trigger+Bolt on the stack", 1, PhaseStep.CLEANUP, playerB, + (i, p, g) -> checkMidExecute(i, playerA, g, 0, 10, 20 - 3 - 2)); + + // Discard for the second cleanup. + setChoice(playerA, "Island", 3); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertLife(playerA, 20 - 3 - 2); + assertHandCount(playerA, 7); + assertGraveyardCount(playerA, "Island", 3 + 3); + } +} diff --git a/Mage/src/main/java/mage/game/turn/EndPhase.java b/Mage/src/main/java/mage/game/turn/EndPhase.java index 5eaa20b258a..03e69c4e8bc 100644 --- a/Mage/src/main/java/mage/game/turn/EndPhase.java +++ b/Mage/src/main/java/mage/game/turn/EndPhase.java @@ -28,8 +28,9 @@ public class EndPhase extends Phase { @Override protected void playStep(Game game) { if (currentStep.getType() == PhaseStep.CLEANUP) { + game.getState().increaseStepNum(); game.getTurn().setEndTurnRequested(false); // so triggers trigger again - currentStep.beginStep(game, activePlayerId); + prePriority(game, activePlayerId); // 514.3a At this point, the game checks to see if any state-based actions would be performed // and/or any triggered abilities are waiting to be put onto the stack (including those that // trigger "at the beginning of the next cleanup step"). If so, those state-based actions are @@ -37,10 +38,19 @@ public class EndPhase extends Phase { // priority. Players may cast spells and activate abilities. Once the stack is empty and all players // pass in succession, another cleanup step begins if (game.checkStateAndTriggered()) { - game.playPriority(activePlayerId, true); - playStep(game); + // Queues a new cleanup step + game.getState().getTurnMods().add(new TurnMod(activePlayerId).withExtraStep(new CleanupStep())); + // resume priority + if (!game.isPaused() && !game.checkIfGameIsOver() && !game.executingRollback()) { + currentStep.priority(game, activePlayerId, false); + if (game.executingRollback()) { + return; + } + } + } + if (!game.isPaused() && !game.checkIfGameIsOver() && !game.executingRollback()) { + postPriority(game, activePlayerId); } - currentStep.endStep(game, activePlayerId); } else { super.playStep(game); } diff --git a/Mage/src/main/java/mage/game/turn/Phase.java b/Mage/src/main/java/mage/game/turn/Phase.java index 89863a8397d..38394cacae3 100644 --- a/Mage/src/main/java/mage/game/turn/Phase.java +++ b/Mage/src/main/java/mage/game/turn/Phase.java @@ -275,4 +275,7 @@ public abstract class Phase implements Serializable { } } + public String toString() { + return type.toString(); + } } diff --git a/Mage/src/main/java/mage/game/turn/Step.java b/Mage/src/main/java/mage/game/turn/Step.java index ce94f2862ea..24e6e7debf6 100644 --- a/Mage/src/main/java/mage/game/turn/Step.java +++ b/Mage/src/main/java/mage/game/turn/Step.java @@ -1,15 +1,15 @@ package mage.game.turn; -import java.io.Serializable; -import java.util.UUID; - import mage.constants.PhaseStep; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.util.Copyable; +import java.io.Serializable; +import java.util.UUID; + /** * Game's step *

@@ -85,4 +85,7 @@ public abstract class Step implements Serializable, Copyable { return stepPart; } + public String toString() { + return type.getStepText(); + } }