From d1e31140cc6b94691ac3eeeeb7544aade9a4cf7d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 29 Jun 2020 14:54:29 +0200 Subject: [PATCH] * Fixed a problem that unintended allowed to cast spells with alternate cost to cast conditions (fixes #6739). --- .../UseAlternateSourceCostsTest.java | 46 +++++++++++++++++++ .../costs/AlternativeCostSourceAbility.java | 12 ++--- .../main/java/mage/players/PlayerImpl.java | 3 ++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/UseAlternateSourceCostsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/UseAlternateSourceCostsTest.java index 1ecc0ebc70d..fe78134d2c5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/UseAlternateSourceCostsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/UseAlternateSourceCostsTest.java @@ -145,6 +145,52 @@ public class UseAlternateSourceCostsTest extends CardTestPlayerBase { assertAllCommandsUsed(); } + @Test + public void test_Playable_WithOpponentGainingLive() { + // If you control a Forest, rather than pay Invigorate's mana cost, you may have an opponent gain 3 life. + // Target creature gets +4/+4 until end of turn. + addCard(Zone.HAND, playerA, "Invigorate"); // Instant {2}{G} + addCard(Zone.BATTLEFIELD, playerA, "Forest"); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Invigorate", "Silvercoat Lion"); + setChoice(playerA, "Yes"); // use alternative cost + addTarget(playerA, playerB); // Opponent to gain live + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Invigorate", 1); + assertPowerToughness(playerA, "Silvercoat Lion", 6, 6); + assertLife(playerB, 23); + } + + @Test + public void test_Not_Playable_WithOpponentGainingLive() { + // If you control a Forest, rather than pay Invigorate's mana cost, you may have an opponent gain 3 life. + // Target creature gets +4/+4 until end of turn. + addCard(Zone.GRAVEYARD, playerA, "Invigorate"); // Instant {2}{G} + addCard(Zone.BATTLEFIELD, playerA, "Forest"); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerB, "Forest"); + + // can't see as playable because in graveyard + checkPlayableAbility("can't", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Invigorate", false); + + checkPlayableAbility("can't", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cast Invigorate", false); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Invigorate", 1); + assertPowerToughness(playerA, "Silvercoat Lion", 2, 2); + assertLife(playerB, 20); + } + @Test @Ignore // TODO: make test to check combo of alternative cost and cost reduction effects public void test_Playable_WithCostReduction() { diff --git a/Mage/src/main/java/mage/abilities/costs/AlternativeCostSourceAbility.java b/Mage/src/main/java/mage/abilities/costs/AlternativeCostSourceAbility.java index 25ba6f8f4fd..7fc082a4230 100644 --- a/Mage/src/main/java/mage/abilities/costs/AlternativeCostSourceAbility.java +++ b/Mage/src/main/java/mage/abilities/costs/AlternativeCostSourceAbility.java @@ -151,11 +151,11 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter for (AlternativeCost2 alternateCost : alternativeCostsToCheck) { alternateCost.activate(); for (Iterator it = ((Costs) alternateCost).iterator(); it.hasNext(); ) { - Cost costDeailed = (Cost) it.next(); - if (costDeailed instanceof ManaCost) { - ability.getManaCostsToPay().add((ManaCost) costDeailed.copy()); - } else { - ability.getCosts().add(costDeailed.copy()); + Cost costDetailed = (Cost) it.next(); + if (costDetailed instanceof ManaCost) { + ability.getManaCostsToPay().add((ManaCost) costDetailed.copy()); + } else if (costDetailed != null) { + ability.getCosts().add(costDetailed.copy()); } } } @@ -222,7 +222,7 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter sb.append("pay "); } String text = alternativeCost.getText(true); - sb.append(Character.toLowerCase(text.charAt(0)) + text.substring(1)); + sb.append(Character.toLowerCase(text.charAt(0))).append(text.substring(1)); } ++numberCosts; } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 0cba9775d28..7842874ad7f 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -3207,6 +3207,9 @@ public abstract class PlayerImpl implements Player, Serializable { // check "can play" condition as affected controller (BUT play from not own hand zone must be checked as original controller) // must check all abilities, not activated only for (Ability ability : candidateAbilities) { + if (!(ability instanceof ActivatedAbility)) { + continue; + } boolean isPlaySpell = (ability instanceof SpellAbility); boolean isPlayLand = (ability instanceof PlayLandAbility);