diff --git a/Mage.Sets/src/mage/sets/commander2013/CurseOfInertia.java b/Mage.Sets/src/mage/sets/commander2013/CurseOfInertia.java index da6f61eaf5b..69d24545cfc 100644 --- a/Mage.Sets/src/mage/sets/commander2013/CurseOfInertia.java +++ b/Mage.Sets/src/mage/sets/commander2013/CurseOfInertia.java @@ -89,27 +89,26 @@ class CurseOfInertiaTriggeredAbility extends TriggeredAbilityImpl { public CurseOfInertiaTriggeredAbility() { super(Zone.BATTLEFIELD, new CurseOfInertiaTapOrUntapTargetEffect(), false); } - - public CurseOfInertiaTriggeredAbility(Effect effect, boolean optional, String text) { - super(Zone.BATTLEFIELD, effect, optional); - } - + public CurseOfInertiaTriggeredAbility(final CurseOfInertiaTriggeredAbility ability) { super(ability); } + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType().equals(EventType.DECLARED_ATTACKERS); + } + @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType().equals(EventType.DECLARED_ATTACKERS)) { - Permanent enchantment = game.getPermanent(this.getSourceId()); - if (enchantment != null - && enchantment.getAttachedTo() != null - && game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) { - for (Effect effect: this.getEffects()) { - effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackerId())); - } - return true; - } + Permanent enchantment = game.getPermanent(this.getSourceId()); + if (enchantment != null + && enchantment.getAttachedTo() != null + && game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) { + TargetPermanent target = new TargetPermanent(); + target.setTargetController(game.getCombat().getAttackerId()); + addTarget(target); + return true; } return false; } @@ -138,24 +137,20 @@ class CurseOfInertiaTapOrUntapTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + Player player = game.getPlayer(source.getTargets().get(0).getTargetController()); if (player != null) { - Target target = new TargetPermanent(); - if (target.canChoose(source.getSourceId(), player.getId(), game) - && player.choose(outcome, target, source.getSourceId(), game)) { - Permanent targetPermanent = game.getPermanent(target.getFirstTarget()); - if (targetPermanent != null) { - if (targetPermanent.isTapped()) { - if (player.chooseUse(Outcome.Untap, "Untap that permanent?", game)) { - targetPermanent.untap(game); - } - } else { - if (player.chooseUse(Outcome.Tap, "Tap that permanent?", game)) { - targetPermanent.tap(game); - } + Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (targetPermanent != null) { + if (targetPermanent.isTapped()) { + if (player.chooseUse(Outcome.Untap, "Untap that permanent?", game)) { + targetPermanent.untap(game); + } + } else { + if (player.chooseUse(Outcome.Tap, "Tap that permanent?", game)) { + targetPermanent.tap(game); } - return true; } + return true; } } return false; diff --git a/Mage.Sets/src/mage/sets/fatereforged/SoulfireGrandMaster.java b/Mage.Sets/src/mage/sets/fatereforged/SoulfireGrandMaster.java index 03c29db4dfd..7ae39c928db 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/SoulfireGrandMaster.java +++ b/Mage.Sets/src/mage/sets/fatereforged/SoulfireGrandMaster.java @@ -48,14 +48,12 @@ import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; -import mage.constants.TargetController; import mage.constants.WatcherScope; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.FilterObject; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; @@ -230,7 +228,10 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect if (zEvent.getFromZone() == Zone.STACK && zEvent.getToZone() == Zone.GRAVEYARD && event.getTargetId().equals(spellId)) { - return true; + Spell spell = game.getStack().getSpell(spellId); + if (spell != null && !spell.isCountered()) { + return true; + } } } return false; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SoulfireGrandMasterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SoulfireGrandMasterTest.java index fd8bed2ff1c..5d7dff07e3b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SoulfireGrandMasterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SoulfireGrandMasterTest.java @@ -30,7 +30,6 @@ package org.mage.test.cards.abilities.other; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -42,7 +41,7 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase { /** * Soulfire Grand Master - * Creature — Human Monk 2/2, 1W (2) + * Creature - Human Monk 2/2, 1W (2) * Lifelink * Instant and sorcery spells you control have lifelink. * {2}{U/R}{U/R}: The next time you cast an instant or sorcery spell from @@ -233,5 +232,67 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase { assertLife(playerA, 20); } + /** + * I activated the ability of Soulfire grand master, it resolved, then i cast Stoke the Flames + * on Whisperwood Elemental, my opponenet sacrificed the elemental, so stoke didnt resolve, + * but i still got the life from lifelink. + */ + @Test + public void testSoulfireStokeTheFlames() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + + addCard(Zone.HAND, playerA, "Stoke the Flames"); + addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Whisperwood Elemental", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{U/R}{U/R}:"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Stoke the Flames", "Whisperwood Elemental"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Sacrifice {this}", null ,"{this} deals 4 damage"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Stoke the Flames", 1); // no legal target left so the spell is countered and goes to graveyard + assertGraveyardCount(playerB, "Whisperwood Elemental", 1); + + assertLife(playerB, 20); + assertLife(playerA, 20); + + } + + /** + * Check if second ability resolved, the next spell that is counterer + * won't go to hand back because it did not resolve + * + */ + + @Test + public void testSoulfireCounteredSpellDontGoesBack() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + + addCard(Zone.HAND, playerA, "Stoke the Flames"); + addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 2); + addCard(Zone.HAND, playerB, "Counterspell", 1); + addCard(Zone.BATTLEFIELD, playerB, "Whisperwood Elemental", 1); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{U/R}{U/R}:"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Stoke the Flames", "Whisperwood Elemental"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Counterspell", "Stoke the Flames"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerB, "Counterspell", 1); + assertGraveyardCount(playerA, "Stoke the Flames", 1); // no legal target left so the spell is countered and goes to graveyard + + assertLife(playerB, 20); + assertLife(playerA, 20); + + } } diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 5c7dcc03b81..9041b9cb61f 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -82,6 +82,7 @@ public class Spell implements StackObject, Card { private UUID controllerId; private boolean copiedSpell; private boolean faceDown; + private boolean countered; public Spell(Card card, SpellAbility ability, UUID controllerId, Zone fromZone) { this.card = card; @@ -100,6 +101,7 @@ public class Spell implements StackObject, Card { } this.controllerId = controllerId; this.fromZone = fromZone; + this.countered = false; } public Spell(final Spell spell) { @@ -521,6 +523,7 @@ public class Spell implements StackObject, Card { @Override public void counter(UUID sourceId, Game game) { + this.countered = true; if (!isCopiedSpell()) { card.moveToZone(Zone.GRAVEYARD, sourceId, game, false); } @@ -1002,4 +1005,8 @@ public class Spell implements StackObject, Card { throw new UnsupportedOperationException("Not supported."); } + public boolean isCountered() { + return countered; + } + } diff --git a/Mage/src/mage/game/stack/SpellStack.java b/Mage/src/mage/game/stack/SpellStack.java index 50caf946515..7f2179d4d77 100644 --- a/Mage/src/mage/game/stack/SpellStack.java +++ b/Mage/src/mage/game/stack/SpellStack.java @@ -97,9 +97,10 @@ public class SpellStack extends ArrayDeque { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, objectId, sourceId, stackObject.getControllerId()))) { if ( stackObject instanceof Spell ) { game.rememberLKI(objectId, Zone.STACK, (Spell)stackObject); + } else { + this.remove(stackObject); } - this.remove(stackObject); - stackObject.counter(sourceId, game); // tries to move to graveyard + stackObject.counter(sourceId, game); if (!game.isSimulation()) game.informPlayers(counteredObjectName + " is countered by " + sourceObject.getLogName()); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERED, objectId, sourceId, stackObject.getControllerId()));