forked from External/mage
Implement [DSK] Valgavoth, Terror Eater (#13593)
This commit is contained in:
parent
7cbd396e39
commit
507991b9e2
5 changed files with 595 additions and 2 deletions
221
Mage.Sets/src/mage/cards/v/ValgavothTerrorEater.java
Normal file
221
Mage.Sets/src/mage/cards/v/ValgavothTerrorEater.java
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
package mage.cards.v;
|
||||
|
||||
import mage.MageIdentifier;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.Costs;
|
||||
import mage.abilities.costs.CostsImpl;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.abilities.keyword.LifelinkAbility;
|
||||
import mage.abilities.keyword.WardAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.CardWithHalves;
|
||||
import mage.constants.*;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public final class ValgavothTerrorEater extends CardImpl {
|
||||
|
||||
public ValgavothTerrorEater(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{B}{B}{B}");
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.ELDER);
|
||||
this.subtype.add(SubType.DEMON);
|
||||
this.power = new MageInt(9);
|
||||
this.toughness = new MageInt(9);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Lifelink
|
||||
this.addAbility(LifelinkAbility.getInstance());
|
||||
|
||||
// Ward--Sacrifice three nonland permanents.
|
||||
this.addAbility(new WardAbility(new SacrificeTargetCost(3, StaticFilters.FILTER_PERMANENTS_NON_LAND)));
|
||||
|
||||
// If a card you didn't control would be put into an opponent's graveyard from anywhere, exile it instead.
|
||||
this.addAbility(new SimpleStaticAbility(new ValgavothTerrorEaterReplacementEffect()));
|
||||
|
||||
// During your turn, you may play cards exiled with Valgavoth. If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost.
|
||||
this.addAbility(new SimpleStaticAbility(new ValgavothTerrorEaterPlayEffect()).setIdentifier(MageIdentifier.ValgavothTerrorEaterAlternateCast));
|
||||
}
|
||||
|
||||
private ValgavothTerrorEater(final ValgavothTerrorEater card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValgavothTerrorEater copy() {
|
||||
return new ValgavothTerrorEater(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ValgavothTerrorEaterReplacementEffect extends GraveyardFromAnywhereExileReplacementEffect {
|
||||
|
||||
ValgavothTerrorEaterReplacementEffect() {
|
||||
super(StaticFilters.FILTER_CARD_A, false);
|
||||
staticText = "If a card you didn't control would be put into an opponent's graveyard from anywhere, exile it instead";
|
||||
}
|
||||
|
||||
private ValgavothTerrorEaterReplacementEffect(final ValgavothTerrorEaterReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValgavothTerrorEaterReplacementEffect copy() {
|
||||
return new ValgavothTerrorEaterReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: part of #13594 refactor to replaceEvent (add exile zone info in ZoneChangeEvent?)
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent != null) {
|
||||
return controller.moveCardsToExile(
|
||||
permanent, source, game, true,
|
||||
CardUtil.getCardExileZoneId(game, source),
|
||||
CardUtil.createObjectRelatedWindowTitle(source, game, "(may be played using life)")
|
||||
);
|
||||
}
|
||||
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null) {
|
||||
return controller.moveCardsToExile(
|
||||
card, source, game, true,
|
||||
CardUtil.getCardExileZoneId(game, source),
|
||||
CardUtil.createObjectRelatedWindowTitle(source, game, "(may be played using life)"));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
// checks that zce movement is to graveyard
|
||||
if (!super.applies(event, source, game)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ZoneChangeEvent zce = (ZoneChangeEvent) event;
|
||||
UUID controllerId = source.getControllerId();
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (zce.getFromZone() == Zone.BATTLEFIELD) {
|
||||
Permanent permanent = zce.getTarget();
|
||||
// is the permanent being moved controlled by someone that's not you?
|
||||
if (permanent == null || permanent.getControllerId().equals(controllerId)) {
|
||||
return false;
|
||||
}
|
||||
} else if (zce.getFromZone() == Zone.STACK) {
|
||||
Spell spell = game.getSpellOrLKIStack(event.getTargetId());
|
||||
if (spell == null) {
|
||||
// there is no direct link between moving a split/mdfc card and the stack part that was cast.
|
||||
// so we try them both and see if we find anything.
|
||||
if (card instanceof CardWithHalves) {
|
||||
CardWithHalves cwh = (CardWithHalves) card;
|
||||
spell = game.getSpellOrLKIStack(cwh.getLeftHalfCard().getId());
|
||||
if (spell == null) {
|
||||
spell = game.getSpellOrLKIStack(cwh.getRightHalfCard().getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
// is the spell being moved controlled by someone that's not you?
|
||||
if (spell == null || spell.getControllerId().equals(controllerId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// is the card going to an opponent's graveyard?
|
||||
return controller.hasOpponent(card.getOwnerId(), game);
|
||||
}
|
||||
}
|
||||
|
||||
class ValgavothTerrorEaterPlayEffect extends AsThoughEffectImpl {
|
||||
|
||||
ValgavothTerrorEaterPlayEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.AIDontUseIt); // AI will need help with this
|
||||
staticText = "during your turn, you may play cards exiled with {this}. If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost";
|
||||
}
|
||||
|
||||
private ValgavothTerrorEaterPlayEffect(final ValgavothTerrorEaterPlayEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValgavothTerrorEaterPlayEffect copy() {
|
||||
return new ValgavothTerrorEaterPlayEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (!source.isControlledBy(affectedControllerId) || !game.isActivePlayer(affectedControllerId)) {
|
||||
return false;
|
||||
}
|
||||
Player player = game.getPlayer(affectedControllerId);
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Card card = game.getCard(objectId);
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
UUID mainId = card.getMainCard().getId(); // for split cards
|
||||
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
UUID exileZoneId = CardUtil.getExileZoneId(game, sourceObject.getId(), sourceObject.getZoneChangeCounter(game));
|
||||
ExileZone exileZone = game.getExile().getExileZone(exileZoneId);
|
||||
if (exileZone == null || !exileZone.contains(mainId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// allows to play/cast with alternative life cost
|
||||
if (!card.isLand(game)) {
|
||||
PayLifeCost lifeCost = new PayLifeCost(card.getSpellAbility().getManaCosts().manaValue());
|
||||
Costs newCosts = new CostsImpl();
|
||||
newCosts.add(lifeCost);
|
||||
newCosts.addAll(card.getSpellAbility().getCosts());
|
||||
player.setCastSourceIdWithAlternateMana(card.getId(), null, newCosts, MageIdentifier.ValgavothTerrorEaterAlternateCast);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -366,6 +366,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Valgavoth's Lair", 327, Rarity.RARE, mage.cards.v.ValgavothsLair.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Valgavoth's Onslaught", 204, Rarity.RARE, mage.cards.v.ValgavothsOnslaught.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Valgavoth's Onslaught", 324, Rarity.RARE, mage.cards.v.ValgavothsOnslaught.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Valgavoth, Terror Eater", 120, Rarity.MYTHIC, mage.cards.v.ValgavothTerrorEater.class));
|
||||
cards.add(new SetCardInfo("Vanish from Sight", 82, Rarity.COMMON, mage.cards.v.VanishFromSight.class));
|
||||
cards.add(new SetCardInfo("Vengeful Possession", 162, Rarity.UNCOMMON, mage.cards.v.VengefulPossession.class));
|
||||
cards.add(new SetCardInfo("Veteran Survivor", 40, Rarity.UNCOMMON, mage.cards.v.VeteranSurvivor.class));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,369 @@
|
|||
package org.mage.test.cards.single.dsk;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class ValgavothTerrorEaterTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.v.ValgavothTerrorEater Valgavoth, Terror Eater} {6}{B}{B}{B}
|
||||
* Legendary Creature — Elder Demon
|
||||
* Flying, lifelink
|
||||
* Ward—Sacrifice three nonland permanents.
|
||||
* If a card you didn’t control would be put into an opponent’s graveyard from anywhere, exile it instead.
|
||||
* During your turn, you may play cards exiled with Valgavoth. If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost.
|
||||
* 9/9
|
||||
*/
|
||||
private static final String valgavoth = "Valgavoth, Terror Eater";
|
||||
|
||||
/**
|
||||
* Donate {2}{U} Sorcery
|
||||
* Target player gains control of target permanent you control.
|
||||
*/
|
||||
private static final String donate = "Donate";
|
||||
private static final String vanguard = "Elite Vanguard";
|
||||
private static final String piker = "Goblin Piker";
|
||||
private static final String bear = "Grizzly Bears";
|
||||
/**
|
||||
* Lightning Bolt {R} Instant
|
||||
* Lightning Bolt deals 3 damage to any target.
|
||||
*/
|
||||
private static final String bolt = "Lightning Bolt";
|
||||
/**
|
||||
* Fire // Ice
|
||||
* Fire {1}{R} Instant
|
||||
* Fire deals 2 damage divided as you choose among one or two targets.
|
||||
* Ice {1}{U} Instant
|
||||
* Tap target permanent.
|
||||
* Draw a card.
|
||||
*/
|
||||
private static final String fireice = "Fire // Ice";
|
||||
private static final String fire = "Fire";
|
||||
private static final String ice = "Ice";
|
||||
/**
|
||||
* Cloudshift {W} Instant
|
||||
* Exile target creature you control, then return that card to the battlefield under your control.
|
||||
*/
|
||||
private static final String cloudshift = "Cloudshift";
|
||||
/**
|
||||
* Pyroclasm {1}{R} Sorcery
|
||||
* Pyroclasm deals 2 damage to each creature.
|
||||
*/
|
||||
private static final String pyroclasm = "Pyroclasm";
|
||||
/**
|
||||
* Legerdemain {2}{U}{U} Sorcery
|
||||
* Exchange control of target artifact or creature and another target permanent that shares one of those types with it.
|
||||
*/
|
||||
private static final String legerdemain = "Legerdemain";
|
||||
/**
|
||||
* Tome Scour {U} Sorcery
|
||||
* Target player mills five cards.
|
||||
*/
|
||||
private static final String scour = "Tome Scour";
|
||||
|
||||
/**
|
||||
* Akoum Warrior // Akoum Teeth
|
||||
* Akoum Warrior {5}{R}
|
||||
* Creature — Minotaur Warrior
|
||||
* Trample
|
||||
* 4/5
|
||||
* Akoum Teeth
|
||||
* Land
|
||||
* This land enters tapped.
|
||||
* {T}: Add {R}.
|
||||
*/
|
||||
private static final String akoum = "Akoum Warrior // Akoum Teeth";
|
||||
private static final String warrior = "Akoum Warrior";
|
||||
private static final String teeth = "Akoum Teeth";
|
||||
|
||||
@Test
|
||||
public void testOwnBolts() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, valgavoth, 1);
|
||||
addCard(Zone.HAND, playerA, bolt, 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerB, vanguard, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, piker, 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, playerB);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, vanguard);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, piker);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerB, vanguard, 1);
|
||||
assertGraveyardCount(playerA, bolt, 3);
|
||||
assertGraveyardCount(playerA, piker, 1);
|
||||
assertLife(playerB, 20 - 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpponentBolts() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, valgavoth, 1);
|
||||
addCard(Zone.HAND, playerB, bolt, 3);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerB, vanguard, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, piker, 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, bolt, playerB);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, bolt, vanguard);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, bolt, piker);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerB, vanguard, 1);
|
||||
assertExileCount(playerB, bolt, 3);
|
||||
assertGraveyardCount(playerA, piker, 1);
|
||||
assertLife(playerB, 20 - 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterLegerdemainOthersA() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, valgavoth, 1);
|
||||
addCard(Zone.HAND, playerA, pyroclasm, 1);
|
||||
addCard(Zone.HAND, playerA, legerdemain, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 6);
|
||||
addCard(Zone.BATTLEFIELD, playerB, vanguard, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, piker, 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, legerdemain, vanguard + "^" + piker);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, pyroclasm);
|
||||
// playerA controls vanguard, so it is not exiled
|
||||
// piker goes into playerA's graveyard, so it is not exiled either
|
||||
// pyroclasm and legerdemain have been cast by playerA, so they are not exiled.
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerA, 0);
|
||||
assertExileCount(playerB, 0);
|
||||
assertGraveyardCount(playerA, 3);
|
||||
assertGraveyardCount(playerB, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterLegerdemainOthersB() {
|
||||
addCard(Zone.BATTLEFIELD, playerB, valgavoth, 1);
|
||||
addCard(Zone.HAND, playerA, pyroclasm, 1);
|
||||
addCard(Zone.HAND, playerA, legerdemain, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 6);
|
||||
addCard(Zone.BATTLEFIELD, playerB, vanguard, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, piker, 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, legerdemain, vanguard + "^" + piker);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, pyroclasm);
|
||||
// playerB controls piker, so it is not exiled
|
||||
// vanguard goes into playerB's graveyard, so it is not exiled either
|
||||
// pyroclasm and legerdemain have been cast by playerA, so they are exiled.
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerA, 2);
|
||||
assertExileCount(playerB, 0);
|
||||
assertGraveyardCount(playerA, 1);
|
||||
assertGraveyardCount(playerB, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterLegerdemainOthersDonate() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, valgavoth, 1);
|
||||
addCard(Zone.HAND, playerA, donate, 1);
|
||||
addCard(Zone.HAND, playerA, pyroclasm, 1);
|
||||
addCard(Zone.HAND, playerA, legerdemain, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 9);
|
||||
addCard(Zone.BATTLEFIELD, playerB, vanguard, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, piker, 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, donate, playerB);
|
||||
addTarget(playerA, valgavoth);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
// Donate ends up exiled as valgavoth is in control of playerB as it finishes resolving
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, legerdemain, vanguard + "^" + piker);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, pyroclasm);
|
||||
// playerB controls piker, so it is not exiled
|
||||
// vanguard goes into playerB's graveyard, so it is not exiled either
|
||||
// pyroclasm and legerdemain have been cast by playerA, so they are exiled.
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerA, 3);
|
||||
assertExileCount(playerB, 0);
|
||||
assertGraveyardCount(playerA, 1);
|
||||
assertGraveyardCount(playerB, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMillSelf() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, valgavoth, 1);
|
||||
addCard(Zone.HAND, playerA, scour, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, scour, playerA);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerA, 0);
|
||||
assertExileCount(playerB, 0);
|
||||
assertGraveyardCount(playerA, 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMillOpponent() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, valgavoth, 1);
|
||||
addCard(Zone.HAND, playerA, scour, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, scour, playerB);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerA, 0);
|
||||
assertExileCount(playerB, 5);
|
||||
assertGraveyardCount(playerA, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCastTimingAndSplitCard() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, valgavoth, 1);
|
||||
addCard(Zone.HAND, playerB, fireice);
|
||||
addCard(Zone.HAND, playerB, bolt);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Volcanic Island", 6);
|
||||
|
||||
castSpell(1, PhaseStep.UPKEEP, playerB, bolt, playerA);
|
||||
checkPlayableAbility("1: Can cast bolt PlA", 1, PhaseStep.END_TURN, playerA, "Cast " + bolt, true);
|
||||
checkPlayableAbility("1: Can not cast bolt PlB", 1, PhaseStep.END_TURN, playerB, "Cast " + bolt, false);
|
||||
checkPlayableAbility("1: Can not cast fire PlA", 1, PhaseStep.END_TURN, playerA, "Cast " + fire, false);
|
||||
checkPlayableAbility("1: Can cast fire PlB", 1, PhaseStep.END_TURN, playerB, "Cast " + fire, true);
|
||||
checkPlayableAbility("1: Can not cast ice PlA", 1, PhaseStep.END_TURN, playerA, "Cast " + ice, false);
|
||||
checkPlayableAbility("1: Can cast ice PlB", 1, PhaseStep.END_TURN, playerB, "Cast " + ice, true);
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, fire, playerA);
|
||||
addTargetAmount(playerB, playerA, 2);
|
||||
checkPlayableAbility("2: Can not cast bolt PlA", 2, PhaseStep.END_TURN, playerA, "Cast " + bolt, false);
|
||||
checkPlayableAbility("2: Can not cast bolt PlB", 2, PhaseStep.END_TURN, playerB, "Cast " + bolt, false);
|
||||
checkPlayableAbility("2: Can not cast fire PlA", 2, PhaseStep.END_TURN, playerA, "Cast " + fire, false);
|
||||
checkPlayableAbility("2: Can not cast fire PlB", 2, PhaseStep.END_TURN, playerB, "Cast " + fire, false);
|
||||
checkPlayableAbility("2: Can not cast ice PlA", 2, PhaseStep.END_TURN, playerA, "Cast " + ice, false);
|
||||
checkPlayableAbility("2: Can not cast ice PlB", 2, PhaseStep.END_TURN, playerB, "Cast " + ice, false);
|
||||
|
||||
waitStackResolved(3, PhaseStep.UPKEEP);
|
||||
checkPlayableAbility("3: Can cast bolt PlA", 3, PhaseStep.END_TURN, playerA, "Cast " + bolt, true);
|
||||
checkPlayableAbility("3: Can not cast bolt PlB", 2, PhaseStep.END_TURN, playerB, "Cast " + bolt, false);
|
||||
checkPlayableAbility("3: Can cast fire PlA", 3, PhaseStep.END_TURN, playerA, "Cast " + fire, true);
|
||||
checkPlayableAbility("3: Can not cast fire PlB", 2, PhaseStep.END_TURN, playerB, "Cast " + fire, false);
|
||||
checkPlayableAbility("3: Can cast ice PlA", 3, PhaseStep.END_TURN, playerA, "Cast " + ice, true);
|
||||
checkPlayableAbility("3: Can not cast ice PlB", 2, PhaseStep.END_TURN, playerB, "Cast " + ice, false);
|
||||
castSpell(3, PhaseStep.END_TURN, playerA, bolt, playerB);
|
||||
castSpell(3, PhaseStep.END_TURN, playerA, fire, playerB);
|
||||
addTargetAmount(playerA, playerB, 2);
|
||||
|
||||
setStopAt(4, PhaseStep.UPKEEP);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, 0);
|
||||
assertGraveyardCount(playerB, 2);
|
||||
assertExileCount(playerA, 0);
|
||||
assertExileCount(playerB, 0);
|
||||
|
||||
assertLife(playerA, 20 - 3 - 2 - 1 - 2);
|
||||
assertLife(playerB, 20 - 3 - 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCastMDFC() {
|
||||
skipInitShuffling();
|
||||
addCard(Zone.BATTLEFIELD, playerA, valgavoth, 1);
|
||||
addCard(Zone.LIBRARY, playerB, akoum, 5);
|
||||
addCard(Zone.HAND, playerA, scour);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, scour, playerB);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
checkPlayableAbility("1: Can cast Akoum Warrior", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + warrior, true);
|
||||
checkPlayableAbility("1: Can play Akoum Teeth", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play " + teeth, true);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, warrior);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, warrior);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, warrior);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
checkPlayableAbility("2: Can not cast Akoum Warrior (not enough life)", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + warrior, false);
|
||||
checkPlayableAbility("2: Can play Akoum Teeth", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play " + teeth, true);
|
||||
|
||||
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, teeth);
|
||||
checkPlayableAbility("3: Can not cast Akoum Warrior (not enough life)", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + warrior, false);
|
||||
checkPlayableAbility("3: Can not play Akoum Teeth (no land drop left)", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play " + teeth, false);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerA, 0);
|
||||
assertExileCount(playerB, 1);
|
||||
|
||||
assertLife(playerA, 20 - 6 * 3);
|
||||
assertPermanentCount(playerA, warrior, 3);
|
||||
assertPermanentCount(playerA, teeth, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWardAndBlink() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, valgavoth, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, bear, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, vanguard, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, piker, 1);
|
||||
addCard(Zone.HAND, playerB, bolt, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
|
||||
addCard(Zone.HAND, playerA, cloudshift, 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, bolt, valgavoth);
|
||||
setChoice(playerB, true); // pay for ward?
|
||||
setChoice(playerB, bear + "^" + vanguard + "^" + piker); // ward sacrifices
|
||||
|
||||
checkPlayableAbility("1: Can cast bear", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast " + bear, true);
|
||||
checkPlayableAbility("1: Can cast vanguard", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast " + vanguard, true);
|
||||
checkPlayableAbility("1: Can cast piker", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast " + piker, true);
|
||||
checkPlayableAbility("1: Can cast bolt", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast " + bolt, true);
|
||||
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, cloudshift, valgavoth);
|
||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
|
||||
// after blink, nothing can be cast
|
||||
checkPlayableAbility("2: Can not cast bear", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast " + bear, false);
|
||||
checkPlayableAbility("2: Can not cast vanguard", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast " + vanguard, false);
|
||||
checkPlayableAbility("2: Can not cast piker", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast " + piker, false);
|
||||
checkPlayableAbility("2: Can not cast bolt", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast " + bolt, false);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertExileCount(playerA, 0);
|
||||
assertExileCount(playerB, 4);
|
||||
assertGraveyardCount(playerA, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -79,7 +79,8 @@ public enum MageIdentifier {
|
|||
FiresOfMountDoomAlternateCast,
|
||||
PrimalPrayersAlternateCast,
|
||||
QuilledGreatwurmAlternateCast,
|
||||
WickerfolkIndomitableAlternateCast;
|
||||
WickerfolkIndomitableAlternateCast,
|
||||
ValgavothTerrorEaterAlternateCast;
|
||||
|
||||
/**
|
||||
* Additional text if there is need to differentiate two very similar effects
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public class GraveyardFromAnywhereExileReplacementEffect extends ReplacementEffe
|
|||
public GraveyardFromAnywhereExileReplacementEffect(Duration duration) {
|
||||
this(duration, StaticFilters.FILTER_CARD_A, true, false);
|
||||
}
|
||||
|
||||
protected GraveyardFromAnywhereExileReplacementEffect(Duration duration, FilterCard filter, boolean onlyYou, boolean tokens) {
|
||||
super(duration, Outcome.Exile);
|
||||
this.filter = filter;
|
||||
|
|
@ -43,7 +44,7 @@ public class GraveyardFromAnywhereExileReplacementEffect extends ReplacementEffe
|
|||
this.setText();
|
||||
}
|
||||
|
||||
private GraveyardFromAnywhereExileReplacementEffect(final GraveyardFromAnywhereExileReplacementEffect effect) {
|
||||
protected GraveyardFromAnywhereExileReplacementEffect(final GraveyardFromAnywhereExileReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
this.onlyYou = effect.onlyYou;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue