diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 1cb63b2cbd9..4804a99552f 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -701,11 +701,22 @@ public class ContinuousEffects implements Serializable { } layer = filterLayeredEffects(layerEffects, Layer.ControlChangingEffects_2); - for (ContinuousEffect effect: layer) { - HashSet abilities = layeredEffects.getAbility(effect.getId()); - for (Ability ability : abilities) { - effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, ability, game); + // apply control changing effects multiple times if it's needed + // for cases when control over permanents with change control abilities is changed + // e.g. Mind Control is controlled by Steal Enchantment + while (true) { + for (ContinuousEffect effect: layer) { + HashSet abilities = layeredEffects.getAbility(effect.getId()); + for (Ability ability : abilities) { + effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, ability, game); + } } + // if control over all permanent has not changed, we can no longer reapply control changing effects + if (!game.getBattlefield().fireControlChangeEvents(game)) { + break; + } + // reset control before reapplying control changing effects + game.getBattlefield().resetPermanentsControl(); } layer = filterLayeredEffects(layerEffects, Layer.TextChangingEffects_3); for (ContinuousEffect effect: layer) { diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java index 023adc36cfe..20217ada449 100644 --- a/Mage/src/mage/game/GameState.java +++ b/Mage/src/mage/game/GameState.java @@ -403,7 +403,6 @@ public class GameState implements Serializable, Copyable { combat.reset(); this.reset(); effects.apply(game); - battlefield.fireControlChangeEvents(game); } // Remove End of Combat effects diff --git a/Mage/src/mage/game/permanent/Battlefield.java b/Mage/src/mage/game/permanent/Battlefield.java index 3cc58387df0..e532f729533 100644 --- a/Mage/src/mage/game/permanent/Battlefield.java +++ b/Mage/src/mage/game/permanent/Battlefield.java @@ -412,18 +412,28 @@ public class Battlefield implements Serializable { return phasedOut; } + public void resetPermanentsControl() { + for (Permanent perm: field.values()) { + if (perm.isPhasedIn()) { + perm.resetControl(); + } + } + } + /** * since control could change several times during applyEvents we only want to fire * control changed events after all control change effects have been applied * * @param game */ - public void fireControlChangeEvents(Game game) { + public boolean fireControlChangeEvents(Game game) { + boolean controlChanged = false; for (Permanent perm: field.values()) { if (perm.isPhasedIn()) { - perm.checkControlChanged(game); + controlChanged |= perm.checkControlChanged(game); } } + return controlChanged; } } diff --git a/Mage/src/mage/game/permanent/Permanent.java b/Mage/src/mage/game/permanent/Permanent.java index 88ab3cc3a28..9874266c171 100644 --- a/Mage/src/mage/game/permanent/Permanent.java +++ b/Mage/src/mage/game/permanent/Permanent.java @@ -76,7 +76,6 @@ public interface Permanent extends Card, Controllable { boolean addAttachment(UUID permanentId, Game game); boolean removeAttachment(UUID permanentId, Game game); - boolean changeControllerId(UUID controllerId, Game game); boolean canBeTargetedBy(MageObject source, UUID controllerId, Game game); boolean hasProtectionFrom(MageObject source, Game game); boolean hasSummoningSickness(); @@ -119,9 +118,12 @@ public interface Permanent extends Card, Controllable { void setLoyaltyUsed(boolean used); boolean isLoyaltyUsed(); + public void resetControl(); + boolean changeControllerId(UUID controllerId, Game game); + boolean checkControlChanged(Game game); + void beginningOfTurn(Game game); void endOfTurn(Game game); - void checkControlChanged(Game game); int getTurnsOnBattlefield(); void addPower(int power); diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index 3889be96c11..0983859e7d6 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -80,7 +80,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { protected UUID originalControllerId; protected UUID controllerId; protected UUID beforeResetControllerId; - protected boolean controllerChanged; protected int damage; protected boolean controlledFromStartOfControllerTurn; protected int turnsOnBattlefield; @@ -169,9 +168,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { */ @Override public void reset(Game game) { - this.beforeResetControllerId = this.controllerId; - this.controllerId = originalControllerId; - controllerChanged = !controllerId.equals(beforeResetControllerId); + this.resetControl(); this.maxBlocks = 1; this.minBlockedBy = 1; this.maxBlockedBy = 0; @@ -448,42 +445,37 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return this.controllerId; } + @Override + public void resetControl() { + this.beforeResetControllerId = this.controllerId; + this.controllerId = this.originalControllerId; + } + @Override public boolean changeControllerId(UUID controllerId, Game game) { - if (!controllerId.equals(this.controllerId)) { - Player newController = game.getPlayer(controllerId); - if (newController != null && (!newController.hasLeft() || !newController.hasLost())) { - // changeControllerId can be called by continuous effect - // so it will lead to this.controlledFromStartOfControllerTurn set to false over and over - // because of reset(game) method called before applying effect as state-based action - // that changes this.controllerId to original one (actually owner) - if (!controllerId.equals(beforeResetControllerId)) { - this.removeFromCombat(game); - this.controlledFromStartOfControllerTurn = false; - this.controllerChanged = true; - } else { - this.controllerChanged = false; - } - this.controllerId = controllerId; - this.abilities.setControllerId(controllerId); - game.getContinuousEffects().setController(this.objectId, controllerId); - return true; - } + Player newController = game.getPlayer(controllerId); + if (newController != null && (!newController.hasLeft() || !newController.hasLost())) { + this.controllerId = controllerId; + return true; } return false; } @Override - public void checkControlChanged(Game game) { - if (this.controllerChanged) { + public boolean checkControlChanged(Game game) { + if (!controllerId.equals(beforeResetControllerId)) { + this.removeFromCombat(game); + this.controlledFromStartOfControllerTurn = false; + + this.abilities.setControllerId(controllerId); + game.getContinuousEffects().setController(objectId, controllerId); + game.fireEvent(new GameEvent(EventType.LOST_CONTROL, objectId, objectId, beforeResetControllerId)); - // reset the original controller to abilities and ContinuousEffects - if (controllerId.equals(originalControllerId)) { - this.abilities.setControllerId(controllerId); - game.getContinuousEffects().setController(this.objectId, controllerId); - } game.fireEvent(new GameEvent(EventType.GAINED_CONTROL, objectId, objectId, controllerId)); + + return true; } + return false; } @Override