Merge branch 'master' into Network_Upgrade

Conflicts:
	Mage.Client/src/main/java/mage/client/chat/ChatPanel.java
	Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java
	Mage.Client/src/main/java/mage/client/table/TablesPanel.java
	Mage.Common/src/mage/remote/SessionImpl.java
	Mage.Server/src/main/java/mage/server/Session.java
This commit is contained in:
betasteward 2015-06-20 23:00:34 -04:00
commit f4aff4a121
894 changed files with 23817 additions and 4981 deletions

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.AI.basic;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseAI;
/**
*
* @author LevelX2
*/
public class CostModificationTest extends CardTestPlayerBaseAI {
/**
* There seems to be a problem when playing Fluctuator against Computer.
* Once played, I am stuck at "Waiting for Computer" forever...
*/
@Test
public void testFluctuator() {
addCard(Zone.HAND, playerA, "Silvercoat Lion");
// Destroy all artifacts, creatures, and enchantments.
// Cycling ({3}, Discard this card: Draw a card.)
addCard(Zone.HAND, playerA, "Akroma's Vengeance");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
// Cycling abilities you activate cost you up to {2} less to activate.
addCard(Zone.BATTLEFIELD, playerA, "Fluctuator");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Akroma's Vengeance", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
}
}

View file

@ -27,7 +27,6 @@
*/
package org.mage.test.cards.abilities.activated;
import mage.abilities.keyword.BloodthirstAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
@ -74,5 +73,46 @@ public class ReturnToHandTest extends CardTestPlayerBase {
}
/**
* Return from graveyard to hand if you play a swamp
*/
@Test
public void VeilbornGhoulTest1() {
// Veilborn Ghoul can't block.
// Whenever a Swamp enters the battlefield under your control, you may return Veilborn Ghoul from your graveyard to your hand.
addCard(Zone.GRAVEYARD, playerA, "Veilborn Ghoul");
addCard(Zone.HAND, playerA, "Swamp");
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Swamp", 1);
assertHandCount(playerA, "Veilborn Ghoul", 1);
}
/**
* Return from graveyard to hand if you play a non swamp land but Urborg, Tomb of Yawgmoth is in play
*/
@Test
public void VeilbornGhoulTest2() {
// Veilborn Ghoul can't block.
// Whenever a Swamp enters the battlefield under your control, you may return Veilborn Ghoul from your graveyard to your hand.
addCard(Zone.GRAVEYARD, playerA, "Veilborn Ghoul");
addCard(Zone.HAND, playerA, "Flood Plain");
// Each land is a Swamp in addition to its other land types.
addCard(Zone.BATTLEFIELD, playerA, "Urborg, Tomb of Yawgmoth", 1);
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flood Plain");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Flood Plain", 1);
assertHandCount(playerA, "Veilborn Ghoul", 1);
}
}
}

View file

@ -0,0 +1,185 @@
/*
* 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.equipped;
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 ScytheOfTheWretchedTest extends CardTestPlayerBase {
/**
* Test that the creature taht died returns to battlefield under your control
* if the previous equiped creature does not die
*/
@Test
public void testEquipAlive() {
addCard(Zone.BATTLEFIELD, playerA, "Soulmender", 1);
addCard(Zone.BATTLEFIELD, playerB, "Plains", 4);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
// Equipped creature gets +2/+2.
// Whenever a creature dealt damage by equipped creature this turn dies, return that card to the battlefield under your control. Attach Scythe of the Wretched to that creature.
// Equip {4}
addCard(Zone.BATTLEFIELD, playerB, "Scythe of the Wretched");
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Equip {4}", "Silvercoat Lion");
attack(2, playerB, "Silvercoat Lion");
block(2, playerA, "Soulmender", "Silvercoat Lion");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerA, 20);
assertLife(playerB, 20);
assertPermanentCount(playerA, "Soulmender", 0);
assertPermanentCount(playerB, "Soulmender", 1);
assertPowerToughness(playerB, "Soulmender", 3, 3);
assertPowerToughness(playerB, "Silvercoat Lion", 2, 2);
Permanent silvercoatLion = getPermanent("Silvercoat Lion", playerB.getId());
Assert.assertTrue("Silvercoat Lion may not have any attachments", silvercoatLion.getAttachments().isEmpty());
}
/**
* Test that the creature that died returns to battlefield under your control
* if the previous equiped creature does die after equipment is removed
*/
@Test
public void testEquipDied() {
addCard(Zone.BATTLEFIELD, playerA, "Oreskos Swiftclaw", 1); // 3/1
addCard(Zone.BATTLEFIELD, playerB, "Plains", 4);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
// Equipped creature gets +2/+2.
// Whenever a creature dealt damage by equipped creature this turn dies, return that card to the battlefield under your control. Attach Scythe of the Wretched to that creature.
// Equip {4}
addCard(Zone.BATTLEFIELD, playerB, "Scythe of the Wretched");
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Equip {4}", "Silvercoat Lion");
attack(2, playerB, "Silvercoat Lion");
block(2, playerA, "Oreskos Swiftclaw", "Silvercoat Lion");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerA, 20);
assertLife(playerB, 20);
assertPermanentCount(playerA, "Oreskos Swiftclaw", 0);
assertPermanentCount(playerB, "Oreskos Swiftclaw", 1);
assertPowerToughness(playerB, "Oreskos Swiftclaw", 5, 3);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
}
/**
* Test that the creature that died returns to battlefield under your control
* if the previous equiped creature does die already in combat
*/
@Test
public void testEquipDiedInCombat() {
addCard(Zone.BATTLEFIELD, playerA, "Serra Angel", 1); // 4/4
addCard(Zone.BATTLEFIELD, playerB, "Plains", 4);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
// Equipped creature gets +2/+2.
// Whenever a creature dealt damage by equipped creature this turn dies, return that card to the battlefield under your control. Attach Scythe of the Wretched to that creature.
// Equip {4}
addCard(Zone.BATTLEFIELD, playerB, "Scythe of the Wretched");
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Equip {4}", "Silvercoat Lion");
attack(2, playerB, "Silvercoat Lion");
block(2, playerA, "Serra Angel", "Silvercoat Lion");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerA, 20);
assertLife(playerB, 20);
assertPermanentCount(playerA, "Serra Angel", 0);
assertPermanentCount(playerB, "Serra Angel", 1);
assertPowerToughness(playerB, "Serra Angel", 6, 6);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
}
/**
* Test that the creature that died returns to battlefield under your control
* if the previous equiped creature does die already in combat and the equipment was destroyed meanwhile
*/
@Test
public void testEquipDiedInCombat2() {
addCard(Zone.BATTLEFIELD, playerA, "Serra Angel", 1); // 4/4
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Zone.HAND, playerA, "Disenchant", 1);
addCard(Zone.BATTLEFIELD, playerB, "Plains", 4);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion");
// Equipped creature gets +2/+2.
// Whenever a creature dealt damage by equipped creature this turn dies, return that card to the battlefield under your control. Attach Scythe of the Wretched to that creature.
// Equip {4}
addCard(Zone.BATTLEFIELD, playerB, "Scythe of the Wretched");
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Equip {4}", "Silvercoat Lion");
attack(2, playerB, "Silvercoat Lion");
block(2, playerA, "Serra Angel", "Silvercoat Lion");
castSpell(2, PhaseStep.COMBAT_DAMAGE, playerA, "Disenchant", "Scythe of the Wretched", "Whenever a creature dealt damage");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerA, 20);
assertLife(playerB, 20);
assertGraveyardCount(playerA, "Disenchant", 1);
assertGraveyardCount(playerB, "Scythe of the Wretched", 1);
assertPermanentCount(playerA, "Serra Angel", 0);
assertPermanentCount(playerB, "Serra Angel", 1);
assertPowerToughness(playerB, "Serra Angel", 4, 4);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
}
}

View file

@ -25,7 +25,6 @@
* 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;
@ -37,16 +36,14 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*
* @author LevelX2
*/
public class DiscardTest extends CardTestPlayerBase {
/*
* If Rest in Peace is in play, every card going to the graveyard goes to exile instead.
* If a card is discarded while Rest in Peace is on the battlefield, abilities that function
* when a card is discarded (such as madness) still work, even though that card never reaches
* a graveyard.
*/
/*
* If Rest in Peace is in play, every card going to the graveyard goes to exile instead.
* If a card is discarded while Rest in Peace is on the battlefield, abilities that function
* when a card is discarded (such as madness) still work, even though that card never reaches
* a graveyard.
*/
@Test
public void testRestInPeaceAndCycle() {
@ -67,4 +64,26 @@ public class DiscardTest extends CardTestPlayerBase {
assertHandCount(playerA, 1); // the card drawn by Cycling
}
}
/**
* With Bazaar of Baghdad, if you use it when you have no cards in hand, you
* draw 2, it asks for you to discard 3, but you can't. So the game can't
* progress and you lose on time.
*/
@Test
public void testBazaarOfBaghdad() {
// {T}: Draw two cards, then discard three cards.
addCard(Zone.BATTLEFIELD, playerA, "Bazaar of Baghdad", 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw two cards, then discard three cards");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 20);
assertLife(playerB, 20);
assertHandCount(playerA, 0);
assertGraveyardCount(playerA, 2);
}
}

View file

@ -75,4 +75,50 @@ public class FlashbackTest extends CardTestPlayerBase {
assertExileCount("Fracturing Gust", 1);
}
/**
* My opponent put Iona on the battlefield using Unburial Rites, but my game
* log didn't show me the color he has chosen.
*
*/
@Test
public void testUnburialRites() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 8);
// Return target creature card from your graveyard to the battlefield.
// Flashback {3}{W}
addCard(Zone.HAND, playerA, "Unburial Rites", 1); // Sorcery - {4}{B}
// Flying
// As Iona, Shield of Emeria enters the battlefield, choose a color.
// Your opponents can't cast spells of the chosen color.
addCard(Zone.GRAVEYARD, playerA, "Iona, Shield of Emeria");
// As Lurebound Scarecrow enters the battlefield, choose a color.
// When you control no permanents of the chosen color, sacrifice Lurebound Scarecrow.
addCard(Zone.GRAVEYARD, playerA, "Lurebound Scarecrow"); // Enchantment - {2}{U}
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
addCard(Zone.HAND, playerB, "Lightning Bolt", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Unburial Rites", "Iona, Shield of Emeria");
setChoice(playerA, "Red");
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback {3}{W}");
addTarget(playerA, "Lurebound Scarecrow");
setChoice(playerA, "White");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", playerA);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Iona, Shield of Emeria", 1);
assertPermanentCount(playerA, "Lurebound Scarecrow", 1);
assertHandCount(playerB, "Lightning Bolt", 1);
assertExileCount("Unburial Rites", 1);
}
}

View file

@ -31,6 +31,7 @@ package org.mage.test.cards.abilities.keywords;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
@ -203,4 +204,92 @@ public class KickerTest extends CardTestPlayerBase {
assertLife(playerB, 20);
}
/**
* Bloodhusk Ritualist's discard trigger does nothing if the Ritualist leaves the battlefield before the trigger resolves.
*/
@Test
public void testBloodhuskRitualist() {
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
addCard(Zone.HAND, playerB, "Lightning Bolt");
addCard(Zone.HAND, playerB, "Fireball", 2);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
addCard(Zone.HAND, playerA, "Bloodhusk Ritualist", 1); // 2/2 {2}{B}
// Multikicker (You may pay an additional {B} any number of times as you cast this spell.)
// When Bloodhusk Ritualist enters the battlefield, target opponent discards a card for each time it was kicked.
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bloodhusk Ritualist");
setChoice(playerA, "Yes"); // 2 x Multikicker
setChoice(playerA, "Yes");
setChoice(playerA, "No");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Bloodhusk Ritualist");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
Assert.assertEquals("All mana has to be used","[]", playerA.getManaAvailable(currentGame).toString());
assertGraveyardCount(playerB, "Lightning Bolt", 1);
assertGraveyardCount(playerA, "Bloodhusk Ritualist", 1);
assertGraveyardCount(playerB, "Fireball", 2);
assertHandCount(playerB, 0);
}
/**
* Test and/or kicker costs
*/
@Test
public void testSunscapeBattlemage1() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
// Kicker {1}{G} and/or {2}{U}
// When {this} enters the battlefield, if it was kicked with its {1}{G} kicker, destroy target creature with flying.
// When {this} enters the battlefield, if it was kicked with its {2}{U} kicker, draw two cards.
addCard(Zone.HAND, playerA, "Sunscape Battlemage", 1); // 2/2 {2}{W}
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sunscape Battlemage");
setChoice(playerA, "No"); // no {1}{G}
setChoice(playerA, "Yes"); // but {2}{U}
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Sunscape Battlemage", 1);
assertHandCount(playerA, 2);
}
/**
* Test and/or kicker costs
*/
@Test
public void testSunscapeBattlemage2() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
// Kicker {1}{G} and/or {2}{U}
// When {this} enters the battlefield, if it was kicked with its {1}{G} kicker, destroy target creature with flying.
// When {this} enters the battlefield, if it was kicked with its {2}{U} kicker, draw two cards.
addCard(Zone.HAND, playerA, "Sunscape Battlemage", 1); // 2/2 {2}{W}
addCard(Zone.BATTLEFIELD, playerB, "Birds of Paradise", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sunscape Battlemage");
addTarget(playerA, "Birds of Paradise");
setChoice(playerA, "Yes"); // no {1}{G}
setChoice(playerA, "Yes"); // but {2}{U}
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerB, "Birds of Paradise", 1);
assertPermanentCount(playerA, "Sunscape Battlemage", 1);
assertHandCount(playerA, 2);
}
}

View file

@ -111,5 +111,93 @@ public class LandfallTest extends CardTestPlayerBase {
assertLife(playerB, 20);
}
/**
* Searing Blaze's landfall doesn't appear to be working. My opponent played
* a mountain, then played searing blaze targeting my Tasigur, the Golden
* Fang. It only dealt 1 damage to me, where it should've dealt 3, because
* my opponent had played a land.
*/
@Test
public void testSearingBlaze() {
// Searing Blaze deals 1 damage to target player and 1 damage to target creature that player controls.
// Landfall - If you had a land enter the battlefield under your control this turn, Searing Blaze deals 3 damage to that player and 3 damage to that creature instead.
addCard(Zone.HAND, playerA, "Searing Blaze",1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain",1);
addCard(Zone.HAND, playerA, "Mountain");
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion",1);
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Searing Blaze");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Mountain", 2);
assertGraveyardCount(playerA, "Searing Blaze" , 1);
assertLife(playerA, 20);
assertLife(playerB, 17);
assertGraveyardCount(playerB, "Silvercoat Lion" , 1);
}
@Test
public void testGroundswellWithoutLandfall() {
// Target creature gets +2/+2 until end of turn.
//Landfall - If you had a land enter the battlefield under your control this turn, that creature gets +4/+4 until end of turn instead.
addCard(Zone.HAND, playerB, "Groundswell",1);
addCard(Zone.BATTLEFIELD, playerB, "Forest",1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion",1);
attack(2, playerB, "Silvercoat Lion");
castSpell(2, PhaseStep.DECLARE_ATTACKERS, playerB, "Groundswell", "Silvercoat Lion");
setStopAt(2, PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerB, "Forest", 1);
assertGraveyardCount(playerB, "Groundswell" , 1);
assertPermanentCount(playerB, "Silvercoat Lion" , 1);
assertPowerToughness(playerB, "Silvercoat Lion", 4, 4);
assertLife(playerA, 16); // 2 + 4
assertLife(playerB, 20);
}
@Test
public void testGroundswellWithLandfall() {
// Target creature gets +2/+2 until end of turn.
//Landfall - If you had a land enter the battlefield under your control this turn, that creature gets +4/+4 until end of turn instead.
addCard(Zone.HAND, playerB, "Groundswell",1);
addCard(Zone.HAND, playerB, "Forest");
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion",1);
playLand(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Forest");
attack(2, playerB, "Silvercoat Lion");
castSpell(2, PhaseStep.DECLARE_ATTACKERS, playerB, "Groundswell", "Silvercoat Lion");
setStopAt(2, PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerB, "Forest", 1);
assertGraveyardCount(playerB, "Groundswell" , 1);
assertPermanentCount(playerB, "Silvercoat Lion" , 1);
assertPowerToughness(playerB, "Silvercoat Lion", 6, 6);
assertLife(playerA, 14); // 2 + 4
assertLife(playerB, 20);
}
}

View file

@ -0,0 +1,144 @@
/*
* 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.abilities.keyword.HasteAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class SpliceOnArcaneTest extends CardTestPlayerBase {
/**
* Test that it works to cast Through the Breach
* by slicing it on an arcane spell
*
*/
@Test
public void testSpliceThroughTheBreach() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
// Sorcery - Arcane {R}
// Lava Spike deals 3 damage to target player.
addCard(Zone.HAND, playerA, "Lava Spike",1);
// You may put a creature card from your hand onto the battlefield. That creature gains haste. Sacrifice that creature at the beginning of the next end step.
// Splice onto Arcane {2}{R}{R} (As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)
addCard(Zone.HAND, playerA, "Through the Breach",1);
addCard(Zone.HAND, playerA, "Silvercoat Lion",1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lava Spike", playerB);
setChoice(playerA, "Silvercoat Lion");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 20);
assertLife(playerB, 17);
assertGraveyardCount(playerA, "Lava Spike", 1);
assertHandCount(playerA, "Through the Breach", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
assertAbility(playerA, "Silvercoat Lion", HasteAbility.getInstance(), true);
Assert.assertEquals("All available mana has to be used", 0, playerA.getManaAvailable(currentGame).size());
}
@Test
public void testSpliceTorrentOfStone() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
// Sorcery - Arcane {R}
// Lava Spike deals 3 damage to target player.
addCard(Zone.HAND, playerA, "Lava Spike",1);
// Torrent of Stone deals 4 damage to target creature.
// Splice onto Arcane-Sacrifice two Mountains. (As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)
addCard(Zone.HAND, playerA, "Torrent of Stone",1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion",1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lava Spike", playerB);
addTarget(playerA, "Silvercoat Lion");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 20);
assertLife(playerB, 17);
assertGraveyardCount(playerA, "Lava Spike", 1);
assertHandCount(playerA, "Torrent of Stone", 1);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
assertPermanentCount(playerA, "Mountain", 0);
Assert.assertEquals("No more mana available", "[]", playerA.getManaAvailable(currentGame).toString());
}
/**
* Nourishing Shoal's interaction with Splicing Through the Breach is
* bugged. You should still need to pay 2RR as an additional cost, which is
* not affected by the alternate casting method of Shoal, but you are able
* to Splice it for free. This is a very relevant bug right now due to the
* appearance of the deck over the weekend, and it makes the deck absurdly
* powerful.
*/
@Test
public void testSpliceThroughTheBreach2() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
// You may exile a green card with converted mana cost X from your hand rather than pay Nourishing Shoal's mana cost.
// You gain X life.
addCard(Zone.HAND, playerA, "Nourishing Shoal",1);
addCard(Zone.HAND, playerA, "Giant Growth",1);
// You may put a creature card from your hand onto the battlefield. That creature gains haste. Sacrifice that creature at the beginning of the next end step.
// Splice onto Arcane {2}{R}{R} (As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)
addCard(Zone.HAND, playerA, "Through the Breach",1);
addCard(Zone.HAND, playerA, "Silvercoat Lion",1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nourishing Shoal");
setChoice(playerA, "Yes");
setChoice(playerA, "Silvercoat Lion");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertLife(playerA, 21);
assertLife(playerB, 20);
assertGraveyardCount(playerA, "Nourishing Shoal", 1);
assertHandCount(playerA, "Through the Breach", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
assertAbility(playerA, "Silvercoat Lion", HasteAbility.getInstance(), true);
Assert.assertEquals("All available mana has to be used","[]", playerA.getManaAvailable(currentGame).toString());
}
}

View file

@ -30,6 +30,7 @@ package org.mage.test.cards.abilities.keywords;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
@ -163,5 +164,39 @@ public class StormTest extends CardTestPlayerBase {
assertLife(playerB, 16); // 3 (Lightning Bolt) + 1 from Storm copied Grapeshot
}
/**
* I provide a game log fo the issue with storm mentioned earlier. I guess Pyromancer Ascension is a culprit.
*
*
*/
@Test
public void testStormAndPyromancerAscension() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
// Whenever you cast an instant or sorcery spell that has the same name as a card in your graveyard, you may put a quest counter on Pyromancer Ascension.
// Whenever you cast an instant or sorcery spell while Pyromancer Ascension has two or more quest counters on it, you may copy that spell. You may choose new targets for the copy.
addCard(Zone.BATTLEFIELD, playerA, "Pyromancer Ascension", 1);
// Grapeshot deals 1 damage to target creature or player. - Sorcery {1}{R}
// Storm (When you cast this spell, copy it for each spell cast before it this turn. You may choose new targets for the copies.)
addCard(Zone.LIBRARY, playerA, "Grapeshot", 2);
skipInitShuffling();
// Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library.
addCard(Zone.HAND, playerA, "Sleight of Hand");
addCard(Zone.HAND, playerA, "Shock", 3);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sleight of Hand");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", playerB);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", "targetPlayer=PlayerB", "Shock", StackClause.WHILE_NOT_ON_STACK);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", "targetPlayer=PlayerB", "Shock", StackClause.WHILE_NOT_ON_STACK);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Grapeshot", playerB);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, "Shock", 3);
assertGraveyardCount(playerA, "Grapeshot", 1);
assertCounterCount("Pyromancer Ascension", CounterType.QUEST, 2);
assertLife(playerB, 8); // 6 from the Shocks + 5 from Grapeshot + 1 from Pyromancer Ascencsion copy
}
}

View file

@ -0,0 +1,68 @@
/*
* 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 mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class TransformTest extends CardTestPlayerBase{
@Test
public void NissaVastwoodSeerTest() {
addCard(Zone.LIBRARY, playerA, "Forest");
addCard(Zone.BATTLEFIELD, playerA, "Forest", 6);
// When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library.
// Whenever a land enters the battlefield under your control, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control.
addCard(Zone.HAND, playerA, "Nissa, Vastwood Seer");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nissa, Vastwood Seer");
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Forest", 7);
assertPermanentCount(playerA, "Nissa, Vastwood Seer", 0);
assertPermanentCount(playerA, "Nissa, Sage Animist", 1);
assertCounterCount("Nissa, Sage Animist", CounterType.LOYALTY, 3);
}
}

View file

@ -0,0 +1,72 @@
/*
* 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.counter;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class AddingCountersToPermanentsTest extends CardTestPlayerBase {
@Test
public void testBlackSunsZenith() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerA, "Witch's Familiar", 1);
// 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);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Black Sun's Zenith");
setChoice(playerA, "X=2");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Silvercoat Lion", 1);
assertGraveyardCount(playerB, "Silvercoat Lion", 1);
assertPermanentCount(playerA, "Witch's Familiar", 1);
assertPowerToughness(playerA, "Witch's Familiar", 0, 1);
assertPermanentCount(playerB, "Witch's Familiar", 1);
assertPowerToughness(playerB, "Witch's Familiar", 0, 1);
}
}

View file

@ -0,0 +1,80 @@
/*
* 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.counter;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class MovingCounterTest extends CardTestPlayerBase {
/**
* I'm having an issue when using Bioshift to move only a portion of
* counters to another creature. When I attempt to do this, it moves all of
* the counters (and in some cases with my Simic deck) kills the creature.
*/
@Test
public void testCantBeCounteredNormal() {
addCard(Zone.BATTLEFIELD, playerA, "Forest", 6);
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
// Move any number of +1/+1 counters from target creature onto another target creature with the same controller.
addCard(Zone.HAND, playerA, "Bioshift", 1);
// Protean Hydra enters the battlefield with X +1/+1 counters on it.
// If damage would be dealt to Protean Hydra, prevent that damage and remove that many +1/+1 counters from it.
// Whenever a +1/+1 counter is removed from Protean Hydra, put two +1/+1 counters on it at the beginning of the next end step.
addCard(Zone.HAND, playerA, "Protean Hydra", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Protean Hydra");
setChoice(playerA, "X=4");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Bioshift", "Protean Hydra^Silvercoat Lion");
setChoice(playerA, "X=2");
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertGraveyardCount(playerA, "Bioshift", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
assertPowerToughness(playerA, "Silvercoat Lion", 4, 4); // added 2 counters
assertPermanentCount(playerA, "Protean Hydra", 1);
assertPowerToughness(playerA, "Protean Hydra", 6, 6); // started with 4, removed 2, added 4 at end = 6
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package org.mage.test.cards.abilities.oneshot.counterspell;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class CounterspellTest extends CardTestPlayerBase {
/**
It looks like Boom//Bust can't be countered (although it says it's countered in the log).
Code: Select all
13:10: Benno casts Boom [8ce] targeting Mountain [4c8] Island [80c]
13:10: Benno casts Counterspell [2b7] targeting Boom [8ce]
13:10: Benno puts Boom [8ce] from stack into his or her graveyard
13:10: Boom is countered by Counterspell [2b7]
13:10: Benno puts Counterspell [2b7] from stack into his or her graveyard
13:10: Mountain [4c8] was destroyed
13:10: Island [80c] was destroyed
*/
@Test
public void testCounterSplitSpell() {
// Boom - Sorcery {1}{R}
// Destroy target land you control and target land you don't control.
addCard(Zone.HAND, playerA, "Boom // Bust");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
addCard(Zone.HAND, playerB, "Counterspell");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boom", "Mountain^Island");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Counterspell", "Boom");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerA, "Boom // Bust", 1);
assertGraveyardCount(playerB, "Counterspell", 1);
assertPermanentCount(playerA, "Mountain", 2);
assertPermanentCount(playerB, "Island", 2);
assertLife(playerA, 20);
assertLife(playerB, 20);
}
}

View file

@ -18,6 +18,12 @@ public class TwoFacedCardEffectsTest extends CardTestPlayerBase {
*/
@Test
public void testEffectTurnedOffOnTransform() {
// Other Human creatures you control get +1/+1.
// At the beginning of each upkeep, if no spells were cast last turn, transform Mayor of Avabruck.
// Howlpack Alpha (transformed side) ----------------
// Each other creature you control that's a Werewolf or a Wolf gets +1/+1.
// At the beginning of your end step, put a 2/2 green Wolf creature token onto the battlefield.
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Howlpack Alpha.
addCard(Zone.BATTLEFIELD, playerA, "Mayor of Avabruck");
addCard(Zone.BATTLEFIELD, playerA, "Wolfir Avenger");
addCard(Zone.BATTLEFIELD, playerA, "Elite Inquisitor");

View file

@ -0,0 +1,94 @@
/*
* 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.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class SerraAscendantTest extends CardTestPlayerBase {
/**
* The game goes on; he plays his Serra Ascendant on turn one, passes the
* turn, you play your newly unbanned Wild Nacatl with a Stomping Ground and
* also pass the turn. On turn 2, he casts a Martyr of Sands and sacrifices
* it, revealing 3 white cards to gain 9 life and end up at 29. He goes to
* the combat phase, declares Serra as an attacker, and you happily block
* him, thinking that this is such a bad move from him. After the damage is
* dealt, the Serra is still there, bigger than ever.
*/
@Test
public void testSilence() {
addCard(Zone.HAND, playerA, "Plains", 2);
// As long as you have 30 or more life, Serra Ascendant gets +5/+5 and has flying.
addCard(Zone.HAND, playerA, "Serra Ascendant");
// {1}, Reveal X white cards from your hand, Sacrifice Martyr of Sands: You gain three times X life.
addCard(Zone.HAND, playerA, "Martyr of Sands");
addCard(Zone.HAND, playerA, "Silvercoat Lion",3);
addCard(Zone.HAND, playerB, "Stomping Ground", 1);
addCard(Zone.HAND, playerB, "Wild Nacatl", 1);
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Serra Ascendant");
playLand(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Stomping Ground");
setChoice(playerB, "Yes");
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Wild Nacatl");
playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains");
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Martyr of Sands");
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{1},You may reveal X white cards from your hand");
setChoice(playerA,"X=3");
attack(3, playerA, "Serra Ascendant");
block(3, playerB, "Wild Nacatl", "Serra Ascendant");
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertGraveyardCount(playerA, "Martyr of Sands", 1);
assertLife(playerB, 18);
assertLife(playerA, 30);
assertPermanentCount(playerB, "Wild Nacatl", 1);
assertPermanentCount(playerA, "Serra Ascendant", 1);
assertPowerToughness(playerA, "Serra Ascendant", 6, 6);
}
}

View file

@ -0,0 +1,210 @@
/*
* 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 PhyrexianMetamorphTest extends CardTestPlayerBase {
@Test
public void testCopyCreature() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
// You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types.
addCard(Zone.HAND, playerA, "Phyrexian Metamorph"); // {3}{UP}
addCard(Zone.HAND, playerA, "Cloudshift");
//Flying
// Vanishing 3 (This permanent enters the battlefield with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.)
// When Aven Riftwatcher enters the battlefield or leaves the battlefield, you gain 2 life.
addCard(Zone.BATTLEFIELD, playerB, "Aven Riftwatcher"); // 2/3
// When Ponyback Brigade enters the battlefield or is turned face up, put three 1/1 red Goblin creature tokens onto the battlefield.
addCard(Zone.BATTLEFIELD, playerB, "Ponyback Brigade"); // 2/2
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph");
setChoice(playerA, "Aven Riftwatcher");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cloudshift", "Aven Riftwatcher");
setChoice(playerA, "Ponyback Brigade");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertLife(playerA, 24);
assertLife(playerB, 20);
assertGraveyardCount(playerA, "Cloudshift", 1);
assertPermanentCount(playerA, "Ponyback Brigade", 1);
assertPermanentCount(playerA, "Goblin", 3);
}
/**
* An opponent cast Phyrexian Metamorph and cloned another opponent's
* Maelstrom Wanderer(his Commander). The first opponent then dealt combat
* damage with Brago, King Eternal and chose to flicker several permanents,
* including the Phyrexian Metamorph/Maelstrom Wanderer, but he was not able
* to choose a new creature to clone when the Phyrexian Metamorph re-entered
* the battlefield.
*/
@Test
public void testFlickerWithBrago() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
// You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types.
addCard(Zone.HAND, playerA, "Phyrexian Metamorph"); // {3}{UP}
// 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, playerA, "Brago, King Eternal"); // 2/4
// Creatures you control have haste.
// Cascade, cascade
addCard(Zone.BATTLEFIELD, playerB, "Maelstrom Wanderer"); // 7/5
// When Ponyback Brigade enters the battlefield or is turned face up, put three 1/1 red Goblin creature tokens onto the battlefield.
addCard(Zone.BATTLEFIELD, playerB, "Ponyback Brigade"); // 2/2
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph");
setChoice(playerA, "Maelstrom Wanderer");
attack(3, playerA, "Brago, King Eternal");
addTarget(playerA, "Maelstrom Wanderer");
setChoice(playerA, "Ponyback Brigade");
setStopAt(3, PhaseStep.END_COMBAT);
execute();
assertLife(playerA, 20);
assertLife(playerB, 18);
assertPermanentCount(playerA, "Ponyback Brigade", 1);
assertPermanentCount(playerA, "Goblin", 3);
}
/**
* I had a Harmonic Sliver, my opponent played Phyrexian Metamorph copying
* it. The resulting copy only had one instance of the artifact-enchantment
* destroying ability, where it should have had two of them and triggered
* twice (the Metamorph might have nothing to do with this)
*/
@Test
public void testHarmonicSliver() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
// You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types.
addCard(Zone.HAND, playerA, "Phyrexian Metamorph"); // {3}{UP}
addCard(Zone.BATTLEFIELD, playerB, "Alloy Myr", 1);
addCard(Zone.BATTLEFIELD, playerB, "Kitesail", 1);
// All Slivers have "When this permanent enters the battlefield, destroy target artifact or enchantment."
addCard(Zone.BATTLEFIELD, playerB, "Harmonic Sliver"); // 2/4
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph");
setChoice(playerA, "Harmonic Sliver");
addTarget(playerA, "Alloy Myr");
addTarget(playerA, "Kitesail");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerA, "Harmonic Sliver", 1);
assertGraveyardCount(playerB, "Alloy Myr", 1);
assertGraveyardCount(playerB, "Kitesail", 1);
}
/**
* If a Harmonic Sliver enters the battlefield
* the controller has to destroy one artifacts or enchantments
*/
@Test
public void testHarmonicSliverNative1() {
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
// All Slivers have "When this permanent enters the battlefield, destroy target artifact or enchantment."
addCard(Zone.HAND, playerA, "Harmonic Sliver");
addCard(Zone.BATTLEFIELD, playerB, "Alloy Myr", 2); // 2/2
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Harmonic Sliver");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerA, "Harmonic Sliver", 1);
assertGraveyardCount(playerB, "Alloy Myr", 1);
}
/**
* If a Harmonic Sliver enters the battlefield and there is already one on the battlefield
* the controller has to destroy two artifacts or enchantments
*/
@Test
public void testHarmonicSliverNative2() {
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Zone.HAND, playerA, "Harmonic Sliver");
addCard(Zone.BATTLEFIELD, playerB, "Alloy Myr", 1);
addCard(Zone.BATTLEFIELD, playerB, "Kitesail", 1);
// All Slivers have "When this permanent enters the battlefield, destroy target artifact or enchantment."
addCard(Zone.BATTLEFIELD, playerB, "Harmonic Sliver"); // 2/4
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Harmonic Sliver");
addTarget(playerA, "Alloy Myr");
addTarget(playerA, "Kitesail");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerA, "Harmonic Sliver", 1);
assertGraveyardCount(playerB, "Alloy Myr", 1);
assertGraveyardCount(playerB, "Kitesail", 1);
}
}

View file

@ -0,0 +1,97 @@
/*
* 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.abilities.keyword.FlyingAbility;
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 TheMimeoplasmTest extends CardTestPlayerBase {
/**
* I cast either Phyrexian Metamorph or Phantasmal Image and copied The
* Mimeoplasm which was copying a Primeval Titan, but my clone became
* another Mimeoplasm, so it exiled two creatures from graveyards and cloned
* one of those instead.
*
* Copying cards that are copy of other cards copies the original, rather
* than the copy.
* To wit, when The Mimeoplasm is out (and lets say is a copy of Elvish
* Mystic), and someone then plays Clone choosing to enter as the cloned
* Elvish Mystic, they are incorrectly getting The Mimeoplasm instead.
*
*/
@Test
public void testCloneMimeoplasm() {
// As The Mimeoplasm enters the battlefield, you may exile two creature cards from graveyards.
// If you do, it enters the battlefield as a copy of one of those cards with a number of additional +1/+1 counters on it equal to the power of the other card.
addCard(Zone.HAND, playerA, "The Mimeoplasm", 1); // {2}{G}{U}{B}
addCard(Zone.HAND, playerA, "Clone", 1); // {3}{U}
addCard(Zone.GRAVEYARD, playerB, "Silvercoat Lion", 1); // 2/2
addCard(Zone.GRAVEYARD, playerB, "Aven Riftwatcher", 1); // 2/3
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 7);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
castSpell(1,PhaseStep.PRECOMBAT_MAIN, playerA, "The Mimeoplasm");
setChoice(playerA, "Aven Riftwatcher");
setChoice(playerA, "Silvercoat Lion");
castSpell(1,PhaseStep.PRECOMBAT_MAIN, playerA, "Clone");
setChoice(playerA, "Aven Riftwatcher");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertHandCount(playerA, "Clone", 0);
assertLife(playerA, 24);
assertLife(playerB, 20);
assertPermanentCount(playerA, "Aven Riftwatcher", 2);
assertPowerToughness(playerA, "Aven Riftwatcher", 4, 5);
assertPowerToughness(playerA, "Aven Riftwatcher", 2, 3);
assertGraveyardCount(playerB, 0);
}
}

View file

@ -66,6 +66,31 @@ public class CantAttackTest extends CardTestPlayerBase {
assertLife(playerB, 14); // 4 + 2
}
@Test
public void testAttackHarborSerpent() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); // 2/2
addCard(Zone.BATTLEFIELD, playerA, "Harbor Serpent"); // 5/5
addCard(Zone.HAND, playerA, "Island");
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); // 2/2
addCard(Zone.BATTLEFIELD, playerB, "Harbor Serpent"); // 5/5
attack(2, playerB, "Harbor Serpent");
attack(2, playerB, "Silvercoat Lion");
playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Island");
attack(3, playerA, "Harbor Serpent");
attack(3, playerA, "Silvercoat Lion");
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 13);
assertLife(playerA, 18);
}
}

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.single;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class SoulFoundryTest extends CardTestPlayerBase {
/**
* Soul Foundry imprinted with Bloodline Keeper costs 8 colorless mana to
* use the ability instead of 4 (the converted mana cost of Bloodline
* Keeper).
*/
@Test
public void testBloodlineKeeper() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 8);
// Imprint - When Soul Foundry enters the battlefield, you may exile a creature card from your hand.
// {X}, {T}: Put a token that's a copy of the exiled card onto the battlefield. X is the converted mana cost of that card.
addCard(Zone.HAND, playerA, "Soul Foundry"); // {4}
addCard(Zone.HAND, playerA, "Bloodline Keeper");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Soul Foundry");
setChoice(playerA, "Yes");
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{X},{T}: Put a token");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Soul Foundry", 1);
assertExileCount("Bloodline Keeper", 1);
assertPermanentCount(playerA, "Bloodline Keeper", 1);
}
}

View file

@ -0,0 +1,95 @@
/*
* 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.cards.Card;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class PossibilityStormTest extends CardTestPlayerBase {
/**
* There's currently a bug with Possibility Storm and Zoetic Cavern. The way
* it's supposed to work is the P. Storm trigger exiles Zoetic Cavern and
* then uses last known information about the spell to determine the type of
* card the trigger is looking for(creature in this instance). Instead it's
* basing the type solely off what's printed on the card. What happened to
* me earlier was the trigger skipped right over an Emrakul and then
* revealed a Flooded Strand. I was prompted whether or not I wanted to
* "cast" Flooded Strand without paying it's cost. Eventually I clicked yes
* and it produced a Game Error that resulted in rollback. I recreated the
* error against an AI opponent and copied the code. Can't actually post it
* because the filter on this site claims it makes my post look too
* "spammy". Here's a screenshot of it instead(in spoiler tag).
*/
@Test
public void TestWithZoeticCavern() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
// Whenever a player casts a spell from his or her hand, that player exiles it, then exiles cards from
// the top of his or her library until he or she exiles a card that shares a card type with it. That
// player may cast that card without paying its mana cost. Then he or she puts all cards exiled with
// Possibility Storm on the bottom of his or her library in a random order.
addCard(Zone.BATTLEFIELD, playerA, "Possibility Storm", 2);
// {T}: Add {1} to your mana pool.
// Morph {2}
addCard(Zone.HAND, playerA, "Zoetic Cavern");
addCard(Zone.LIBRARY, playerA, "Silvercoat Lion");
skipInitShuffling();
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Zoetic Cavern");
setChoice(playerA, "Yes");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Zoetic Cavern", 0);
boolean zoeticCavernInLibrary = false;
for (Card card: playerA.getLibrary().getCards(currentGame)) {
if (card.getName().equals("Zoetic Cavern")) {
zoeticCavernInLibrary = true;
}
}
Assert.assertEquals("Zoetic Cavern has to be in the library", true, zoeticCavernInLibrary);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
}
}

View file

@ -113,4 +113,45 @@ public class SpellskiteTest extends CardTestPlayerBase {
}
/**
* Spellskite fails to redirect Cryptic Command on itself
*/
@Test
public void testSpellskite() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
// Choose two -
// Counter target spell;
// or return target permanent to its owner's hand;
// or tap all creatures your opponents control;
// or draw a card.
addCard(Zone.HAND, playerA, "Cryptic Command");
addCard(Zone.BATTLEFIELD, playerB, "Spellskite", 1);
addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
addCard(Zone.BATTLEFIELD, playerB, "Island", 1);
addCard(Zone.HAND, playerB, "Lightning Bolt", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cryptic Command", "mode=1Lightning Bolt^mode=2Silvercoat Lion", "Lightning Bolt");
setModeChoice(playerA, "1"); // Counter target spell
setModeChoice(playerA, "2"); // return target permanent to its owner's hand
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Cryptic Command");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerB, "Lightning Bolt", 1);
assertGraveyardCount(playerA, "Cryptic Command", 1);
assertHandCount(playerB, "Spellskite", 1);
assertPermanentCount(playerB, "Silvercoat Lion", 1);
assertLife(playerA, 20);
assertLife(playerB, 20);
}
}

View file

@ -7,6 +7,7 @@ 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;
@ -116,4 +117,73 @@ public class WorldgorgerDragonTest extends CardTestPlayerBase {
}
/**
* v9: Worldgorger Dragon + Animate Dead is still acting up (yey complex rules interactions!).
* The first time you return Animate Dead from Worldgorger's exile, it works like it's supposed
* to. You have to pick a creature, and it brings it back. But if you pick Worldgorger Dragon
* again, it allows you to not pick a creature, and regardless of whether you choose to skip or pick
* a different creature, it always returns the first creature you picked. Kind of hard to explain,
* but here's how to reproduce:
*
* 1) Cast Animate Dead, targeting Worldgorger Dragon
* 2) Worldgorger Dragon will exile Animate Dead, killing the dragon and returning the permanents
* 3) Select Worldgorger again
* 4) Step 2 repeats
* 5) Attempt to select a different creature. Worldgorger Dragon is returned instead.
*
*/
@Test
@Ignore
public void testWithAnimateDeadDifferentTargets() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
// When Worldgorger Dragon enters the battlefield, exile all other permanents you control.
// When Worldgorger Dragon leaves the battlefield, return the exiled cards to the battlefield under their owners' control.
addCard(Zone.GRAVEYARD, playerA, "Worldgorger Dragon", 1);
addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 1);
// When Animate Dead enters the battlefield, if it's on the battlefield, it loses "enchant creature card in a graveyard"
// and gains "enchant creature put onto the battlefield with Animate Dead." Return enchanted creature card to the battlefield
// under your control and attach Animate Dead to it. When Animate Dead leaves the battlefield, that creature's controller sacrifices it.
addCard(Zone.HAND, playerA, "Animate Dead");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
// Instant {X}{R}{R}
// Volcanic Geyser deals X damage to target creature or player.
addCard(Zone.HAND, playerA, "Volcanic Geyser", 1);
// When Staunch Defenders enters the battlefield, you gain 4 life.
addCard(Zone.BATTLEFIELD, playerA, "Staunch Defenders", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Animate Dead", "Worldgorger Dragon");
addTarget(playerA, "Worldgorger Dragon");
addTarget(playerA, "Worldgorger Dragon");
addTarget(playerA, "Silvercoat Lion");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Volcanic Geyser", playerB, 9);
setChoice(playerA, "X=7");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Worldgorger Dragon", 1);
assertPermanentCount(playerA, "Silvercoat Lion", 1);
assertLife(playerA, 24);
assertLife(playerB, 11);
assertGraveyardCount(playerA, "Volcanic Geyser", 1);
}
}

View file

@ -0,0 +1,65 @@
package org.mage.test.cards.triggers.dies;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/*
* 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.
*/
/**
*
* @author LevelX2
*/
public class FecundityTest extends CardTestPlayerBase {
/**
*
*/
@Test
public void testOpponentDrawsACard() {
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
// Whenever a creature dies, that creature's controller may draw a card.
addCard(Zone.BATTLEFIELD, playerB, "Fecundity", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Silvercoat Lion");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Lightning Bolt", 1);
assertGraveyardCount(playerA, "Silvercoat Lion", 1);
assertHandCount(playerA, 1);
}
}

View file

@ -38,7 +38,7 @@ import org.mage.test.serverside.base.CardTestCommanderDuelBase;
*/
public class CastCommanderTest extends CardTestCommanderDuelBase {
@Test
public void testFirstAbility() {
public void testCastCommander() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ob Nixilis of the Black Oath");
@ -50,5 +50,5 @@ public class CastCommanderTest extends CardTestCommanderDuelBase {
assertLife(playerB, 40);
assertPermanentCount(playerA, "Ob Nixilis of the Black Oath", 1);
}
}
}

View file

@ -0,0 +1,98 @@
/*
* 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.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
/**
*
* @author LevelX2
*/
public class TeferiMageOfZhalfirTest extends CardTestCommanderDuelBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
setDecknamePlayerA("CommanderDuel_UW.dck"); // Commander = Daxos of Meletis
return super.createNewGameAndPlayers();
}
@Test
public void castCommanderWithFlash() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
addCard(Zone.BATTLEFIELD, playerA, "Teferi, Mage of Zhalfir");
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Daxos of Meletis");
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertPermanentCount(playerA, "Daxos of Meletis", 1);
}
@Test
public void testCommanderDamage() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 6);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
// Enchant creature
// Enchanted creature gets +4/+4, has flying and first strike, and is an Angel in addition to its other types.
// When enchanted creature dies, return Angelic Destiny to its owner's hand.
addCard(Zone.HAND, playerA, "Angelic Destiny");
addCard(Zone.BATTLEFIELD, playerA, "Teferi, Mage of Zhalfir");
// Daxos of Meletis can't be blocked by creatures with power 3 or greater.
// Whenever Daxos of Meletis deals combat damage to a player, exile the top card of that player's library. You gain life equal to that card's converted mana cost. Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast it.
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Daxos of Meletis");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Angelic Destiny","Daxos of Meletis");
attack(3, playerA, "Daxos of Meletis");
attack(5, playerA, "Daxos of Meletis");
attack(7, playerA, "Daxos of Meletis");
attack(9, playerA, "Daxos of Meletis");
setStopAt(9, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertPermanentCount(playerA, "Daxos of Meletis", 1);
assertPowerToughness(playerA, "Daxos of Meletis", 6, 6);
Assert.assertEquals("Player A has won because of commander damage", true, playerA.hasWon());
Assert.assertEquals("Player A has lost because of commander damage", true, playerB.hasLost());
}
}

View file

@ -29,6 +29,7 @@ package org.mage.test.player;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -91,6 +92,7 @@ import mage.target.TargetPermanent;
import mage.target.TargetPlayer;
import mage.target.TargetSource;
import mage.target.TargetSpell;
import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetCreaturePermanentAmount;
@ -604,17 +606,53 @@ public class TestPlayer implements Player {
}
}
}
if (target instanceof TargetCardInGraveyard) {
TargetCardInGraveyard targetCardInGraveyard = ((TargetCardInGraveyard) target);
Set<UUID> possibleTargets = new HashSet<>();
for(UUID playerId: this.getInRange()) {
Player player = game.getPlayer(playerId);
if (player != null) {
possibleTargets.addAll(player.getGraveyard());
}
}
for (String choose2 : choices) {
String[] targetList = choose2.split("\\^");
boolean targetFound = false;
for (UUID targetId : possibleTargets) {
MageObject targetObject = game.getObject(targetId);
if (targetObject != null) {
for (String targetName : targetList) {
if (targetObject.getName().equals(targetName)) {
List<UUID> alreadyTargetted = targetCardInGraveyard.getTargets();
if (targetCardInGraveyard.canTarget(targetObject.getId(), game)) {
if (alreadyTargetted != null && !alreadyTargetted.contains(targetObject.getId())) {
targetCardInGraveyard.add(targetObject.getId(), game);
choices.remove(choose2);
targetFound = true;
}
}
}
}
if (targetFound && targetCardInGraveyard.isChosen()) {
choices.remove(choose2);
return true;
}
}
}
}
}
if (target instanceof TargetSource) {
Set<UUID> possibleTargets;
TargetSource t = ((TargetSource) target);
possibleTargets = t.possibleTargets(sourceId, computerPlayer.getId(), game);
for (UUID targetId : possibleTargets) {
MageObject targetObject = game.getObject(targetId);
if (targetObject != null) {
for (String choose2 : choices) {
String[] targetList = choose2.split("\\^");
boolean targetFound = false;
for (String targetName : targetList) {
for (String choose2 : choices) {
String[] targetList = choose2.split("\\^");
boolean targetFound = false;
for (String targetName : targetList) {
for (UUID targetId : possibleTargets) {
MageObject targetObject = game.getObject(targetId);
if (targetObject != null) {
if (targetObject.getName().equals(targetName)) {
List<UUID> alreadyTargetted = target.getTargets();
if (t.canTarget(targetObject.getId(), game)) {

View file

@ -42,12 +42,18 @@ import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl;
public abstract class CardTestCommanderDuelBase extends CardTestPlayerAPIImpl {
public CardTestCommanderDuelBase() {
super();
this.deckNameA = "CommanderDuel.dck";
this.deckNameB = "CommanderDuel.dck";
}
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new CommanderDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0, 40);
playerA = createPlayer(game, playerA, "PlayerA","CommanderDuel.dck");
playerB = createPlayer(game, playerB, "PlayerB","CommanderDuel.dck");
playerA = createPlayer(game, playerA, "PlayerA",deckNameA);
playerB = createPlayer(game, playerB, "PlayerB",deckNameB);
return game;
}

View file

@ -15,12 +15,17 @@ import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl;
*/
public abstract class CardTestPlayerBase extends CardTestPlayerAPIImpl {
public CardTestPlayerBase() {
deckNameA = "RB Aggro.dck";
deckNameB = "RB Aggro.dck";
}
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0, 20);
playerA = createPlayer(game, playerA, "PlayerA");
playerB = createPlayer(game, playerB, "PlayerB");
playerA = createPlayer(game, playerA, "PlayerA", deckNameA);
playerB = createPlayer(game, playerB, "PlayerB", deckNameB);
return game;
}

View file

@ -44,6 +44,9 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
protected GameOptions gameOptions;
protected String deckNameA;
protected String deckNameB;
protected enum ExpectedType {
TURN_NUMBER,
RESULT,
@ -1009,6 +1012,14 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
player.addTarget("targetPlayer="+targetPlayer.getName());
}
public void setDecknamePlayerA(String deckname) {
deckNameA = deckname;
}
public void setDecknamePlayerB(String deckname) {
deckNameB = deckname;
}
protected void skipInitShuffling() {
gameOptions.skipInitShuffling = true;
}