* Fixed that Soulfire Grand Master did not work for adventure or split cards (fixes #6182).

This commit is contained in:
LevelX2 2020-01-14 23:26:04 +01:00
parent afbae25fd1
commit 7575510c85
3 changed files with 111 additions and 51 deletions

View file

@ -1,5 +1,6 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -10,9 +11,11 @@ import mage.abilities.effects.Effect;
import mage.abilities.effects.GainAbilitySpellsEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.keyword.LifelinkAbility;
import mage.cards.AdventureCardSpell;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.SplitCardHalf;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.FilterObject;
@ -23,8 +26,6 @@ import mage.game.events.ZoneChangeEvent;
import mage.game.stack.Spell;
import mage.players.Player;
import java.util.UUID;
/**
* @author LevelX2
*/
@ -99,12 +100,10 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
MageObject mageObject = game.getObject(spellId);
if (!(mageObject instanceof Spell) || mageObject.isCopy()) {
return false;
} else {
Spell spell = (Spell) game.getStack().getFirst();
if (!spell.isCopy() && !spell.isCountered()) {
Card sourceCard = game.getCard(spellId);
if (sourceCard != null) {
if (sourceCard != null && Zone.STACK.equals(game.getState().getZone(spellId))) {
Player player = game.getPlayer(sourceCard.getOwnerId());
if (player != null) {
player.moveCards(sourceCard, Zone.HAND, source, game);
@ -141,9 +140,17 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect
if (zEvent.getFromZone() == Zone.STACK
&& zEvent.getToZone() == Zone.GRAVEYARD
&& event.getTargetId().equals(spellId)) {
Spell spell = game.getStack().getSpell(spellId);
if (spell != null && !spell.isCountered()) {
return true;
if (game.getStack().getFirst() instanceof Spell) {
Card cardOfSpell = ((Spell) game.getStack().getFirst()).getCard();
if (cardOfSpell instanceof SplitCardHalf) {
return ((SplitCardHalf) cardOfSpell).getParentCard().getId().equals(spellId);
} else if (cardOfSpell instanceof AdventureCardSpell) {
return (((AdventureCardSpell) cardOfSpell).getParentCard().getId().equals(spellId));
} else {
if (cardOfSpell.getId().equals(spellId)) {
return true;
}
}
}
}
}

View file

@ -0,0 +1,52 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.mage.test.cards.cost.splitcards;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class SplitCardsTest extends CardTestPlayerBase {
@Test
public void testReturnCardFromSoulfireGrandMaster() {
// Total CMC of Failure // Comply is 3, so should be exiled by Transgress the Mind.
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 6);
// 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 your hand this turn, put that card into your hand instead of your graveyard as it resolves.
addCard(Zone.BATTLEFIELD, playerA, "Soulfire Grand Master");
// Fire - Instant {1}{R}
// Fire deals 2 damage divided as you choose among one or two target creatures and/or players.
// Ice - Instant {1}{U}
// Tap target permanent.
// Draw a card.
addCard(Zone.HAND, playerA, "Fire // Ice");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{U/R}{U/R}");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Fire", playerB);
addTargetAmount(playerA, "targetPlayer=PlayerB", 2);
setStopAt(1, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
assertLife(playerA, 22);
assertLife(playerB, 18);
assertHandCount(playerA, "Fire // Ice", 1);
}
}

View file

@ -1,5 +1,10 @@
package org.mage.test.player;
import java.io.Serializable;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import mage.MageItem;
import mage.MageObject;
import mage.MageObjectReference;
@ -56,13 +61,6 @@ import mage.util.CardUtil;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Ignore;
import java.io.Serializable;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*;
/**
@ -179,7 +177,7 @@ public class TestPlayer implements Player {
/**
* @param maxCallsWithoutAction max number of priority passes a player may
* have for this test (default = 100)
* have for this test (default = 100)
*/
public void setMaxCallsWithoutAction(int maxCallsWithoutAction) {
this.maxCallsWithoutAction = maxCallsWithoutAction;
@ -333,6 +331,9 @@ public class TestPlayer implements Player {
if (ability.getTargets().isEmpty()) {
throw new UnsupportedOperationException("Ability has no targets, but there is a player target set - " + ability.toString());
}
if (ability.getTargets().get(0) instanceof TargetAmount) {
return true; // targetAmount have to be set by setTargetAmount in the test script
}
ability.getTargets().get(0).addTarget(player.getId(), ability, game);
targetsSet++;
break;
@ -900,12 +901,12 @@ public class TestPlayer implements Player {
List<String> data = cards.stream()
.map(c -> (((c instanceof PermanentToken) ? "[T] " : "[C] ")
+ c.getIdName()
+ (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "")
+ " - " + c.getPower().getValue() + "/" + c.getToughness().getValue()
+ (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "")
+ ", " + (c.isTapped() ? "Tapped" : "Untapped")
+ (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName())))
+ c.getIdName()
+ (c.isCopy() ? " [copy of " + c.getCopyFrom().getId().toString().substring(0, 3) + "]" : "")
+ " - " + c.getPower().getValue() + "/" + c.getToughness().getValue()
+ (c.isPlaneswalker() ? " - L" + c.getCounters(game).getCount(CounterType.LOYALTY) : "")
+ ", " + (c.isTapped() ? "Tapped" : "Untapped")
+ (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName())))
.sorted()
.collect(Collectors.toList());
@ -929,11 +930,11 @@ public class TestPlayer implements Player {
List<String> data = abilities.stream()
.map(a -> (a.getZone() + " -> "
+ a.getSourceObject(game).getIdName() + " -> "
+ (a.toString().length() > 0
? a.toString().substring(0, Math.min(20, a.toString().length()) - 1)
: a.getClass().getSimpleName())
+ "..."))
+ a.getSourceObject(game).getIdName() + " -> "
+ (a.toString().length() > 0
? a.toString().substring(0, Math.min(20, a.toString().length()) - 1)
: a.getClass().getSimpleName())
+ "..."))
.sorted()
.collect(Collectors.toList());
@ -1287,7 +1288,7 @@ public class TestPlayer implements Player {
UUID defenderId = null;
boolean mustAttackByAction = false;
boolean madeAttackByAction = false;
for (Iterator<org.mage.test.player.PlayerAction> it = actions.iterator(); it.hasNext(); ) {
for (Iterator<org.mage.test.player.PlayerAction> it = actions.iterator(); it.hasNext();) {
PlayerAction action = it.next();
if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("attack:")) {
mustAttackByAction = true;
@ -1769,7 +1770,7 @@ public class TestPlayer implements Player {
// skip targets
if (targets.get(0).equals(TARGET_SKIP)) {
Assert.assertTrue("found skip target, but it require more targets, needs "
+ (target.getMinNumberOfTargets() - target.getTargets().size()) + " more",
+ (target.getMinNumberOfTargets() - target.getTargets().size()) + " more",
target.getTargets().size() >= target.getMinNumberOfTargets());
targets.remove(0);
return true;
@ -3243,7 +3244,7 @@ public class TestPlayer implements Player {
@Override
public boolean choose(Outcome outcome, Target target,
UUID sourceId, Game game
UUID sourceId, Game game
) {
// needed to call here the TestPlayer because it's overwitten
return choose(outcome, target, sourceId, game, null);
@ -3251,7 +3252,7 @@ public class TestPlayer implements Player {
@Override
public boolean choose(Outcome outcome, Cards cards,
TargetCard target, Game game
TargetCard target, Game game
) {
if (!choices.isEmpty()) {
for (String choose2 : choices) {
@ -3287,7 +3288,7 @@ public class TestPlayer implements Player {
@Override
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target,
Ability source, Game game
Ability source, Game game
) {
// chooseTargetAmount calls for EACH target cycle (e.g. one target per click, see TargetAmount)
// if use want to stop choosing then chooseTargetAmount must return false (example: up to xxx)
@ -3299,7 +3300,7 @@ public class TestPlayer implements Player {
// skip targets
if (targets.get(0).equals(TARGET_SKIP)) {
Assert.assertTrue("found skip target, but it require more targets, needs "
+ (target.getMinNumberOfTargets() - target.getTargets().size()) + " more",
+ (target.getMinNumberOfTargets() - target.getTargets().size()) + " more",
target.getTargets().size() >= target.getMinNumberOfTargets());
targets.remove(0);
return false; // false in chooseTargetAmount = stop to choose
@ -3352,15 +3353,15 @@ public class TestPlayer implements Player {
@Override
public boolean choosePile(Outcome outcome, String message,
List<? extends Card> pile1, List<? extends Card> pile2,
Game game
List<? extends Card> pile1, List<? extends Card> pile2,
Game game
) {
return computerPlayer.choosePile(outcome, message, pile1, pile2, game);
}
@Override
public boolean playMana(Ability ability, ManaCost unpaid,
String promptText, Game game
String promptText, Game game
) {
groupsForTargetHandling = null;
return computerPlayer.playMana(ability, unpaid, promptText, game);
@ -3374,15 +3375,15 @@ public class TestPlayer implements Player {
@Override
public UUID chooseBlockerOrder(List<Permanent> blockers, CombatGroup combatGroup,
List<UUID> blockerOrder, Game game
List<UUID> blockerOrder, Game game
) {
return computerPlayer.chooseBlockerOrder(blockers, combatGroup, blockerOrder, game);
}
@Override
public void assignDamage(int damage, List<UUID> targets,
String singleTargetName, UUID sourceId,
Game game
String singleTargetName, UUID sourceId,
Game game
) {
computerPlayer.assignDamage(damage, targets, singleTargetName, sourceId, game);
}
@ -3401,14 +3402,14 @@ public class TestPlayer implements Player {
@Override
public void pickCard(List<Card> cards, Deck deck,
Draft draft
Draft draft
) {
computerPlayer.pickCard(cards, deck, draft);
}
@Override
public boolean scry(int value, Ability source,
Game game
Game game
) {
// Don't scry at the start of the game.
if (game.getTurnNum() == 1 && game.getStep() == null) {
@ -3419,44 +3420,44 @@ public class TestPlayer implements Player {
@Override
public boolean surveil(int value, Ability source,
Game game
Game game
) {
return computerPlayer.surveil(value, source, game);
}
@Override
public boolean moveCards(Card card, Zone toZone,
Ability source, Game game
Ability source, Game game
) {
return computerPlayer.moveCards(card, toZone, source, game);
}
@Override
public boolean moveCards(Card card, Zone toZone,
Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
) {
return computerPlayer.moveCards(card, toZone, source, game, tapped, faceDown, byOwner, appliedEffects);
}
@Override
public boolean moveCards(Cards cards, Zone toZone,
Ability source, Game game
Ability source, Game game
) {
return computerPlayer.moveCards(cards, toZone, source, game);
}
@Override
public boolean moveCards(Set<Card> cards, Zone toZone,
Ability source, Game game
Ability source, Game game
) {
return computerPlayer.moveCards(cards, toZone, source, game);
}
@Override
public boolean moveCards(Set<Card> cards, Zone toZone,
Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
Ability source, Game game,
boolean tapped, boolean faceDown, boolean byOwner, List<UUID> appliedEffects
) {
return computerPlayer.moveCards(cards, toZone, source, game, tapped, faceDown, byOwner, appliedEffects);
}