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 { UUID fireReflexiveTriggeredAbility(ReflexiveTriggeredAbility reflexiveAbility, Ability source); + /** + * Inner game engine call to reset game objects to actual versions + * (reset all objects and apply all effects due layer system) + *

+ * 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 { this.gameOver = true; } - // 608.2e + /** + * Must be called between effects/steps in the ability's resolve + *

+ * 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) {