mirror of
https://github.com/magefree/mage.git
synced 2026-01-10 21:02:08 -08:00
Changed ability handling of modal spells to be able to select the same mode multiple times with different targets.
This commit is contained in:
parent
b18cae5100
commit
4711e0cf99
40 changed files with 488 additions and 421 deletions
|
|
@ -45,11 +45,13 @@ public class CastDestroySpellsTest extends CardTestPlayerBaseAI {
|
|||
@Test
|
||||
public void testOrzhovCharm() {
|
||||
// Choose one -
|
||||
// Return target creature you control and all Auras you control attached to it to their owner's hand;
|
||||
// or destroy target creature and you lose life equal to its toughness;
|
||||
// or return target creature card with converted mana cost 1 or less from your graveyard to the battlefield.
|
||||
// - Return target creature you control and all Auras you control attached to it to their owner's hand;
|
||||
// - Destroy target creature and you lose life equal to its toughness;
|
||||
// - Return target creature card with converted mana cost 1 or less from your graveyard to the battlefield.
|
||||
addCard(Zone.HAND, playerA, "Orzhov Charm"); // {W}{B}
|
||||
|
||||
// {T}: Add {1} to your mana pool.
|
||||
// {T} {W/B}, {T}: Add {W}{W}, {W}{B}, or {B}{B} to your mana pool.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Fetid Heath", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,10 +51,11 @@ public class ReturnToHandTest extends CardTestPlayerBase {
|
|||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3);
|
||||
addCard(Zone.HAND, playerB, "Bone Splinters");
|
||||
|
||||
// As an additional cost to cast Bone Splinters, sacrifice a creature.
|
||||
// Destroy target creature.
|
||||
addCard(Zone.HAND, playerB, "Bone Splinters");
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Bone Splinters", "Pillarfield Ox");
|
||||
setChoice(playerB, "Skarrgan Firebird");
|
||||
|
||||
|
|
@ -126,7 +127,7 @@ public class ReturnToHandTest extends CardTestPlayerBase {
|
|||
// Devoid
|
||||
// Choose one or both
|
||||
// - Return target spell or creature to its owner's hand;
|
||||
// or Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead.
|
||||
// - Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead.
|
||||
addCard(Zone.HAND, playerA, "Brutal Expulsion"); // {2}{U}{R}
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Plains", 4);
|
||||
|
|
@ -135,6 +136,8 @@ public class ReturnToHandTest extends CardTestPlayerBase {
|
|||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Pillarfield Ox");
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Brutal Expulsion", "mode=1Pillarfield Ox^mode=2Silvercoat Lion", "Pillarfield Ox");
|
||||
setModeChoice(playerA, "1");
|
||||
setModeChoice(playerA, "2");
|
||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||
|
||||
execute();
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public class DeathtouchTest extends CardTestPlayerBase {
|
|||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Marath, Will of the Wild");
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {2}", "Marath, Will of the Wild");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {2}", "Marath, Will of the Wild", "Marath, Will of the Wild", StackClause.WHILE_NOT_ON_STACK);
|
||||
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{X},Remove X +1/+1 counters from Marath", "Archangel of Thune");
|
||||
setChoice(playerA, "X=3");
|
||||
|
|
|
|||
|
|
@ -36,30 +36,29 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class HeroicTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* When casting Dromoka's Command targeting two of my own Heroic creatures, only one of them triggers.
|
||||
* It appears to be the one targeted with mode 4 (fight) rather than the one targeted with mode 3 (+1/+1 counter).
|
||||
* When casting Dromoka's Command targeting two of my own Heroic creatures,
|
||||
* only one of them triggers. It appears to be the one targeted with mode 4
|
||||
* (fight) rather than the one targeted with mode 3 (+1/+1 counter).
|
||||
* Screenshot attached. Reproducible.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testHeroicWithModal() {
|
||||
// Heroic - Whenever you cast a spell that targets Favored Hoplite, put a +1/+1 counter on Favored Hoplite and prevent all damage that would be dealt to it this turn.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Favored Hoplite", 1); // 1/2
|
||||
// Heroic — Whenever you cast a spell that targets Lagonna-Band Trailblazer, put a +1/+1 counter on Lagonna-Band Trailblazer.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Lagonna-Band Trailblazer"); // 0/4
|
||||
|
||||
|
||||
// Mode 3 = Put a +1/+1 counter on target creature
|
||||
// Mode 4 = Target creature you control fights target creature you don't control
|
||||
addCard(Zone.HAND, playerA, "Dromoka's Command", 1); // {G}{W}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dromoka's Command", "mode=3Lagonna-Band Trailblazer^mode=4Favored Hoplite^Silvercoat Lion");
|
||||
// Silvercoat lion will be set by AI as only possible target
|
||||
setModeChoice(playerA, "3");
|
||||
|
|
@ -69,11 +68,11 @@ public class HeroicTest extends CardTestPlayerBase {
|
|||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Dromoka's Command", 1);
|
||||
|
||||
|
||||
assertPowerToughness(playerA, "Favored Hoplite", 2, 3);
|
||||
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
|
||||
assertPowerToughness(playerA, "Lagonna-Band Trailblazer", 2, 6);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,30 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package org.mage.test.cards.abilities.oneshot.counterspell;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
|
|
@ -34,17 +33,17 @@ import org.junit.Test;
|
|||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* Cryptic Command
|
||||
* Instant, 1UUU
|
||||
* Choose two — Counter target spell; or return target permanent to its owner's hand; or tap all creatures your opponents control; or draw a card.
|
||||
* Cryptic Command Instant, 1UUU Choose two — Counter target spell; or return
|
||||
* target permanent to its owner's hand; or tap all creatures your opponents
|
||||
* control; or draw a card.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class CrypticCommandTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* Test that if command has only one target and that targets is not valid on resolution, Cryptic Command fizzeles
|
||||
* The player does not draw a card
|
||||
* Test that if command has only one target and that targets is not valid on
|
||||
* resolution, Cryptic Command fizzeles The player does not draw a card
|
||||
*/
|
||||
@Test
|
||||
public void testCommand() {
|
||||
|
|
@ -54,16 +53,16 @@ public class CrypticCommandTest extends CardTestPlayerBase {
|
|||
addCard(Zone.HAND, playerA, "Remand");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||
|
||||
|
||||
addCard(Zone.HAND, playerB, "Cryptic Command");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 4);
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thoughtseize", playerB);
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cryptic Command", "Thoughtseize");
|
||||
setModeChoice(playerB, "1"); // Counter target spell
|
||||
setModeChoice(playerB, "4"); // Draw a card
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Remand", "Thoughtseize", "Cast Cryptic Command");
|
||||
|
||||
setStopAt(1, PhaseStep.CLEANUP);
|
||||
|
|
@ -78,14 +77,16 @@ public class CrypticCommandTest extends CardTestPlayerBase {
|
|||
assertGraveyardCount(playerB, 1);
|
||||
assertHandCount(playerA, 2); // Thoughtsize + card drawn from Remand
|
||||
assertHandCount(playerB, 0); // Because Cryptic Command has no legal target playerB does not draw a card and has 0 cards in hand
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
* Game is not letting me play Ricochet Trap targetting oponent's Cryptic Command,
|
||||
* modes 1 and 4. It only has one target and should be allowed
|
||||
|
||||
/**
|
||||
* Game is not letting me play Ricochet Trap targetting oponent's Cryptic
|
||||
* Command, modes 1 and 4. It only has one target and should be allowed
|
||||
*/
|
||||
@Test
|
||||
public void testCommandChangeTarget() {
|
||||
// Target player reveals his or her hand. You choose a nonland card from it. That player discards that card. You lose 2 life.
|
||||
addCard(Zone.HAND, playerA, "Thoughtseize");
|
||||
// Counter target spell. If that spell is countered this way, put it into its owner's hand instead of into that player's graveyard.
|
||||
// Draw a card.
|
||||
|
|
@ -93,19 +94,19 @@ public class CrypticCommandTest extends CardTestPlayerBase {
|
|||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
|
||||
|
||||
|
||||
addCard(Zone.HAND, playerB, "Cryptic Command");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 4);
|
||||
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thoughtseize", playerB);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cryptic Command", "Thoughtseize");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Cryptic Command", "mode=1Thoughtseize", "Thoughtseize", StackClause.WHILE_ON_STACK);
|
||||
setModeChoice(playerB, "1"); // Counter target spell
|
||||
setModeChoice(playerB, "4"); // Draw a card
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ricochet Trap", "Cryptic Command");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ricochet Trap", "Cryptic Command", "Cryptic Command", StackClause.WHILE_ON_STACK);
|
||||
addTarget(playerA, "Lightning Bolt");
|
||||
|
||||
|
||||
setStopAt(1, PhaseStep.CLEANUP);
|
||||
execute();
|
||||
|
||||
|
|
@ -118,6 +119,6 @@ public class CrypticCommandTest extends CardTestPlayerBase {
|
|||
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||
|
||||
assertHandCount(playerB, 1); // card drawn from Cryptic Command
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ public class NotOfThisWorldTest extends CardTestPlayerBase {
|
|||
setStopAt(2, PhaseStep.PRECOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertHandCount(playerB, "Not of This World", 0);
|
||||
assertGraveyardCount(playerB, "Not of This World", 1);
|
||||
assertPermanentCount(playerB, "Ruhan of the Fomori", 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public class GainControlTargetEffectTest extends CardTestPlayerBase {
|
|||
*/
|
||||
@Test
|
||||
public void testPermanentControlEffect() {
|
||||
// When Smelt-Ward Gatekeepers enters the battlefield, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. That creature gains haste until end of turn.
|
||||
addCard(Zone.HAND, playerA, "Smelt-Ward Gatekeepers", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Boros Guildgate", 2);
|
||||
|
|
|
|||
|
|
@ -13,25 +13,25 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class AbattoirGhoulTest extends CardTestPlayerBase{
|
||||
|
||||
public class AbattoirGhoulTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void testAbattoirGhoulEffect() {
|
||||
|
||||
// Whenever a creature dealt damage by Abattoir Ghoul this turn dies, you gain life equal to that creature's toughness.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Abattoir Ghoul", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Shivan Dragon", 1);
|
||||
|
||||
|
||||
attack(1, playerA, "Abattoir Ghoul");
|
||||
block(1, playerB, "Memnite", "Abattoir Ghoul");
|
||||
block(1, playerB, "Shivan Dragon", "Abattoir Ghoul");
|
||||
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
|
||||
assertLife(playerA, 21);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,23 +36,21 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
|||
*
|
||||
* @author LeveX2
|
||||
*/
|
||||
|
||||
public class JourneyToNowhereTest extends CardTestPlayerBase {
|
||||
|
||||
/*
|
||||
Journey to Nowhere Enchantment {1}{W}
|
||||
When Journey to Nowhere enters the battlefield, exile target creature.
|
||||
When Journey to Nowhere leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
|
||||
10/1/2009: If Journey to Nowhere leaves the battlefield before its first ability has resolved, its second ability will
|
||||
trigger and do nothing. Then its first ability will resolve and exile the targeted creature forever.
|
||||
*/
|
||||
When Journey to Nowhere enters the battlefield, exile target creature.
|
||||
When Journey to Nowhere leaves the battlefield, return the exiled card to the battlefield under its owner's control.
|
||||
|
||||
10/1/2009: If Journey to Nowhere leaves the battlefield before its first ability has resolved, its second ability will
|
||||
trigger and do nothing. Then its first ability will resolve and exile the targeted creature forever.
|
||||
*/
|
||||
@Test
|
||||
public void testTargetGetsExiled() {
|
||||
addCard(Zone.HAND, playerA, "Journey to Nowhere");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
||||
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Journey to Nowhere");
|
||||
|
|
@ -63,13 +61,12 @@ public class JourneyToNowhereTest extends CardTestPlayerBase {
|
|||
assertPermanentCount(playerA, "Journey to Nowhere", 1);
|
||||
assertExileCount("Silvercoat Lion", 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testTargetGetsExiledAndReturns() {
|
||||
addCard(Zone.HAND, playerA, "Journey to Nowhere");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
||||
|
||||
|
||||
addCard(Zone.HAND, playerB, "Disenchant", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
|
||||
|
|
@ -78,7 +75,7 @@ public class JourneyToNowhereTest extends CardTestPlayerBase {
|
|||
addTarget(playerA, "Silvercoat Lion");
|
||||
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Disenchant", "Journey to Nowhere");
|
||||
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
|
|
@ -88,14 +85,14 @@ public class JourneyToNowhereTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
/*
|
||||
10/1/2009: If Journey to Nowhere leaves the battlefield before its first ability has resolved, its second ability will
|
||||
trigger and do nothing. Then its first ability will resolve and exile the targeted creature forever.
|
||||
*/
|
||||
10/1/2009: If Journey to Nowhere leaves the battlefield before its first ability has resolved, its second ability will
|
||||
trigger and do nothing. Then its first ability will resolve and exile the targeted creature forever.
|
||||
*/
|
||||
@Test
|
||||
public void testTargetGetsExiledAndDoesNeverReturn() {
|
||||
addCard(Zone.HAND, playerA, "Journey to Nowhere");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
||||
|
||||
|
||||
addCard(Zone.HAND, playerB, "Disenchant", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
|
||||
|
|
@ -103,29 +100,29 @@ public class JourneyToNowhereTest extends CardTestPlayerBase {
|
|||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Journey to Nowhere");
|
||||
addTarget(playerA, "Silvercoat Lion");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Disenchant", "Journey to Nowhere");
|
||||
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Journey to Nowhere", 1);
|
||||
assertGraveyardCount(playerB, "Disenchant", 1);
|
||||
assertExileCount("Silvercoat Lion", 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Journey is played and targets the creature as it enters the battlefield.
|
||||
The Journey will be returned to hand before the ability resolves.
|
||||
The Journey will be played again targeting another creature.
|
||||
The Journey will be disenchanted later, so only the second creature has to return to battlefield.
|
||||
|
||||
*/
|
||||
Journey is played and targets the creature as it enters the battlefield.
|
||||
The Journey will be returned to hand before the ability resolves.
|
||||
The Journey will be played again targeting another creature.
|
||||
The Journey will be disenchanted later, so only the second creature has to return to battlefield.
|
||||
|
||||
*/
|
||||
@Test
|
||||
public void testTargetGetsExiledAndDoesNeverReturnAndJourneyPlayedAgain() {
|
||||
addCard(Zone.HAND, playerA, "Journey to Nowhere");
|
||||
addCard(Zone.HAND, playerA, "Boomerang");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
|
||||
|
||||
addCard(Zone.HAND, playerB, "Disenchant", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1);
|
||||
|
|
@ -133,11 +130,11 @@ public class JourneyToNowhereTest extends CardTestPlayerBase {
|
|||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Journey to Nowhere");
|
||||
addTarget(playerA, "Silvercoat Lion");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Journey to Nowhere");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Journey to Nowhere", "Journey to Nowhere", StackClause.WHILE_NOT_ON_STACK);
|
||||
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Journey to Nowhere");
|
||||
addTarget(playerA, "Pillarfield Ox");
|
||||
|
||||
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Disenchant", "Journey to Nowhere");
|
||||
|
||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||
|
|
@ -145,11 +142,11 @@ public class JourneyToNowhereTest extends CardTestPlayerBase {
|
|||
|
||||
assertGraveyardCount(playerA, "Boomerang", 1);
|
||||
assertGraveyardCount(playerA, "Journey to Nowhere", 1);
|
||||
assertGraveyardCount(playerB, "Disenchant", 1);
|
||||
assertGraveyardCount(playerB, "Disenchant", 1);
|
||||
assertPermanentCount(playerB, "Pillarfield Ox", 1);
|
||||
|
||||
|
||||
assertPermanentCount(playerB, "Silvercoat Lion", 0);
|
||||
assertExileCount("Silvercoat Lion", 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,12 +94,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase {
|
|||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Stormfront Riders", 1);
|
||||
assertPermanentCount(playerA, "Rat", 0);
|
||||
assertHandCount(playerA, "Silvercoat Lion", 2);
|
||||
assertGraveyardCount(playerA, "Lab Rats", 1);
|
||||
assertGraveyardCount(playerB, "Boomerang", 1);
|
||||
|
||||
assertPermanentCount(playerA, "Soldier", 3);
|
||||
assertPermanentCount(playerA, "Rat", 0);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,10 +123,10 @@ public class SpellskiteTest extends CardTestPlayerBase {
|
|||
public void testSpellskite() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
// Choose two -
|
||||
// Counter target spell;
|
||||
// or return target permanent to its owner's hand;
|
||||
// or tap all creatures your opponents control;
|
||||
// or draw a card.
|
||||
// - Counter target spell;
|
||||
// - return target permanent to its owner's hand;
|
||||
// - tap all creatures your opponents control;
|
||||
// - draw a card.
|
||||
addCard(Zone.HAND, playerA, "Cryptic Command");
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Spellskite", 1);
|
||||
|
|
@ -141,7 +141,7 @@ public class SpellskiteTest extends CardTestPlayerBase {
|
|||
setModeChoice(playerA, "1"); // Counter target spell
|
||||
setModeChoice(playerA, "2"); // return target permanent to its owner's hand
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Cryptic Command");
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Cryptic Command", "Cryptic Command");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
package org.mage.test.lki;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
|
|
@ -20,10 +19,10 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
|||
/**
|
||||
* see here for more information
|
||||
* http://www.slightlymagic.net/forum/viewtopic.php?f=116&t=14516
|
||||
*
|
||||
* Tests Safehold Elite with persist returns to battlefield with -1/-1 counter
|
||||
* Murder Investigation has to put 2 tokens onto battlefield because enchanted Safehold Elite
|
||||
* was 2/2
|
||||
*
|
||||
* Tests Safehold Elite with persist returns to battlefield with -1/-1
|
||||
* counter Murder Investigation has to put 2 tokens onto battlefield because
|
||||
* enchanted Safehold Elite was 2/2
|
||||
*
|
||||
* @author LevelX
|
||||
*/
|
||||
|
|
@ -38,9 +37,9 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
|||
// {1}{W}
|
||||
// Enchant creature you control
|
||||
// When enchanted creature dies, put X 1/1 white Soldier creature tokens onto the battlefield, where X is its power.
|
||||
addCard(Zone.HAND, playerA, "Murder Investigation",1);
|
||||
addCard(Zone.HAND, playerA, "Murder Investigation", 1);
|
||||
|
||||
addCard(Zone.HAND, playerB, "Lightning Bolt",2);
|
||||
addCard(Zone.HAND, playerB, "Lightning Bolt", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder Investigation", "Safehold Elite");
|
||||
|
|
@ -58,17 +57,20 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
|||
// because enchanted Safehold Elite's P/T was 2/2, Murder Investigation has to put 2 Soldier onto the battlefield
|
||||
assertPermanentCount(playerA, "Soldier", 2);
|
||||
assertGraveyardCount(playerB, "Lightning Bolt", 2);
|
||||
|
||||
assertActionCount(playerB, 0);
|
||||
|
||||
assertActionCount(playerB, 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Here we test that Trostani's first ability checks the toughness on resolve.
|
||||
* Here we test that Trostani's first ability checks the toughness on
|
||||
* resolve.
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testTrostaniSelesnyasVoice1() {
|
||||
// Whenever another creature enters the battlefield under your control, you gain life equal to that creature's toughness.
|
||||
// {1}{G}{W}, {T}: Populate. (Put a token onto the battlefield that's a copy of a creature token you control.)
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Trostani, Selesnya's Voice");
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
|
||||
|
|
@ -76,20 +78,21 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
|||
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears", "Grizzly Bears", StackClause.WHILE_NOT_ON_STACK);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Giant Growth", 1);
|
||||
assertPermanentCount(playerA, "Grizzly Bears", 1);
|
||||
assertLife(playerA, 25);
|
||||
}
|
||||
|
||||
/**
|
||||
* Here we test correct spell interaction by playing Cloudshift BEFORE Giant Growth resolves.
|
||||
* Cloudshift will remove 2/2 creature and it will return as 2/2.
|
||||
* Giant Growth will be fizzled.
|
||||
* That means that player should gain 2 + 2 life.
|
||||
* Here we test correct spell interaction by playing Cloudshift BEFORE Giant
|
||||
* Growth resolves. Cloudshift will remove 2/2 creature and it will return
|
||||
* as 2/2. Giant Growth will be fizzled. That means that player should gain
|
||||
* 2 + 2 life.
|
||||
*/
|
||||
@Test
|
||||
public void testTrostaniSelesnyasVoice2() {
|
||||
|
|
@ -102,7 +105,7 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
|||
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears", "Grizzly Bears", StackClause.WHILE_NOT_ON_STACK);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloudshift", "Grizzly Bears", "Giant Growth",
|
||||
StackClause.WHILE_ON_STACK);
|
||||
|
||||
|
|
@ -114,8 +117,8 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Here we test actual use of LKI by playing Cloudshift AFTER Giant Growth resolves.
|
||||
* Cloudshift will remove 5/5 creature and it will return as 2/2.
|
||||
* Here we test actual use of LKI by playing Cloudshift AFTER Giant Growth
|
||||
* resolves. Cloudshift will remove 5/5 creature and it will return as 2/2.
|
||||
* That means that player should gain 5 + 2 life.
|
||||
*
|
||||
*/
|
||||
|
|
@ -130,7 +133,7 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
|||
addCard(Zone.HAND, playerA, "Grizzly Bears", 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Giant Growth", "Grizzly Bears", "Grizzly Bears", StackClause.WHILE_NOT_ON_STACK);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloudshift", "Grizzly Bears", "Giant Growth",
|
||||
StackClause.WHILE_NOT_ON_STACK);
|
||||
|
||||
|
|
@ -142,5 +145,4 @@ public class LastKnownInformationTest extends CardTestPlayerBase {
|
|||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ public class TestPlayer implements Player {
|
|||
|
||||
private final ComputerPlayer computerPlayer;
|
||||
|
||||
private String[] groupsForTargetHandling = null;
|
||||
|
||||
public TestPlayer(ComputerPlayer computerPlayer) {
|
||||
this.computerPlayer = computerPlayer;
|
||||
AIPlayer = false;
|
||||
|
|
@ -204,23 +206,14 @@ public class TestPlayer implements Player {
|
|||
return true;
|
||||
}
|
||||
|
||||
// private boolean checkSpellOnTopOfStackCondition(String[] groups, Game game) {
|
||||
// if (groups.length > 2 && groups[2].startsWith("spellOnTopOfStack=")) {
|
||||
// String spellOnTopOFStack = groups[2].substring(18);
|
||||
// if (game.getStack().size() > 0) {
|
||||
// StackObject stackObject = game.getStack().getFirst();
|
||||
// if (stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
private boolean addTargets(Ability ability, String[] groups, Game game) {
|
||||
@Override
|
||||
public boolean addTargets(Ability ability, Game game) {
|
||||
if (groupsForTargetHandling == null) {
|
||||
return true;
|
||||
}
|
||||
boolean result = true;
|
||||
for (int i = 1; i < groups.length; i++) {
|
||||
String group = groups[i];
|
||||
for (int i = 1; i < groupsForTargetHandling.length; i++) {
|
||||
String group = groupsForTargetHandling[i];
|
||||
if (group.startsWith("spellOnStack") || group.startsWith("spellOnTopOfStack") || group.startsWith("!spellOnStack") || group.startsWith("target=null") || group.startsWith("manaInPool=")) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -277,29 +270,36 @@ public class TestPlayer implements Player {
|
|||
int index = 0;
|
||||
int targetsSet = 0;
|
||||
for (String targetName : targetList) {
|
||||
Mode selectedMode = null;
|
||||
if (targetName.startsWith("mode=")) {
|
||||
int modeNr = Integer.parseInt(targetName.substring(5, 6));
|
||||
if (modeNr == 0 || modeNr > ability.getModes().size()) {
|
||||
throw new UnsupportedOperationException("Given mode number (" + modeNr + ") not available for " + ability.toString());
|
||||
}
|
||||
int modeCounter = 1;
|
||||
for (Mode mode : ability.getModes().values()) {
|
||||
if (modeCounter == modeNr) {
|
||||
ability.getModes().setMode(mode);
|
||||
UUID modeId = ability.getModes().getModeId(modeNr);
|
||||
|
||||
for (Mode mode : ability.getModes().getSelectedModes()) {
|
||||
if (mode.getId().equals(modeId)) {
|
||||
selectedMode = mode;
|
||||
ability.getModes().setActiveMode(mode);
|
||||
index = 0; // reset target index if mode changes
|
||||
break;
|
||||
}
|
||||
modeCounter++;
|
||||
}
|
||||
targetName = targetName.substring(6);
|
||||
} else {
|
||||
selectedMode = ability.getModes().getMode();
|
||||
}
|
||||
if (ability.getTargets().size() == 0) {
|
||||
if (selectedMode == null) {
|
||||
throw new UnsupportedOperationException("Mode not available for " + ability.toString());
|
||||
}
|
||||
if (selectedMode.getTargets().size() == 0) {
|
||||
throw new AssertionError("Ability has no targets. " + ability.toString());
|
||||
}
|
||||
if (index >= ability.getTargets().size()) {
|
||||
if (index >= selectedMode.getTargets().size()) {
|
||||
break; // this can happen if targets should be set but can't be used because of hexproof e.g.
|
||||
}
|
||||
Target currentTarget = ability.getTargets().get(index);
|
||||
Target currentTarget = selectedMode.getTargets().get(index);
|
||||
if (targetName.startsWith("targetPlayer=")) {
|
||||
target = targetName.substring(targetName.indexOf("targetPlayer=") + 13);
|
||||
for (Player player : game.getPlayers().values()) {
|
||||
|
|
@ -362,6 +362,7 @@ public class TestPlayer implements Player {
|
|||
if (action.getAction().startsWith("activate:")) {
|
||||
String command = action.getAction();
|
||||
command = command.substring(command.indexOf("activate:") + 9);
|
||||
groupsForTargetHandling = null;
|
||||
String[] groups = command.split("\\$");
|
||||
if (groups.length > 2 && !checkExecuteCondition(groups, game)) {
|
||||
break;
|
||||
|
|
@ -371,13 +372,11 @@ public class TestPlayer implements Player {
|
|||
int bookmark = game.bookmarkState();
|
||||
Ability newAbility = ability.copy();
|
||||
if (groups.length > 1 && !groups[1].equals("target=NO_TARGET")) {
|
||||
if (!addTargets(newAbility, groups, game)) {
|
||||
// targets could not be set -> try next priority
|
||||
break;
|
||||
}
|
||||
groupsForTargetHandling = groups;
|
||||
}
|
||||
if (computerPlayer.activateAbility((ActivatedAbility) newAbility, game)) {
|
||||
actions.remove(action);
|
||||
groupsForTargetHandling = null;
|
||||
return true;
|
||||
} else {
|
||||
game.restoreState(bookmark, ability.getRule());
|
||||
|
|
@ -1913,6 +1912,7 @@ public class TestPlayer implements Player {
|
|||
|
||||
@Override
|
||||
public boolean playMana(Ability ability, ManaCost unpaid, String promptText, Game game) {
|
||||
groupsForTargetHandling = null;
|
||||
return computerPlayer.playMana(ability, unpaid, promptText, game);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue