fix usable zone logic for abilities that function from other zones (#12446)

* remove superfluous constructor params

* fix Syrix, Carrier of the Flame

* standardize Zone = Battlefield

* rename class

* remove redundant class

* add docs

* adjustment
This commit is contained in:
xenohedron 2024-06-09 22:15:04 -04:00 committed by GitHub
parent 0d4acf26e5
commit a5488228b8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 111 additions and 172 deletions

View file

@ -430,6 +430,12 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
return this;
}
/**
* 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) {
// Get the source permanent of the ability
MageObject sourceObject = null;

View file

@ -82,6 +82,10 @@ public class DiesCreatureTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game);
if (this.zone == Zone.BATTLEFIELD) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game);
} else {
return super.isInUseableZone(game, source, event);
}
}
}

View file

@ -1,66 +0,0 @@
package mage.abilities.common;
import mage.MageObject;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.Zone;
import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
/**
* @author noxx
*/
public class DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility extends TriggeredAbilityImpl {
protected FilterCreatureOrPlaneswalkerPermanent filter;
public DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility(Effect effect, boolean optional) {
this(effect, optional, new FilterCreatureOrPlaneswalkerPermanent());
}
public DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility(Effect effect, boolean optional, FilterCreatureOrPlaneswalkerPermanent filter) {
super(Zone.ALL, effect, optional); // Needs "ALL" if the source itself should trigger or multiple (incl. source go to grave)
this.filter = filter;
setTriggerPhrase("Whenever {this} or another " + filter.getMessage() + " dies, ");
}
public DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility(DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility ability) {
super(ability);
this.filter = ability.filter;
}
@Override
public DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility copy() {
return new DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.isDiesEvent()) {
if (zEvent.getTarget() != null) {
if (zEvent.getTarget().getId().equals(this.getSourceId())) {
return true;
} else {
if (filter.match(zEvent.getTarget(), getControllerId(), this, game)) {
return true;
}
}
}
}
return false;
}
@Override
public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, event, game);
}
}

View file

@ -13,17 +13,17 @@ import mage.game.events.ZoneChangeEvent;
/**
* @author noxx
*/
public class DiesThisOrAnotherCreatureTriggeredAbility extends TriggeredAbilityImpl {
public class DiesThisOrAnotherTriggeredAbility extends TriggeredAbilityImpl {
protected FilterPermanent filter;
private boolean applyFilterOnSource = false;
public DiesThisOrAnotherCreatureTriggeredAbility(Effect effect, boolean optional) {
public DiesThisOrAnotherTriggeredAbility(Effect effect, boolean optional) {
this(effect, optional, StaticFilters.FILTER_PERMANENT_CREATURE);
}
public DiesThisOrAnotherCreatureTriggeredAbility(Effect effect, boolean optional, FilterPermanent filter) {
super(Zone.ALL, effect, optional); // Needs "ALL" if the source itself should trigger or multiple (incl. source go to grave)
public DiesThisOrAnotherTriggeredAbility(Effect effect, boolean optional, FilterPermanent filter) {
super(Zone.BATTLEFIELD, effect, optional);
this.filter = filter;
String filterMessage = filter.getMessage();
if (filterMessage.startsWith("a ")) {
@ -32,20 +32,20 @@ public class DiesThisOrAnotherCreatureTriggeredAbility extends TriggeredAbilityI
setTriggerPhrase("Whenever {this} or another " + filterMessage + " dies, ");
}
protected DiesThisOrAnotherCreatureTriggeredAbility(final DiesThisOrAnotherCreatureTriggeredAbility ability) {
protected DiesThisOrAnotherTriggeredAbility(final DiesThisOrAnotherTriggeredAbility ability) {
super(ability);
this.filter = ability.filter;
this.applyFilterOnSource = ability.applyFilterOnSource;
}
public DiesThisOrAnotherCreatureTriggeredAbility setApplyFilterOnSource(boolean applyFilterOnSource) {
public DiesThisOrAnotherTriggeredAbility setApplyFilterOnSource(boolean applyFilterOnSource) {
this.applyFilterOnSource = applyFilterOnSource;
return this;
}
@Override
public DiesThisOrAnotherCreatureTriggeredAbility copy() {
return new DiesThisOrAnotherCreatureTriggeredAbility(this);
public DiesThisOrAnotherTriggeredAbility copy() {
return new DiesThisOrAnotherTriggeredAbility(this);
}
@Override
@ -59,6 +59,7 @@ public class DiesThisOrAnotherCreatureTriggeredAbility extends TriggeredAbilityI
if (zEvent.isDiesEvent()) {
if (zEvent.getTarget() != null) {
if (!applyFilterOnSource && zEvent.getTarget().getId().equals(this.getSourceId())) {
// TODO: remove this workaround for Basri's Lieutenant
return true;
} else {
if (filter.match(zEvent.getTarget(), getControllerId(), this, game)) {

View file

@ -17,8 +17,8 @@ import mage.target.targetpointer.FixedTarget;
public class PutIntoGraveFromBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
private final FilterPermanent filter;
private boolean setTargetPointer;
private boolean onlyToControllerGraveyard;
private final boolean setTargetPointer;
private final boolean onlyToControllerGraveyard;
public PutIntoGraveFromBattlefieldAllTriggeredAbility(Effect effect, boolean optional, FilterPermanent filter, boolean setTargetPointer) {
this(effect, optional, filter, setTargetPointer, false);

View file

@ -21,7 +21,7 @@ public class PutIntoGraveFromBattlefieldSourceTriggeredAbility extends Triggered
}
public PutIntoGraveFromBattlefieldSourceTriggeredAbility(Effect effect, boolean optional, boolean onlyToControllerGraveyard) {
super(Zone.ALL, effect, optional);
super(Zone.BATTLEFIELD, effect, optional);
setLeavesTheBattlefieldTrigger(true);
this.onlyToControllerGraveyard = onlyToControllerGraveyard;
setTriggerPhrase("When {this} is put into " + (onlyToControllerGraveyard ? "your" : "a") + " graveyard from the battlefield, ");