diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java index 5ebd9205c41..f3a8cd4a9a7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java @@ -40,8 +40,8 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class CantAttackTest extends CardTestPlayerBase { /** - * Tests "If all other elves get the Forestwalk ability and can't be blockt - * from creatures whose controler has a forest in game" + * Tests "If all other elves get the Forestwalk ability and can't be blocked + * from creatures whose controller has a forest in game" */ @Test public void testAttack() { @@ -250,4 +250,158 @@ public class CantAttackTest extends CardTestPlayerBase { assertGraveyardCount(playerA, eFirecraft, 1); assertPermanentCount(playerA, medomai, 1); } + + @Test + public void sphereOfSafetyPaidCostAllowsAttack() { + /* + Sphere of Safety {4}{W} + Enchantment + Creatures can't attack you or a planeswalker you control unless their controller pays {X} for each of those creatures, where X is the number of enchantments you control. + */ + String sphere = "Sphere of Safety"; + String memnite = "Memnite"; + + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 + addCard(Zone.BATTLEFIELD, playerB, sphere); + addCard(Zone.BATTLEFIELD, playerA, "Forest"); + + attack(1, playerA, memnite); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, sphere, 1); + assertLife(playerB, 19); // took the hit from memnite + assertTapped("Forest", true); // forest had to be tapped + } + + @Test + public void sphereOfSafetyCostNotPaid_NoAttackAllowed() { + /* + Sphere of Safety {4}{W} + Enchantment + Creatures can't attack you or a planeswalker you control unless their controller pays {X} for each of those creatures, where X is the number of enchantments you control. + */ + String sphere = "Sphere of Safety"; + String memnite = "Memnite"; + + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 + addCard(Zone.BATTLEFIELD, playerB, sphere); + addCard(Zone.BATTLEFIELD, playerA, "Forest"); + + attack(1, playerA, memnite); + setChoice(playerA, "No"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, sphere, 1); + assertLife(playerB, 20); // no damage went through, did not elect to pay + assertTapped("Forest", false); // forest not tapped + } + + @Test + public void collectiveResistanceCostPaid_AttackAllowed() + { + /* + Collective Restraint {3}{U} + Enchantment + Domain — Creatures can't attack you unless their controller pays {X} for each creature he or she controls that's attacking you, where X is the number of basic land types among lands you control. + */ + String cRestraint = "Collective Restraint"; + String memnite = "Memnite"; + + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 + addCard(Zone.BATTLEFIELD, playerB, cRestraint); + addCard(Zone.BATTLEFIELD, playerB, "Island"); // 1 basic land type = pay 1 to attack + addCard(Zone.BATTLEFIELD, playerA, "Forest"); + + attack(1, playerA, memnite); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, cRestraint, 1); + assertLife(playerB, 19); // took the hit from memnite + assertTapped("Forest", true); // forest had to be tapped + } + + @Test + public void collectiveResistanceCostNotPaid_NoAttackAllowed() + { + /* + Collective Restraint {3}{U} + Enchantment + Domain — Creatures can't attack you unless their controller pays {X} for each creature he or she controls that's attacking you, where X is the number of basic land types among lands you control. + */ + String cRestraint = "Collective Restraint"; + String memnite = "Memnite"; + + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 + addCard(Zone.BATTLEFIELD, playerB, cRestraint); + addCard(Zone.BATTLEFIELD, playerB, "Island"); // 1 basic land type = pay 1 to attack + addCard(Zone.BATTLEFIELD, playerA, "Forest"); + + attack(1, playerA, memnite); + setChoice(playerA, "No"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, cRestraint, 1); + assertLife(playerB, 20); // no damage went through, did not elect to pay + assertTapped("Forest", false); // forest not tapped + } + + @Test + public void ghostlyPrison_PaidCost_AllowsAttack() { + /* + Ghostly Prison {2}{W} + Enchantment + Creatures can't attack you unless their controller pays {2} for each creature he or she controls that's attacking you. + */ + String gPrison = "Ghostly Prison"; + String memnite = "Memnite"; + + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 + addCard(Zone.BATTLEFIELD, playerB, gPrison); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + + attack(1, playerA, memnite); + setChoice(playerA, "Yes"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, gPrison, 1); + assertLife(playerB, 19); // took the hit from memnite + assertTappedCount("Forest", true, 2); // forests had to be tapped + } + + @Test + public void ghostlyPrison_CostNotPaid_NoAttackAllowed() { + /* + Ghostly Prison {2}{W} + Enchantment + Creatures can't attack you unless their controller pays {2} for each creature he or she controls that's attacking you. + */ + String gPrison = "Ghostly Prison"; + String memnite = "Memnite"; + + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 + addCard(Zone.BATTLEFIELD, playerB, gPrison); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + + attack(1, playerA, memnite); + setChoice(playerA, "No"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, gPrison, 1); + assertLife(playerB, 20); // no damage went through, did not elect to pay + assertTapped("Forest", false); // no forests tapped + } } diff --git a/Mage/src/main/java/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java index 48c16da477e..cad17d724e8 100644 --- a/Mage/src/main/java/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/PayCostToAttackBlockEffectImpl.java @@ -27,6 +27,7 @@ */ package mage.abilities.effects; +import java.util.Iterator; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; @@ -43,9 +44,6 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.players.Player; -import java.util.Iterator; -import java.util.List; - /** * * @author LevelX2 @@ -72,7 +70,6 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm protected final Cost cost; protected final ManaCosts manaCosts; - protected final RestrictType restrictType; public PayCostToAttackBlockEffectImpl(Duration duration, Outcome outcome, RestrictType restrictType) { @@ -149,7 +146,9 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm attackBlockManaTax.clearPaid(); if (attackBlockManaTax.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Neutral, chooseText, source, game)) { - handlePhyrexianManaCosts(manaCosts, player, source, game); + + handlePhyrexianManaCosts(getManaCostToPay(event, source, game), player, source, game); + if (attackBlockManaTax instanceof ManaCostsImpl) { if (attackBlockManaTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) { return false; @@ -162,6 +161,9 @@ public abstract class PayCostToAttackBlockEffectImpl extends ReplacementEffectIm } private void handlePhyrexianManaCosts(ManaCosts manaCosts, Player player, Ability source, Game game) { + + if (manaCosts == null) return; // nothing to be done without any mana costs. prevents NRE from occurring here + Iterator manaCostIterator = manaCosts.iterator(); Costs costs = new CostsImpl<>();