mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00:00
* Fixed that Soulfire Grand Master did not work for adventure or split cards (fixes #6182).
This commit is contained in:
parent
afbae25fd1
commit
7575510c85
3 changed files with 111 additions and 51 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue