diff --git a/Mage.Sets/src/mage/cards/d/DaxosBlessedByTheSun.java b/Mage.Sets/src/mage/cards/d/DaxosBlessedByTheSun.java index 8b7b30d757e..774f1cbf73f 100644 --- a/Mage.Sets/src/mage/cards/d/DaxosBlessedByTheSun.java +++ b/Mage.Sets/src/mage/cards/d/DaxosBlessedByTheSun.java @@ -54,6 +54,7 @@ class DaxosBlessedByTheSunAbility extends TriggeredAbilityImpl { DaxosBlessedByTheSunAbility() { super(Zone.BATTLEFIELD, new GainLifeEffect(1)); + setLeavesTheBattlefieldTrigger(true); } private DaxosBlessedByTheSunAbility(DaxosBlessedByTheSunAbility ability) { diff --git a/Mage.Sets/src/mage/cards/d/DeathTyrant.java b/Mage.Sets/src/mage/cards/d/DeathTyrant.java index 5c2826e3451..0a670188b4c 100644 --- a/Mage.Sets/src/mage/cards/d/DeathTyrant.java +++ b/Mage.Sets/src/mage/cards/d/DeathTyrant.java @@ -62,6 +62,7 @@ class DeathTyrantTriggeredAbility extends TriggeredAbilityImpl { DeathTyrantTriggeredAbility() { super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken())); setTriggerPhrase("Whenever an attacking creature you control or a blocking creature an opponent controls dies, "); + setLeavesTheBattlefieldTrigger(true); } private DeathTyrantTriggeredAbility(final DeathTyrantTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/d/Dreadhound.java b/Mage.Sets/src/mage/cards/d/Dreadhound.java index be6fe64a348..3df8fc02676 100644 --- a/Mage.Sets/src/mage/cards/d/Dreadhound.java +++ b/Mage.Sets/src/mage/cards/d/Dreadhound.java @@ -53,6 +53,7 @@ class DreadhoundTriggeredAbility extends TriggeredAbilityImpl { public DreadhoundTriggeredAbility() { super(Zone.BATTLEFIELD, new LoseLifeOpponentsEffect(1)); setTriggerPhrase("Whenever a creature dies or a creature card is put into a graveyard from a library, "); + setLeavesTheBattlefieldTrigger(true); } private DreadhoundTriggeredAbility(final DreadhoundTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/g/GutterGrime.java b/Mage.Sets/src/mage/cards/g/GutterGrime.java index ca06176f03e..a5044904968 100644 --- a/Mage.Sets/src/mage/cards/g/GutterGrime.java +++ b/Mage.Sets/src/mage/cards/g/GutterGrime.java @@ -48,6 +48,7 @@ class GutterGrimeTriggeredAbility extends TriggeredAbilityImpl { public GutterGrimeTriggeredAbility() { super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.SLIME.createInstance()), false); this.addEffect(new GutterGrimeEffect()); + setLeavesTheBattlefieldTrigger(true); } private GutterGrimeTriggeredAbility(final GutterGrimeTriggeredAbility ability) { @@ -83,6 +84,11 @@ class GutterGrimeTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever a nontoken creature you control dies, put a slime counter on {this}, then create a green Ooze creature token with \"This creature's power and toughness are each equal to the number of slime counters on {this}.\""; } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game); + } } class GutterGrimeEffect extends OneShotEffect { diff --git a/Mage.Sets/src/mage/cards/h/HatefulEidolon.java b/Mage.Sets/src/mage/cards/h/HatefulEidolon.java index a615cf25fc9..4f92ff17ce7 100644 --- a/Mage.Sets/src/mage/cards/h/HatefulEidolon.java +++ b/Mage.Sets/src/mage/cards/h/HatefulEidolon.java @@ -1,6 +1,7 @@ package mage.cards.h; import mage.MageInt; +import mage.MageObject; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; @@ -51,6 +52,7 @@ class HatefulEidolonTriggeredAbility extends TriggeredAbilityImpl { HatefulEidolonTriggeredAbility() { super(Zone.BATTLEFIELD, null, false); + setLeavesTheBattlefieldTrigger(true); } private HatefulEidolonTriggeredAbility(final HatefulEidolonTriggeredAbility ability) { @@ -105,4 +107,9 @@ class HatefulEidolonTriggeredAbility extends TriggeredAbilityImpl { return "Whenever an enchanted creature dies, draw a card for each " + "Aura you controlled that was attached to it."; } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game); + } } diff --git a/Mage.Sets/src/mage/cards/i/InfestedThrinax.java b/Mage.Sets/src/mage/cards/i/InfestedThrinax.java index 6aaf3d51784..a8c84cd0b61 100644 --- a/Mage.Sets/src/mage/cards/i/InfestedThrinax.java +++ b/Mage.Sets/src/mage/cards/i/InfestedThrinax.java @@ -1,7 +1,9 @@ package mage.cards.i; import mage.MageInt; +import mage.MageObject; import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; @@ -55,6 +57,7 @@ class InfestedThrinaxTriggeredAbility extends DelayedTriggeredAbility { InfestedThrinaxTriggeredAbility() { super(new CreateTokenEffect(new SaprolingToken(), SavedDamageValue.MUCH), Duration.EndOfTurn, false, false); + setLeavesTheBattlefieldTrigger(true); } private InfestedThrinaxTriggeredAbility(final InfestedThrinaxTriggeredAbility ability) { @@ -89,4 +92,9 @@ class InfestedThrinaxTriggeredAbility extends DelayedTriggeredAbility { return "Whenever a nontoken creature you control dies, " + "create a number of 1/1 green Saproling creature tokens equal to that creature's power."; } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game); + } } diff --git a/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java b/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java index 0b514ae90af..606bec7fe1e 100644 --- a/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java +++ b/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java @@ -94,6 +94,7 @@ class JerrenCorruptedBishopTriggeredAbility extends TriggeredAbilityImpl { JerrenCorruptedBishopTriggeredAbility() { super(Zone.BATTLEFIELD, new LoseLifeSourceControllerEffect(1)); this.addEffect(new CreateTokenEffect(new HumanToken())); + setLeavesTheBattlefieldTrigger(true); } private JerrenCorruptedBishopTriggeredAbility(final JerrenCorruptedBishopTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/m/MassacreGirl.java b/Mage.Sets/src/mage/cards/m/MassacreGirl.java index 219837f3e6a..10be05d22dd 100644 --- a/Mage.Sets/src/mage/cards/m/MassacreGirl.java +++ b/Mage.Sets/src/mage/cards/m/MassacreGirl.java @@ -1,8 +1,10 @@ package mage.cards.m; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; @@ -77,6 +79,7 @@ class MassacreGirlDelayedTriggeredAbility extends DelayedTriggeredAbility { MassacreGirlDelayedTriggeredAbility() { super(new BoostAllEffect(-1, -1, Duration.EndOfTurn, true), Duration.EndOfTurn, false); + setLeavesTheBattlefieldTrigger(true); } private MassacreGirlDelayedTriggeredAbility(final MassacreGirlDelayedTriggeredAbility ability) { @@ -103,4 +106,9 @@ class MassacreGirlDelayedTriggeredAbility extends DelayedTriggeredAbility { public String getRule() { return "Whenever a creature dies this turn, each creature other than {this} gets -1/-1 until end of turn"; } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game); + } } \ No newline at end of file diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 7480120691b..7ea9473f5bb 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -1994,6 +1994,9 @@ public class VerifyCardDataTest { .filter(a -> !a.getRule().contains("with \"When")) // ignore token creating effects .filter(a -> !a.getRule().contains("gains \"When")) // ignore token creating effects .filter(a -> !a.getRule().contains("and \"When")) // ignore token creating effects + .filter(a -> !card.getName().equals("Massacre Girl") // delayed trigger fixed, but verify check can't find it + && !card.getName().equals("Infested Thrinax") + ) .filter(a -> !a.isLeavesTheBattlefieldTrigger()) .forEach(a -> { fail(card, "abilities", "dies trigger must use setLeavesTheBattlefieldTrigger(true) and override isInUseableZone - " + a.getClass().getSimpleName()); @@ -2319,6 +2322,9 @@ public class VerifyCardDataTest { } private void checkWrongAbilitiesTextStart() { + if (FULL_ABILITIES_CHECK_SET_CODES.isEmpty()) { + return; + } System.out.println("Ability text checks started for " + FULL_ABILITIES_CHECK_SET_CODES); wrongAbilityStatsTotal = 0; wrongAbilityStatsGood = 0; @@ -2326,6 +2332,10 @@ public class VerifyCardDataTest { } private void checkWrongAbilitiesTextEnd() { + if (FULL_ABILITIES_CHECK_SET_CODES.isEmpty()) { + return; + } + // TODO: implement tests result/stats by github actions to show in check message compared to prev version System.out.println(); System.out.printf("Stats for %d cards checked for abilities text:%n", wrongAbilityStatsTotal); diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 6552a59b112..de6448aff7b 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -1255,13 +1255,13 @@ public abstract class AbilityImpl implements Ability { } return allEvents.stream().anyMatch(e -> { - // TODO: add more events with zone change logic (or make it even't param)? + // TODO: add more events with zone change logic (or make it event's param)? switch (e.getType()) { case DESTROYED_PERMANENT: case EXPLOITED_CREATURE: return true; case ZONE_CHANGE: - return ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD; + return ((ZoneChangeEvent) e).getFromZone() == Zone.BATTLEFIELD; default: return false; } diff --git a/Mage/src/main/java/mage/abilities/common/DealtDamageAttachedAndDiedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealtDamageAttachedAndDiedTriggeredAbility.java index 1ad19fa0246..e0c3e7de9de 100644 --- a/Mage/src/main/java/mage/abilities/common/DealtDamageAttachedAndDiedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealtDamageAttachedAndDiedTriggeredAbility.java @@ -1,5 +1,6 @@ package mage.abilities.common; +import mage.MageObject; import mage.MageObjectReference; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -32,6 +33,7 @@ public class DealtDamageAttachedAndDiedTriggeredAbility extends TriggeredAbility setTriggerPhrase(getWhen() + CardUtil.addArticle(filter.getMessage()) + " dealt damage by " + CardUtil.getTextWithFirstCharLowerCase(attachmentType.verb()) + " creature this turn dies, "); + setLeavesTheBattlefieldTrigger(true); } protected DealtDamageAttachedAndDiedTriggeredAbility(final DealtDamageAttachedAndDiedTriggeredAbility ability) { @@ -75,4 +77,9 @@ public class DealtDamageAttachedAndDiedTriggeredAbility extends TriggeredAbility } return true; } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game); + } } diff --git a/Mage/src/main/java/mage/abilities/common/DiesAttachedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesAttachedTriggeredAbility.java index d88602941b5..2befcc668bc 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesAttachedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesAttachedTriggeredAbility.java @@ -1,5 +1,6 @@ package mage.abilities.common; +import mage.MageObject; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.cards.Card; @@ -48,6 +49,7 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { this.setTargetPointer = setTargetPointer; this.rememberSource = rememberSource; setTriggerPhrase(generateTriggerPhrase()); + setLeavesTheBattlefieldTrigger(true); } protected DiesAttachedTriggeredAbility(final DiesAttachedTriggeredAbility ability) { @@ -157,4 +159,9 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { } return sb.toString(); } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game); + } } diff --git a/Mage/src/main/java/mage/abilities/common/delayed/UntilYourNextTurnDelayedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/UntilYourNextTurnDelayedTriggeredAbility.java index 98c7a9dba5b..74950868014 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/UntilYourNextTurnDelayedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/UntilYourNextTurnDelayedTriggeredAbility.java @@ -1,9 +1,11 @@ package mage.abilities.common.delayed; +import mage.MageObject; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.Modes; import mage.abilities.TriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.constants.Duration; @@ -103,4 +105,14 @@ public class UntilYourNextTurnDelayedTriggeredAbility extends DelayedTriggeredAb public int getSourceObjectZoneChangeCounter() { return ability.getSourceObjectZoneChangeCounter(); } + + @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/decorator/ConditionalTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java index cb12f7b2b66..c6aad85b6bf 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java @@ -1,5 +1,6 @@ package mage.abilities.decorator; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Modes; import mage.abilities.TriggeredAbility; @@ -41,6 +42,9 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl { this.ability = ability; this.condition = condition; this.abilityText = text; + if (ability.isLeavesTheBattlefieldTrigger()) { + this.setLeavesTheBattlefieldTrigger(true); + } } protected ConditionalTriggeredAbility(final ConditionalTriggeredAbility triggered) { @@ -118,4 +122,13 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl { return this; } + @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); + } + } }