mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
refactor: fixed dies events support in single cards (part 7, related to #13089, continue from #13088);
This commit is contained in:
parent
b571080260
commit
8af7a492c8
7 changed files with 162 additions and 1 deletions
|
|
@ -83,6 +83,9 @@ class NadierAgentOfTheDuskenelEffect extends OneShotEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
|
// For Nadier's second ability, use its power from when it was last on the battlefield to determine
|
||||||
|
// how many tokens to create.
|
||||||
|
// (2020-11-10)
|
||||||
Object obj = getValue("permanentLeftBattlefield");
|
Object obj = getValue("permanentLeftBattlefield");
|
||||||
if (!(obj instanceof Permanent)) {
|
if (!(obj instanceof Permanent)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ class ThreeTreeScribeTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
super(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()));
|
super(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()));
|
||||||
this.setTriggerPhrase("Whenever {this} or another creature you control leaves the battlefield without dying, ");
|
this.setTriggerPhrase("Whenever {this} or another creature you control leaves the battlefield without dying, ");
|
||||||
this.addTarget(new TargetControlledCreaturePermanent());
|
this.addTarget(new TargetControlledCreaturePermanent());
|
||||||
|
setLeavesTheBattlefieldTrigger(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ThreeTreeScribeTriggeredAbility(final ThreeTreeScribeTriggeredAbility ability) {
|
private ThreeTreeScribeTriggeredAbility(final ThreeTreeScribeTriggeredAbility ability) {
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ class LeavesTheBattlefieldAttachedTriggeredAbility extends ZoneChangeTriggeredAb
|
||||||
|
|
||||||
public LeavesTheBattlefieldAttachedTriggeredAbility() {
|
public LeavesTheBattlefieldAttachedTriggeredAbility() {
|
||||||
super(Zone.BATTLEFIELD, new CreateTokenEffect(new SpiritWhiteToken()), "When enchanted creature leaves the battlefield, ", Boolean.FALSE);
|
super(Zone.BATTLEFIELD, new CreateTokenEffect(new SpiritWhiteToken()), "When enchanted creature leaves the battlefield, ", Boolean.FALSE);
|
||||||
|
setLeavesTheBattlefieldTrigger(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LeavesTheBattlefieldAttachedTriggeredAbility(final LeavesTheBattlefieldAttachedTriggeredAbility ability) {
|
private LeavesTheBattlefieldAttachedTriggeredAbility(final LeavesTheBattlefieldAttachedTriggeredAbility ability) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
package org.mage.test.cards.single.cmr;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class NadierAgentOfTheDuskenelTest extends CardTestCommanderDuelBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_DieAnother() {
|
||||||
|
addCustomEffect_TargetDestroy(playerA);
|
||||||
|
|
||||||
|
// Whenever a token you control leaves the battlefield, put a +1/+1 counter on Nadier, Agent of the Duskenel.
|
||||||
|
// When Nadier leaves the battlefield, create a number of 1/1 green Elf Warrior creature tokens equal to its power.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Nadier, Agent of the Duskenel", 1);
|
||||||
|
//
|
||||||
|
// {5}, {T}: Create a 1/1 colorless Insect artifact creature token with flying named Wasp.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "The Hive", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
|
||||||
|
|
||||||
|
// prepare token
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{5}, {T}: Create");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
checkPermanentCount("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wasp", 1);
|
||||||
|
|
||||||
|
// on leaves non-token -- nothing to happen
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy", "The Hive");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 1);
|
||||||
|
checkGraveyardCount("on non-token", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "The Hive", 1);
|
||||||
|
checkStackSize("on non-token - no triggers", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0);
|
||||||
|
|
||||||
|
// on leaves token - must trigger
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy", "Wasp");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
checkPermanentCount("on token", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wasp", 0);
|
||||||
|
checkPermanentCounters("on token - must trigger", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nadier, Agent of the Duskenel", CounterType.P1P1, 1);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_DieItself() {
|
||||||
|
addCustomEffect_TargetDestroy(playerA, 2);
|
||||||
|
|
||||||
|
// Whenever a token you control leaves the battlefield, put a +1/+1 counter on Nadier, Agent of the Duskenel.
|
||||||
|
// When Nadier leaves the battlefield, create a number of 1/1 green Elf Warrior creature tokens equal to its power.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Nadier, Agent of the Duskenel", 1);
|
||||||
|
//
|
||||||
|
// {5}, {T}: Create a 1/1 colorless Insect artifact creature token with flying named Wasp.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "The Hive", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
|
||||||
|
|
||||||
|
// prepare token
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{5}, {T}: Create");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
checkPermanentCount("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wasp", 1);
|
||||||
|
|
||||||
|
// on leaves token and itself -- must x2 triggers:
|
||||||
|
// * one with counter to fizzle
|
||||||
|
// * one with new token
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy", "Wasp^Nadier, Agent of the Duskenel");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 1);
|
||||||
|
checkStackSize("must triggers x2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
|
||||||
|
setChoice(playerA, "Whenever a token you control leaves"); // x2 triggers from Nadier
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "The Hive", 1);
|
||||||
|
assertPermanentCount(playerA, "Wasp", 0);
|
||||||
|
assertGraveyardCount(playerA, "Nadier, Agent of the Duskenel", 1);
|
||||||
|
assertPermanentCount(playerA, "Elf Warrior Token", 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
package org.mage.test.cards.single.khm;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class ValorOfTheWorthyTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_DieTarget() {
|
||||||
|
addCustomEffect_TargetDestroy(playerA);
|
||||||
|
|
||||||
|
// Enchant creature
|
||||||
|
// Enchanted creature gets +1/+1.
|
||||||
|
// When enchanted creature leaves the battlefield, create a 1/1 white Spirit creature token with flying.
|
||||||
|
addCard(Zone.HAND, playerA, "Valor of the Worthy"); // {W}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1);
|
||||||
|
|
||||||
|
// attach
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Valor of the Worthy", "Grizzly Bears");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||||
|
checkPT("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 2 + 1, 2 + 1);
|
||||||
|
|
||||||
|
// destroy target - must trigger
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy");
|
||||||
|
addTarget(playerA, "Grizzly Bears");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 1); // resolve destroy
|
||||||
|
checkStackObject("must trigger on destroy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "When enchanted creature leaves the battlefield", 1);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertTokenCount(playerA, "Spirit Token", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_DieItself() {
|
||||||
|
addCustomEffect_TargetDestroy(playerA, 2);
|
||||||
|
|
||||||
|
// Enchant creature
|
||||||
|
// Enchanted creature gets +1/+1.
|
||||||
|
// When enchanted creature leaves the battlefield, create a 1/1 white Spirit creature token with flying.
|
||||||
|
addCard(Zone.HAND, playerA, "Valor of the Worthy"); // {W}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1);
|
||||||
|
|
||||||
|
// attach
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Valor of the Worthy", "Grizzly Bears");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||||
|
checkPT("prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 2 + 1, 2 + 1);
|
||||||
|
|
||||||
|
// destroy all - must trigger anyway
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy");
|
||||||
|
addTarget(playerA, "Valor of the Worthy^Grizzly Bears");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 1); // resolve destroy
|
||||||
|
checkStackObject("must trigger on destroy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "When enchanted creature leaves the battlefield", 1);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertTokenCount(playerA, "Spirit Token", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2021,10 +2021,12 @@ public class VerifyCardDataTest {
|
||||||
boolean isPutToGraveAbility = rules.contains("put into")
|
boolean isPutToGraveAbility = rules.contains("put into")
|
||||||
&& rules.contains("graveyard")
|
&& rules.contains("graveyard")
|
||||||
&& rules.contains("from the battlefield");
|
&& rules.contains("from the battlefield");
|
||||||
|
boolean isLeavesBattlefield = rules.contains("leaves the battlefield");
|
||||||
|
isLeavesBattlefield = false; // TODO: remove and fix all bad cards
|
||||||
if (triggeredAbility.isLeavesTheBattlefieldTrigger()) {
|
if (triggeredAbility.isLeavesTheBattlefieldTrigger()) {
|
||||||
// TODO: add check for wrongly enabled settings too?
|
// TODO: add check for wrongly enabled settings too?
|
||||||
} else {
|
} else {
|
||||||
if (isDiesAbility || isPutToGraveAbility) {
|
if (isDiesAbility || isPutToGraveAbility || isLeavesBattlefield) {
|
||||||
fail(card, "abilities", "dies related trigger must use setLeavesTheBattlefieldTrigger(true) and possibly override isInUseableZone - "
|
fail(card, "abilities", "dies related trigger must use setLeavesTheBattlefieldTrigger(true) and possibly override isInUseableZone - "
|
||||||
+ triggeredAbility.getClass().getSimpleName());
|
+ triggeredAbility.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ public class LeavesBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.setTargetPointer = setTargetPointer;
|
this.setTargetPointer = setTargetPointer;
|
||||||
setTriggerPhrase("Whenever " + filter.getMessage() + " leaves the battlefield, ");
|
setTriggerPhrase("Whenever " + filter.getMessage() + " leaves the battlefield, ");
|
||||||
|
setLeavesTheBattlefieldTrigger(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LeavesBattlefieldAllTriggeredAbility(final LeavesBattlefieldAllTriggeredAbility ability) {
|
protected LeavesBattlefieldAllTriggeredAbility(final LeavesBattlefieldAllTriggeredAbility ability) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue