mirror of
https://github.com/magefree/mage.git
synced 2026-01-10 12:52:06 -08:00
tests: added tests for non-stack delayed trigger and details docs about problem
This commit is contained in:
parent
7fa4648316
commit
367defd995
7 changed files with 234 additions and 17 deletions
|
|
@ -2068,12 +2068,16 @@ public abstract class GameImpl implements Game {
|
|||
}
|
||||
if (ability instanceof TriggeredManaAbility || ability instanceof DelayedTriggeredManaAbility) {
|
||||
// 20110715 - 605.4
|
||||
// 605.4a A triggered mana ability doesn’t go on the stack, so it can’t be targeted,
|
||||
// countered, or otherwise responded to. Rather, it resolves immediately after the mana
|
||||
// ability that triggered it, without waiting for priority.
|
||||
Ability manaAbility = ability.copy();
|
||||
if (manaAbility.getSourceObjectZoneChangeCounter() == 0) {
|
||||
manaAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId()));
|
||||
}
|
||||
manaAbility.activate(this, false);
|
||||
manaAbility.resolve(this);
|
||||
if (manaAbility.activate(this, false)) {
|
||||
manaAbility.resolve(this);
|
||||
}
|
||||
} else {
|
||||
TriggeredAbility newAbility = ability.copy();
|
||||
newAbility.newId();
|
||||
|
|
@ -2084,6 +2088,46 @@ public abstract class GameImpl implements Game {
|
|||
newAbility.setSourcePermanentTransformCount(this);
|
||||
}
|
||||
newAbility.setTriggerEvent(triggeringEvent);
|
||||
|
||||
// TODO: non-stack delayed triggers are xmage's workaround to support specific cards
|
||||
// instead replacement effects usage. That triggers must be executed immediately like mana abilities
|
||||
// or be reworked, cause current code do not support rule "nothing happens between the two events,
|
||||
// including state-based actions"
|
||||
//
|
||||
// Search related cards by "usesStack = false".
|
||||
// See conflicting tests in StateBaseTriggeredAbilityTest and BanisherPriestTest
|
||||
//
|
||||
// example 1:
|
||||
// Grasp of Fate: exile ... until Grasp of Fate leaves the battlefield
|
||||
// The exiled cards return to the battlefield immediately after Grasp of Fate leaves the battlefield. Nothing
|
||||
// happens between the two events, including state-based actions.
|
||||
// (2015-11-04)
|
||||
//
|
||||
// example 2:
|
||||
// Banisher Priest: exile ... until Banisher Priest leaves the battlefield
|
||||
// Banisher Priest's ability causes a zone change with a duration, a new style of ability that's
|
||||
// somewhat reminiscent of older cards like Oblivion Ring. However, unlike Oblivion Ring, cards
|
||||
// like Banisher Priest have a single ability that creates two one-shot effects: one that exiles
|
||||
// the creature when the ability resolves, and another that returns the exiled card to the battlefield
|
||||
// immediately after Banisher Priest leaves the battlefield.
|
||||
// (2013-07-01)
|
||||
// The exiled card returns to the battlefield immediately after Banisher Priest leaves the battlefield.
|
||||
// Nothing happens between the two events, including state-based actions. The two creatures aren't on
|
||||
// the battlefield at the same time. For example, if the returning creature is a Clone, it can't enter
|
||||
// the battlefield as a copy of Banisher Priest.
|
||||
// (2013-07-01)
|
||||
//
|
||||
//
|
||||
/* possible code:
|
||||
if (newAbility.isUsesStack()) {
|
||||
state.addTriggeredAbility(newAbility);
|
||||
} else {
|
||||
if (newAbility.activate(this, false)) {
|
||||
newAbility.resolve(this);
|
||||
}
|
||||
}//*/
|
||||
|
||||
// original code
|
||||
state.addTriggeredAbility(newAbility);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
private final Map<UUID, LookedAt> lookedAt = new HashMap<>();
|
||||
private final Revealed companion;
|
||||
|
||||
private DelayedTriggeredAbilities delayed;
|
||||
private SpecialActions specialActions;
|
||||
private Watchers watchers;
|
||||
private Turn turn;
|
||||
|
|
@ -94,8 +93,9 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
private boolean gameOver;
|
||||
private boolean paused;
|
||||
private ContinuousEffects effects;
|
||||
private TriggeredAbilities triggers;
|
||||
private List<TriggeredAbility> triggered = new ArrayList<>();
|
||||
private TriggeredAbilities triggers; // all normal triggers
|
||||
private DelayedTriggeredAbilities delayed; // all delayed triggers
|
||||
private List<TriggeredAbility> triggered = new ArrayList<>(); // raised triggers, waiting to resolve (can contains both normal and delayed)
|
||||
private Combat combat;
|
||||
private Map<String, Object> values = new HashMap<>();
|
||||
private Map<UUID, Zone> zones = new HashMap<>();
|
||||
|
|
@ -233,6 +233,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
}
|
||||
|
||||
public void restore(GameState state) {
|
||||
// no needs in copy here cause GameState already copied on save and it will be used only one time here
|
||||
this.activePlayerId = state.activePlayerId;
|
||||
this.playerList.setCurrent(state.activePlayerId);
|
||||
this.playerByOrderId = state.playerByOrderId;
|
||||
|
|
@ -1175,6 +1176,8 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
|
||||
public void addTriggeredAbility(TriggeredAbility ability) {
|
||||
this.triggered.add(ability);
|
||||
System.out.println("added: " + triggered.size());
|
||||
System.out.println(triggered.stream().map(Ability::toString).collect(Collectors.joining("\r\n")));
|
||||
}
|
||||
|
||||
public void removeTriggeredAbility(TriggeredAbility ability) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue