Merge branch 'master' into Network_Upgrade

Conflicts:
	Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java
	Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java
	Mage.Client/src/main/java/mage/client/game/GamePanel.java
	Mage.Server/src/main/java/mage/server/game/GameSessionPlayer.java
This commit is contained in:
betasteward 2015-09-10 10:30:51 -04:00
commit 49558e091d
687 changed files with 32892 additions and 4564 deletions

View file

@ -52,6 +52,10 @@ public class CastCreaturesTest extends CardTestPlayerBaseAI {
assertPermanentCount(playerA, "Silvercoat Lion", 1);
}
/**
* This test fails sometimes, probably because two plains are tapped for the
* first creature
*/
@Test
public void testSimpleCast2() {
addCard(Zone.HAND, playerA, "Silvercoat Lion");
@ -100,6 +104,35 @@ public class CastCreaturesTest extends CardTestPlayerBaseAI {
assertPermanentCount(playerA, "Blazing Specter", 1);
}
@Test
public void testSimpleCast5() {
addCard(Zone.HAND, playerA, "Plains", 2);
addCard(Zone.HAND, playerA, "Mountain", 1);
addCard(Zone.HAND, playerA, "Silvercoat Lion", 3);
addCard(Zone.HAND, playerA, "Soul Warden");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Plains", 1);
assertPermanentCount(playerA, "Soul Warden", 1);
}
@Test
public void testSimpleCast6() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
addCard(Zone.HAND, playerA, "Plains", 2);
addCard(Zone.HAND, playerA, "Mountain", 2);
addCard(Zone.HAND, playerA, "Silvercoat Lion", 1);
addCard(Zone.HAND, playerA, "Pillarfield Ox", 1);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Plains", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
}
@Test
public void testCast4Creature() {
addCard(Zone.LIBRARY, playerA, "Swamp", 1);

View file

@ -63,7 +63,7 @@ public class TargetsAreChosenTest extends CardTestPlayerBaseAI {
/**
* Check that the AI does not cast Rack and Ruin if it would destroy the
* owly creature on the battlefield owned by the AI
* only creature on the battlefield owned by the AI
*/
@Test
public void testRackAndRuin2() {
@ -196,7 +196,7 @@ public class TargetsAreChosenTest extends CardTestPlayerBaseAI {
}
/**
* Test that AI counters creatire spell
* Test that AI counters creature spell
*/
@Test
@Ignore // counter spells don't seem to be cast by AI
@ -222,4 +222,13 @@ public class TargetsAreChosenTest extends CardTestPlayerBaseAI {
}
/**
* Target selection from EntersTheBattlefield is not varied in the AI
* calculation, so value is only calculated for the one selected target set.
*
* E.g. If AI casts an Eyeblight Assassin and opponent has a 3/1 and a 2/2,
* the AI should target the 3/1.
*
* Add test to check such situations
*/
}

View file

@ -0,0 +1,89 @@
/*
* 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.abilitywords;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class ConvergeTest extends CardTestPlayerBase {
/**
* Test with only red mana
*/
@Test
public void testOnlyOneColor() {
// Converge Radiant Flames deals X damage to each creature, where X is the number of colors of mana spent to cast Radiant Flames.
addCard(Zone.HAND, playerA, "Radiant Flames", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerA, "Akroan Jailer", 1); // 1/1
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerB, "Akroan Jailer", 1); // 1/1
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Radiant Flames");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Akroan Jailer", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
assertGraveyardCount(playerB, "Akroan Jailer", 1);
assertPermanentCount(playerB, "Silvercoat Lion", 1);
}
@Test
public void testWithTwoColors() {
// Converge Radiant Flames deals X damage to each creature, where X is the number of colors of mana spent to cast Radiant Flames.
addCard(Zone.HAND, playerA, "Radiant Flames", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerA, "Akroan Jailer", 1); // 1/1
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerB, "Akroan Jailer", 1); // 1/1
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Radiant Flames");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Akroan Jailer", 1);
assertGraveyardCount(playerA, "Silvercoat Lion", 1);
assertGraveyardCount(playerB, "Akroan Jailer", 1);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
}
}

View file

@ -0,0 +1,61 @@
/*
* 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.keywords;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class AwakenTest extends CardTestPlayerBase {
@Test
public void testCastWithAwaken() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
// Destroy target creature or planeswalker.
// Awaken 4-{5}{B}{B}
addCard(Zone.HAND, playerA, "Ruinous Path", 1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ruinous Path with awaken", "Silvercoat Lion");
addTarget(playerA, "Plains");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPowerToughness(playerA, "Plains", 4, 4);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
}
}

View file

@ -37,21 +37,23 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*
* @author LevelX2
*/
public class InfectTest extends CardTestPlayerBase {
/**
702.89. Infect
702.89a Infect is a static ability.
702.89b Damage dealt to a player by a source with infect doesnt cause that player to lose life. Rather, it causes the player to get that many poison counters. See rule 119.3.
702.89c Damage dealt to a creature by a source with infect isnt marked on that creature. Rather, it causes that many -1/-1 counters to be put on that creature. See rule 119.3.
702.89d If a permanent leaves the battlefield before an effect causes it to deal damage, its last known information is used to determine whether it had infect.
702.89e The infect rules function no matter what zone an object with infect deals damage from.
702.89f Multiple instances of infect on the same object are redundant.
*
* 702.89. Infect 702.89a Infect is a static ability. 702.89b Damage dealt
* to a player by a source with infect doesnt cause that player to lose
* life. Rather, it causes the player to get that many poison counters. See
* rule 119.3. 702.89c Damage dealt to a creature by a source with infect
* isnt marked on that creature. Rather, it causes that many -1/-1 counters
* to be put on that creature. See rule 119.3. 702.89d If a permanent leaves
* the battlefield before an effect causes it to deal damage, its last known
* information is used to determine whether it had infect. 702.89e The
* infect rules function no matter what zone an object with infect deals
* damage from. 702.89f Multiple instances of infect on the same object are
* redundant.
*
*/
@Test
public void testNormalUse() {
addCard(Zone.BATTLEFIELD, playerB, "Tine Shrike"); // 2/1 Infect
@ -64,16 +66,15 @@ public class InfectTest extends CardTestPlayerBase {
assertCounterCount(playerA, CounterType.POISON, 2);
assertLife(playerA, 20);
assertLife(playerB, 20);
assertLife(playerB, 20);
}
@Test
public void testLoseInfectUse() {
// Creatures your opponents control lose infect.
addCard(Zone.BATTLEFIELD, playerA, "Melira, Sylvok Outcast");
// Creatures your opponents control lose infect.
addCard(Zone.BATTLEFIELD, playerA, "Melira, Sylvok Outcast");
addCard(Zone.BATTLEFIELD, playerB, "Tine Shrike"); // 2/1 Infect
attack(2, playerB, "Tine Shrike");
@ -84,23 +85,29 @@ public class InfectTest extends CardTestPlayerBase {
assertCounterCount(playerA, CounterType.POISON, 0);
assertLife(playerA, 18);
assertLife(playerB, 20);
}
assertLife(playerB, 20);
}
/**
* Inkmoth Nexus has no effect it he attacks becaus it has infect but there are no counters added
* Inkmoth Nexus has no effect it he attacks becaus it has infect but there
* are no counters added
* http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/296553-melira-sylvok-outcast-vs-inkmoth-nexus
*/
@Test
public void testInkmothNexusLoseInfect() {
// Creatures your opponents control lose infect.
addCard(Zone.BATTLEFIELD, playerA, "Melira, Sylvok Outcast");
addCard(Zone.BATTLEFIELD, playerB, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerB, "Inkmoth Nexus");
// Creatures your opponents control lose infect.
// Creatures you control can't have -1/-1 counters placed on them.
addCard(Zone.BATTLEFIELD, playerA, "Melira, Sylvok Outcast");
// Put a -1/-1 counter on target creature. When that creature dies this turn, its controller gets a poison counter.
addCard(Zone.HAND, playerA, "Virulent Wound"); // Instant {B}
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
// {1}: Inkmoth Nexus becomes a 1/1 Blinkmoth artifact creature with flying and infect until end of turn. It's still a land.
addCard(Zone.BATTLEFIELD, playerB, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerB, "Inkmoth Nexus");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Virulent Wound", "Melira, Sylvok Outcast");
// {1}: Inkmoth Nexus becomes a 1/1 Blinkmoth artifact creature with flying and infect until end of turn. It's still a land.
// (It deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters.)
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}: {this} becomes");
attack(2, playerB, "Inkmoth Nexus");
@ -108,13 +115,15 @@ public class InfectTest extends CardTestPlayerBase {
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertGraveyardCount(playerA, "Virulent Wound", 1);
assertPowerToughness(playerA, "Melira, Sylvok Outcast", 2, 2);
assertTapped("Plains", true);
assertTapped("Inkmoth Nexus", true);
assertCounterCount(playerA, CounterType.POISON, 0);
assertLife(playerA, 20);
assertLife(playerB, 20);
}
assertLife(playerB, 20);
}
}

View file

@ -27,7 +27,6 @@
*/
package org.mage.test.cards.abilities.keywords;
import mage.cards.Card;
import mage.constants.PhaseStep;
import mage.constants.Zone;
@ -39,7 +38,6 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*
* @author LevelX2
*/
public class ManifestTest extends CardTestPlayerBase {
/**
@ -73,7 +71,8 @@ public class ManifestTest extends CardTestPlayerBase {
}
/**
* If Doomwake Giant gets manifested, it's Constellation trigger may not trigger
* If Doomwake Giant gets manifested, it's Constellation trigger may not
* trigger
*/
@Test
public void testETBTriggeredAbilities2() {
@ -103,8 +102,10 @@ public class ManifestTest extends CardTestPlayerBase {
assertPermanentCount(playerB, "Silvercoat Lion", 1);
assertPowerToughness(playerB, "Silvercoat Lion", 2, 2);
}
/**
* If Doomwake Giant gets manifested, it's Constellation trigger may not trigger
* If Doomwake Giant gets manifested, it's Constellation trigger may not
* trigger
*/
@Test
public void testETBTriggeredAbilities3() {
@ -115,10 +116,10 @@ public class ManifestTest extends CardTestPlayerBase {
// Constellation - When Doomwake Giant or another enchantment enters the battlefield
// under your control, creatures your opponents control get -1/-1 until end of turn.
addCard(Zone.LIBRARY, playerA, "Doomwake Giant");
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox");
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox");
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
skipInitShuffling();
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Reality Shift", "Silvercoat Lion");
@ -130,7 +131,7 @@ public class ManifestTest extends CardTestPlayerBase {
assertLife(playerA, 20);
assertLife(playerB, 20);
assertGraveyardCount(playerB, "Reality Shift", 1);
assertExileCount("Silvercoat Lion" , 1);
assertExileCount("Silvercoat Lion", 1);
// a facedown creature is on the battlefield
assertPermanentCount(playerA, "", 1);
assertPowerToughness(playerA, "", 2, 2);
@ -138,8 +139,10 @@ public class ManifestTest extends CardTestPlayerBase {
assertPermanentCount(playerB, "Pillarfield Ox", 1);
assertPowerToughness(playerB, "Pillarfield Ox", 2, 4);
}
/**
* If Doomwake Giant gets manifested, it's Constellation trigger may not trigger
* If Doomwake Giant gets manifested, it's Constellation trigger may not
* trigger
*/
@Test
public void testNylea() {
@ -150,7 +153,7 @@ public class ManifestTest extends CardTestPlayerBase {
// As long as your devotion to white is less than five, Nylea isn't a creature.
// <i>(Each {G} in the mana costs of permanents you control counts towards your devotion to green.)</i>
addCard(Zone.LIBRARY, playerA, "Nylea, God of the Hunt");
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
skipInitShuffling();
@ -164,17 +167,17 @@ public class ManifestTest extends CardTestPlayerBase {
assertLife(playerA, 20);
assertLife(playerB, 20);
assertGraveyardCount(playerB, "Reality Shift", 1);
assertExileCount("Silvercoat Lion" , 1);
assertExileCount("Silvercoat Lion", 1);
// a facedown creature is on the battlefield
assertPermanentCount(playerA, "", 1);
assertPowerToughness(playerA, "", 2, 2);
}
/*
Had a Foundry Street Denizen and another creature out.
Opponent Reality Shift'ed the other creature, manifested card was a red creature. This pumped the foundry street denizen even though it shouldn't.
*/
Had a Foundry Street Denizen and another creature out.
Opponent Reality Shift'ed the other creature, manifested card was a red creature. This pumped the foundry street denizen even though it shouldn't.
*/
@Test
public void testColorOfManifestedCardDoesNotCount() {
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
@ -184,7 +187,7 @@ public class ManifestTest extends CardTestPlayerBase {
// Gore Swine {2}{R}
// 4/1
addCard(Zone.LIBRARY, playerA, "Gore Swine");
// Whenever another red creature enters the battlefield under your control, Foundry Street Denizen gets +1/+0 until end of turn.
addCard(Zone.BATTLEFIELD, playerA, "Foundry Street Denizen");
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
@ -200,16 +203,17 @@ public class ManifestTest extends CardTestPlayerBase {
assertLife(playerA, 20);
assertLife(playerB, 20);
assertGraveyardCount(playerB, "Reality Shift", 1);
assertExileCount("Silvercoat Lion" , 1);
assertExileCount("Silvercoat Lion", 1);
// a facedown creature is on the battlefield
assertPermanentCount(playerA, "", 1);
assertPowerToughness(playerA, "", 2, 2);
assertPowerToughness(playerA, "Foundry Street Denizen", 1, 1);
}
}
/*
I casted a Silence the Believers on a manifested card. It moved to the exile zone face-down.
*/
I casted a Silence the Believers on a manifested card. It moved to the exile zone face-down.
*/
@Test
public void testCardGetsExiledFaceUp() {
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
@ -224,7 +228,7 @@ public class ManifestTest extends CardTestPlayerBase {
// Gore Swine {2}{R}
// 4/1
addCard(Zone.LIBRARY, playerA, "Gore Swine");
// Whenever another red creature enters the battlefield under your control, Foundry Street Denizen gets +1/+0 until end of turn.
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
@ -240,12 +244,12 @@ public class ManifestTest extends CardTestPlayerBase {
assertLife(playerA, 20);
assertLife(playerB, 20);
assertGraveyardCount(playerB, "Reality Shift", 1);
assertExileCount("Silvercoat Lion" , 1);
assertExileCount("Gore Swine" , 1);
assertExileCount("Silvercoat Lion", 1);
assertExileCount("Gore Swine", 1);
// no facedown creature is on the battlefield
assertPermanentCount(playerA, "", 0);
for (Card card :currentGame.getExile().getAllCards(currentGame)){
for (Card card : currentGame.getExile().getAllCards(currentGame)) {
if (card.getName().equals("Gore Swine")) {
Assert.assertTrue("Gore Swine may not be face down in exile", !card.isFaceDown(currentGame));
}
@ -255,7 +259,6 @@ public class ManifestTest extends CardTestPlayerBase {
// Qarsi High Priest went to manifest Illusory Gains,
// but it made me choose a target for gains, then enchanted the card to that creature.
@Test
public void testManifestAura() {
@ -282,15 +285,13 @@ public class ManifestTest extends CardTestPlayerBase {
assertGraveyardCount(playerB, "Illusory Gains", 0);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
// a facedown creature is on the battlefield
assertPermanentCount(playerB, "", 1);
}
// Check if a Megamorph card is manifested and truned by their megamorph ability
// Check if a Megamorph card is manifested and turned face up by their megamorph ability
// it gets the +1/+1 counter.
@Test
public void testManifestMegamorph() {
@ -300,6 +301,8 @@ public class ManifestTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerB, "Qarsi High Priest", 1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
// Reach (This creature can block creatures with flying.)
// Megamorph {5}{G}
addCard(Zone.LIBRARY, playerB, "Aerie Bowmasters", 1);
addCard(Zone.LIBRARY, playerB, "Mountain", 1);
@ -324,10 +327,11 @@ public class ManifestTest extends CardTestPlayerBase {
assertPowerToughness(playerB, "Aerie Bowmasters", 4, 5); // 3/4 and the +1/+1 counter from Megamorph
}
/**
* When a Forest came manifested into play my Courser of Kruphix gained me a life.
*
* When a Forest came manifested into play my Courser of Kruphix gained me a
* life.
*
*/
@Test
public void testManifestForest() {
@ -349,7 +353,6 @@ public class ManifestTest extends CardTestPlayerBase {
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{B},{T}, Sacrifice another creature");
addTarget(playerB, "Silvercoat Lion");
setStopAt(2, PhaseStep.END_TURN);
execute();
@ -361,41 +364,40 @@ public class ManifestTest extends CardTestPlayerBase {
assertPermanentCount(playerB, "", 1);
}
/**
}
/**
* Whisperwood Elemental - Its sacrifice ability doesn't work..
*
*
*/
@Test
public void testWhisperwoodElemental() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
// Seismic Rupture deals 2 damage to each creature without flying.
addCard(Zone.HAND, playerA, "Seismic Rupture", 1);
// At the beginning of your end step, manifest the top card of your library.
// Sacrifice Whisperwood Elemental: Until end of turn, face-up, nontoken creatures you control gain "When this creature dies, manifest the top card of your library."
addCard(Zone.BATTLEFIELD, playerB, "Whisperwood Elemental", 1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Sacrifice");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Seismic Rupture");
setStopAt(1, PhaseStep.END_TURN);
execute();
// no life gain
assertLife(playerA, 20);
assertLife(playerB, 20);
assertGraveyardCount(playerA, "Seismic Rupture", 1);
assertGraveyardCount(playerB, "Whisperwood Elemental", 1);
assertGraveyardCount(playerB, "Silvercoat Lion", 2);
assertPermanentCount(playerB, "", 2);
}
}
}

View file

@ -198,4 +198,34 @@ public class PersistTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Glen Elendra Archmage", 1);
assertPowerToughness(playerA, "Glen Elendra Archmage", 1, 1);
}
@Test
public void testMeliraSylvokOutcast() {
// You can't get poison counters.
// Creatures you control can't have -1/-1 counters placed on them.
// Creatures your opponents control lose infect.
addCard(Zone.BATTLEFIELD, playerA, "Melira, Sylvok Outcast", 1); // 2/2
// When Murderous Redcap enters the battlefield, it deals damage equal to its power to target creature or player.
// Persist
addCard(Zone.HAND, playerA, "Murderous Redcap", 1); // 2/2
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 2);
addCard(Zone.HAND, playerB, "Lightning Bolt", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murderous Redcap");
addTarget(playerA, "Silvercoat Lion");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Murderous Redcap");
addTarget(playerA, "Silvercoat Lion");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, "Lightning Bolt", 1);
assertGraveyardCount(playerB, "Silvercoat Lion", 2);
assertPowerToughness(playerA, "Murderous Redcap", 2, 2); // Got no -1/-1 after returning because of Melira in play
}
}

View file

@ -88,14 +88,18 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
}
/**
* Tests Soulbond effect disabling whenever Soulbond creature changes its controller
* Tests Soulbond effect disabling whenever Soulbond creature changes its
* controller
*/
@Test
public void testChangeControllerForSoulbondCreature() {
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard");
// Soulbond (You may pair this creature with another unpaired creature when either enters the battlefield. They remain paired for as long as you control both of them.)
// As long as Trusted Forcemage is paired with another creature, each of those creatures gets +1/+1.
addCard(Zone.HAND, playerA, "Trusted Forcemage");
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
// Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. (It can attack and Tap this turn.)
addCard(Zone.HAND, playerB, "Act of Treason");
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3);
@ -115,12 +119,15 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
}
/**
* Tests Soulbond effect disabling when paired creture changes its controller
* Tests Soulbond effect disabling when paired creture changes its
* controller
*/
@Test
public void testChangeControllerForAnotherCreature() {
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard");
addCard(Zone.HAND, playerA, "Trusted Forcemage");
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard"); // 2,1
// Soulbond (You may pair this creature with another unpaired creature when either enters the battlefield. They remain paired for as long as you control both of them.)
// As long as Trusted Forcemage is paired with another creature, each of those creatures gets +1/+1.
addCard(Zone.HAND, playerA, "Trusted Forcemage"); // 2/2
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
addCard(Zone.HAND, playerB, "Act of Treason");
@ -141,8 +148,8 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
}
/**
* Tests Soulbond effect disabling when Soulbond creature changes its controller and then returns back.
* Effect should not be restored.
* Tests Soulbond effect disabling when Soulbond creature changes its
* controller and then returns back. Effect should not be restored.
*/
@Test
public void testChangeControllerAndGettingBack() {
@ -166,7 +173,8 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
}
/**
* Tests that stealing creature will allow to use Soulbond ability on controller's creature
* Tests that stealing creature will allow to use Soulbond ability on
* controller's creature
*/
@Test
public void testSoulbondWorksOnControllerSide() {
@ -243,7 +251,8 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
}
/**
* Tests that it is possible to animate land and pair it on next coming Soulbond creature
* Tests that it is possible to animate land and pair it on next coming
* Soulbond creature
*/
@Test
public void testPairOnAnimatedLand() {
@ -263,7 +272,8 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
}
/**
* Tests no effect whether land was animated after Soulbond creature has entered the battlefield
* Tests no effect whether land was animated after Soulbond creature has
* entered the battlefield
*/
@Test
public void testPairOnPostAnimatedLand() {
@ -302,7 +312,8 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
}
/**
* Tests that after loosing first pair it is possible to pair creature with another one
* Tests that after loosing first pair it is possible to pair creature with
* another one
*/
@Test
public void testRebondOnNextCreature() {
@ -357,6 +368,8 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
public void testExileAndReturnBack() {
addCard(Zone.HAND, playerA, "Elite Vanguard");
addCard(Zone.HAND, playerA, "Cloudshift");
// Soulbond (You may pair this creature with another unpaired creature when either enters the battlefield. They remain paired for as long as you control both of them.)
// As long as Trusted Forcemage is paired with another creature, each of those creatures gets +1/+1.
addCard(Zone.BATTLEFIELD, playerA, "Trusted Forcemage");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
@ -375,6 +388,6 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
Permanent trustedForcemange = getPermanent("Trusted Forcemage", playerA.getId());
Permanent eliteVanguard = getPermanent("Elite Vanguard", playerA.getId());
Assert.assertEquals(trustedForcemange.getPairedCard(), null);
Assert.assertEquals(eliteVanguard.getPairedCard(),null);
Assert.assertEquals(eliteVanguard.getPairedCard(), null);
}
}

View file

@ -27,6 +27,7 @@
*/
package org.mage.test.cards.abilities.keywords;
import mage.abilities.keyword.HasteAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
@ -40,16 +41,16 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
public class SuspendTest extends CardTestPlayerBase {
/**
* Tests Epochrasite works (give suspend to a exiled card)
* When Epochrasite dies, exile it with three time counters on it and it gains suspend.
* Tests Epochrasite works (give suspend to a exiled card) When Epochrasite
* dies, exile it with three time counters on it and it gains suspend.
*
*/
@Test
public void testEpochrasite() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Zone.HAND, playerA, "Epochrasite",1);
addCard(Zone.HAND, playerB, "Lightning Bolt",1);
addCard(Zone.HAND, playerA, "Epochrasite", 1);
addCard(Zone.HAND, playerB, "Lightning Bolt", 1);
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Epochrasite");
@ -61,11 +62,14 @@ public class SuspendTest extends CardTestPlayerBase {
assertGraveyardCount(playerB, "Lightning Bolt", 1);
assertPermanentCount(playerA, "Epochrasite", 1); // returned on turn 7 with 3 +1/+1 Counter
assertPowerToughness(playerA, "Epochrasite", 4, 4);
assertAbility(playerA, "Epochrasite", HasteAbility.getInstance(), true);
}
/**
* Tests Jhoira of the Ghitu works (give suspend to a exiled card)
* {2}, Exile a nonland card from your hand: Put four time counters on the exiled card. If it doesn't have suspend, it gains suspend.
* Tests Jhoira of the Ghitu works (give suspend to a exiled card) {2},
* Exile a nonland card from your hand: Put four time counters on the exiled
* card. If it doesn't have suspend, it gains suspend.
*
*/
@Test
@ -73,7 +77,7 @@ public class SuspendTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.HAND, playerA, "Silvercoat Lion",1);
addCard(Zone.HAND, playerA, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerA, "Jhoira of the Ghitu", 1);
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{2},Exile a nonland card from your hand: Put four time counters on the exiled card. If it doesn't have suspend, it gains suspend <i>(At the beginning of your upkeep, remove a time counter from that card. When the last is removed, cast it without paying its mana cost. If it's a creature, it has haste.)</i>.");
@ -85,11 +89,12 @@ public class SuspendTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Jhoira of the Ghitu", 1);
assertHandCount(playerA, "Silvercoat Lion", 0);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
}
/**
* Tests that a spell countered with delay goes to exile with 3 time counters
* and can be cast after the 3 counters are removed
* Tests that a spell countered with delay goes to exile with 3 time
* counters and can be cast after the 3 counters are removed
*
*/
@Test
@ -97,13 +102,13 @@ public class SuspendTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Zone.HAND, playerA, "Silvercoat Lion",1);
addCard(Zone.HAND, playerA, "Silvercoat Lion", 1);
// Instant {1}{U}
// Counter target spell. If the spell is countered this way, exile it with three time counters on it instead of putting it into its owner's graveyard. If it doesn't have suspend, it gains suspend. (At the beginning of its owner's upkeep, remove a counter from that card. When the last is removed, the player plays it without paying its mana cost. If it's a creature, it has haste.)
addCard(Zone.HAND, playerB, "Delay",1);
addCard(Zone.HAND, playerB, "Delay", 1);
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Delay", "Silvercoat Lion");
setChoice(playerA, "Silvercoat Lion");
@ -113,20 +118,21 @@ public class SuspendTest extends CardTestPlayerBase {
assertGraveyardCount(playerB, "Delay", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
}
}
@Test
public void testDeepSeaKraken() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
// Suspend 9-{2}{U}
// Whenever an opponent casts a spell, if Deep-Sea Kraken is suspended, remove a time counter from it.
addCard(Zone.HAND, playerA, "Deep-Sea Kraken",1);
addCard(Zone.HAND, playerA, "Deep-Sea Kraken", 1);
// Instant {1}{U}
// Counter target spell. If the spell is countered this way, exile it with three time counters on it instead of putting it into its owner's graveyard. If it doesn't have suspend, it gains suspend. (At the beginning of its owner's upkeep, remove a counter from that card. When the last is removed, the player plays it without paying its mana cost. If it's a creature, it has haste.)
addCard(Zone.HAND, playerB, "Lightning Bolt",1);
addCard(Zone.HAND, playerB, "Lightning Bolt", 1);
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Suspend");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", playerA);
@ -135,8 +141,8 @@ public class SuspendTest extends CardTestPlayerBase {
assertGraveyardCount(playerB, "Lightning Bolt", 1);
assertExileCount("Deep-Sea Kraken", 1);
assertCounterOnExiledCardCount("Deep-Sea Kraken", CounterType.TIME, 8); // -1 from spell of player B
}
}
}

View file

@ -11,7 +11,8 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
public class UndyingTest extends CardTestPlayerBase {
/**
* Tests boost weren't be applied second time when creature back to battlefield
* Tests boost weren't be applied second time when creature back to
* battlefield
*/
@Test
public void testWithBoost() {
@ -29,7 +30,8 @@ public class UndyingTest extends CardTestPlayerBase {
}
/**
* Tests boost weren't be applied second time when creature back to battlefield
* Tests boost weren't be applied second time when creature back to
* battlefield
*/
@Test
public void testWithMassBoost() {
@ -62,7 +64,7 @@ public class UndyingTest extends CardTestPlayerBase {
// Target creature gets -3/-3 until end of turn.
addCard(Zone.HAND, playerA, "Last Gasp");
// Undying Evil
// Target creature gains undying until end of turn.
// Target creature gains undying until end of turn.
// When it dies, if it had no +1/+1 counters on it, return it to the battlefield under its owner's control with a +1/+1 counter on it.)
addCard(Zone.HAND, playerA, "Undying Evil");
@ -76,9 +78,9 @@ public class UndyingTest extends CardTestPlayerBase {
assertPowerToughness(playerA, "Elite Vanguard", 3, 2);
}
/**
* Tests "Threads of Disloyalty enchanting Strangleroot Geist: after geist died it returns to the bf under opponent's control."
* Tests "Threads of Disloyalty enchanting Strangleroot Geist: after geist
* died it returns to the bf under opponent's control."
*/
@Test
public void testUndyingControlledReturnsToOwner() {
@ -105,18 +107,20 @@ public class UndyingTest extends CardTestPlayerBase {
setStopAt(2, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, "Threads of Disloyalty", 1);
assertGraveyardCount(playerA, "Lightning Bolt",1);
assertGraveyardCount(playerB, "Threads of Disloyalty", 1);
assertGraveyardCount(playerA, "Lightning Bolt", 1);
assertPermanentCount(playerB, "Strangleroot Geist", 0);
assertPermanentCount(playerA, "Strangleroot Geist", 1);
assertPowerToughness(playerA, "Strangleroot Geist", 3, 2);
}
/**
* Tests "Target creature with Undying will be exiled by Anafenza before it returns to battlefield
*
* Anafenza the foremost doesn't exile an undying creature when dying at the same time as
* that undying one. The undying comes back to the field when he shouldn't.
* Tests "Target creature with Undying will be exiled by Anafenza before it
* returns to battlefield
*
* Anafenza the foremost doesn't exile an undying creature when dying at the
* same time as that undying one. The undying comes back to the field when
* he shouldn't.
*/
@Test
public void testReplacementEffectPreventsReturnOfUndying() {
@ -125,7 +129,7 @@ public class UndyingTest extends CardTestPlayerBase {
// Creature - Zombie, 1/1 {1}{B}
// Undying (When this creature dies, if it had no +1/+1 counters on it, return it to the battlefield under its owner's control with a +1/+1 counter on it.)
addCard(Zone.HAND, playerA, "Butcher Ghoul");
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
addCard(Zone.HAND, playerB, "Lightning Bolt");
// Anafenza, the Foremost
@ -141,17 +145,18 @@ public class UndyingTest extends CardTestPlayerBase {
assertPermanentCount(playerB, "Anafenza, the Foremost", 1);
assertGraveyardCount(playerB, "Lightning Bolt", 1);
assertPermanentCount(playerA, "Butcher Ghoul", 0);
assertExileCount("Butcher Ghoul", 1);
}
/**
* Tests "Target creature with Undying will be exiled by Anafenza before it returns to battlefield
* if both leave the battlefield at the same time
* Tests "Target creature with Undying will be exiled by Anafenza before it
* returns to battlefield if both leave the battlefield at the same time
*
* Anafenza the foremost doesn't exile an undying creature when dying at the same time as
* that undying one. The undying comes back to the field when he shouldn't.
* Anafenza the foremost doesn't exile an undying creature when dying at the
* same time as that undying one. The undying comes back to the field when
* he shouldn't.
*/
@Test
public void testReplacementEffectPreventsReturnOfUndyingWrath() {
@ -208,4 +213,33 @@ public class UndyingTest extends CardTestPlayerBase {
assertPowerToughness(playerA, "Silvercoat Lion", 4, 4);
}
/**
* Tatterkite is getting counters on it, i have him in a edh deck with
* Mikaeus, the Lunarch and when Tatterkite dies it triggers the undying and
* he gets the +1/+1 counters
*/
@Test
public void testUndyingMikaeusAndTatterkite() {
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
// Whenever a Human deals damage to you, destroy it.
// Other non-Human creatures you control get +1/+1 and have undying.
addCard(Zone.BATTLEFIELD, playerA, "Mikaeus, the Unhallowed", 1);
addCard(Zone.BATTLEFIELD, playerA, "Tatterkite", 1); // Artifact Creature - Scarecrow 2/1
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Tatterkite");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Lightning Bolt", 1);
assertPermanentCount(playerA, "Tatterkite", 1);
assertPermanentCount(playerA, "Mikaeus, the Unhallowed", 1);
assertPowerToughness(playerA, "Tatterkite", 3, 2);
}
}

View file

@ -36,7 +36,6 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*
* @author LevelX2
*/
public class AddingCountersToPermanentsTest extends CardTestPlayerBase {
@Test
@ -47,7 +46,7 @@ public class AddingCountersToPermanentsTest extends CardTestPlayerBase {
// Put X -1/-1 counters on each creature. Shuffle Black Sun's Zenith into its owner's library.
addCard(Zone.HAND, playerA, "Black Sun's Zenith", 1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerB, "Witch's Familiar", 1);
@ -59,14 +58,13 @@ public class AddingCountersToPermanentsTest extends CardTestPlayerBase {
assertGraveyardCount(playerA, "Silvercoat Lion", 1);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
assertPermanentCount(playerA, "Witch's Familiar", 1);
assertPermanentCount(playerA, "Witch's Familiar", 1);
assertPowerToughness(playerA, "Witch's Familiar", 0, 1);
assertPermanentCount(playerB, "Witch's Familiar", 1);
assertPermanentCount(playerB, "Witch's Familiar", 1);
assertPowerToughness(playerB, "Witch's Familiar", 0, 1);
}
}
}

View file

@ -0,0 +1,66 @@
/*
* 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.destroy;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class BoilTest extends CardTestPlayerBase {
@Test
public void testDestroy() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
addCard(Zone.BATTLEFIELD, playerA, "Breeding Pool");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
// Destroy all Islands.
addCard(Zone.HAND, playerA, "Boil"); // {3}{R}
addCard(Zone.BATTLEFIELD, playerB, "Island", 1);
addCard(Zone.BATTLEFIELD, playerB, "Breeding Pool");
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boil");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Island", 0);
assertPermanentCount(playerA, "Breeding Pool", 0);
assertPermanentCount(playerA, "Mountain", 2);
assertPermanentCount(playerB, "Island", 0);
assertPermanentCount(playerB, "Breeding Pool", 0);
assertPermanentCount(playerB, "Mountain", 2);
}
}

View file

@ -36,14 +36,31 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*
* @author LevelX2
*/
public class PlayFromNonHandZoneTest extends CardTestPlayerBase {
@Test
public void testWorldheartPhoenixNormal() {
// Creature - Phoenix {3}{R}
// Flying
// You may cast Worldheart Phoenix from your graveyard by paying {W}{U}{B}{R}{G} rather than paying its mana cost.
// If you do, it enters the battlefield with two +1/+1 counters on it.
addCard(Zone.HAND, playerA, "Worldheart Phoenix");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Worldheart Phoenix"); // can only be cast by {W}{U}{B}{R}{G}
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertPowerToughness(playerA, "Worldheart Phoenix", 2, 2);
}
@Test
public void testWorldheartPhoenixNoMana() {
// Creature - Phoenix {3}{R}
// Flying
// You may cast Worldheart Phoenix from your graveyard by paying {W}{U}{B}{R}{G} rather than paying its mana cost.
// Flying
// You may cast Worldheart Phoenix from your graveyard by paying {W}{U}{B}{R}{G} rather than paying its mana cost.
// If you do, it enters the battlefield with two +1/+1 counters on it.
addCard(Zone.GRAVEYARD, playerA, "Worldheart Phoenix");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
@ -53,16 +70,15 @@ public class PlayFromNonHandZoneTest extends CardTestPlayerBase {
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerA, "Worldheart Phoenix", 0);
}
assertPermanentCount(playerA, "Worldheart Phoenix", 0);
}
@Test
public void testWorldheartPhoenix() {
// Creature - Phoenix {3}{R}
// Flying
// You may cast Worldheart Phoenix from your graveyard by paying {W}{U}{B}{R}{G} rather than paying its mana cost.
// Flying
// You may cast Worldheart Phoenix from your graveyard by paying {W}{U}{B}{R}{G} rather than paying its mana cost.
// If you do, it enters the battlefield with two +1/+1 counters on it.
addCard(Zone.GRAVEYARD, playerA, "Worldheart Phoenix");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
@ -76,11 +92,10 @@ public class PlayFromNonHandZoneTest extends CardTestPlayerBase {
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerA, "Worldheart Phoenix", 1);
}
assertPermanentCount(playerA, "Worldheart Phoenix", 1);
}
@Test
public void testNarsetEnlightenedMaster() {
// First strike
@ -90,38 +105,36 @@ public class PlayFromNonHandZoneTest extends CardTestPlayerBase {
skipInitShuffling();
addCard(Zone.LIBRARY, playerB, "Silvercoat Lion");
addCard(Zone.LIBRARY, playerB, "Abzan Banner");
addCard(Zone.LIBRARY, playerB, "Abzan Banner");
// Ferocious - If you control a creature with power 4 or greater, you may cast Dragon Grip as though it had flash. (You may cast it any time you could cast an instant.)
// Enchant creature
// Enchanted creature gets +2/+0 and has first strike.
addCard(Zone.LIBRARY, playerB, "Dragon Grip");
addCard(Zone.LIBRARY, playerB, "Dragon Grip");
// You gain 2 life for each creature you control.
addCard(Zone.LIBRARY, playerB, "Peach Garden Oath");
addCard(Zone.LIBRARY, playerB, "Plains");
addCard(Zone.LIBRARY, playerB, "Peach Garden Oath");
addCard(Zone.LIBRARY, playerB, "Plains");
attack(2, playerB, "Narset, Enlightened Master");
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Silvercoat Lion"); // can't be cast from exile
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Abzan Banner"); // can be cast from exile
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Dragon Grip", "Narset, Enlightened Master"); // can be cast from exile
castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Peach Garden Oath"); // can be cast from exile
setStopAt(2, PhaseStep.END_TURN);
execute();
assertExileCount("Silvercoat Lion", 1);
assertPermanentCount(playerB, "Abzan Banner", 1);
assertPermanentCount(playerB, "Dragon Grip", 1);
assertPermanentCount(playerB, "Abzan Banner", 1);
assertPermanentCount(playerB, "Dragon Grip", 1);
assertGraveyardCount(playerB, "Peach Garden Oath", 1);
assertPowerToughness(playerB, "Narset, Enlightened Master", 5, 2);
assertHandCount(playerB, "Plains", 1);
assertLife(playerA, 17);
assertLife(playerB, 22);
}
}
}

View file

@ -0,0 +1,176 @@
/*
* 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.continuous;
import mage.abilities.Ability;
import mage.constants.AbilityType;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.game.permanent.Permanent;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class DependentEffectsTest extends CardTestPlayerBase {
/**
* Opalescence plus Enchanted Evening are still not wiping any lands.
*/
@Test
public void testLandsAreDestroyed() {
// Each other non-Aura enchantment is a creature in addition to its other types and has base power and base toughness each equal to its converted mana cost.
addCard(Zone.HAND, playerA, "Opalescence", 1); // {2}{W}{W}
addCard(Zone.BATTLEFIELD, playerA, "Plains", 9);
addCard(Zone.BATTLEFIELD, playerA, "War Horn", 1);
// All permanents are enchantments in addition to their other types.
addCard(Zone.HAND, playerA, "Enchanted Evening"); // {3}{W/U}{W/U}
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Opalescence");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Enchanted Evening");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPowerToughness(playerA, "Enchanted Evening", 5, 5);
assertPowerToughness(playerA, "War Horn", 3, 3);
assertPermanentCount(playerA, "Island", 0);
assertPermanentCount(playerB, "Plains", 0);
}
/**
* Opalescense is dependent on Enchanted Evening, so it will be applied
* after it regardless of timestamp.
*
* Tokens can also have mana costs, and as a consequence of that, converted
* mana costs. A token created with Rite of Replication would have the mana
* cost of the creature it targeted. Most tokens do not have mana costs
* though.
*
* Tokens with no mana costs would be 0/0, as you said, and would indeed be
* put into owner's graveyard next time State Based Actionas are performed.
* Tokens with mana costs would naturally have whatever power and toughness
* their CMC indicated.
*/
@Test
public void testTokensAreDestroyed() {
// Each other non-Aura enchantment is a creature in addition to its other types and has base power and base toughness each equal to its converted mana cost.
addCard(Zone.BATTLEFIELD, playerA, "Opalescence", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 9);
// Kicker {5}
// Put a token that's a copy of target creature onto the battlefield. If Rite of Replication was kicked, put five of those tokens onto the battlefield instead.
addCard(Zone.HAND, playerA, "Rite of Replication", 1); // This token can have a cmc
// All permanents are enchantments in addition to their other types.
addCard(Zone.HAND, playerA, "Enchanted Evening"); // {3}{W/U}{W/U}
addCard(Zone.BATTLEFIELD, playerB, "Cobblebrute", 1); // 5/2 cmc = 4
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
// Put two 1/1 white Soldier creature tokens onto the battlefield.
addCard(Zone.HAND, playerB, "Raise the Alarm"); // Instant {1}{W}
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rite of Replication", "Cobblebrute");
setChoice(playerA, "No"); // no kicker
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Raise the Alarm");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Enchanted Evening");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, "Rite of Replication", 1);
assertGraveyardCount(playerB, "Raise the Alarm", 1);
assertPowerToughness(playerA, "Enchanted Evening", 5, 5);
assertPowerToughness(playerB, "Cobblebrute", 4, 4);
assertPowerToughness(playerA, "Cobblebrute", 4, 4);
assertPermanentCount(playerB, "Soldier", 0);
assertPermanentCount(playerA, "Island", 0);
assertPermanentCount(playerB, "Plains", 0);
}
@Test
public void testYixlidJailerAndNecroticOozeBasic() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// As long as Necrotic Ooze is on the battlefield, it has all activated abilities of all creature cards in all graveyards
addCard(Zone.BATTLEFIELD, playerA, "Necrotic Ooze", 1);
// {2}{1},{T}: Tap target creature.
addCard(Zone.GRAVEYARD, playerA, "Akroan Jailer", 1);
// {T}: Target attacking creature gets +1/+1 until end of turn.
addCard(Zone.GRAVEYARD, playerB, "Anointer of Champions", 1);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
Permanent necroticOoze = getPermanent("Necrotic Ooze", playerA);
int numberOfActivatedAbilities = 0;
for (Ability ability : necroticOoze.getAbilities(currentGame)) {
if (ability.getAbilityType().equals(AbilityType.ACTIVATED)) {
numberOfActivatedAbilities++;
}
}
Assert.assertEquals("Two abilities for Necrotic Ooze", 2, numberOfActivatedAbilities);
}
@Test
public void testYixlidJailerAndNecroticOozeLooseAll() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// As long as Necrotic Ooze is on the battlefield, it has all activated abilities of all creature cards in all graveyards
addCard(Zone.BATTLEFIELD, playerA, "Necrotic Ooze", 1);
// {2}{1},{T}: Tap target creature.
addCard(Zone.GRAVEYARD, playerA, "Akroan Jailer", 1);
// {T}: Target attacking creature gets +1/+1 until end of turn.
addCard(Zone.GRAVEYARD, playerB, "Anointer of Champions", 1);
// Cards in graveyards lose all abilities.
addCard(Zone.HAND, playerA, "Yixlid Jailer", 1); // Creature - {1}{B}
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Yixlid Jailer");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Yixlid Jailer", 1);
Permanent necroticOoze = getPermanent("Necrotic Ooze", playerA);
int numberOfActivatedAbilities = 0;
for (Ability ability : necroticOoze.getAbilities(currentGame)) {
if (ability.getAbilityType().equals(AbilityType.ACTIVATED)) {
numberOfActivatedAbilities++;
}
}
Assert.assertEquals("All abilities from cards in graveyard are removed - so no abilities for Necrotic Ooze", 0, numberOfActivatedAbilities);
}
}

View file

@ -38,28 +38,28 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*
* @author LevelX2
*/
public class ArtisanOfFormsTest extends CardTestPlayerBase {
/**
* Targeting a Artisan of Forms triggers it Heroic ability. So it can copy a target creature.
* If Cackling Counterpart later resolves, it should copy the creature that Artisan of Forms copies, not
* the Artisan itself.
* Targeting a Artisan of Forms triggers it Heroic ability. So it can copy a
* target creature. If Cackling Counterpart later resolves, it should copy
* the creature that Artisan of Forms copies, not the Artisan itself.
*/
@Test
public void testCopyTriggeredByCracklingCounterpart() {
// Heroic - Whenever you cast a spell that targets Artisan of Forms, you may have Artisan of Forms become a copy of target creature and gain this ability.
addCard(Zone.BATTLEFIELD, playerA, "Artisan of Forms");
addCard(Zone.HAND, playerA, "Artisan of Forms"); // {1}{U}
// {1}{U}{U} Put a token onto the battlefield that's a copy of target creature you control.
addCard(Zone.HAND, playerA, "Cackling Counterpart");
addCard(Zone.BATTLEFIELD, playerA, "Island",3);
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart", "Artisan of Forms");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Artisan of Forms");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cackling Counterpart", "Artisan of Forms");
addTarget(playerA, "Silvercoat Lion");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertLife(playerA, 20);
@ -70,18 +70,18 @@ public class ArtisanOfFormsTest extends CardTestPlayerBase {
assertPermanentCount(playerB, "Silvercoat Lion", 1);
// 1 + 2 Silvercoat Lion at the end
assertPermanentCount(playerA, "Silvercoat Lion", 2);
for (Permanent permanent :currentGame.getBattlefield().getAllActivePermanents(playerA.getId())) {
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(playerA.getId())) {
if (permanent.getName().equals("Silvercoat Lion")) {
Assert.assertEquals("Creature has to have Cast + Heroic ability", 2, permanent.getAbilities().size());
}
}
}
/**
* Targeting a Artisan of Forms triggers it Heroic ability. So it can copy a target creature.
* If populate spell later resolves, it should copy the creature that Artisan of Forms copies, not
* the Artisan itself.
/**
* Targeting a Artisan of Forms triggers it Heroic ability. So it can copy a
* target creature. If populate spell later resolves, it should copy the
* creature that Artisan of Forms copies, not the Artisan itself.
*/
@Test
public void testCopyTriggeredByPopulate() {
@ -90,17 +90,17 @@ public class ArtisanOfFormsTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Artisan of Forms");
// {1}{U}{U} Put a token onto the battlefield that's a copy of target creature you control.
addCard(Zone.HAND, playerA, "Cackling Counterpart");
addCard(Zone.BATTLEFIELD, playerA, "Island",3);
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
addCard(Zone.HAND, playerA, "Eyes in the Skies");
addCard(Zone.BATTLEFIELD, playerA, "Plains",4);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart", "Artisan of Forms");
addTarget(playerA, "Silvercoat Lion");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Eyes in the Skies");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Eyes in the Skies");
addTarget(playerA, "Silvercoat Lion");
setStopAt(1, PhaseStep.END_TURN);
execute();
@ -113,12 +113,12 @@ public class ArtisanOfFormsTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Bird", 1);
// 3 Silvercoat Lion at the end
assertPermanentCount(playerA, "Silvercoat Lion", 3);
for (Permanent permanent :currentGame.getBattlefield().getAllActivePermanents(playerA.getId())) {
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(playerA.getId())) {
if (permanent.getName().equals("Silvercoat Lion")) {
Assert.assertEquals("Creature has to have Cast + Heroic ability", 2, permanent.getAbilities().size());
}
}
}
}
}

View file

@ -0,0 +1,64 @@
/*
* 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.copy;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class CopySpellTest extends CardTestPlayerBase {
@Test
public void copyChainOfVapor() {
// Return target nonland permanent to its owner's hand. Then that permanent's controller may sacrifice a land. If the player does, he or she may copy this spell and may choose a new target for that copy.
addCard(Zone.HAND, playerA, "Chain of Vapor", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1);
addCard(Zone.BATTLEFIELD, playerB, "Island", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Chain of Vapor", "Pillarfield Ox");
setChoice(playerB, "Yes");
addTarget(playerB, "Silvercoat Lion");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerB, "Island", 1);
assertHandCount(playerB, "Pillarfield Ox", 1);
assertHandCount(playerA, "Silvercoat Lion", 1);
}
}

View file

@ -19,4 +19,99 @@ public class CryptoplasmTest extends CardTestPlayerBase {
assertLife(playerB, 20);
assertPermanentCount(playerA, "Craw Wurm", 2);
}
/**
* I have a Cryptoplasm in play, currently copying a Sigiled Paladin, and I
* enchant it with a Followed Footsteps. Next turn the aura triggers (the
* Crypto is still copying the same creature) and places a token on the
* battlefield, except the token is an untransformed Cryptoplasm, when it
* should be a Sigiled Paladin with Cryptoplasm's ability (as per rule
* 706.3), since that's what the enchanted creature currently is.
*
* 6/1/2011 If another creature becomes a copy of Cryptoplasm, it will
* become a copy of whatever Cryptoplasm is currently copying (if anything),
* plus it will have Cryptoplasm's triggered ability.
*/
@Test
public void testFollowedFootsteps() {
// First strike
// Exalted (Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn.)
addCard(Zone.BATTLEFIELD, playerA, "Sigiled Paladin", 1); // {W}{W}
addCard(Zone.BATTLEFIELD, playerB, "Island", 5);
// Enchant creature
// At the beginning of your upkeep, put a token that's a copy of enchanted creature onto the battlefield.
addCard(Zone.HAND, playerB, "Followed Footsteps", 1); // {3}{U}{U}
// At the beginning of your upkeep, you may have Cryptoplasm become a copy of another target creature. If you do, Cryptoplasm gains this ability.
addCard(Zone.BATTLEFIELD, playerB, "Cryptoplasm", 1); // {1}{U}{U}
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Followed Footsteps");
addTarget(playerB, "Sigiled Paladin[only copy]");
setStopAt(4, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerB, "Followed Footsteps", 1);
assertPermanentCount(playerB, "Cryptoplasm", 0);
assertPermanentCount(playerB, "Sigiled Paladin", 2);
}
/**
* I'm at 8 life, opponent (AI) is at 21. I have a Cryptoplasm currently
* copying my opponent's Divinity of Pride, the Crypto also has my Followed
* Footsteps attached to it. Additionally, I have another Cryptoplasm on the
* battlefield also copying the same Divinity, and a Clever Impersonator
* that ETB copying the first Cryptoplasm and is currently also a copy of
* the Divinity.
*
* Opponent attacks with his only Divinity of Pride (4/4) and a Serra
* Avenger (3/3). I block the Divinity with two of my Divinity copies (the
* Clever Impersonator and unenchanted Cryptoplasm) and the Avenger with the
* enchanted Divinity (originally a Cryptoplasm). My opponent's Divinity
* kills my two copies and dies, and then his Avenger dies and kills the
* Divinity blocking it, also sending my Followed Footsteps down with it.
*
* How does any of that add up? Not only should his Divinity only kill one
* of mine since it was a 4/4 and only becomes an 8/8 after dealing its
* damage (at which point it should be too late to go back and say the 4
* damage are now 8, since it was that exact damage that put him at 25
* life), but even more confusing is how the Serra Avenger, which is a 3/3,
* somehow kills my 4/4 that had suffered no other damage that turn.
*
* No other permanents in play at that moment had any influence in this
* either, they were only basic lands and a couple of creatures with no
* relevant abilities.
*
* I won't put aside me completely missing something here, but I really
* can't see any other explanation to this other than a game bug.
*/
@Test
public void testDamageLifelink() {
setLife(playerA, 21);
setLife(playerB, 8);
// First strike
// Exalted (Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn.)
addCard(Zone.BATTLEFIELD, playerA, "Divinity of Pride", 1); // {W}{W}
addCard(Zone.BATTLEFIELD, playerB, "Island", 5);
// At the beginning of your upkeep, you may have Cryptoplasm become a copy of another target creature. If you do, Cryptoplasm gains this ability.
addCard(Zone.BATTLEFIELD, playerB, "Cryptoplasm", 2); // {1}{U}{U}
addTarget(playerB, "Divinity of Pride");
addTarget(playerB, "Divinity of Pride");
attack(3, playerA, "Divinity of Pride");
block(3, playerB, "Divinity of Pride", "Divinity of Pride");
block(3, playerB, "Divinity of Pride", "Divinity of Pride");
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertPermanentCount(playerB, "Cryptoplasm", 0);
assertPermanentCount(playerA, "Divinity of Pride", 0);
assertPermanentCount(playerB, "Divinity of Pride", 1);
assertLife(playerB, 16);
assertLife(playerA, 25);
}
}

View file

@ -94,4 +94,35 @@ public class FelhideSpiritbinderTest extends CardTestPlayerBase {
assertLife(playerB, 20);
}
@Test
public void testCopyATokenCreature() {
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
addCard(Zone.HAND, playerA, "Call of the Herd", 1);
// Inspired - Whenever Felhide Spiritbinder becomes untapped, you may pay {1}{R}.
// If you do, put a token onto the battlefield that's a copy of another target creature
// except it's an enchantment in addition to its other types. It gains haste. Exile it at the beginning of the next end step.
addCard(Zone.BATTLEFIELD, playerB, "Felhide Spiritbinder", 1);
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Call of the Herd");
attack(2, playerB, "Felhide Spiritbinder");
setStopAt(4, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, "Elephant", 1);
assertPermanentCount(playerB, "Elephant", 1);
assertAbility(playerB, "Elephant", HasteAbility.getInstance(), true);
Permanent copiedTokenElephant = getPermanent("Elephant", playerB);
Assert.assertEquals("Elephant has Enchantment card type", true, copiedTokenElephant.getCardType().contains(CardType.ENCHANTMENT));
assertLife(playerA, 17);
assertLife(playerB, 20);
}
}

View file

@ -72,4 +72,41 @@ public class FlameshadowConjuringTest extends CardTestPlayerBase {
assertLife(playerA, 18);
}
/**
* I created a token copy of Wurmcoil Engine and sacrificed it. This gave me
* 4 tokens
*/
@Test
public void testWurmcoilEngine() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 7);
// Whenever a nontoken creature enters the battlefield under your control, you may pay {R}. If you do, put a token onto the battlefield that's a copy of that creature.
// That token gains haste. Exile it at the beginning of the next end step.
addCard(Zone.BATTLEFIELD, playerA, "Flameshadow Conjuring", 1);
// Deathtouch, lifelink
// When Wurmcoil Engine dies, put a 3/3 colorless Wurm artifact creature token with deathtouch and a 3/3 colorless Wurm artifact creature token with lifelink onto the battlefield.
addCard(Zone.HAND, playerA, "Wurmcoil Engine", 1); // 6/6 - {6}
addCard(Zone.BATTLEFIELD, playerB, "Plains", 3);
// Destroy target attacking creature.
addCard(Zone.HAND, playerB, "Kill Shot", 1); // {2}{U}
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wurmcoil Engine");
setChoice(playerA, "Yes");
attack(1, playerA, "Wurmcoil Engine");
castSpell(1, PhaseStep.END_COMBAT, playerB, "Kill Shot", "Wurmcoil Engine");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, "Kill Shot", 1);
assertPermanentCount(playerA, "Wurmcoil Engine", 1);
assertLife(playerB, 14);
assertLife(playerA, 26);
assertPermanentCount(playerA, "Wurm", 2);
}
}

View file

@ -125,11 +125,11 @@ public class EmblemsTest extends CardTestPlayerBase {
/**
* Liliana, Defiant Necromancer: -8: You get an emblem with "Whenever a
* creature you control dies, return it to the battlefield under your
* control at the beginning of the next end step.";
* creature dies, return it to the battlefield under your control at the
* beginning of the next end step.";
*
* Tests "Whenever a creature you control dies, return it to the battlefield
* under your control at the beginning of the next end step."
* Tests "Whenever a creature dies, return it to the battlefield under your
* control at the beginning of the next end step."
*/
@Test
public void testLilianaDefiantNecromancer() {
@ -152,7 +152,7 @@ public class EmblemsTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1);
assertPermanentCount(playerA, "Elite Vanguard", 1);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
assertHandCount(playerA, 0);

View file

@ -0,0 +1,63 @@
/*
* 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.protection;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class ProtectionTest extends CardTestPlayerBase {
@Test
public void testProtectionFromColoredSpells() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
// Delve
// Destroy target creature.
addCard(Zone.HAND, playerA, "Murderous Cut"); // {4}{B}
// Emrakul, the Aeons Torn can't be countered.
// When you cast Emrakul, take an extra turn after this one.
// Flying, protection from colored spells, annihilator 6
// When Emrakul is put into a graveyard from anywhere, its owner shuffles his or her graveyard into his or her library.
addCard(Zone.BATTLEFIELD, playerB, "Emrakul, the Aeons Torn");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murderous Cut", "Emrakul, the Aeons Torn");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Emrakul, the Aeons Torn", 1);
assertHandCount(playerA, "Murderous Cut", 1);
}
}

View file

@ -70,4 +70,64 @@ public class GainProtectionTest extends CardTestPlayerBase {
assertPowerToughness(playerA, "Elite Vanguard", 6, 5);
}
@Test
public void testGainProtectionByEnchantment() {
addCard(Zone.BATTLEFIELD, playerB, "Plains", 5);
// Flying
// When Brago, King Eternal deals combat damage to a player, exile any number of target nonland permanents you control, then return those cards to the battlefield under their owner's control.
addCard(Zone.BATTLEFIELD, playerB, "Brago, King Eternal");
// Enchant creature
// When Pentarch Ward enters the battlefield, draw a card.
// As Pentarch Ward enters the battlefield, choose a color.
// Enchanted creature has protection from the chosen color. This effect doesn't remove Pentarch Ward.
addCard(Zone.HAND, playerB, "Pentarch Ward");// "{2}{W}"
// Enchant creature
// Enchanted creature gets +1/+1 and has "Whenever this creature attacks, tap target creature defending player controls."
addCard(Zone.HAND, playerB, "Grasp of the Hieromancer");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Pentarch Ward", "Brago, King Eternal");
setChoice(playerB, "White");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Grasp of the Hieromancer", "Brago, King Eternal");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerB, "Pentarch Ward", 1);
assertHandCount(playerB, "Grasp of the Hieromancer", 1);
assertHandCount(playerB, 3);
}
/**
* Pentarch Ward on Brago naming white. Brago combat trigger resolves
* blinking Pentarch Ward. Brago retains protection from white even though
* Pentarch Ward is now exiled, making him unable to be re-enchanted by
* Pentarch Ward.
*/
@Test
public void testGainLooseProtectionByEnchantment() {
addCard(Zone.BATTLEFIELD, playerB, "Plains", 3);
// Flying
// When Brago, King Eternal deals combat damage to a player, exile any number of target nonland permanents you control, then return those cards to the battlefield under their owner's control.
addCard(Zone.BATTLEFIELD, playerB, "Brago, King Eternal");
// Enchant creature
// When Pentarch Ward enters the battlefield, draw a card.
// As Pentarch Ward enters the battlefield, choose a color.
// Enchanted creature has protection from the chosen color. This effect doesn't remove Pentarch Ward.
addCard(Zone.HAND, playerB, "Pentarch Ward");// "{2}{W}"
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Pentarch Ward", "Brago, King Eternal");
setChoice(playerB, "White");
attack(2, playerB, "Brago, King Eternal");
addTarget(playerB, "Pentarch Ward");
addTarget(playerB, "Brago, King Eternal");
setStopAt(2, PhaseStep.END_COMBAT);
execute();
assertLife(playerA, 18);
assertPermanentCount(playerB, "Pentarch Ward", 1);
assertHandCount(playerB, 3);
}
}

View file

@ -382,4 +382,39 @@ public class ZoneChangeReplacementTest extends CardTestPlayerBase {
}
/**
* I was using Anafenza, the Foremost as Commander. She attacked and traded
* with two creatures. I moved Anafenza to the Command Zone, but the
* opponent's creatures "when {this} dies" abilities triggered. Since
* Anafenza and those creatures all received lethal damage at the same time,
* the creatures should have been exiled due to Anafenza's replacement
* effect, but I guess since the logic asks if you want to use the Command
* Zone replacement effect first, that it doesn't see her leaving the
* battlefield at the same time as the other creatures.
*
* http://blogs.magicjudges.org/rulestips/2015/05/anafenza-vs-deathmist-raptor/
*/
@Test
public void testAnafenzaExileInCombat() {
// Whenever Anafenza, the Foremost attacks, put a +1/+1 counter on another target tapped creature you control.
// If a creature card would be put into an opponent's graveyard from anywhere, exile it instead.
addCard(Zone.BATTLEFIELD, playerA, "Anafenza, the Foremost"); // 4/4
// Reach (This creature can block creatures with flying.)
addCard(Zone.BATTLEFIELD, playerB, "Skyraker Giant"); // 4/3
attack(2, playerB, "Skyraker Giant");
block(2, playerA, "Anafenza, the Foremost", "Skyraker Giant");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerA, 20);
assertLife(playerB, 20);
assertExileCount("Skyraker Giant", 1);
assertPermanentCount(playerA, "Anafenza, the Foremost", 0);
assertGraveyardCount(playerA, "Anafenza, the Foremost", 1);
}
}

View file

@ -0,0 +1,67 @@
/*
* 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.triggers;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class TargetedTriggeredTest extends CardTestPlayerBase {
/**
* Tests that the first spell that targets Kira, Great Glass-Spinner is
* countered.
*
*/
@Test
@Ignore
// this does currently not work in test, because the target event will be fired earlier during tests,
// so the zone change counter for the fixed target of the counterspell will not work
public void testKiraGreatGlassSpinnerFirstSpellTurn() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
addCard(Zone.HAND, playerA, "Lightning Bolt");
addCard(Zone.BATTLEFIELD, playerB, "Kira, Great Glass-Spinner", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Kira, Great Glass-Spinner");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Lightning Bolt", 1);
assertPermanentCount(playerB, "Kira, Great Glass-Spinner", 1);
}
}

View file

@ -0,0 +1,71 @@
/*
* 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.triggers.state;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class PhyrexianDevourerTest extends CardTestPlayerBase {
/**
* Check that Phyrexian Devourer is sacrifriced as soon as the counters are
* added
*
*/
@Test
public void testBoostChecked() {
// When Phyrexian Devourer's power is 7 or greater, sacrifice it.
// Exile the top card of your library: Put X +1/+1 counters on Phyrexian Devourer, where X is the exiled card's converted mana cost.
addCard(Zone.BATTLEFIELD, playerA, "Phyrexian Devourer");
addCard(Zone.LIBRARY, playerA, "Phyrexian Devourer");
skipInitShuffling();
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
attack(2, playerB, "Silvercoat Lion");
block(2, playerA, "Phyrexian Devourer", "Silvercoat Lion");
activateAbility(2, PhaseStep.DECLARE_BLOCKERS, playerA, "Exile the top card of your library");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertGraveyardCount(playerA, "Phyrexian Devourer", 1);
assertExileCount("Phyrexian Devourer", 1);
assertPermanentCount(playerB, "Silvercoat Lion", 1);
}
}

View file

@ -0,0 +1,142 @@
/*
* 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.commander.duel;
import java.io.FileNotFoundException;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.GameException;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
/**
*
* @author LevelX2
*/
public class AnafenzaTest extends CardTestCommanderDuelBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
setDecknamePlayerA("CommanderAnafenza_WBG.dck"); // Commander = Anafenza, the Foremost
return super.createNewGameAndPlayers();
}
/**
* I was using Anafenza, the Foremost as Commander. She attacked and traded
* with two creatures. I moved Anafenza to the Command Zone, but the
* opponent's creatures "when {this} dies" abilities triggered. Since
* Anafenza and those creatures all received lethal damage at the same time,
* the creatures should have been exiled due to Anafenza's replacement
* effect, but I guess since the logic asks if you want to use the Command
* Zone replacement effect first, that it doesn't see her leaving the
* battlefield at the same time as the other creatures.
*
* http://blogs.magicjudges.org/rulestips/2015/05/anafenza-vs-deathmist-raptor/
*/
@Test
public void testAnafenzaExileInCombat() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
// When Runed Servitor dies, each player draws a card.
addCard(Zone.BATTLEFIELD, playerB, "Runed Servitor", 2);
// Whenever Anafenza, the Foremost attacks, put a +1/+1 counter on another target tapped creature you control.
// If a creature card would be put into an opponent's graveyard from anywhere, exile it instead.
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Anafenza, the Foremost");
attack(3, playerA, "Anafenza, the Foremost");
block(3, playerB, "Runed Servitor", "Anafenza, the Foremost");
block(3, playerB, "Runed Servitor", "Anafenza, the Foremost");
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerA, 40);
assertLife(playerB, 40);
assertExileCount("Runed Servitor", 2);
assertCommandZoneCount(playerA, "Anafenza, the Foremost", 1);
assertGraveyardCount(playerA, "Anafenza, the Foremost", 0);
assertHandCount(playerA, 1); // turn 3 draw
assertHandCount(playerB, 1); // turn 2 draw
}
/**
* Token don't go to exile because they are no creature cards
*/
@Test
public void testAnafenzaExileInCombatOmnathToken() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
addCard(Zone.BATTLEFIELD, playerA, "Acidic Slime", 1);
addCard(Zone.HAND, playerB, "Forest", 2);
// <i>Landfall</i> - Whenever a land enters the battlefield under your control, put a 5/5 red and green Elemental creature token onto the battlefield.
// Whenever Omnath, Locus of Rage or another Elemental you control dies, Omnath deals 3 damage to target creature or player.
addCard(Zone.BATTLEFIELD, playerB, "Omnath, Locus of Rage", 1);
// Whenever Anafenza, the Foremost attacks, put a +1/+1 counter on another target tapped creature you control.
// If a creature card would be put into an opponent's graveyard from anywhere, exile it instead.
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Anafenza, the Foremost");
playLand(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Forest");
playLand(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Forest");
attack(5, playerA, "Acidic Slime");
block(5, playerB, "Elemental", "Acidic Slime");
attack(5, playerA, "Anafenza, the Foremost");
block(5, playerB, "Elemental", "Anafenza, the Foremost");
addTarget(playerB, playerA);
setStopAt(5, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertExileCount(playerA, 0);
assertExileCount(playerB, 0);
assertPermanentCount(playerB, "Elemental", 1);
assertGraveyardCount(playerA, "Acidic Slime", 1);
assertGraveyardCount(playerA, "Anafenza, the Foremost", 0);
assertCommandZoneCount(playerA, "Anafenza, the Foremost", 1);
assertHandCount(playerA, 2); // turn 3 + 5 draw
assertHandCount(playerB, 2); // turn 2 + 4 draw
assertLife(playerA, 37);
assertLife(playerB, 40);
}
}

View file

@ -53,6 +53,7 @@ import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.decks.Deck;
import mage.choices.Choice;
import mage.constants.AbilityType;
import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
@ -70,6 +71,7 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.permanent.AttackingPredicate;
import mage.filter.predicate.permanent.BlockingPredicate;
import mage.filter.predicate.permanent.SummoningSicknessPredicate;
import mage.game.Game;
import mage.game.Graveyard;
import mage.game.Table;
@ -97,6 +99,7 @@ import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetCreaturePermanentAmount;
import mage.target.common.TargetPermanentOrPlayer;
import mage.util.MessageToClient;
import org.junit.Ignore;
/**
@ -476,6 +479,7 @@ public class TestPlayer implements Player {
FilterCreatureForCombat filter = new FilterCreatureForCombat();
filter.add(new NamePredicate(groups[0]));
filter.add(Predicates.not(new AttackingPredicate()));
filter.add(Predicates.not(new SummoningSicknessPredicate()));
Permanent attacker = findPermanent(filter, computerPlayer.getId(), game);
if (attacker != null && attacker.canAttack(defenderId, game)) {
computerPlayer.declareAttacker(attacker.getId(), defenderId, game, false);
@ -569,21 +573,37 @@ public class TestPlayer implements Player {
String[] targetList = choose2.split("\\^");
boolean targetFound = false;
for (String targetName : targetList) {
boolean originOnly = false;
boolean copyOnly = false;
if (targetName.endsWith("]")) {
if (targetName.endsWith("[no copy]")) {
originOnly = true;
targetName = targetName.substring(0, targetName.length() - 9);
}
if (targetName.endsWith("[only copy]")) {
copyOnly = true;
targetName = targetName.substring(0, targetName.length() - 11);
}
}
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filterPermanent, game)) {
if (target.getTargets().contains(permanent.getId())) {
continue;
}
if (permanent.getName().equals(targetName)) {
if (target.isNotTarget() || ((TargetPermanent) target).canTarget(computerPlayer.getId(), permanent.getId(), null, game)) {
target.add(permanent.getId(), game);
targetFound = true;
break;
if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) {
target.add(permanent.getId(), game);
targetFound = true;
break;
}
}
} else if ((permanent.getName() + "-" + permanent.getExpansionSetCode()).equals(targetName)) {
if (target.isNotTarget() || ((TargetPermanent) target).canTarget(computerPlayer.getId(), permanent.getId(), null, game)) {
target.add(permanent.getId(), game);
targetFound = true;
break;
if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) {
target.add(permanent.getId(), game);
targetFound = true;
break;
}
}
}
}
@ -797,6 +817,14 @@ public class TestPlayer implements Player {
@Override
public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) {
return this.chooseUse(outcome, new MessageToClient(message), source, game);
}
@Override
public boolean chooseUse(Outcome outcome, MessageToClient message, Ability source, Game game) {
if (message.getMessage().equals("Scry 1?")) {
return false;
}
if (!choices.isEmpty()) {
if (choices.get(0).equals("No")) {
choices.remove(0);
@ -807,7 +835,7 @@ public class TestPlayer implements Player {
return true;
}
}
return true;
return computerPlayer.chooseUse(outcome, message, source, game);
}
@Override
@ -1816,6 +1844,16 @@ public class TestPlayer implements Player {
return computerPlayer.getMatchPlayer();
}
@Override
public AbilityType getJustActivatedType() {
return computerPlayer.getJustActivatedType();
}
@Override
public void setJustActivatedType(AbilityType justActivatedType) {
computerPlayer.setJustActivatedType(justActivatedType);
}
@Override
public void cleanUpOnMatchEnd() {
computerPlayer.cleanUpOnMatchEnd();
@ -1897,6 +1935,11 @@ public class TestPlayer implements Player {
computerPlayer.pickCard(cards, deck, draft);
}
@Override
public boolean scry(int value, Ability source, Game game) {
return computerPlayer.scry(value, source, game);
}
public void setAIPlayer(boolean AIPlayer) {
this.AIPlayer = AIPlayer;
}

View file

@ -8,8 +8,6 @@ import mage.filter.Filter;
import mage.players.Player;
import org.mage.test.player.TestPlayer;
/**
* Interface for all test initialization and assertion operations.
*/
@ -19,21 +17,23 @@ public interface CardTestAPI {
* Types of game result.
*/
public enum GameResult {
WON,
LOST,
DRAW
}
//******* INITIALIZATION METHODS *******/
/**
* Default game initialization params for red player (that plays with Mountains)
* Default game initialization params for red player (that plays with
* Mountains)
*/
void useRedDefault();
/**
* Removes all cards from player's library from the game.
* Usually this should be used once before initialization to form the library in certain order.
* Removes all cards from player's library from the game. Usually this
* should be used once before initialization to form the library in certain
* order.
*
* @param player {@link Player} to remove all library cards from.
*/
@ -43,7 +43,8 @@ public interface CardTestAPI {
* Add a card to specified zone of specified player.
*
* @param gameZone {@link mage.constants.Zone} to add cards to.
* @param player {@link Player} to add cards for. Use either playerA or playerB.
* @param player {@link Player} to add cards for. Use either playerA or
* playerB.
* @param cardName Card name in string format.
*/
void addCard(Zone gameZone, TestPlayer player, String cardName);
@ -52,9 +53,10 @@ public interface CardTestAPI {
* Add any amount of cards to specified zone of specified player.
*
* @param gameZone {@link mage.constants.Zone} to add cards to.
* @param player {@link Player} to add cards for. Use either playerA or playerB.
* @param player {@link Player} to add cards for. Use either playerA or
* playerB.
* @param cardName Card name in string format.
* @param count Amount of cards to be added.
* @param count Amount of cards to be added.
*/
void addCard(Zone gameZone, TestPlayer player, String cardName, int count);
@ -62,11 +64,13 @@ public interface CardTestAPI {
* Add any amount of cards to specified zone of specified player.
*
* @param gameZone {@link mage.constants.Zone} to add cards to.
* @param player {@link Player} to add cards for. Use either playerA or playerB.
* @param player {@link Player} to add cards for. Use either playerA or
* playerB.
* @param cardName Card name in string format.
* @param count Amount of cards to be added.
* @param tapped In case gameZone is Battlefield, determines whether permanent should be tapped.
* In case gameZone is other than Battlefield, {@link IllegalArgumentException} is thrown
* @param count Amount of cards to be added.
* @param tapped In case gameZone is Battlefield, determines whether
* permanent should be tapped. In case gameZone is other than Battlefield,
* {@link IllegalArgumentException} is thrown
*/
void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped);
@ -74,27 +78,27 @@ public interface CardTestAPI {
* Set player's initial life count.
*
* @param player {@link Player} to set life count for.
* @param life Life count to set.
* @param life Life count to set.
*/
void setLife(TestPlayer player, int life);
//******* GAME OPTIONS *******/
/**
* Define turn number to stop the game on.
*
* @param turn
*/
void setStopOnTurn(int turn);
/**
* Define the turn number and step to stop the game on.
*
* @param turn
* @param step
*/
void setStopAt(int turn, PhaseStep step);
//******* ASSERT METHODS *******/
/**
* Assert turn number after test execution.
*
@ -114,26 +118,26 @@ public interface CardTestAPI {
* Assert player's life count after test execution.
*
* @param player {@link Player} to get life for comparison.
* @param life Expected player's life to compare with.
* @param life Expected player's life to compare with.
*/
void assertLife(Player player, int life) throws AssertionError;
/**
* Assert creature's power and toughness by card name.
* <p/>
* Throws {@link AssertionError} in the following cases:
* 1. no such player
* 2. no such creature under player's control
* 3. depending on comparison scope:
* 3a. any: no creature under player's control with the specified p\t params
* 3b. all: there is at least one creature with the cardName with the different p\t params
* Throws {@link AssertionError} in the following cases: 1. no such player
* 2. no such creature under player's control 3. depending on comparison
* scope: 3a. any: no creature under player's control with the specified p\t
* params 3b. all: there is at least one creature with the cardName with the
* different p\t params
*
* @param player {@link Player} to get creatures for comparison.
* @param cardName Card name to compare with.
* @param power Expected power to compare with.
* @param player {@link Player} to get creatures for comparison.
* @param cardName Card name to compare with.
* @param power Expected power to compare with.
* @param toughness Expected toughness to compare with.
* @param scope {@link Filter.ComparisonScope} Use ANY, if you want "at least one creature with given name should have specified p\t"
* Use ALL, if you want "all creature with gived name should have specified p\t"
* @param scope {@link Filter.ComparisonScope} Use ANY, if you want "at
* least one creature with given name should have specified p\t" Use ALL, if
* you want "all creature with gived name should have specified p\t"
*/
void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope)
throws AssertionError;
@ -141,13 +145,12 @@ public interface CardTestAPI {
/**
* Assert creature's abilities.
* <p/>
* Throws {@link AssertionError} in the following cases:
* 1. no such player
* 2. no such creature under player's control
* 3. there is more than one creature with such name
* Throws {@link AssertionError} in the following cases: 1. no such player
* 2. no such creature under player's control 3. there is more than one
* creature with such name
*
* @param player {@link Player} to get creatures for comparison.
* @param cardName Card name to compare with.
* @param player {@link Player} to get creatures for comparison.
* @param cardName Card name to compare with.
* @param abilities Expected abilities
*/
void assertAbilities(Player player, String cardName, List<Ability> abilities)
@ -157,7 +160,7 @@ public interface CardTestAPI {
* Assert permanent count under player's control.
*
* @param player {@link Player} which permanents should be counted.
* @param count Expected count.
* @param count Expected count.
*/
void assertPermanentCount(Player player, int count) throws AssertionError;
@ -166,7 +169,26 @@ public interface CardTestAPI {
*
* @param player {@link Player} which permanents should be counted.
* @param cardName Name of the cards that should be counted.
* @param count Expected count.
* @param count Expected count.
*/
void assertPermanentCount(Player player, String cardName, int count) throws AssertionError;
/**
* Assert command zone object count in player's command zone
*
* @param player {@link Player} which permanents should be counted.
* @param commandZoneObjectName Name of the commander or emblem that should
* be counted.
* @param count Expected count.
*/
void assertCommandZoneCount(Player player, String commandZoneObjectName, int count) throws AssertionError;
/**
* Assert emblem count under player's control
*
* @param player
* @param count
* @throws AssertionError
*/
void assertEmblemCount(Player player, int count) throws AssertionError;
}

View file

@ -577,6 +577,17 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
Assert.assertEquals("(Battlefield) Card counts are not equal (" + cardName + ")", count, actualCount);
}
@Override
public void assertCommandZoneCount(Player player, String commandZoneObjectName, int count) throws AssertionError {
int actualCount = 0;
for (CommandObject commandObject : currentGame.getState().getCommand()) {
if (commandObject.getControllerId().equals(player.getId()) && commandObject.getName().equals(commandZoneObjectName)) {
actualCount++;
}
}
Assert.assertEquals("(Command Zone) Card counts are not equal (" + commandZoneObjectName + ")", count, actualCount);
}
/**
* Assert emblem count under player's control
*
@ -584,6 +595,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param count
* @throws AssertionError
*/
@Override
public void assertEmblemCount(Player player, int count) throws AssertionError {
int actualCount = 0;
for (CommandObject commandObject : currentGame.getState().getCommand()) {
@ -765,7 +777,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
*/
public void assertHandCount(Player player, int count) throws AssertionError {
int actual = currentGame.getPlayer(player.getId()).getHand().size();
Assert.assertEquals("(Hand) Card counts are not equal ", count, actual);
Assert.assertEquals("(Hand " + player.getName() + ") Card counts are not equal ", count, actual);
}
/**
@ -779,7 +791,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
FilterCard filter = new FilterCard();
filter.add(new NamePredicate(cardName));
int actual = currentGame.getPlayer(player.getId()).getHand().count(filter, player.getId(), currentGame);
Assert.assertEquals("(Hand) Card counts for card " + cardName + " are not equal ", count, actual);
Assert.assertEquals("(Hand) Card counts for card " + cardName + " for " + player.getName() + " are not equal ", count, actual);
}
/**