mirror of
https://github.com/correl/mage.git
synced 2025-03-07 20:53:18 -10:00
* Soulfire Grand Master - Fixed that delayed effects (e.g. Deflecting Palm) have also lifelink if Soulfire Grand Master is still on the battlefield.
This commit is contained in:
parent
7b5b4928a4
commit
f0ef479402
3 changed files with 73 additions and 61 deletions
|
@ -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<StackObject> 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<UUID> 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<Ability> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<UUID> 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<UUID> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue