diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java index c045c0998af..ba0ab31d770 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java @@ -29,6 +29,7 @@ package org.mage.test.cards.copy; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -72,4 +73,107 @@ public class CleverImpersonatorTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Gilded Drake", 1); assertPermanentCount(playerB, "Pillarfield Ox", 1); } + + /** + * Copy a planeswalker on the battlefield + */ + @Test + public void testCopyPlaneswalker() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. + addCard(Zone.HAND, playerA, "Clever Impersonator", 1); // {2}{U}{U} + + // +2: Each player discards a card. + // -X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield. + // -8: You get an emblem with "Whenever a creature dies, return it to the battlefield under your control at the beginning of the next end step."; + addCard(Zone.BATTLEFIELD, playerB, "Liliana, Defiant Necromancer", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator"); + setChoice(playerA, "Liliana, Defiant Necromancer"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2: Each player discards a card"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertHandCount(playerA, "Clever Impersonator", 0); + assertCounterCount(playerB, "Liliana, Defiant Necromancer", CounterType.LOYALTY, 3); // 3 + assertPermanentCount(playerB, "Liliana, Defiant Necromancer", 1); + assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1); + assertCounterCount(playerA, "Liliana, Defiant Necromancer", CounterType.LOYALTY, 5); // 3 + 2 + } + + /** + * I had an Alesha, Who Smiles at Death returning a Clever Impersonator who + * was supposed to copy a flipped Liliana, Defiant Necromancer, but it + * entered the battlefield with 0 loyalty and died immediately. If I am not + * mistaken it should have entered with 3 loyalty (see Gatherer entry). + */ + @Test + public void testCopyPlaneswalkerFromGraveyard() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + // First strike + // Whenever Alesha, Who Smiles at Death attacks, you may pay {W/B}{W/B}. If you do, return target creature card with power 2 or less from your graveyard to the battlefield tapped and attacking. + addCard(Zone.BATTLEFIELD, playerA, "Alesha, Who Smiles at Death", 1); // {2}{R} - 3/2 + + // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. + addCard(Zone.GRAVEYARD, playerA, "Clever Impersonator", 1); // {2}{U}{U} + + // +2: Each player discards a card. + // -X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield. + // -8: You get an emblem with "Whenever a creature dies, return it to the battlefield under your control at the beginning of the next end step."; + addCard(Zone.BATTLEFIELD, playerB, "Liliana, Defiant Necromancer", 1); + + attack(1, playerA, "Alesha, Who Smiles at Death"); + addTarget(playerA, "Clever Impersonator"); + setChoice(playerA, "Liliana, Defiant Necromancer"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertTapped("Alesha, Who Smiles at Death", true); + assertLife(playerB, 17); + assertGraveyardCount(playerA, "Clever Impersonator", 0); + + assertCounterCount(playerB, "Liliana, Defiant Necromancer", CounterType.LOYALTY, 3); // 3 + assertPermanentCount(playerB, "Liliana, Defiant Necromancer", 1); + assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1); + assertCounterCount(playerA, "Liliana, Defiant Necromancer", CounterType.LOYALTY, 5); // 3 + 2 + } + + /** + * So I copied Jace, Vryns Prodigy with Clever Impersonator (it was tapped + * and I needed a blocker for a token...), and Jace got to survive until the + * next turn. When I looted, he flipped, and I got an error message I + * couldn't get rid of, forcing me to concede. I'm not sure what the correct + * outcome is rules-wise. + */ + @Test + public void testCopyCreatureOfFlipPlaneswalker() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + // {T}: Draw a card, then discard a card. If there are five or more cards in your graveyard, exile Jace, Vryn's Prodigy, then return him to the battefield transformed under his owner's control. + addCard(Zone.BATTLEFIELD, playerA, "Jace, Vryn's Prodigy", 1); // {2}{R} - 3/2 + + // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. + addCard(Zone.HAND, playerA, "Clever Impersonator", 1); // {2}{U}{U} + addCard(Zone.GRAVEYARD, playerA, "Mountain", 4); + + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator"); + setChoice(playerA, "Jace, Vryn's Prodigy"); + addTarget(playerA, "Jace, Vryn's Prodigy[only copy]"); // keep the copied Jace + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card"); + setChoice(playerA, "Pillarfield Ox"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Jace, Vryn's Prodigy", 1); + assertPermanentCount(playerA, "Pillarfield Ox", 1); + + } + } diff --git a/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java b/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java index aad230eaf2d..05e208b0815 100644 --- a/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java +++ b/Mage/src/mage/abilities/common/PlanswalkerEntersWithLoyalityCountersAbility.java @@ -24,7 +24,7 @@ public class PlanswalkerEntersWithLoyalityCountersAbility extends EntersBattlefi } @Override - public EntersBattlefieldAbility copy() { + public PlanswalkerEntersWithLoyalityCountersAbility copy() { return new PlanswalkerEntersWithLoyalityCountersAbility(this); } } diff --git a/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java b/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java index 72874fb2fd0..6f3170a0700 100644 --- a/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/ExileAndReturnTransformedSourceEffect.java @@ -61,12 +61,11 @@ public class ExileAndReturnTransformedSourceEffect extends OneShotEffect { Permanent sourceObject = game.getPermanent(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); if (sourceObject != null && controller != null && sourceObject.getZoneChangeCounter(game) == source.getSourceObjectZoneChangeCounter()) { - Card card = (Card) sourceObject; - if (controller.moveCards(card, Zone.BATTLEFIELD, Zone.EXILED, source, game)) { - Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null) { - game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - owner.moveCards(card, Zone.BATTLEFIELD, source, game); + if (controller.moveCards(sourceObject, Zone.EXILED, source, game)) { + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); + Card cardFromExile = game.getCard(source.getSourceId()); + if (cardFromExile != null) { + controller.moveCards(cardFromExile, Zone.BATTLEFIELD, source, game, false, false, true, null); if (additionalEffect != null) { if (additionalEffect instanceof ContinuousEffect) { game.addEffect((ContinuousEffect) additionalEffect, source); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 816db0ded7b..ba89c05297f 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -1876,7 +1876,7 @@ public abstract class GameImpl implements Game, Serializable { Player controller = this.getPlayer(legend.getControllerId()); if (controller != null) { Target targetLegendaryToKeep = new TargetPermanent(filterLegendName); - targetLegendaryToKeep.setTargetName(new StringBuilder(legend.getName()).append(" to keep (Legendary Rule)?").toString()); + targetLegendaryToKeep.setTargetName(legend.getName() + " to keep (Legendary Rule)?"); controller.chooseTarget(Outcome.Benefit, targetLegendaryToKeep, null, this); for (Permanent dupLegend : getBattlefield().getActivePermanents(filterLegendName, legend.getControllerId(), this)) { if (!targetLegendaryToKeep.getTargets().contains(dupLegend.getId())) {