Merge pull request #11417 from ssk97/TagTracking3_KeywordAbilities

Costs Tag Tracking part 3: Most keyword abilities
This commit is contained in:
xenohedron 2023-11-20 21:28:40 -05:00 committed by GitHub
commit 4977fea307
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 510 additions and 404 deletions

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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
}
}

View file

@ -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);

View file

@ -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);
}
}