From f0ef479402e265176289aabce9328f84afadff59 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 26 May 2015 22:16:32 +0200 Subject: [PATCH] * Soulfire Grand Master - Fixed that delayed effects (e.g. Deflecting Palm) have also lifelink if Soulfire Grand Master is still on the battlefield. --- .../fatereforged/SoulfireGrandMaster.java | 74 ++++++------------- .../other/SoulfireGrandMasterTest.java | 38 +++++++++- .../java/org/mage/test/player/TestPlayer.java | 22 ++++-- 3 files changed, 73 insertions(+), 61 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fatereforged/SoulfireGrandMaster.java b/Mage.Sets/src/mage/sets/fatereforged/SoulfireGrandMaster.java index 7ae39c928db..00b2744e19f 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/SoulfireGrandMaster.java +++ b/Mage.Sets/src/mage/sets/fatereforged/SoulfireGrandMaster.java @@ -27,8 +27,6 @@ */ package mage.sets.fatereforged; -import java.util.HashSet; -import java.util.Iterator; import java.util.UUID; import mage.MageInt; import mage.MageObject; @@ -48,7 +46,6 @@ import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.SubLayer; -import mage.constants.WatcherScope; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.FilterObject; @@ -61,7 +58,6 @@ import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; -import mage.watchers.Watcher; /** * @@ -89,7 +85,7 @@ public class SoulfireGrandMaster extends CardImpl { // Instant and sorcery spells you control have lifelink. Effect effect = new GainAbilitySpellsEffect(LifelinkAbility.getInstance(), filter); effect.setText("Instant and sorcery spells you control have lifelink"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect), new SoulfireGrandMasterLeavesStackWatcher()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); // {2}{U/R}{U/R}: The next time you cast an instant or sorcery spell from your hand this turn, put that card into your hand instead of your graveyard as it resolves. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SoulfireGrandMasterCastFromHandReplacementEffect(), new ManaCostsImpl("{2}{U/R}{U/R}"))); @@ -134,17 +130,32 @@ class GainAbilitySpellsEffect extends ContinuousEffectImpl { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { - for (Iterator iterator = game.getStack().iterator(); iterator.hasNext();) { - StackObject stackObject = iterator.next(); + for (Card card: game.getExile().getAllCards(game)) { + if (card.getOwnerId().equals(source.getControllerId()) && filter.match(card, game)) { + game.getState().addOtherAbility(card, ability); + } + } + for (Card card: player.getLibrary().getCards(game)) { + if (filter.match(card, game)) { + game.getState().addOtherAbility(card, ability); + } + } + for (Card card: player.getHand().getCards(game)) { + if (filter.match(card, game)) { + game.getState().addOtherAbility(card, ability); + } + } + for (Card card: player.getGraveyard().getCards(game)) { + if (filter.match(card, game)) { + game.getState().addOtherAbility(card, ability); + } + } + for (StackObject stackObject : game.getStack()) { if (stackObject.getControllerId().equals(source.getControllerId())) { Card card = game.getCard(stackObject.getSourceId()); if (card != null && filter.match(card, game)) { if (!card.getAbilities().contains(ability)) { game.getState().addOtherAbility(card, ability); - SoulfireGrandMasterLeavesStackWatcher watcher = (SoulfireGrandMasterLeavesStackWatcher) game.getState().getWatchers().get("SoulfireGrandMasterLeavesStackWatcher"); - if (watcher != null) { - watcher.addCardId(card.getId()); - } } } } @@ -238,44 +249,3 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect } } - -class SoulfireGrandMasterLeavesStackWatcher extends Watcher { - - private final HashSet cardIds = new HashSet<>(); - - public SoulfireGrandMasterLeavesStackWatcher() { - super("SoulfireGrandMasterLeavesStackWatcher", WatcherScope.GAME); - } - - public SoulfireGrandMasterLeavesStackWatcher(final SoulfireGrandMasterLeavesStackWatcher watcher) { - super(watcher); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE && cardIds.contains(event.getTargetId())) { - Card card = game.getCard(event.getTargetId()); - if (card != null) { - Iterator it = card.getAbilities().iterator(); - while (it.hasNext()) { - if (it.next() instanceof LifelinkAbility) { - it.remove(); - break; - } - } - cardIds.remove(event.getTargetId()); - } - } - } - - public void addCardId(UUID cardId) { - cardIds.add(cardId); - } - - @Override - public SoulfireGrandMasterLeavesStackWatcher copy() { - return new SoulfireGrandMasterLeavesStackWatcher(this); - } - -} - 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 5d7dff07e3b..795122d82e1 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 @@ -205,7 +205,7 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase { } /** * Test that if Soulfire Grand Master has left the battlefield - * spell have no longer lifelink + * spell has no longer lifelink */ @Test @@ -294,5 +294,39 @@ public class SoulfireGrandMasterTest extends CardTestPlayerBase { assertLife(playerB, 20); assertLife(playerA, 20); - } + } + /** + * With a Soulfire Grand Master in play, Deflecting Palm doesn't gain the caster life. + * It should as it has lifelink, and it's Deflecting Palm (an instant) dealing damage. + * I was playing against a human in Standard Constructed. + * + */ + + @Test + public void testWithDeflectingPalm() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + // Instant -{R}{W} + // The next time a source of your choice would deal damage to you this turn, prevent that damage. + // If damage is prevented this way, Deflecting Palm deals that much damage to that source's controller. + addCard(Zone.HAND, playerA, "Deflecting Palm"); + addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + addCard(Zone.HAND, playerB, "Lightning Bolt", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Deflecting Palm", null, "Lightning Bolt"); + setChoice(playerA, "Lightning Bolt"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerB, "Lightning Bolt", 1); + assertGraveyardCount(playerA, "Deflecting Palm", 1); + + assertLife(playerB, 17); + assertLife(playerA, 23); // damage is prevented + lifelink + 3 + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 5af22397fb8..bf48c2f8738 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -360,16 +360,24 @@ public class TestPlayer extends ComputerPlayer { MageObject targetObject = game.getObject(targetId); if (targetObject != null) { for (String choose2: choices) { - if (targetObject.getName().equals(choose2)) { - List alreadyTargetted = target.getTargets(); - if (t.canTarget(targetObject.getId(), game)) { - if (alreadyTargetted != null && !alreadyTargetted.contains(targetObject.getId())) { - target.add(targetObject.getId(), game); - choices.remove(choose2); - return true; + String[] targetList = choose2.split("\\^"); + boolean targetFound = false; + for (String targetName: targetList) { + if (targetObject.getName().equals(targetName)) { + List alreadyTargetted = target.getTargets(); + if (t.canTarget(targetObject.getId(), game)) { + if (alreadyTargetted != null && !alreadyTargetted.contains(targetObject.getId())) { + target.add(targetObject.getId(), game); + choices.remove(choose2); + targetFound = true; + } } } } + if (targetFound) { + choices.remove(choose2); + return true; + } } } }