forked from External/mage
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:
parent
a2ed52b8de
commit
66b338c6fc
18 changed files with 233 additions and 63 deletions
|
|
@ -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<GameEvent> allEvents = new ArrayList<>();
|
||||
if (event instanceof BatchEvent) {
|
||||
allEvents.addAll(((BatchEvent) event).getEvents());
|
||||
} else {
|
||||
allEvents.add(event);
|
||||
}
|
||||
|
||||
return allEvents.stream().anyMatch(e -> {
|
||||
// TODO: add more events with zone change logic (or make it even't param)?
|
||||
switch (e.getType()) {
|
||||
case DESTROYED_PERMANENT:
|
||||
case EXPLOITED_CREATURE:
|
||||
return true;
|
||||
case ZONE_CHANGE:
|
||||
return ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue