diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index a721ae1c49e..bc0d2f98dec 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -214,16 +214,14 @@ public abstract class AbilityImpl implements Ability { } else { game.addEffect((ContinuousEffect) effect, this); } + /** * All restrained trigger events are fired now. To restrain the * events is mainly neccessary because of the movement of multiple * object at once. If the event is fired directly as one object * moved, other objects are not already in the correct zone to check * for their effects. (e.g. Valakut, the Molten Pinnacle) - */ - game.getState().handleSimultaneousEvent(game); - game.resetShortLivingLKI(); - /** + *
* game.applyEffects() has to be done at least for every effect that
* moves cards/permanent between zones, or changes control of
* objects so Static effects work as intended if dependant from the
@@ -231,8 +229,7 @@ public abstract class AbilityImpl implements Ability {
* abilities with replacement effects deactivated too late Example:
* {@link org.mage.test.cards.replacement.DryadMilitantTest#testDiesByDestroy testDiesByDestroy}
*/
- game.applyEffects();
- game.getState().getTriggers().checkStateTriggers(game);
+ game.getState().processAction(game);
}
return result;
}
diff --git a/Mage/src/main/java/mage/abilities/StateTriggeredAbility.java b/Mage/src/main/java/mage/abilities/StateTriggeredAbility.java
index 137ea7f95ff..3bebed88257 100644
--- a/Mage/src/main/java/mage/abilities/StateTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/StateTriggeredAbility.java
@@ -8,6 +8,15 @@ import mage.game.events.GameEvent;
import java.util.UUID;
/**
+ * 603.8.
+ * Some triggered abilities trigger when a game state (such as a player controlling no permanents of
+ * a particular card type) is true, rather than triggering when an event occurs. These abilities trigger
+ * as soon as the game state matches the condition. They'll go onto the stack at the next available opportunity.
+ * These are called state triggers. (Note that state triggers aren't the same as state-based actions.)
+ * A state-triggered ability doesn't trigger again until the ability has resolved, has been countered,
+ * or has otherwise left the stack. Then, if the object with the ability is still in the same zone and
+ * the game state still matches its trigger condition, the ability will trigger again.
+ *
* @author BetaSteward_at_googlemail.com
*/
public abstract class StateTriggeredAbility extends TriggeredAbilityImpl {
@@ -21,7 +30,8 @@ public abstract class StateTriggeredAbility extends TriggeredAbilityImpl {
}
public boolean canTrigger(Game game) {
- //20100716 - 603.8
+ // 603.8 - A state-triggered ability doesn't trigger again until the ability has resolved,
+ // has been countered, or has otherwise left the stack
return !Boolean.TRUE.equals(game.getState().getValue(getSourceId().toString() + "triggered"));
}
diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java
index 3cc68f8f465..5e671ebac9d 100644
--- a/Mage/src/main/java/mage/game/Game.java
+++ b/Mage/src/main/java/mage/game/Game.java
@@ -465,6 +465,13 @@ public interface Game extends MageItem, Serializable, Copyable
+ * Warning, if you need to process object moves in the middle of the effect/ability
+ * then call game.getState().processAction(game) instead
+ */
void applyEffects();
boolean checkStateAndTriggered();
diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java
index 3c09a509330..01a8873c15b 100644
--- a/Mage/src/main/java/mage/game/GameState.java
+++ b/Mage/src/main/java/mage/game/GameState.java
@@ -655,10 +655,19 @@ public class GameState implements Serializable, Copyable
+ * 608.2e
+ * Some spells and abilities have multiple steps or actions, denoted by separate sentences or clauses,
+ * that involve multiple players. In these cases, the choices for the first action are made in APNAP order,
+ * and then the first action is processed simultaneously. Then the choices for the second action are made in
+ * APNAP order, and then that action is processed simultaneously, and so on. See rule 101.4.
+ */
public void processAction(Game game) {
game.getState().handleSimultaneousEvent(game);
game.applyEffects();
+ game.getState().getTriggers().checkStateTriggers(game);
}
public void applyEffects(Game game) {