dies triggers improves:

* tests: added additional tests and verify/runtime checks for wrong die trigger settings;
* refactor: removed some usage of short LKI ;
* fixed dies events support in "or trigger" and "conditional trigger" (use cases like sacrifice cost);
* fixed dies events support in shared triggered abilities (use cases like sacrifice cost);
This commit is contained in:
Oleg Agafonov 2024-11-04 23:55:14 +04:00
parent a2ed52b8de
commit 66b338c6fc
18 changed files with 233 additions and 63 deletions

View file

@ -668,4 +668,66 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
assertTrue("Cloak and Dagger should be a Rogue", cloakB.hasSubtype(SubType.ROGUE, currentGame));
assertTrue("Cloak and Dagger should be an Equipment", cloakB.hasSubtype(SubType.EQUIPMENT, currentGame));
}
@Test
public void test_SelfExploit_SidisiUndeadVizier_Normal() {
// bug https://github.com/magefree/mage/issues/5925
// You may have Phantasmal Image enter the battlefield as a copy of any creature on the battlefield,
// except it's an Illusion in addition to its other types and it has "When this creature becomes the
// target of a spell or ability, sacrifice it."
addCard(Zone.HAND, playerA, "Phantasmal Image"); // {1}{U}
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
//
// Exploit (When this creature enters the battlefield, you may sacrifice a creature.)
// When Sidisi, Undead Vizier exploits a creature, you may search your library for a card, put it into your hand, then shuffle your library.
addCard(Zone.BATTLEFIELD, playerA, "Sidisi, Undead Vizier");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy
setChoice(playerA, "Sidisi, Undead Vizier"); // to copy
setChoice(playerA, "Sidisi, Undead Vizier[only copy]"); // legendary rule, keep copy
setChoice(playerA, true); // use exploit on etb
setChoice(playerA, "Sidisi, Undead Vizier[only copy]"); // sacrifice itself on exploit
setChoice(playerA, true); // use exploit trigger (search lib)
addTarget(playerA, "Mountain"); // tutor mountain
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertHandCount(playerA, "Mountain", 1);
}
@Test
public void test_SelfExploit_SidisiUndeadVizier_Exile() {
// exploit look for sacrifice only, not a dies conditional - so it must work with exile replace
// You may have Phantasmal Image enter the battlefield as a copy of any creature on the battlefield,
// except it's an Illusion in addition to its other types and it has "When this creature becomes the
// target of a spell or ability, sacrifice it."
addCard(Zone.HAND, playerA, "Phantasmal Image"); // {1}{U}
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
//
// Exploit (When this creature enters the battlefield, you may sacrifice a creature.)
// When Sidisi, Undead Vizier exploits a creature, you may search your library for a card, put it into your hand, then shuffle your library.
addCard(Zone.BATTLEFIELD, playerA, "Sidisi, Undead Vizier");
//
// If a card or token would be put into a graveyard from anywhere, exile it instead.
addCard(Zone.BATTLEFIELD, playerA, "Rest in Peace");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
setChoice(playerA, true); // use copy
setChoice(playerA, "Sidisi, Undead Vizier"); // to copy
setChoice(playerA, "Sidisi, Undead Vizier[only copy]"); // legendary rule, keep copy
setChoice(playerA, true); // use exploit on etb
setChoice(playerA, "Sidisi, Undead Vizier[only copy]"); // sacrifice itself on exploit
setChoice(playerA, true); // use exploit trigger (search lib)
addTarget(playerA, "Mountain"); // tutor mountain
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertHandCount(playerA, "Mountain", 1);
}
}

View file

@ -116,4 +116,25 @@ public class VerrakWarpedSengirTest extends CardTestPlayerBase {
assertLife(playerA, 20 - 2 * 2 + 2 * 2); // x2 pays, x2 gains
assertLife(playerB, 20 - 2 * 2); // x2 lose
}
@Test
public void test_MustNotTriggerOnDiscardCost() {
// bug: https://github.com/magefree/mage/issues/12089
// Whenever you activate an ability that isnt a mana ability, if life was paid to activate it,
// you may pay that much life again. If you do, copy that ability. You may choose new targets for the copy.
addCard(Zone.BATTLEFIELD, playerA, "Verrak, Warped Sengir");
//
// Pay 2 life, Sacrifice another creature: Search your library for a card, put that card into your hand, then shuffle.
addCard(Zone.BATTLEFIELD, playerA, "Razaketh, the Foulblooded");
// activate without copy trigger (discard cost pay will remove Verrak before activate the ability)
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pay 2 life, Sacrifice");
setChoice(playerA, "Verrak, Warped Sengir"); // sacrifice cost
addTarget(playerA, "Mountain"); // search lib
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
setStrictChooseMode(true);
execute();
}
}

View file

@ -23,7 +23,7 @@ public class ChronozoaTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
// 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 Chronozoa is put into a graveyard from play, if it had no time counters on it, create two tokens that are copies of it.
// When Chronozoa dies, if it had no time counters on it, create two tokens that are copies of it.
addCard(Zone.HAND, playerA, "Chronozoa"); // {3}{U}
addCard(Zone.GRAVEYARD, playerA, "Chronozoa");
// Sacrifice a creature: Scry 1. (To scry 1, look at the top card of your library, then you may put that card on the bottom of your library.)