diff --git a/Mage/src/mage/abilities/common/delayed/AtTheEndOfTurnDelayedTriggeredAbility.java b/Mage/src/mage/abilities/common/delayed/AtTheEndOfTurnDelayedTriggeredAbility.java new file mode 100644 index 00000000000..369da57d5d0 --- /dev/null +++ b/Mage/src/mage/abilities/common/delayed/AtTheEndOfTurnDelayedTriggeredAbility.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.common.delayed; + +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * @author nantuko + */ +public class AtTheEndOfTurnDelayedTriggeredAbility extends DelayedTriggeredAbility { + + public AtTheEndOfTurnDelayedTriggeredAbility(Effect effect) { + super(effect); + } + + public AtTheEndOfTurnDelayedTriggeredAbility(Effect effect, boolean usesStack) { + super(effect); + this.usesStack = usesStack; + } + + + public AtTheEndOfTurnDelayedTriggeredAbility(AtTheEndOfTurnDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public AtTheEndOfTurnDelayedTriggeredAbility copy() { + return new AtTheEndOfTurnDelayedTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.COMBAT_PHASE_POST) { + return true; + } + return false; + } + + @Override + public String getRule() { + return "At end of turn " + modes.getText(); + } +} diff --git a/Mage/src/mage/abilities/effects/common/LoseControlOnOtherPlayersControllerEffect.java b/Mage/src/mage/abilities/effects/common/LoseControlOnOtherPlayersControllerEffect.java new file mode 100644 index 00000000000..2788af6e04b --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/LoseControlOnOtherPlayersControllerEffect.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.abilities.effects.common; + +import mage.Constants.Outcome; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author nantuko + */ +public class LoseControlOnOtherPlayersControllerEffect extends OneShotEffect { + + public LoseControlOnOtherPlayersControllerEffect() { + super(Outcome.Detriment); + } + + public LoseControlOnOtherPlayersControllerEffect(final LoseControlOnOtherPlayersControllerEffect effect) { + super(effect); + } + + @Override + public LoseControlOnOtherPlayersControllerEffect copy() { + return new LoseControlOnOtherPlayersControllerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.resetOtherTurnsControlled(); + return true; + } + return false; + } + +} diff --git a/Mage/src/mage/abilities/effects/common/turn/ControlTargetPlayerNextTurnEffect.java b/Mage/src/mage/abilities/effects/common/turn/ControlTargetPlayerNextTurnEffect.java new file mode 100644 index 00000000000..af38be782e4 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/turn/ControlTargetPlayerNextTurnEffect.java @@ -0,0 +1,67 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. +*/ +package mage.abilities.effects.common.turn; + +import mage.Constants; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.game.Game; +import mage.game.turn.TurnMod; + +import java.util.UUID; + +/** + * @author nantuko + */ +public class ControlTargetPlayerNextTurnEffect extends OneShotEffect { + + public ControlTargetPlayerNextTurnEffect() { + super(Constants.Outcome.Benefit); + staticText = "You control target player during that player's next turn. (You see all cards that player could see and make all decisions for the player.)"; + } + + public ControlTargetPlayerNextTurnEffect(ControlTargetPlayerNextTurnEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID targetId = source.getFirstTarget(); + UUID controllerId = source.getControllerId(); + if (targetId != null && controllerId != null && !targetId.equals(controllerId)) { + game.getState().getTurnMods().add(new TurnMod(targetId, controllerId)); + return true; + } + return false; + } + + @Override + public ControlTargetPlayerNextTurnEffect copy() { + return new ControlTargetPlayerNextTurnEffect(); + } +} diff --git a/Mage/src/mage/game/turn/CleanupStep.java b/Mage/src/mage/game/turn/CleanupStep.java index f0aa0f20403..d973557a04d 100644 --- a/Mage/src/mage/game/turn/CleanupStep.java +++ b/Mage/src/mage/game/turn/CleanupStep.java @@ -56,8 +56,10 @@ public class CleanupStep extends Step { super.beginStep(game, activePlayerId); Player activePlayer = game.getPlayer(activePlayerId); //20091005 - 514.1 - if (!activePlayer.hasLeft() && !activePlayer.hasLost()) + if (!activePlayer.hasLeft() && !activePlayer.hasLost()) { activePlayer.discardToMax(game); + activePlayer.setGameUnderYourControl(true); + } //20100423 - 514.2 game.getBattlefield().endOfTurn(activePlayerId, game); game.getState().removeEotEffects(game); diff --git a/Mage/src/mage/game/turn/Turn.java b/Mage/src/mage/game/turn/Turn.java index 16fff6a74de..212e973df3f 100644 --- a/Mage/src/mage/game/turn/Turn.java +++ b/Mage/src/mage/game/turn/Turn.java @@ -106,6 +106,8 @@ public class Turn implements Serializable { if (game.getState().getTurnMods().skipTurn(activePlayerId)) return; + checkTurnIsControlledByOtherPlayer(game, activePlayerId); + this.activePlayerId = activePlayerId; resetCounts(); game.getPlayer(activePlayerId).beginTurn(game); @@ -127,6 +129,13 @@ public class Turn implements Serializable { playExtraTurns(game); } + private void checkTurnIsControlledByOtherPlayer(Game game, UUID activePlayerId) { + UUID newControllerId = game.getState().getTurnMods().controlsTurn(activePlayerId); + if (newControllerId != null && !newControllerId.equals(activePlayerId)) { + game.getPlayer(newControllerId).controlPlayersTurn(game, activePlayerId); + } + } + private void resetCounts() { for (Phase phase: phases) { phase.resetCount(); diff --git a/Mage/src/mage/game/turn/TurnMod.java b/Mage/src/mage/game/turn/TurnMod.java index bceddbebda5..0310ab4c1bc 100644 --- a/Mage/src/mage/game/turn/TurnMod.java +++ b/Mage/src/mage/game/turn/TurnMod.java @@ -41,6 +41,7 @@ import mage.Constants.TurnPhase; public class TurnMod implements Serializable { private UUID playerId; + private UUID newControllerId; private boolean extraTurn; private boolean skipTurn; private TurnPhase extraPhase; @@ -58,8 +59,14 @@ public class TurnMod implements Serializable { this.extraTurn = true; } + public TurnMod(UUID playerId, UUID newControllerId) { + this.playerId = playerId; + this.newControllerId = newControllerId; + } + public TurnMod(final TurnMod mod) { this.playerId = mod.playerId; + this.newControllerId = mod.newControllerId; this.extraTurn = mod.extraTurn; this.skipTurn = mod.skipTurn; this.extraPhase = mod.extraPhase; @@ -74,7 +81,7 @@ public class TurnMod implements Serializable { /** * * @param playerId - * @param extraPhase + * @param phase * @param afterPhase - set to null if extraPhase is after the next phase */ public TurnMod(UUID playerId, TurnPhase phase, TurnPhase afterPhase, boolean skip) { @@ -89,7 +96,7 @@ public class TurnMod implements Serializable { /** * * @param playerId - * @param extraStep + * @param step * @param afterStep - set to null if extraStep is after the next step */ public TurnMod(UUID playerId, Step step, PhaseStep afterStep) { @@ -139,6 +146,10 @@ public class TurnMod implements Serializable { return afterStep; } + public UUID getNewControllerId() { + return newControllerId; + } + public TurnMod copy() { return new TurnMod(this); } diff --git a/Mage/src/mage/game/turn/TurnMods.java b/Mage/src/mage/game/turn/TurnMods.java index 8456d44c754..d0b10bf395a 100644 --- a/Mage/src/mage/game/turn/TurnMods.java +++ b/Mage/src/mage/game/turn/TurnMods.java @@ -72,6 +72,27 @@ public class TurnMods extends ArrayList { return false; } + public UUID controlsTurn(UUID playerId) { + ListIterator it = this.listIterator(this.size()); + UUID newControllerId = null; + while (it.hasPrevious()) { + TurnMod turnMod = it.previous(); + if (turnMod.getNewControllerId() != null && turnMod.getPlayerId().equals(playerId)) { + newControllerId = turnMod.getNewControllerId(); + it.remove(); + } + } + // now delete all other - control next turn effect is not cumulative + it = this.listIterator(this.size()); + while (it.hasPrevious()) { + TurnMod turnMod = it.previous(); + if (turnMod.getNewControllerId() != null && turnMod.getPlayerId().equals(playerId)) { + it.remove(); + } + } + return newControllerId; + } + public Step extraStep(UUID playerId, PhaseStep afterStep) { ListIterator it = this.listIterator(this.size()); while (it.hasPrevious()) { diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index 5fef0679a5c..40a713cb45c 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -102,6 +102,43 @@ public interface Player extends MageItem, Copyable { public ManaPool getManaPool(); public Set getInRange(); + /** + * Returns a set of players which turns under you control. + * Doesn't include yourself. + * + * @return + */ + public Set getPlayersUnderYourControl(); + + /** + * Defines player whose turn you control at the moment. + * @param playerId + */ + public void controlPlayersTurn(Game game, UUID playerId); + + /** + * Resets players whose turns you control at the moment. + */ + public void resetOtherTurnsControlled(); + + /** + * Returns false in case you don't control the game. + * + * Note: For effects like "You control target player during that player's next turn". + * + * @return + */ + public boolean isGameUnderYourControl(); + + /** + * Returns false in case you don't control the game. + * + * Note: For effects like "You control target player during that player's next turn". + * + * @param value + */ + public void setGameUnderYourControl(boolean value); + public boolean isTestMode(); public void setTestMode(boolean value); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index ae22dfff243..27d2ee3707c 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -42,17 +42,11 @@ import mage.Constants.RangeOfInfluence; import mage.Constants.Zone; import mage.MageObject; import mage.Mana; -import mage.abilities.Abilities; -import mage.abilities.AbilitiesImpl; -import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; -import mage.abilities.Mode; -import mage.abilities.PlayLandAbility; -import mage.abilities.SpecialAction; -import mage.abilities.SpellAbility; -import mage.abilities.TriggeredAbility; +import mage.abilities.*; import mage.abilities.common.PassAbility; +import mage.abilities.common.delayed.AtTheEndOfTurnDelayedTriggeredAbility; import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.LoseControlOnOtherPlayersControllerEffect; import mage.abilities.keyword.*; import mage.abilities.mana.ManaAbility; import mage.abilities.mana.ManaOptions; @@ -100,6 +94,8 @@ public abstract class PlayerImpl> implements Player, Ser protected Set inRange = new HashSet(); protected boolean isTestMode = false; protected boolean lifeTotalCanChange = true; + protected boolean isGameUnderYourControl = true; + protected Set playersUnderYourControl = new HashSet(); @Override public abstract T copy(); @@ -234,6 +230,41 @@ public abstract class PlayerImpl> implements Player, Ser return inRange; } + @Override + public Set getPlayersUnderYourControl() { + return this.playersUnderYourControl; + } + + @Override + public void controlPlayersTurn(Game game, UUID playerId) { + if (!playerId.equals(getId())) { + this.playersUnderYourControl.add(playerId); + Player player = game.getPlayer(playerId); + if (!player.hasLeft() && !player.hasLost()) { + player.setGameUnderYourControl(false); + } + DelayedTriggeredAbility ability = new AtTheEndOfTurnDelayedTriggeredAbility(new LoseControlOnOtherPlayersControllerEffect()); + ability.setSourceId(getId()); + ability.setControllerId(getId()); + game.addDelayedTriggeredAbility(ability); + } + } + + @Override + public void resetOtherTurnsControlled() { + playersUnderYourControl.clear(); + } + + @Override + public boolean isGameUnderYourControl() { + return isGameUnderYourControl; + } + + @Override + public void setGameUnderYourControl(boolean value) { + this.isGameUnderYourControl = value; + } + @Override public void endOfTurn(Game game) { this.passedTurn = false;