diff --git a/Mage.Sets/src/mage/cards/b/BolassCitadel.java b/Mage.Sets/src/mage/cards/b/BolassCitadel.java index bf220306bab..2cb133e3d8e 100644 --- a/Mage.Sets/src/mage/cards/b/BolassCitadel.java +++ b/Mage.Sets/src/mage/cards/b/BolassCitadel.java @@ -1,7 +1,6 @@ package mage.cards.b; import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Costs; @@ -98,24 +97,20 @@ class BolassCitadelPlayTheTopCardEffect extends AsThoughEffectImpl { Card cardToCheck = game.getCard(objectId); objectId = CardUtil.getMainCardId(game, objectId); // for split cards - if (cardToCheck != null - && playerId.equals(source.getControllerId()) - && cardToCheck.isOwnedBy(source.getControllerId())) { - Player controller = game.getPlayer(cardToCheck.getOwnerId()); - if (controller != null - && controller.getLibrary().getFromTop(game) != null - && objectId.equals(controller.getLibrary().getFromTop(game).getId())) { - if (affectedAbility instanceof ActivatedAbility) { - ActivatedAbility activatedAbility = (ActivatedAbility) affectedAbility; - // add the life cost first - PayLifeCost cost = new PayLifeCost(activatedAbility.getManaCosts().convertedManaCost()); - Costs costs = new CostsImpl(); - costs.add(cost); - costs.addAll(activatedAbility.getCosts()); - controller.setCastSourceIdWithAlternateMana(activatedAbility.getSourceId(), null, costs); - return true; - } - } + if (!isAbilityAppliedForAlternateCast(cardToCheck, affectedAbility, playerId, source)) { + return false; + } + + Player controller = game.getPlayer(cardToCheck.getOwnerId()); + Card topCard = controller == null ? null : controller.getLibrary().getFromTop(game); + if (topCard != null && objectId.equals(topCard.getId())) { + // add the life cost first + PayLifeCost cost = new PayLifeCost(affectedAbility.getManaCosts().convertedManaCost()); + Costs costs = new CostsImpl(); + costs.add(cost); + costs.addAll(affectedAbility.getCosts()); + controller.setCastSourceIdWithAlternateMana(affectedAbility.getSourceId(), null, costs); + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/m/MindsDesire.java b/Mage.Sets/src/mage/cards/m/MindsDesire.java index b270cd023c5..eea1c4c7fae 100644 --- a/Mage.Sets/src/mage/cards/m/MindsDesire.java +++ b/Mage.Sets/src/mage/cards/m/MindsDesire.java @@ -105,16 +105,26 @@ class MindsDesireCastFromExileEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId()) && getTargetPointer().getTargets(game, source).contains(objectId)) { - Card card = game.getCard(objectId); - if (card != null && !card.isLand() && card.getSpellAbility().getCosts() != null) { - Player player = game.getPlayer(affectedControllerId); - if (player != null) { - player.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts()); - } - } + return applies(objectId, null, source, game, affectedControllerId); + } + + @Override + public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { + Card cardToCheck = game.getCard(objectId); + objectId = CardUtil.getMainCardId(game, objectId); // for split cards + + if (!isAbilityAppliedForAlternateCast(cardToCheck, affectedAbility, playerId, source)) { + return false; + } + + Player controller = game.getPlayer(cardToCheck.getOwnerId()); + if (controller != null + && getTargetPointer().getTargets(game, source).contains(objectId)) { + controller.setCastSourceIdWithAlternateMana(affectedAbility.getSourceId(), null, affectedAbility.getCosts()); return true; } + + return false; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java index b4013c696b1..db9cc79df87 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java @@ -19,7 +19,7 @@ public class PlayTopCardFromLibraryTest extends CardTestPlayerBase { */ @Test - public void test_CreaturePlay() { + public void test_BolassCitadel_CreaturePlay() { removeAllCardsFromLibrary(playerA); addCard(Zone.LIBRARY, playerA, "Balduvian Bears", 1); addCard(Zone.BATTLEFIELD, playerA, "Bolas's Citadel", 1); @@ -36,7 +36,7 @@ public class PlayTopCardFromLibraryTest extends CardTestPlayerBase { } @Test - public void test_CreaturePlay2() { + public void test_Vizier_CreaturePlay() { removeAllCardsFromLibrary(playerA); addCard(Zone.LIBRARY, playerA, "Balduvian Bears", 1); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); @@ -75,7 +75,7 @@ public class PlayTopCardFromLibraryTest extends CardTestPlayerBase { } @Test - public void test_SplitRightPlay() { + public void test_BolassCitadel_SplitRightPlay() { // https://github.com/magefree/mage/issues/5912 // Bolas's citadel requires you to pay mana instead of life for a split card on top of library. // @@ -106,7 +106,7 @@ public class PlayTopCardFromLibraryTest extends CardTestPlayerBase { } @Test - public void test_SplitLeftPlay() { + public void test_BolassCitadel_SplitLeftPlay() { removeAllCardsFromLibrary(playerA); addCard(Zone.LIBRARY, playerA, "Revival // Revenge", 1); addCard(Zone.BATTLEFIELD, playerA, "Bolas's Citadel", 1); @@ -125,4 +125,104 @@ public class PlayTopCardFromLibraryTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Balduvian Bears", 0); assertPermanentCount(playerA, "Balduvian Bears", 1); } + + @Test + public void test_MindsDesire_CreaturePlay() { + removeAllCardsFromLibrary(playerA); + + addCard(Zone.HAND, playerA, "Mind's Desire", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + // + addCard(Zone.LIBRARY, playerA, "Balduvian Bears", 1); + + // prepare mind + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mind's Desire"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Balduvian Bears"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Balduvian Bears", 1); + assertLife(playerA, 20); + } + + @Test + public void test_MindsDesire_LandPlay() { + removeAllCardsFromLibrary(playerA); + removeAllCardsFromHand(playerA); + + addCard(Zone.HAND, playerA, "Mind's Desire", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + // + addCard(Zone.LIBRARY, playerA, "Swamp", 1); + + // prepare mind + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mind's Desire"); + + playLand(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Swamp"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Swamp", 1); + assertLife(playerA, 20); + } + + @Test + public void test_MindsDesire_SplitRightPlay() { + removeAllCardsFromLibrary(playerA); + + // Shuffle your library. Then exile the top card of your library. Until end of turn, you may play that card without paying its mana cost. + // Storm (When you cast this spell, copy it for each spell cast before it this turn.) + addCard(Zone.HAND, playerA, "Mind's Desire", 1); // {4}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + // + addCard(Zone.LIBRARY, playerA, "Revival // Revenge", 1); + + // prepare mind + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mind's Desire"); + + // Double your life total. Target opponent loses half their life, rounded up. + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Revenge", playerB); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20 * 2); + assertLife(playerB, 20 / 2); + } + + @Test + public void test_MindsDesire_SplitLeftPlay() { + removeAllCardsFromLibrary(playerA); + + addCard(Zone.HAND, playerA, "Mind's Desire", 1); // {4}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + // + addCard(Zone.LIBRARY, playerA, "Revival // Revenge", 1); + addCard(Zone.GRAVEYARD, playerA, "Balduvian Bears", 1); + + // prepare mind + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mind's Desire"); + + // Return target creature card with converted mana cost 3 or less from your graveyard to the battlefield. + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Revival", "Balduvian Bears"); // {W/B}{W/B} = 2 life + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertGraveyardCount(playerA, "Balduvian Bears", 0); + assertPermanentCount(playerA, "Balduvian Bears", 1); + } } diff --git a/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java index a21b0e3a25e..d17ca0e2633 100644 --- a/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java @@ -1,10 +1,9 @@ package mage.abilities.effects; import mage.abilities.Ability; -import mage.constants.AsThoughEffectType; -import mage.constants.Duration; -import mage.constants.EffectType; -import mage.constants.Outcome; +import mage.abilities.ActivatedAbility; +import mage.cards.Card; +import mage.constants.*; import mage.game.Game; import java.util.UUID; @@ -42,4 +41,15 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements return type; } + /** + * Helper to check that affectedAbility is compatible for alternative cast modifications by setCastSourceIdWithAlternateMana + */ + public boolean isAbilityAppliedForAlternateCast(Card cardToCheck, Ability affectedAbilityToCheck, UUID playerToCheck, Ability source) { + return cardToCheck != null + && playerToCheck.equals(source.getControllerId()) + && cardToCheck.isOwnedBy(source.getControllerId()) + && affectedAbilityToCheck instanceof ActivatedAbility + && (affectedAbilityToCheck.getAbilityType() == AbilityType.SPELL + || affectedAbilityToCheck.getAbilityType() == AbilityType.PLAY_LAND); + } }