diff --git a/Mage.Sets/src/mage/cards/m/MimicVat.java b/Mage.Sets/src/mage/cards/m/MimicVat.java index 8d7a377ec93..a09b547b86b 100644 --- a/Mage.Sets/src/mage/cards/m/MimicVat.java +++ b/Mage.Sets/src/mage/cards/m/MimicVat.java @@ -42,7 +42,7 @@ public final class MimicVat extends CardImpl { // Imprint - Whenever a nontoken creature dies, you may exile that card. If you do, return each other card exiled with Mimic Vat to its owner's graveyard. this.addAbility(new MimicVatTriggeredAbility()); - // {3}, {tap}: Create a token that's a copy of the exiled card. It gains haste. Exile it at the beginning of the next end step. + // {3}, {T}: Create a token that's a copy of the exiled card. It gains haste. Exile it at the beginning of the next end step. Ability ability = new SimpleActivatedAbility(new MimicVatCreateTokenEffect(), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java index 138c9f6ac1c..7d4c6d447a7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java @@ -47,6 +47,7 @@ public class ConspireTest extends CardTestPlayerBase { setChoice(playerA, "Goblin Roughrider^Raging Goblin"); // tap for conspire setChoice(playerA, false); // don't change target + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -54,7 +55,6 @@ public class ConspireTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Burn Trail", 1); assertTapped("Goblin Roughrider", true); assertTapped("Raging Goblin", true); - } @Test @@ -67,6 +67,7 @@ public class ConspireTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB); setChoice(playerA, false); + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -103,7 +104,6 @@ public class ConspireTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Wort, the Raidmother", 1); assertGraveyardCount(playerA, "Lightning Bolt", 1); assertLife(playerB, 20 - 3 - 3); - } @Test @@ -137,7 +137,6 @@ public class ConspireTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Lightning Bolt", 1); assertTapped("Raging Goblin", false); assertLife(playerB, 20 - 3 - 3 - 2); - } @Test @@ -158,8 +157,10 @@ public class ConspireTest extends CardTestPlayerBase { setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire setChoice(playerA, false); // keep targets + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); + assertPermanentCount(playerA, "Wort, the Raidmother", 1); assertLife(playerB, 20 - 3 - 3); assertLife(playerA, 20); @@ -181,22 +182,20 @@ public class ConspireTest extends CardTestPlayerBase { castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Burn Trail", playerB); setChoice(playerA, true); // use Conspire from Burn Trail itself setChoice(playerA, true); // use Conspire gained from Wort, the Raidmother - setChoice(playerA, "When you pay the conspire"); // order triggers - setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire - setChoice(playerA, false); // keep targets - setChoice(playerA, "Raging Goblin", 2); // tap for conspire + setChoice(playerA, "When you pay the conspire"); // order triggers + setChoice(playerA, false); // keep targets setChoice(playerA, false); // keep targets - + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); + assertPermanentCount(playerA, "Wort, the Raidmother", 1); assertLife(playerB, 20 - 3 - 3 - 3); assertLife(playerA, 20); assertGraveyardCount(playerA, "Burn Trail", 1); - } @Test @@ -221,8 +220,10 @@ public class ConspireTest extends CardTestPlayerBase { setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire setChoice(playerA, false); // keep targets + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); + assertPermanentCount(playerA, "Wort, the Raidmother", 1); assertPermanentCount(playerA, "Sakashima the Impostor", 1); assertLife(playerB, 20 - 3 - 3); @@ -248,15 +249,16 @@ public class ConspireTest extends CardTestPlayerBase { castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); setChoice(playerA, true); // use Conspire gained from Wort, the Raidmother setChoice(playerA, true); // use Conspire gained from Sakashima the Imposter + setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire + setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire setChoice(playerA, "When you pay the conspire"); // order triggers - - setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire setChoice(playerA, false); // keep targets - setChoice(playerA, "Goblin Warrior Token", 2); // tap for conspire setChoice(playerA, false); // keep targets + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); + assertPermanentCount(playerA, "Wort, the Raidmother", 1); assertPermanentCount(playerA, "Sakashima the Impostor", 1); assertLife(playerB, 20 - 3 - 3 - 3); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/MimicVatTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/MimicVatTest.java index feb34603a76..ae18716ec97 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/MimicVatTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/MimicVatTest.java @@ -10,10 +10,10 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * {3} * Artifact * Imprint — Whenever a nontoken creature dies, you may exile that card. - * If you do, return each other card exiled with Mimic Vat to its owner’s graveyard. + * If you do, return each other card exiled with Mimic Vat to its owner’s graveyard. * {3}, {T}: Create a token that’s a copy of a card exiled with Mimic Vat. - * It gains haste. - * Exile it at the beginning of the next end step. + * It gains haste. + * Exile it at the beginning of the next end step. * * @author LevelX2 */ @@ -77,17 +77,23 @@ public class MimicVatTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + // prepare copy castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph", true); - setChoice(playerA, true); - setChoice(playerA, "Silvercoat Lion"); + setChoice(playerA, true); // pay 2 life + setChoice(playerA, true); // copy on etb + setChoice(playerA, "Silvercoat Lion"); // copy + // sacrifice and exile a copy activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}, {T}, Sacrifice a creature"); - setChoice(playerA, true); - - activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Create a token that's a copy of a card exiled with "); - setChoice(playerA, true); setChoice(playerA, "Silvercoat Lion"); + setChoice(playerA, true); + // create copy of exiled Metamorph + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Create a token that's a copy of a card exiled with "); + setChoice(playerA, true); // copy on etb + setChoice(playerA, "Silvercoat Lion"); // copy + + setStrictChooseMode(true); setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); @@ -125,6 +131,7 @@ public class MimicVatTest extends CardTestPlayerBase { activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}, {T}: Create a token that's a copy of a card exiled with "); + setStrictChooseMode(true); setStopAt(3, PhaseStep.BEGIN_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java index 75ef87401b0..e1f47e65aa0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java @@ -9,12 +9,13 @@ import mage.constants.Zone; import mage.game.permanent.Permanent; import org.junit.Assert; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; import static org.junit.Assert.*; /** - * @author noxx + * @author noxx, JayDi85 *

* Card: You may have {this} enter the battlefield as a copy of any creature on * the battlefield, except it's an Illusion in addition to its other types and @@ -30,7 +31,10 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Craw Wurm"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); + setChoice(playerA, true); // use copy on etb + setChoice(playerA, "Craw Wurm"); // copy + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -51,7 +55,10 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Howling Banshee"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); + setChoice(playerA, true); // use copy on etb + setChoice(playerA, "Howling Banshee"); // copy + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -79,7 +86,10 @@ public class PhantasmalImageTest extends CardTestPlayerBase { } castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); + setChoice(playerB, true); // use copy on etb + setChoice(playerB, "Transcendent Master"); // copy + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -112,10 +122,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Illusionary Servant"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image", true); + setChoice(playerA, true); // use copy on etb setChoice(playerA, "Illusionary Servant"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); + setChoice(playerA, true); // use copy on etb setChoice(playerA, "Illusionary Servant-M10"); + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -147,16 +161,28 @@ public class PhantasmalImageTest extends CardTestPlayerBase { // Enchantment - Creatures you control have hexproof. addCard(Zone.HAND, playerA, "Asceticism"); + // Huntmaster of the Fells: // Whenever this creature enters the battlefield or transforms into // Huntmaster of the Fells, put a 2/2 green Wolf creature token onto // the battlefield and you gain 2 life. // At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells. ==> Ravager of the Fells + // Ravager of the Fells: + // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. addCard(Zone.BATTLEFIELD, playerA, "Huntmaster of the Fells"); + // transform on upkeep to Ravager of the Fells + addTarget(playerA, playerB); // x2 damage on transform (player) + addTarget(playerA, TestPlayer.TARGET_SKIP); // x2 damage on transform (creature) + + // copy transformed castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // copy target: Ravergers of the Fells + setChoice(playerB, true); // use copy on etb + setChoice(playerB, "Ravager of the Fells"); // copy + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Asceticism"); castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Titanic Growth", "Ravager of the Fells"); + setStrictChooseMode(true); setStopAt(3, PhaseStep.END_TURN); execute(); @@ -167,7 +193,6 @@ public class PhantasmalImageTest extends CardTestPlayerBase { // check playerB's creature was sacrificed assertGraveyardCount(playerB, "Phantasmal Image", 1); assertPermanentCount(playerB, "Ravager of the Fells", 0); - } /** @@ -175,7 +200,7 @@ public class PhantasmalImageTest extends CardTestPlayerBase { * Messenger: Geralf's Messenger enters the battlefield tapped */ @Test - public void testCopyEntersTapped() { + public void testCopyEntersTappedAndEtb() { addCard(Zone.BATTLEFIELD, playerA, "Island", 2); // You may have Phantasmal Image enter the battlefield as a copy of any creature // on the battlefield, except it's an Illusion in addition to its other types and @@ -184,7 +209,11 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Geralf's Messenger"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); + setChoice(playerA, true); // use copy on etb + setChoice(playerA, "Geralf's Messenger"); // copy + addTarget(playerA, playerB); // x2 damage from etb of copied + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -211,11 +240,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase { // When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow. addCard(Zone.HAND, playerA, "Lurebound Scarecrow"); - setChoice(playerA, "Green"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lurebound Scarecrow"); - setChoice(playerA, "Red"); + setChoice(playerA, "Green"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Phantasmal Image"); + setChoice(playerA, true); // use copy on etb + setChoice(playerA, "Lurebound Scarecrow"); // copy + setChoice(playerA, "Red"); + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -235,11 +267,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Phantasmal Image"); addCard(Zone.HAND, playerA, "Lurebound Scarecrow"); - setChoice(playerA, "Green"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lurebound Scarecrow"); - setChoice(playerA, "Red"); + setChoice(playerA, "Green"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Phantasmal Image"); + setChoice(playerA, true); // use copy on etb + setChoice(playerA, "Lurebound Scarecrow"); // copy + setChoice(playerA, "Red"); + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -257,12 +292,16 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Llanowar Elves"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); + setChoice(playerA, true); // use copy on etb + setChoice(playerA, "Azure Drake"); // copy + attack(1, playerA, "Azure Drake"); block(1, playerB, "Llanowar Elves", "Azure Drake"); attack(2, playerB, "Azure Drake"); block(2, playerA, "Elite Vanguard", "Azure Drake"); + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -288,13 +327,15 @@ public class PhantasmalImageTest extends CardTestPlayerBase { setChoice(playerA, "X=0"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); - setChoice(playerB, "Steel Hellkite"); + setChoice(playerB, true); // use copy on etb + setChoice(playerB, "Steel Hellkite"); // copy attack(4, playerB, "Steel Hellkite"); activateAbility(4, PhaseStep.POSTCOMBAT_MAIN, playerB, "{X}:"); setChoice(playerB, "X=0"); + setStrictChooseMode(true); setStopAt(4, PhaseStep.END_TURN); execute(); @@ -306,7 +347,6 @@ public class PhantasmalImageTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Chalice of the Void", 0); assertGraveyardCount(playerA, "Chalice of the Void", 1); - } /** @@ -317,38 +357,59 @@ public class PhantasmalImageTest extends CardTestPlayerBase { */ @Test public void testCopiedFrostTitan() { - // Whenever Frost Titan becomes the target of a spell or ability an opponent controls, counter that spell or ability unless its controller pays {2}. - // Whenever Frost Titan enters the battlefield or attacks, tap target permanent. It doesn't untap during its controller's next untap step. + // Whenever Frost Titan becomes the target of a spell or ability an opponent controls, + // counter that spell or ability unless its controller pays 2. + // Whenever Frost Titan enters the battlefield or attacks, tap target permanent. It doesn't + // untap during its controller's next untap step. addCard(Zone.BATTLEFIELD, playerA, "Frost Titan"); - addCard(Zone.HAND, playerA, "Terror"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); // for counter pay + addCard(Zone.BATTLEFIELD, playerB, "Island", 2); // for counter pay + // // {1}{U} - Target creature gains shroud until end of turn and can't be blocked this turn. - addCard(Zone.HAND, playerA, "Veil of Secrecy"); - addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.HAND, playerA, "Veil of Secrecy", 1); addCard(Zone.BATTLEFIELD, playerA, "Island", 2); - + addCard(Zone.HAND, playerB, "Veil of Secrecy", 1); + addCard(Zone.BATTLEFIELD, playerB, "Island", 2); + // + addCard(Zone.HAND, playerB, "Phantasmal Image"); // {1}{U} addCard(Zone.BATTLEFIELD, playerB, "Island", 2); - addCard(Zone.HAND, playerB, "Phantasmal Image"); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Veil of Secrecy", "Frost Titan"); // so it's no longer targetable - setChoice(playerB, "Frost Titan"); + // prepare copy + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); + setChoice(playerB, true); // use copy on etb + setChoice(playerB, "Frost Titan"); // copy + addTarget(playerB, "Island"); // tap on etb + waitStackResolved(2, PhaseStep.PRECOMBAT_MAIN); - castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Terror", "Frost Titan"); // of player Bs Phantasmal Image copying Frost Titan - // should be countered if not paying {2} + // make sure both has titan permanent + checkPermanentCount("after prepare", 2, PhaseStep.PRECOMBAT_MAIN, playerB, playerA, "Frost Titan", 1); + checkPermanentCount("after prepare", 2, PhaseStep.PRECOMBAT_MAIN, playerB, playerB, "Frost Titan", 1); + // try original target trigger (B cast into A's titan and ask to anti-counter pay) + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Veil of Secrecy"); + addTarget(playerB, "Frost Titan[no copy]"); + setChoice(playerB, true); // pay to stop counter + waitStackResolved(2, PhaseStep.POSTCOMBAT_MAIN); + + // try copied target trigger (A cast into B's titan and ask to anti-counter pay) + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Veil of Secrecy"); + addTarget(playerA, "Frost Titan[only copy]"); + setChoice(playerB, "When {this} becomes the target of a spell or ability, sacrifice it."); // x2 triggers (make sure illusion's will go first) + setChoice(playerA, true); // pay to stop counter (it's useless here, but will sure trigger works fine) + + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); execute(); - assertGraveyardCount(playerA, "Veil of Secrecy", 1); - assertGraveyardCount(playerA, "Terror", 1); - assertLife(playerB, 20); assertLife(playerA, 20); assertPermanentCount(playerA, "Frost Titan", 1); + assertPermanentCount(playerB, "Frost Titan", 0); + assertGraveyardCount(playerB, "Phantasmal Image", 1); - assertGraveyardCount(playerB, "Phantasmal Image", 1); // if triggered ability did not work, the Titan would be in the graveyard instaed - + // 2 from cast Phantasmal + 4 from cast Veil + 4 from counter pay + assertTappedCount("Island", true, 2 + 2 * 2 + 2 * 2); } // I've casted a Phantasmal Image targeting opponent's Wurmcoil Engine @@ -365,12 +426,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Island", 2); addCard(Zone.HAND, playerB, "Phantasmal Image"); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted - setChoice(playerB, "Wurmcoil Engine"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); + setChoice(playerB, true); // use copy on etb + setChoice(playerB, "Wurmcoil Engine"); // copy - castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Wurmcoil Engine"); // of player Bs Phantasmal Image copying Frost Titan - // should be countered if not paying {2} + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution"); + addTarget(playerA, "Wurmcoil Engine[only copy]"); + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -403,11 +466,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Island", 2); addCard(Zone.HAND, playerB, "Phantasmal Image"); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted - setChoice(playerB, "Thalakos Seer"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); + setChoice(playerB, true); // use copy on etb + setChoice(playerB, "Thalakos Seer"); // copy - castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Thalakos Seer"); + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution"); + addTarget(playerA, "Thalakos Seer[only copy]"); + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -474,11 +540,16 @@ public class PhantasmalImageTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitchen Finks"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted + setChoice(playerB, true); // use copy on etb + setChoice(playerB, "Kitchen Finks"); // copy + + // destroy and return to battlefield by persist + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution"); + addTarget(playerA, "Kitchen Finks[only copy]"); + setChoice(playerB, true); // use copy on etb setChoice(playerB, "Kitchen Finks"); - castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Kitchen Finks"); - setChoice(playerB, "Kitchen Finks"); - + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -515,11 +586,16 @@ public class PhantasmalImageTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Butcher Ghoul"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); // not targeted - setChoice(playerB, "Butcher Ghoul"); + setChoice(playerB, true); // use copy on etb + setChoice(playerB, "Butcher Ghoul"); // copy - castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution", "Butcher Ghoul"); - setChoice(playerB, "Butcher Ghoul"); + // destroy and return to battlefield by undying + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Public Execution"); + addTarget(playerA, "Butcher Ghoul[only copy]"); + setChoice(playerB, true); // use copy on etb + setChoice(playerB, "Butcher Ghoul"); // copy + setStrictChooseMode(true); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -559,10 +635,13 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Phantasmal Image"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); // not targeted + setChoice(playerA, true); // use copy on etb setChoice(playerA, "Wurmcoil Engine"); attack(2, playerB, "Wurmcoil Engine"); block(2, playerA, "Wurmcoil Engine", "Wurmcoil Engine"); + + setStrictChooseMode(true); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); @@ -591,10 +670,13 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Phantasmal Image"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); // not targeted + setChoice(playerA, true); // use copy on etb setChoice(playerA, "Voice of Resurgence"); attack(2, playerB, "Voice of Resurgence"); block(2, playerA, "Voice of Resurgence", "Voice of Resurgence"); + + setStrictChooseMode(true); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); @@ -615,12 +697,14 @@ public class PhantasmalImageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Island", 2); addCard(Zone.HAND, playerA, "Phantasmal Image"); - setChoice(playerB, "X=1"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{X}"); + setChoice(playerB, "X=1"); - setChoice(playerA, "Chimeric Staff"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Phantasmal Image"); + setChoice(playerA, true); // use copy on etb + setChoice(playerA, "Chimeric Staff"); // copy + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -646,9 +730,11 @@ public class PhantasmalImageTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Karn's Touch", "Cloak and Dagger"); - setChoice(playerA, "Cloak and Dagger"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Phantasmal Image"); + setChoice(playerA, true); // use copy on etb + setChoice(playerA, "Cloak and Dagger"); // copy + setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/additional/RemoveCounterCostTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/additional/RemoveCounterCostTest.java index da992b438a4..41dd7262dbc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/additional/RemoveCounterCostTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/additional/RemoveCounterCostTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.cost.additional; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ @@ -15,16 +13,18 @@ public class RemoveCounterCostTest extends CardTestPlayerBase { @Test public void testNovijenSages() { - addCard(Zone.BATTLEFIELD, playerA, "Island", 7); // Graft 4 // {1}, Remove two +1/+1 counters from among creatures you control: Draw a card. addCard(Zone.HAND, playerA, "Novijen Sages"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 7); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Novijen Sages", true); - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, Remove two +1/+1 counters"); - setChoice(playerA, "X=2"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, Remove two +1/+1 counters"); + setChoice(playerA, "Novijen Sages"); // counters to remove + setChoice(playerA, "X=2"); // counters to remove + + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -32,9 +32,8 @@ public class RemoveCounterCostTest extends CardTestPlayerBase { assertPowerToughness(playerA, "Novijen Sages", 2, 2); assertHandCount(playerA, 1); - + assertLife(playerA, 20); assertLife(playerB, 20); } - } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/HeartstoneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/HeartstoneTest.java index 1ec742aa810..13ecc8352a1 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/HeartstoneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/HeartstoneTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.cost.modification; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class HeartstoneTest extends CardTestPlayerBase { @@ -29,8 +27,12 @@ public class HeartstoneTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{U}", "Lightning Bolt", "Lightning Bolt"); - setChoice(playerA, true); - addTarget(playerA, playerB); + setChoice(playerA, "Fugitive Wizard"); // tap cost 1 of 2 + setChoice(playerA, "Sigil Tracer"); // tap cost 2 of 2 + setChoice(playerA, true); // change target + addTarget(playerA, playerB); // new target + + setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -41,7 +43,6 @@ public class HeartstoneTest extends CardTestPlayerBase { assertLife(playerB, 17); assertTappedCount("Island", true, 1); - } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/sacrifice/SacrificeLandTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/sacrifice/SacrificeLandTest.java index b895bf7b1f0..c95d87b64b7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/sacrifice/SacrificeLandTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/sacrifice/SacrificeLandTest.java @@ -4,16 +4,14 @@ import mage.constants.PhaseStep; import mage.constants.Zone; import mage.util.RandomUtil; import org.junit.Test; -import org.mage.test.sba.PlaneswalkerRuleTest; import org.mage.test.serverside.base.CardTestPlayerBase; -import java.util.Random; - /** * Reported bugs: https://github.com/magefree/mage/issues/8980 - * Cards like Soldevi Excavations, Heart of Yavimaya, and Lake of the Dead - * will sometimes immediately go to the graveyard without asking the controller if they wish to sacrifice a land - * even though they had one available + * Cards like Soldevi Excavations, Heart of Yavimaya, and Lake of the Dead + * will sometimes immediately go to the graveyard without asking the controller if they wish to sacrifice a land + * even though they had one available + * * @author Alex-Vasile */ public class SacrificeLandTest extends CardTestPlayerBase { @@ -35,14 +33,21 @@ public class SacrificeLandTest extends CardTestPlayerBase { playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, soldeviExcavations); setChoice(playerA, sacFirstLand); + if (sacFirstLand) { + setChoice(playerA, "Island"); + } rollbackTurns(1, PhaseStep.PRECOMBAT_MAIN, playerA, 0); rollbackAfterActionsStart(); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, soldeviExcavations); setChoice(playerA, sacSecondLand); + if (sacSecondLand) { + setChoice(playerA, "Island"); + } rollbackAfterActionsEnd(); + setStrictChooseMode(true); setStopAt(1, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -73,14 +78,18 @@ public class SacrificeLandTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Swamp"); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, soldeviExcavations); - setChoice(playerA, "Yes"); + setChoice(playerA, "Yes"); // use sacrifice to keep soldevi + setChoice(playerA, "Island"); // sacrifice playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, heartofYavimaya); - setChoice(playerA, "Yes"); + setChoice(playerA, "Yes"); // use sacrifice to keep heart + setChoice(playerA, "Forest"); // sacrifice playLand(5, PhaseStep.PRECOMBAT_MAIN, playerA, lakeOfTheDead); - setChoice(playerA, "Yes"); + setChoice(playerA, "Yes"); // use sacrifice to keep lake + setChoice(playerA, "Swamp"); // sacrifice + setStrictChooseMode(true); setStopAt(5, PhaseStep.PRECOMBAT_MAIN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/PrimalClayTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/PrimalClayTest.java index 6177edc5bec..3fba06e5618 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/PrimalClayTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/PrimalClayTest.java @@ -181,8 +181,8 @@ public class PrimalClayTest extends CardTestPlayerBase { castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, clone); setChoice(playerB, true); // whether to copy - setFlipCoinResult(playerB, false); setChoice(playerB, sentry); // what to copy + setFlipCoinResult(playerB, false); setStrictChooseMode(true); setStopAt(2, PhaseStep.BEGIN_COMBAT); @@ -218,7 +218,7 @@ public class PrimalClayTest extends CardTestPlayerBase { // Target creature you control gets +2/+2 until end of turn if its power is 2. Then it fights target creature you don’t control. addCard(Zone.BATTLEFIELD, playerB, "Siege Mastodon", 1); // 3/5 creature for fighting - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aquamorph+" using Morph"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aquamorph + " using Morph"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Savage Swipe"); addTarget(playerA, EmptyNames.FACE_DOWN_CREATURE.getTestCommand()); // morph diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/CadricSoulKindlerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/CadricSoulKindlerTest.java index 1c93a61452e..19070a56425 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/CadricSoulKindlerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/CadricSoulKindlerTest.java @@ -10,6 +10,9 @@ import org.mage.test.serverside.base.CardTestPlayerBase; */ public class CadricSoulKindlerTest extends CardTestPlayerBase { + // The "legend rule" doesn't apply to tokens you control. + // Whenever another nontoken legendary permanent you control enters, you may pay {1}. If you do, create a token + // that's a copy of it. That token gains haste. Sacrifice it at the beginning of the next end step. private static final String cadric = "Cadric, Soul Kindler"; private static final String isamaru = "Isamaru, Hound of Konda"; @@ -20,7 +23,7 @@ public class CadricSoulKindlerTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, isamaru); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, isamaru); - setChoice(playerA, true); + setChoice(playerA, true); // create copy setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); setStrictChooseMode(true); @@ -36,12 +39,14 @@ public class CadricSoulKindlerTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); addCard(Zone.HAND, playerA, isamaru, 2); + // first isamaru and copy of it castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, isamaru); - setChoice(playerA, true); + setChoice(playerA, true); // create copy + // second isamaru and copy of it castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, isamaru); - setChoice(playerA, true); - setChoice(playerA, isamaru); + setChoice(playerA, isamaru); // keep 1 perm due legendary rule + setChoice(playerA, true); // create copy setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); setStrictChooseMode(true); 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 2d086bc2b0f..e09423b00c4 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 @@ -2293,7 +2293,8 @@ public class TestPlayer implements Player { } else { filterPermanent = ((TargetPermanent) target.getOriginalTarget()).getFilter(); } - for (String choiceRecord : choices) { + while (!choices.isEmpty()) { + String choiceRecord = choices.get(0); String[] targetList = choiceRecord.split("\\^"); boolean targetFound = false; for (String targetName : targetList) { @@ -2332,9 +2333,17 @@ public class TestPlayer implements Player { } } } - if (targetFound) { - choices.remove(choiceRecord); - return true; + + try { + if (target.isChosen(game)) { + return true; + } else { + if (!targetFound) { + Assert.fail(String.format("Found wrong choice command:\n%s\n%s\n%s", choiceRecord, getInfo(target, game), getInfo(source, game))); + } + } + } finally { + choices.remove(0); } } } diff --git a/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java b/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java index f952023890d..15f52b824ad 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java @@ -78,8 +78,9 @@ public class RemoveCounterCost extends CostImpl { Outcome outcome; if (target instanceof TargetPermanent) { - outcome = Outcome.UnboostCreature; - } else if (target instanceof TargetCard) { // For Mari, the Killing Quill + outcome = Outcome.AIDontUseIt; + } else if (target instanceof TargetCard) { + // Mari, the Killing Quill - AI can safely use it all the time outcome = Outcome.Neutral; } else { throw new IllegalArgumentException( @@ -123,7 +124,7 @@ public class RemoveCounterCost extends CostImpl { } choice.setChoices(choices); choice.setMessage("Choose a counter to remove from " + targetObject.getLogName()); - if (!controller.choose(Outcome.UnboostCreature, choice, game)) { + if (!controller.choose(outcome, choice, game)) { return false; } counterName = choice.getChoice(); @@ -135,7 +136,7 @@ public class RemoveCounterCost extends CostImpl { int numberOfCountersSelected = 1; if (countersLeft > 1 && countersOnPermanent > 1) { numberOfCountersSelected = controller.getAmount(1, Math.min(countersLeft, countersOnPermanent), - "Remove how many counters from " + targetObject.getIdName(), game); + "Choose how many counters (" + counterName + ") to remove from " + targetObject.getLogName() + " as payment", game); } targetObject.removeCounters(counterName, numberOfCountersSelected, source, game); countersRemoved += numberOfCountersSelected;