mirror of
https://github.com/magefree/mage.git
synced 2025-12-21 19:11:59 -08:00
Merge pull request #11417 from ssk97/TagTracking3_KeywordAbilities
Costs Tag Tracking part 3: Most keyword abilities
This commit is contained in:
commit
4977fea307
40 changed files with 510 additions and 404 deletions
|
|
@ -67,6 +67,48 @@ public class BlitzTest extends CardTestPlayerBase {
|
|||
assertHandCount(playerA, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlitzCopy() {
|
||||
//Copying the spell on the stack must include the Blitz ability activation
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6);
|
||||
addCard(Zone.HAND, playerA, decoy);
|
||||
addCard(Zone.HAND, playerA, "Double Major");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, decoy + withBlitz);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major",decoy);
|
||||
|
||||
setChoice(playerA, ""); //stack triggers
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, decoy, 0);
|
||||
assertGraveyardCount(playerA, decoy, 1);
|
||||
assertGraveyardCount(playerA, "Double Major", 1);
|
||||
assertHandCount(playerA, 2);
|
||||
}
|
||||
@Test
|
||||
public void testBlitzClone() {
|
||||
//Copying the creature permanent must not include Blitz activation
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8);
|
||||
addCard(Zone.HAND, playerA, decoy);
|
||||
addCard(Zone.HAND, playerA, "Clone");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, decoy + withBlitz);
|
||||
waitStackResolved(1,PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clone");
|
||||
setChoice(playerA,true);
|
||||
setChoice(playerA,decoy);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, decoy, 1);
|
||||
assertGraveyardCount(playerA, decoy, 1);
|
||||
assertHandCount(playerA, 1);
|
||||
}
|
||||
@Test
|
||||
public void testNoBlitz() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
|
||||
|
|
|
|||
|
|
@ -70,5 +70,41 @@ public class EchoTest extends CardTestPlayerBase {
|
|||
assertTappedCount("Mountain", true, 0);
|
||||
}
|
||||
|
||||
//Deranged Hermit has been cloned with Phantasmal Image.
|
||||
//The Phantasmal Image version of the Deranged Hermit had to pay the echo cost multiple times.
|
||||
@Test
|
||||
public void testEchoTriggerClone() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 15);
|
||||
// Deranged Hermit {3}{G}{G}
|
||||
// Echo
|
||||
addCard(Zone.HAND, playerA, "Deranged Hermit");
|
||||
addCard(Zone.HAND, playerA, "Phantasmal Image");
|
||||
addCard(Zone.HAND, playerA, "Double Major");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Deranged Hermit");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major", "Deranged Hermit");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
|
||||
setChoice(playerA, true);
|
||||
setChoice(playerA, "Deranged Hermit");
|
||||
|
||||
setChoice(playerA, ""); //stack triggers
|
||||
setChoice(playerA, "");
|
||||
|
||||
setChoice(playerA, true); //Pay echo costs
|
||||
setChoice(playerA, true);
|
||||
setChoice(playerA, true);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
assertPermanentCount(playerA, "Deranged Hermit", 3);
|
||||
assertTappedCount("Tropical Island", true, 15);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
|
||||
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 notgreat
|
||||
*/
|
||||
public class SpectacleTest extends CardTestPlayerBase {
|
||||
@Test
|
||||
public void testWithoutSpectacleBasic() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1+4);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt"); // {R}
|
||||
addCard(Zone.HAND, playerA, "Spikewheel Acrobat"); // {3}{R}, Spectacle {2}{R}
|
||||
|
||||
checkPlayableAbility("Can't cast with Spectacle yet", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Spikewheel Acrobat with spectacle", false);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
waitStackResolved(1,PhaseStep.PRECOMBAT_MAIN);
|
||||
checkPlayableAbility("Can cast with Spectacle", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Spikewheel Acrobat with spectacle", true);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spikewheel Acrobat");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA,"Spikewheel Acrobat",1);
|
||||
assertTappedCount("Mountain",true,1+4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithoutSpectacleTriggerAfterDamage() {
|
||||
// Rafter Demon {2}{B}{R}
|
||||
// Spectacle {3}{B}{R}
|
||||
// When Rafter Demon enters the battlefield, if its spectacle cost was paid, each opponent discards a card.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Badlands", 6);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt"); // {R}
|
||||
addCard(Zone.HAND, playerA, "Rafter Demon"); // {2}{B}{R}
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
waitStackResolved(1,PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rafter Demon");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA,"Rafter Demon",1);
|
||||
assertTappedCount("Badlands",true,5);
|
||||
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||
assertLife(playerB, 17);
|
||||
assertGraveyardCount(playerB, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithSpectacle() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt"); // {R}
|
||||
addCard(Zone.HAND, playerA, "Spikewheel Acrobat"); // Spectacle {2}{R}
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt",playerB);
|
||||
waitStackResolved(1,PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spikewheel Acrobat with spectacle");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA,"Spikewheel Acrobat",1);
|
||||
assertTappedCount("Mountain",true,4);
|
||||
assertLife(playerB, 17);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRafterDemonCopyClone() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Badlands", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Wastes", 5);
|
||||
// Rafter Demon {2}{B}{R}
|
||||
// Spectacle {3}{B}{R}
|
||||
// When Rafter Demon enters the battlefield, if its spectacle cost was paid, each opponent discards a card.
|
||||
addCard(Zone.HAND, playerA, "Rafter Demon");
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
addCard(Zone.HAND, playerB, "Darksteel Relic",5);
|
||||
|
||||
addCard(Zone.HAND, playerA, "Double Major");
|
||||
addCard(Zone.HAND, playerA, "Clone");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rafter Demon with spectacle");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major");
|
||||
addTarget(playerA, "Rafter Demon");
|
||||
addTarget(playerB, "Darksteel Relic",2);
|
||||
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
checkGraveyardCount("Discard x2", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Darksteel Relic", 2);
|
||||
checkPermanentCount("Rafter Demon x2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rafter Demon", 2);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clone");
|
||||
setChoice(playerA, true); // copy
|
||||
setChoice(playerA, "Rafter Demon");
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||
assertGraveyardCount(playerB, 2);
|
||||
assertHandCount(playerB, "Darksteel Relic", 3);
|
||||
assertPermanentCount(playerA, "Rafter Demon", 3);
|
||||
|
||||
assertLife(playerB, 17);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void SnapcasterMageWithSpectacle() {
|
||||
//Should not be castable with Spectacle on flashback, since that's two alternative casts at once
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 3+2+2);
|
||||
|
||||
addCard(Zone.HAND, playerA, "Snapcaster Mage", 1);
|
||||
addCard(Zone.HAND, playerA, "Skewer the Critics", 1);
|
||||
addCard(Zone.HAND, playerA, "Snapcaster Mage", 1);
|
||||
addCard(Zone.HAND, playerA, "Pyretic Ritual", 1);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Skewer the Critics", playerB);
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage");
|
||||
addTarget(playerA, "Skewer the Critics");
|
||||
|
||||
checkPlayableAbility("No flashback with Spectacle available", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback", false );
|
||||
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Pyretic Ritual", true);
|
||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback");
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
setStrictChooseMode(true);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20-3-3);
|
||||
assertTappedCount("Volcanic Island", true, 3+2+2);
|
||||
assertExileCount("Skewer the Critics", 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -280,9 +280,7 @@ public class SquadTest extends CardTestPlayerBase {
|
|||
assertPermanentCount(playerA, flagellant, 3); // One original + its squad buddy + the squad buddy from the additional trigger
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
//TODO: Enable after fixing clones activating it if they have the same zcc. Also affects Kicker
|
||||
public void test_CloneMustNotCopySquad() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, swamp, 8); // 3 + 2 + 3
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
|
|
|
|||
|
|
@ -53,4 +53,34 @@ public class AlteredEgoTest extends CardTestPlayerBase {
|
|||
assertGraveyardCount(playerA, "Altered Ego", 1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* If the chosen creature has {X} in its mana cost, that X is considered to be 0.
|
||||
* The value of X in Altered Ego's last ability will be whatever value was chosen for X while casting Altered Ego.
|
||||
* (2016-04-08)
|
||||
*/
|
||||
@Test
|
||||
public void copyXCreature() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Wastes", 2);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Tropical Island", 7);
|
||||
addCard(Zone.HAND, playerA, "Endless One"); // {X}, ETB with X +1/+1 counters, 0/0
|
||||
addCard(Zone.HAND, playerB, "Altered Ego"); // {X}{2}{G}{U}
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Endless One");
|
||||
setChoice(playerA, "X=2");
|
||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Altered Ego");
|
||||
setChoice(playerB, "X=3");
|
||||
setChoice(playerB, true); // use copy
|
||||
setChoice(playerB, "Endless One"); // copy target
|
||||
setChoice(playerB, ""); // Order place counters effects
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Endless One", 1);
|
||||
assertPowerToughness(playerA, "Endless One", 2, 2);
|
||||
assertPermanentCount(playerB, "Endless One", 1);
|
||||
assertPowerToughness(playerB, "Endless One", 3, 3); //The X should not be copied
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ public class CopyPermanentSpellTest extends CardTestPlayerBase {
|
|||
assertPowerToughness(playerA, "Aether Figment", 3, 3, Filter.ComparisonScope.All);
|
||||
}
|
||||
|
||||
@Ignore // currently fails
|
||||
@Test
|
||||
public void testSurgeTrigger() {
|
||||
makeTester();
|
||||
|
|
@ -121,7 +120,7 @@ public class CopyPermanentSpellTest extends CardTestPlayerBase {
|
|||
addCard(Zone.HAND, playerA, "Memnite");
|
||||
addCard(Zone.HAND, playerA, "Reckless Bushwhacker");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Memnite");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Memnite", true);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reckless Bushwhacker with surge");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
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 notgreat
|
||||
*/
|
||||
public class CostTagCopyCloneTests extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void KickerETBCountersClone() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 11);
|
||||
addCard(Zone.HAND, playerA, "Aether Figment");
|
||||
addCard(Zone.HAND, playerA, "Clone");
|
||||
addCard(Zone.HAND, playerA, "Shrivel");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aether Figment");
|
||||
setChoice(playerA, true); // with Kicker
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, false);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clone");
|
||||
setChoice(playerA, true); // use copy
|
||||
setChoice(playerA, "Aether Figment"); // copy target
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, false);
|
||||
|
||||
// since Clone wasn't kicked, it's a 1/1. Cast Shrivel to easily separate
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shrivel");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, false);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Aether Figment", 1);
|
||||
assertGraveyardCount(playerA, "Clone", 1);
|
||||
}
|
||||
@Test
|
||||
public void XCountersCopyClone() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 7);
|
||||
addCard(Zone.HAND, playerA, "Endless One");
|
||||
addCard(Zone.HAND, playerA, "Clone");
|
||||
addCard(Zone.HAND, playerA, "Double Major");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Endless One");
|
||||
setChoice(playerA, "X=1");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major");
|
||||
addTarget(playerA, "Endless One");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clone");
|
||||
setChoice(playerA, true);
|
||||
setChoice(playerA, "Endless One"); // since Clone doesn't copy X, it's a 0/0 and dies
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Endless One", 2);
|
||||
assertGraveyardCount(playerA, "Clone", 1);
|
||||
}
|
||||
@Test
|
||||
public void ETBXClone() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 4+4);
|
||||
addCard(Zone.HAND, playerA, "Defenders of Humanity");
|
||||
addCard(Zone.HAND, playerA, "Clever Impersonator");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Defenders of Humanity");
|
||||
setChoice(playerA, "X=1");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, false);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator");
|
||||
setChoice(playerA, true);
|
||||
setChoice(playerA, "Defenders of Humanity"); //clones don't copy X
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, false);
|
||||
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA,"Defenders of Humanity",2);
|
||||
assertPermanentCount(playerA,"Astartes Warrior Token",1);
|
||||
}
|
||||
@Test
|
||||
public void ETBXCopy() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 4+1);
|
||||
addCard(Zone.HAND, playerA, "Defenders of Humanity");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Overloaded Mage-Ring");
|
||||
|
||||
assertPermanentCount(playerA,"Astartes Warrior Token",0);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Defenders of Humanity");
|
||||
setChoice(playerA, "X=1");
|
||||
|
||||
activateAbility(1,PhaseStep.PRECOMBAT_MAIN,playerA,
|
||||
"{1}, {T}, Sacrifice {this}: Copy target spell you control.",
|
||||
"Defenders of Humanity");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA,"Defenders of Humanity",2);
|
||||
assertPermanentCount(playerA,"Astartes Warrior Token",2);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue