forked from External/mage
[OTJ] Implement Satoru, the Infiltrator and Freestrider Commando (#12052)
This commit is contained in:
parent
d1de8b8cd3
commit
62279bbe6a
5 changed files with 589 additions and 0 deletions
78
Mage.Sets/src/mage/cards/f/FreestriderCommando.java
Normal file
78
Mage.Sets/src/mage/cards/f/FreestriderCommando.java
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
package mage.cards.f;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.decorator.ConditionalOneShotEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.abilities.keyword.PlotAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public final class FreestriderCommando extends CardImpl {
|
||||
|
||||
public FreestriderCommando(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");
|
||||
|
||||
this.subtype.add(SubType.CENTAUR);
|
||||
this.subtype.add(SubType.MERCENARY);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Freestrider Commando enters the battlefield with two +1/+1 counters on it if it wasn't cast or no mana was spent to cast it.
|
||||
this.addAbility(new EntersBattlefieldAbility(
|
||||
new ConditionalOneShotEffect(
|
||||
new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)),
|
||||
FreestriderCommandoCondition.instance, ""
|
||||
), "with two +1/+1 counters on it if it wasn't cast or no mana was spent to cast it"
|
||||
));
|
||||
|
||||
// Plot {3}{G}
|
||||
this.addAbility(new PlotAbility("{3}{G}"));
|
||||
}
|
||||
|
||||
private FreestriderCommando(final FreestriderCommando card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FreestriderCommando copy() {
|
||||
return new FreestriderCommando(this);
|
||||
}
|
||||
}
|
||||
|
||||
enum FreestriderCommandoCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanentEntering(source.getSourceId());
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
// Check if the spell exists on the stack
|
||||
Spell spell = game.getStack().getSpell(source.getSourceId());
|
||||
if (spell == null) {
|
||||
return true; // cannot find the spell, so it wasn't cast.
|
||||
}
|
||||
// spell was found, did it cost mana?
|
||||
return 0 == spell.getStackAbility().getManaCostsToPay().getUsedManaToPay().count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if it wasn't cast or no mana was spent to cast it";
|
||||
}
|
||||
}
|
||||
114
Mage.Sets/src/mage/cards/s/SatoruTheInfiltrator.java
Normal file
114
Mage.Sets/src/mage/cards/s/SatoruTheInfiltrator.java
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
package mage.cards.s;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.keyword.MenaceAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeBatchEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public final class SatoruTheInfiltrator extends CardImpl {
|
||||
|
||||
public SatoruTheInfiltrator(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}");
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.NINJA);
|
||||
this.subtype.add(SubType.ROGUE);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Menace
|
||||
this.addAbility(new MenaceAbility());
|
||||
|
||||
// Whenever Satoru, the Infiltrator and/or one or more other nontoken creatures enter the battlefield under your control, if none of them were cast or no mana was spent to cast them, draw a card.
|
||||
this.addAbility(new SatoruTheInfiltratorTriggeredAbility());
|
||||
}
|
||||
|
||||
private SatoruTheInfiltrator(final SatoruTheInfiltrator card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SatoruTheInfiltrator copy() {
|
||||
return new SatoruTheInfiltrator(this);
|
||||
}
|
||||
}
|
||||
|
||||
class SatoruTheInfiltratorTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public SatoruTheInfiltratorTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false);
|
||||
this.setTriggerPhrase("Whenever {this} and/or one or more other nontoken creatures "
|
||||
+ "enter the battlefield under your control, if none of them were cast or no mana was spent to cast them, ");
|
||||
}
|
||||
|
||||
protected SatoruTheInfiltratorTriggeredAbility(final SatoruTheInfiltratorTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SatoruTheInfiltratorTriggeredAbility copy() {
|
||||
return new SatoruTheInfiltratorTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE_BATCH;
|
||||
}
|
||||
|
||||
// event is GameEvent.EventType.ENTERS_THE_BATTLEFIELD
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
ZoneChangeBatchEvent zEvent = (ZoneChangeBatchEvent) event;
|
||||
List<ZoneChangeEvent> moved = zEvent.getEvents()
|
||||
.stream()
|
||||
.filter(e -> e.getToZone() == Zone.BATTLEFIELD) // Keep only to the battlefield
|
||||
.filter(e -> {
|
||||
Permanent permanent = e.getTarget();
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
return permanent.isControlledBy(getControllerId()) // under your control
|
||||
&& (permanent.getId().equals(getSourceId()) // {this}
|
||||
|| (permanent.isCreature(game) && !(permanent instanceof PermanentToken)) // other nontoken Creature
|
||||
);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (moved.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// At this point, we have at least one event matching
|
||||
// "Whenever {this} and/or one or more other nontoken creatures enter the battlefield under your control"
|
||||
// Now to check that none were cast using mana
|
||||
for (ZoneChangeEvent zce : moved) {
|
||||
if (zce.getFromZone() != Zone.STACK) {
|
||||
continue; // not from stack, we good for this one event
|
||||
}
|
||||
Spell spell = game.getSpellOrLKIStack(zce.getTargetId());
|
||||
if (spell != null && spell.getStackAbility().getManaCostsToPay().getUsedManaToPay().count() > 0) {
|
||||
return false; // found one that did use mana, so no triggering.
|
||||
}
|
||||
}
|
||||
return true; // all relevant permanents passed the spell mana check, so triggering.
|
||||
}
|
||||
}
|
||||
|
|
@ -113,6 +113,7 @@ public final class OutlawsOfThunderJunction extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Form a Posse", 204, Rarity.UNCOMMON, mage.cards.f.FormAPosse.class));
|
||||
cards.add(new SetCardInfo("Forsaken Miner", 88, Rarity.UNCOMMON, mage.cards.f.ForsakenMiner.class));
|
||||
cards.add(new SetCardInfo("Fortune, Loyal Steed", 12, Rarity.RARE, mage.cards.f.FortuneLoyalSteed.class));
|
||||
cards.add(new SetCardInfo("Freestrider Commando", 162, Rarity.COMMON, mage.cards.f.FreestriderCommando.class));
|
||||
cards.add(new SetCardInfo("Freestrider Lookout", 163, Rarity.RARE, mage.cards.f.FreestriderLookout.class));
|
||||
cards.add(new SetCardInfo("Frontier Seeker", 13, Rarity.UNCOMMON, mage.cards.f.FrontierSeeker.class));
|
||||
cards.add(new SetCardInfo("Full Steam Ahead", 164, Rarity.UNCOMMON, mage.cards.f.FullSteamAhead.class));
|
||||
|
|
@ -235,6 +236,7 @@ public final class OutlawsOfThunderJunction extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Rustler Rampage", 27, Rarity.UNCOMMON, mage.cards.r.RustlerRampage.class));
|
||||
cards.add(new SetCardInfo("Ruthless Lawbringer", 229, Rarity.UNCOMMON, mage.cards.r.RuthlessLawbringer.class));
|
||||
cards.add(new SetCardInfo("Sandstorm Verge", 263, Rarity.UNCOMMON, mage.cards.s.SandstormVerge.class));
|
||||
cards.add(new SetCardInfo("Satoru, the Infiltrator", 230, Rarity.RARE, mage.cards.s.SatoruTheInfiltrator.class));
|
||||
cards.add(new SetCardInfo("Scalestorm Summoner", 144, Rarity.UNCOMMON, mage.cards.s.ScalestormSummoner.class));
|
||||
cards.add(new SetCardInfo("Scorching Shot", 145, Rarity.UNCOMMON, mage.cards.s.ScorchingShot.class));
|
||||
cards.add(new SetCardInfo("Seize the Secrets", 64, Rarity.COMMON, mage.cards.s.SeizeTheSecrets.class));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
package org.mage.test.cards.single.otj;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class FreestriderCommandoTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.f.FreestriderCommando Freestrider Commando} {2}{G}
|
||||
* Creature — Centaur Mercenary
|
||||
* Freestrider Commando enters the battlefield with two +1/+1 counters on it if it wasn’t cast or no mana was spent to cast it.
|
||||
* Plot {3}{G} (You may pay {3}{G} and exile this card from your hand. Cast it as a sorcery on a later turn without paying its mana cost. Plot only as a sorcery.)
|
||||
* 3/3
|
||||
*/
|
||||
private static final String commando = "Freestrider Commando";
|
||||
|
||||
@Test
|
||||
public void test_RegularCast() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, commando);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
// No +1/+1 as cast with mana
|
||||
assertPowerToughness(playerA, commando, 3, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_PlotCast() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plot");
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, commando + " using Plot");
|
||||
|
||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
// 2 +1/+1 as cast free with plot
|
||||
assertPowerToughness(playerA, commando, 3 + 2, 3 + 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_OmniscienceCast() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Omniscience");
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, commando);
|
||||
setChoice(playerA, true); // Omniscience asks for confirmation to cast to avoid missclick?
|
||||
|
||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
// 2 +1/+1 as cast free with Omniscience
|
||||
assertPowerToughness(playerA, commando, 3 + 2, 3 + 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_PlotCast_WithTax() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Sphere of Resistance"); // Spells cost {1} more to cast
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plot");
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, commando + " using Plot");
|
||||
|
||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
// no +1/+1 as cast free with plot, but tax make mana being paid
|
||||
assertPowerToughness(playerA, commando, 3, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Blink() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Savannah", 4);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
addCard(Zone.HAND, playerA, "Ephemerate");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, commando);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ephemerate", "Freestrider Commando");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
// 2 +1/+1 as cast free with plot, as re-enter without being cast
|
||||
assertPowerToughness(playerA, commando, 3 + 2, 3 + 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_DoubleMajor() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
addCard(Zone.HAND, playerA, "Double Major");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, commando);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major", "Freestrider Commando");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 2); // resolve Double Major + the copy
|
||||
checkPT("double major copy enters as a 5/5", 1, PhaseStep.PRECOMBAT_MAIN, playerA, commando, 3 + 2, 3 + 2);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, commando, 2); // real + copy
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,268 @@
|
|||
package org.mage.test.cards.single.otj;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class SatoruTheInfiltratorTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.s.SatoruTheInfiltrator Satoru, the Infiltrator} {U}{B}
|
||||
* Legendary Creature — Human Ninja Rogue
|
||||
* Menace
|
||||
* Whenever Satoru, the Infiltrator and/or one or more other nontoken creatures enter the battlefield under your control, if none of them were cast or no mana was spent to cast them, draw a card.
|
||||
*/
|
||||
private static final String satoru = "Satoru, the Infiltrator";
|
||||
|
||||
/**
|
||||
* {@link mage.cards.f.FreestriderCommando Freestrider Commando} {2}{G}
|
||||
* Creature — Centaur Mercenary
|
||||
* Freestrider Commando enters the battlefield with two +1/+1 counters on it if it wasn’t cast or no mana was spent to cast it.
|
||||
* Plot {3}{G} (You may pay {3}{G} and exile this card from your hand. Cast it as a sorcery on a later turn without paying its mana cost. Plot only as a sorcery.)
|
||||
* 3/3
|
||||
*/
|
||||
private static final String commando = "Freestrider Commando";
|
||||
|
||||
@Test
|
||||
public void test_RegularCast_Other() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, satoru);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, commando);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, commando, 1);
|
||||
assertHandCount(playerA, 0); // no card draw.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_RegularCast_Other_Memnite() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, satoru);
|
||||
addCard(Zone.HAND, playerA, "Memnite"); // Is free!
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Memnite");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Memnite", 1);
|
||||
assertHandCount(playerA, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_RegularCast_Satoru() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 2);
|
||||
addCard(Zone.HAND, playerA, satoru);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, satoru);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, satoru, 1);
|
||||
assertHandCount(playerA, 0); // no card draw.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_PlotCast() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, satoru);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plot");
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, commando + " using Plot");
|
||||
|
||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, commando, 1);
|
||||
assertHandCount(playerA, 1 + 1); // Drawn 1 from draw step + 1 from Satoru
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Omniscience_CastOther() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, satoru);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Omniscience");
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, commando);
|
||||
setChoice(playerA, true); // Omniscience asks for confirmation to cast to avoid missclick?
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, commando, 1);
|
||||
assertHandCount(playerA, 1); // Drawn 1 from Satoru
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Omniscience_CastSatoru() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Omniscience");
|
||||
addCard(Zone.HAND, playerA, satoru);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, satoru);
|
||||
setChoice(playerA, true); // Omniscience asks for confirmation to cast to avoid missclick?
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, satoru, 1);
|
||||
assertHandCount(playerA, 1); // Drawn 1 from Satoru
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_PlotCast_WithTax() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, satoru);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Sphere of Resistance"); // Spells cost {1} more to cast
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plot");
|
||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, commando + " using Plot");
|
||||
|
||||
setStopAt(3, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, commando, 1);
|
||||
assertHandCount(playerA, 1); // Drawn 1 from draw step, 0 from Satoru
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Blink() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, satoru);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Savannah", 4);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
addCard(Zone.HAND, playerA, "Ephemerate");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, commando);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ephemerate", commando);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, commando, 1);
|
||||
assertHandCount(playerA, 1); // Drawn 1 from Satoru
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_MultipleOtherEnter() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, satoru);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 6);
|
||||
addCard(Zone.GRAVEYARD, playerA, commando, 3);
|
||||
addCard(Zone.HAND, playerA, "Storm of Souls"); // Return all creature cards from your graveyard to the battlefield. Each of them is a 1/1 Spirit with flying in addition to its other types. Exile Storm of Souls.
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Storm of Souls");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, commando, 3);
|
||||
assertHandCount(playerA, 1); // Drawn 1 from Satoru
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Saturo_AndAnother_Enter() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, satoru);
|
||||
addCard(Zone.GRAVEYARD, playerA, commando, 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
|
||||
// Each player exiles all creature cards from their graveyard, then sacrifices all creatures they control,
|
||||
// then puts all cards they exiled this way onto the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Living Death");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Living Death");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, commando, 3);
|
||||
assertPermanentCount(playerA, satoru, 1);
|
||||
assertHandCount(playerA, 1); // Drawn 1 from Satoru
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopyOnStack() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, satoru);
|
||||
addCard(Zone.HAND, playerA, commando);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 5);
|
||||
// Copy target creature spell you control, except it isn’t legendary if the spell is legendary
|
||||
addCard(Zone.HAND, playerA, "Double Major");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, commando);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major", commando);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, commando, 2);
|
||||
assertPermanentCount(playerA, satoru, 1);
|
||||
assertHandCount(playerA, 0); // Drawn 0 from Satoru, as token does not count.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Tokens() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, satoru);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||
addCard(Zone.HAND, playerA, "Krenko's Command"); // Create two 1/1 red Goblin creature tokens.
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Krenko's Command");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Goblin Token", 2);
|
||||
assertPermanentCount(playerA, satoru, 1);
|
||||
assertHandCount(playerA, 0); // Drawn 0 from Satoru, as token does not count.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CopySatoruOnStack() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.HAND, playerA, satoru);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
// Copy target creature spell you control, except it isn’t legendary if the spell is legendary
|
||||
addCard(Zone.HAND, playerA, "Double Major");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, satoru);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major", satoru);
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, satoru, 2);
|
||||
assertHandCount(playerA, 1); // While Satoru does not trigger on other tokens, a copy of Satoru on the stack will trigger its own etb.
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue