diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java index 3b066bf2145..75ef87401b0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java @@ -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); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/VerrakWarpedSengirTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/VerrakWarpedSengirTest.java index 1df34463bf4..50823474d0f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/VerrakWarpedSengirTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dmc/VerrakWarpedSengirTest.java @@ -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 isn’t 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(); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ChronozoaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ChronozoaTest.java index 4949f349a9c..19ebc89e380 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ChronozoaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ChronozoaTest.java @@ -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.) diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 064801a98cf..270b22da238 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -7,6 +7,7 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.AbilityImpl; import mage.abilities.Mode; +import mage.abilities.TriggeredAbility; import mage.abilities.common.*; import mage.abilities.condition.Condition; import mage.abilities.costs.Cost; @@ -1979,10 +1980,23 @@ public class VerifyCardDataTest { fail(card, "abilities", "legendary nonpermanent cards need to have LegendarySpellAbility"); } + // special check: mutate is not supported yet, so must be removed from sets if (card.getAbilities().containsClass(MutateAbility.class)) { fail(card, "abilities", "mutate cards aren't implemented and shouldn't be available"); } + // special check: wrong dies triggers + card.getAbilities().stream() + .filter(a -> a instanceof TriggeredAbility) + .map(a -> (TriggeredAbility) a) + .filter(a -> a.getRule().contains("whenever") || a.getRule().contains("Whenever")) + .filter(a -> a.getRule().contains("dies")) + .filter(a -> !a.getRule().contains("with \"When")) // ignore token creating effects + .filter(a -> !a.isLeavesTheBattlefieldTrigger()) + .forEach(a -> { + fail(card, "abilities", "dies trigger must use setLeavesTheBattlefieldTrigger(true) and override isInUseableZone - " + a.getClass().getSimpleName()); + }); + // special check: duplicated words in ability text (wrong target/filter usage) // example: You may exile __two two__ blue cards // possible fixes: diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index ab458969a70..a3300a0092f 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -351,7 +351,12 @@ public interface Ability extends Controllable, Serializable { void addWatcher(Watcher watcher); /** - * Returns true if this abilities source is in the zone for the ability + * Allow to control ability/trigger's lifecycle + *
+ * How-to use:
+ * - for normal abilities and triggers - keep default
+ * - for leave battlefield triggers - keep default + set setLeavesTheBattlefieldTrigger(true)
+ * - for dies triggers - override and use TriggeredAbilityImpl.isInUseableZoneDiesTrigger inside + set setLeavesTheBattlefieldTrigger(true)
*/
boolean isInUseableZone(Game game, MageObject source, GameEvent event);
diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java
index 0830467cbdb..6552a59b112 100644
--- a/Mage/src/main/java/mage/abilities/AbilityImpl.java
+++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java
@@ -29,7 +29,9 @@ import mage.game.Game;
import mage.game.command.Dungeon;
import mage.game.command.Emblem;
import mage.game.command.Plane;
+import mage.game.events.BatchEvent;
import mage.game.events.GameEvent;
+import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.game.stack.StackAbility;
@@ -1172,11 +1174,6 @@ public abstract class AbilityImpl implements Ability {
return false;
}
- /**
- * @param game
- * @param source
- * @return
- */
@Override
public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
if (!this.hasSourceObjectAbility(game, source, event)) {
@@ -1201,13 +1198,74 @@ public abstract class AbilityImpl implements Ability {
} else {
parameterSourceId = getSourceId();
}
+
+ // old code:
+ // TODO: delete after dies fix
// check against shortLKI for effects that move multiple object at the same time (e.g. destroy all)
if (game.checkShortLivingLKI(getSourceId(), getZone())) {
- return true;
+ //return true; // fix 1
}
- // check against current state
- Zone test = game.getState().getZone(parameterSourceId);
- return zone.match(test);
+
+
+ // 603.10.
+ // Normally, objects that exist immediately after an event are checked to see if the event matched
+ // any trigger conditions, and continuous effects that exist at that time are used to determine what the
+ // trigger conditions are and what the objects involved in the event look like.
+ // ...
+ Zone lookingInZone = game.getState().getZone(parameterSourceId);
+
+ // 603.10.
+ // ...
+ // However, some triggered abilities are exceptions to this rule; the game “looks back in time” to determine
+ // if those abilities trigger, using the existence of those abilities and the appearance of objects
+ // immediately prior to the event. The list of exceptions is as follows:
+
+ // 603.10a
+ // Some zone-change triggers look back in time. These are leaves-the-battlefield abilities,
+ // abilities that trigger when a card leaves a graveyard, and abilities that trigger when an object that all
+ // players can see is put into a hand or library.
+ // TODO: research "leaves a graveyard"
+ // TODO: research "put into a hand or library"
+ if (source instanceof Permanent && isTriggerCanFireAfterLeaveBattlefield(event)) {
+ // support leaves-the-battlefield abilities
+ lookingInZone = Zone.BATTLEFIELD;
+ }
+
+ // TODO: research use cases and implement shared logic with "looking zone" instead LKI only
+ // 603.10b Abilities that trigger when a permanent phases out look back in time.
+ // 603.10c Abilities that trigger specifically when an object becomes unattached look back in time.
+ // 603.10d Abilities that trigger when a player loses control of an object look back in time.
+ // 603.10e Abilities that trigger when a spell is countered look back in time.
+ // 603.10f Abilities that trigger when a player loses the game look back in time.
+ // 603.10g Abilities that trigger when a player planeswalks away from a plane look back in time.
+
+ return zone.match(lookingInZone);
+ }
+
+ public static boolean isTriggerCanFireAfterLeaveBattlefield(GameEvent event) {
+ if (event == null) {
+ return false;
+ }
+
+ List
* For triggered abilities that function from the battlefield that must trigger when the source permanent dies
* and/or for any other events that happen simultaneously to the source permanent dying.
* (Similar logic must be used for any leaves-the-battlefield, but this method assumes to graveyard only.)
* NOTE: If your ability functions from another zone (not battlefield) then must use standard logic, not this.
*/
public static boolean isInUseableZoneDiesTrigger(TriggeredAbility source, GameEvent event, Game game) {
+ // runtime check: wrong trigger settings
+ if (!source.isLeavesTheBattlefieldTrigger()) {
+ // TODO: enable after fix
+ // throw new IllegalArgumentException("Wrong code usage: all dies triggers must use setLeavesTheBattlefieldTrigger(true)");
+ }
+
// Get the source permanent of the ability
MageObject sourceObject = null;
if (game.getState().getZone(source.getSourceId()) == Zone.BATTLEFIELD) {
@@ -481,7 +482,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
// --!---------------!-------------!-----!-----------!
// -
if (game.checkShortLivingLKI(source.getSourceId(), Zone.BATTLEFIELD)) {
- sourceObject = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
+ sourceObject = game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD);
}
}
if (sourceObject == null) { // source is no permanent
diff --git a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java
index cc6f9fc8624..421d95bd9be 100644
--- a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java
@@ -48,6 +48,7 @@ public class DiesCreatureTriggeredAbility extends TriggeredAbilityImpl {
super(zone, effect, optional);
this.filter = filter;
this.setTargetPointer = setTargetPointer;
+ setLeavesTheBattlefieldTrigger(true);
setTriggerPhrase("Whenever " + filter.getMessage() + (filter.getMessage().startsWith("one or more") ? " die, " : " dies, "));
}
diff --git a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherTriggeredAbility.java
index 8a19656b323..96851179e44 100644
--- a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherTriggeredAbility.java
@@ -30,6 +30,7 @@ public class DiesThisOrAnotherTriggeredAbility extends TriggeredAbilityImpl {
filterMessage = filterMessage.substring(2);
}
setTriggerPhrase("Whenever {this} or another " + filterMessage + " dies, ");
+ setLeavesTheBattlefieldTrigger(true);
}
protected DiesThisOrAnotherTriggeredAbility(final DiesThisOrAnotherTriggeredAbility ability) {
diff --git a/Mage/src/main/java/mage/abilities/common/ExploitCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/ExploitCreatureTriggeredAbility.java
index 9989905a53f..1a380412bc9 100644
--- a/Mage/src/main/java/mage/abilities/common/ExploitCreatureTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/ExploitCreatureTriggeredAbility.java
@@ -48,22 +48,6 @@ public class ExploitCreatureTriggeredAbility extends TriggeredAbilityImpl {
return event.getType() == GameEvent.EventType.EXPLOITED_CREATURE;
}
- @Override
- public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
- Permanent sourcePermanent = null;
- if (game.getState().getZone(getSourceId()) == Zone.BATTLEFIELD) {
- sourcePermanent = game.getPermanent(getSourceId());
- } else {
- if (game.checkShortLivingLKI(getSourceId(), Zone.BATTLEFIELD)) {
- sourcePermanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD);
- }
- }
- if (sourcePermanent == null) {
- return false;
- }
- return hasSourceObjectAbility(game, sourcePermanent, event);
- }
-
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getSourceId().equals(getSourceId())) {
diff --git a/Mage/src/main/java/mage/abilities/common/GodEternalDiesTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/GodEternalDiesTriggeredAbility.java
index f8cc58d95b0..d280ed8f614 100644
--- a/Mage/src/main/java/mage/abilities/common/GodEternalDiesTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/GodEternalDiesTriggeredAbility.java
@@ -21,6 +21,7 @@ public class GodEternalDiesTriggeredAbility extends TriggeredAbilityImpl {
public GodEternalDiesTriggeredAbility() {
super(Zone.ALL, null, true);
+ this.setLeavesTheBattlefieldTrigger(true);
}
private GodEternalDiesTriggeredAbility(GodEternalDiesTriggeredAbility ability) {
@@ -49,22 +50,6 @@ public class GodEternalDiesTriggeredAbility extends TriggeredAbilityImpl {
return false;
}
- @Override
- public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
- Permanent sourcePermanent = null;
- if (game.getState().getZone(getSourceId()) == Zone.BATTLEFIELD) {
- sourcePermanent = game.getPermanent(getSourceId());
- } else {
- if (game.checkShortLivingLKI(getSourceId(), Zone.BATTLEFIELD)) {
- sourcePermanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD);
- }
- }
- if (sourcePermanent == null) {
- return false;
- }
- return hasSourceObjectAbility(game, sourcePermanent, event);
- }
-
@Override
public GodEternalDiesTriggeredAbility copy() {
return new GodEternalDiesTriggeredAbility(this);
diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java
index 2244f6f8123..1fd9bdd5f90 100644
--- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java
+++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java
@@ -259,8 +259,8 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost {
return false;
}
- // TODO: is it require Phyrexian stile effects here for single payment?
- //AbilityImpl.preparePhyrexianCost(game, source, player, ability, this);
+ // no needs to call
+ //AbilityImpl.handlePhyrexianLikeEffects(game, source, ability, this);
if (!player.getManaPool().isForcedToPay()) {
assignPayment(game, ability, player.getManaPool(), costToPay != null ? costToPay : this);
diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java
index b8e0b6f57d3..dfb28160590 100644
--- a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java
@@ -1,5 +1,6 @@
package mage.abilities.decorator;
+import mage.MageObject;
import mage.abilities.Modes;
import mage.abilities.TriggeredAbility;
import mage.abilities.TriggeredAbilityImpl;
@@ -7,6 +8,7 @@ import mage.abilities.condition.Condition;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.constants.EffectType;
+import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.util.CardUtil;
@@ -133,4 +135,14 @@ public class ConditionalInterveningIfTriggeredAbility extends TriggeredAbilityIm
public boolean caresAboutManaColor() {
return condition.caresAboutManaColor();
}
+
+ @Override
+ public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
+ if (isLeavesTheBattlefieldTrigger()) {
+ // TODO: leaves battlefield and die are not same! Is it possible make a diff logic?
+ return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game);
+ } else {
+ return super.isInUseableZone(game, source, event);
+ }
+ }
}
diff --git a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java
index c5fce43af6c..90bc73e0e0e 100644
--- a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java
@@ -1,5 +1,6 @@
package mage.abilities.meta;
+import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbility;
import mage.abilities.TriggeredAbilityImpl;
@@ -10,10 +11,7 @@ import mage.game.events.GameEvent;
import mage.util.CardUtil;
import mage.watchers.Watcher;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
+import java.util.*;
import java.util.stream.Collectors;
/**
@@ -46,6 +44,10 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl {
for(Watcher watcher : ability.getWatchers()) {
super.addWatcher(watcher);
}
+
+ if (ability.isLeavesTheBattlefieldTrigger()) {
+ this.setLeavesTheBattlefieldTrigger(true);
+ }
}
setTriggerPhrase(generateTriggerPhrase());
}
@@ -123,4 +125,19 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl {
ability.addWatcher(watcher);
}
}
+
+ @Override
+ public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
+ boolean res = false;
+ for (TriggeredAbility ability : triggeredAbilities) {
+ // TODO: call full inner trigger instead like ability.isInUseableZone()?! Need research why it fails
+ if (ability.isLeavesTheBattlefieldTrigger()) {
+ // TODO: leaves battlefield and die are not same! Is it possible make a diff logic?
+ res |= TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game);
+ } else {
+ res |= super.isInUseableZone(game, source, event);
+ }
+ }
+ return res;
+ }
}
diff --git a/Mage/src/main/java/mage/game/command/emblems/DackFaydenEmblem.java b/Mage/src/main/java/mage/game/command/emblems/DackFaydenEmblem.java
index f56faea246d..0a2dabc7efb 100644
--- a/Mage/src/main/java/mage/game/command/emblems/DackFaydenEmblem.java
+++ b/Mage/src/main/java/mage/game/command/emblems/DackFaydenEmblem.java
@@ -63,7 +63,7 @@ class DackFaydenEmblemTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
boolean returnValue = false;
- List