diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java index d0d3e2ff573..beaef32b615 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java @@ -90,45 +90,6 @@ public class PersistTest extends CardTestPlayerBase { } - - /** - * see here for more information - * http://www.slightlymagic.net/forum/viewtopic.php?f=116&t=14516 - * - * Tests Safehold Elite with persist returns to battlefield with -1/-1 counter - * Murder Investigation puts 2 tokens onto battlefield because enchanted Safehold Elite - * was 2/2 - * - */ - @Test - public void testUndyingTriggersInTime() { - // Safehold Elite {1}{G/W} - // Creature - Elf Scout - // 2/2 - // Persist - - addCard(Zone.BATTLEFIELD, playerA, "Safehold Elite"); - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - addCard(Zone.HAND, playerA, "Murder Investigation",2); - - addCard(Zone.HAND, playerB, "Lightning Bolt",2); - addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder Investigation", "Safehold Elite"); - - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Safehold Elite"); - // choose triggered ability order - playerA.addChoice("When enchanted creature dies, put X 1/1 red and white Soldier creature token with haste onto the battlefield, where X is its power."); - //castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Safehold Elite", "When enchanted creature dies, put X 1/1 red and white Soldier creature token with haste onto the battlefield, where X is its power"); - - setStopAt(1, PhaseStep.END_TURN); - execute(); - - assertPermanentCount(playerA, "Safehold Elite", 1); - assertPowerToughness(playerA, "Safehold Elite", 1, 1); - // because enchanted Safehold Elite's P/T was 2/2, Murder Investigation has to put 2 Soldier onto the battlefield - assertPermanentCount(playerA, "Soldier", 2); - - } + // some tests were moved to LastKnownInformationTest } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index d18d751a5dc..b930c7500e6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -28,24 +28,29 @@ package org.mage.test.player; +import mage.MageObject; +import mage.abilities.*; +import mage.abilities.costs.VariableCost; +import mage.choices.Choice; import mage.constants.Outcome; import mage.constants.PhaseStep; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; -import mage.choices.Choice; import mage.constants.RangeOfInfluence; +import mage.constants.SpellAbilityType; import mage.counters.Counter; import mage.filter.FilterPermanent; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterCreatureForCombat; +import mage.filter.common.FilterCreatureForCombatBlock; +import mage.filter.common.FilterPlaneswalkerPermanent; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; import mage.player.ai.ComputerPlayer; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanentAmount; import org.junit.Ignore; @@ -54,16 +59,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; -import mage.abilities.Mode; -import mage.abilities.Modes; -import mage.abilities.SpellAbility; -import mage.abilities.TriggeredAbility; -import mage.abilities.costs.VariableCost; -import mage.constants.SpellAbilityType; -import mage.filter.common.FilterCreatureForCombatBlock; -import mage.filter.common.FilterPlaneswalkerPermanent; -import mage.game.stack.StackObject; -import mage.target.TargetPlayer; /** * @@ -390,6 +385,14 @@ public class TestPlayer extends ComputerPlayer { } } return false; + } else if (groups.length > 2 && groups[2].startsWith("!spellOnStack=")) { + String spellNotOnStack = groups[2].substring(14); + for (StackObject stackObject: game.getStack()) { + if (stackObject.getStackAbility().toString().equals(spellNotOnStack)) { + return false; + } + } + return true; } return true; } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 325b9060d54..324667d336d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -1,7 +1,5 @@ package org.mage.test.serverside.base.impl; -import mage.constants.CardType; -import mage.constants.PhaseStep; import mage.abilities.Ability; import mage.cards.Card; import mage.cards.decks.Deck; @@ -9,9 +7,13 @@ import mage.cards.decks.importer.DeckImporterUtil; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.cards.repository.CardScanner; +import mage.constants.CardType; +import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.Filter; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; import mage.game.ExileZone; import mage.game.Game; import mage.game.GameException; @@ -26,8 +28,6 @@ import org.mage.test.serverside.base.MageTestPlayerBase; import java.util.List; import java.util.UUID; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.NamePredicate; /** * API for test initialization and asserting the test results. @@ -657,6 +657,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement player.addAction(turnNum, step, "activate:Cast " + cardName + ";target=" + targetName); } + public enum StackClause { + WHILE_ON_STACK, + WHILE_NOT_ON_STACK; + } + /** * Spell will only be cast, if a spell / ability with the given name is on the stack * @@ -668,7 +673,26 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param spellOnStack */ public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack) { - player.addAction(turnNum, step, "activate:Cast " + cardName + ";target=" + targetName + ";spellOnStack=" + spellOnStack); + castSpell(turnNum, step, player, cardName, targetName, spellOnStack, StackClause.WHILE_ON_STACK); + } + + /** + * Spell will only be cast, if a spell / ability with the given name IS or IS NOT on the stack + * + * @param turnNum + * @param step + * @param player + * @param cardName + * @param targetName + * @param spellOnStack + * @param clause + */ + public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack, StackClause clause) { + if (StackClause.WHILE_ON_STACK.equals(clause)) { + player.addAction(turnNum, step, "activate:Cast " + cardName + ";target=" + targetName + ";spellOnStack=" + spellOnStack); + } else { + player.addAction(turnNum, step, "activate:Cast " + cardName + ";target=" + targetName + ";!spellOnStack=" + spellOnStack); + } } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack, String spellOnTopOfStack) { diff --git a/Mage.Tests/src/test/java/org/mage/test/testapi/TestAPITest.java b/Mage.Tests/src/test/java/org/mage/test/testapi/TestAPITest.java new file mode 100644 index 00000000000..63a201ba2ad --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/testapi/TestAPITest.java @@ -0,0 +1,67 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ + +package org.mage.test.testapi; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author noxx + */ +public class TestAPITest extends CardTestPlayerBase { + + /** + * Tests that it is possible to cast two instants in a row. + * Shock should be able to remove Last Breath's target before it resolves + */ + @Test + public void testCardTestPlayerAPIImpl1() { + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + addCard(Zone.HAND, playerA, "Last Breath"); + addCard(Zone.HAND, playerA, "Shock"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Last Breath", "Grizzly Bears"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", "Grizzly Bears"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Grizzly Bears", 0); + assertLife(playerA, 20); // no life gain, Last Breath should have been fizzled + } + + /** + * Tests that it is possible to wait until certain spell resolves with StackClause.WHILE_NOT_ON_STACK. + * Shock won't be even cast here as no Last Breath should resolve. + */ + @Test + public void testCardTestPlayerAPIImpl2() { + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + addCard(Zone.HAND, playerA, "Last Breath"); + addCard(Zone.HAND, playerA, "Shock"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Last Breath", "Grizzly Bears"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", "Grizzly Bears", "Last Breath", + StackClause.WHILE_NOT_ON_STACK); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Grizzly Bears", 0); + assertLife(playerA, 24); // gain 4 life from Last Breath + } + +} diff --git a/Mage/src/mage/game/match/MatchImpl.java b/Mage/src/mage/game/match/MatchImpl.java index 3ec77c794f9..b5f332449aa 100644 --- a/Mage/src/mage/game/match/MatchImpl.java +++ b/Mage/src/mage/game/match/MatchImpl.java @@ -28,12 +28,6 @@ package mage.game.match; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Random; -import java.util.UUID; import mage.cards.decks.Deck; import mage.game.Game; import mage.game.GameException; @@ -43,6 +37,8 @@ import mage.game.events.TableEvent.EventType; import mage.game.events.TableEventSource; import mage.players.Player; +import java.util.*; + /** * @@ -286,6 +282,21 @@ public abstract class MatchImpl implements Match { } } return true; + + } + + //@Override + public boolean areAllDoneSideboarding() { + int count = 0; + for (MatchPlayer player: this.players) { + if (!player.hasQuit() && player.isDoneSideboarding()) { + return true; + } + if (player.hasQuit()) { + count++; + } + } + return count < this.players.size(); } @Override