/* * 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.game.turn; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.UUID; import mage.constants.PhaseStep; import mage.constants.TurnPhase; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; /** * * @author BetaSteward_at_googlemail.com */ public class Turn implements Serializable { private Phase currentPhase; private UUID activePlayerId; private final List phases = new ArrayList<>(); private boolean declareAttackersStepStarted = false; public Turn() { phases.add(new BeginningPhase()); phases.add(new PreCombatMainPhase()); phases.add(new CombatPhase()); phases.add(new PostCombatMainPhase()); phases.add(new EndPhase()); } public Turn(final Turn turn) { if (turn.currentPhase != null) { this.currentPhase = turn.currentPhase.copy(); } this.activePlayerId = turn.activePlayerId; for (Phase phase: turn.phases) { this.phases.add(phase.copy()); } } public TurnPhase getPhaseType() { if (currentPhase != null) { return currentPhase.getType(); } return null; } public Phase getPhase() { return currentPhase; } public Phase getPhase(TurnPhase turnPhase) { for (Phase phase: phases) { if (phase.getType() == turnPhase) { return phase; } } return null; } public void setPhase(Phase phase) { this.currentPhase = phase; } public Step getStep() { if (currentPhase != null) { return currentPhase.getStep(); } return null; } public PhaseStep getStepType() { if (currentPhase != null && currentPhase.getStep() != null) { return currentPhase.getStep().getType(); } return null; } public void play(Game game, UUID activePlayerId) { this.setDeclareAttackersStepStarted(false); if (game.isPaused() || game.gameOver(null)) { return; } if (game.getState().getTurnMods().skipTurn(activePlayerId)) { return; } checkTurnIsControlledByOtherPlayer(game, activePlayerId); this.activePlayerId = activePlayerId; resetCounts(); game.getPlayer(activePlayerId).beginTurn(game); for (Phase phase: phases) { if (game.isPaused() || game.gameOver(null)) { return; } currentPhase = phase; game.fireEvent(new GameEvent(GameEvent.EventType.PHASE_CHANGED, activePlayerId, null, activePlayerId)); if (!game.getState().getTurnMods().skipPhase(activePlayerId, currentPhase.getType())) { if (phase.play(game, activePlayerId)) { //20091005 - 500.4/703.4n game.emptyManaPools(); //game.saveState(); //20091005 - 500.8 while (playExtraPhases(game, phase.getType())) { } } } // magenoxx: this causes bugs when we need to add several phases connected with each other (WorldAtWarTest) //if (!currentPhase.equals(phase)) // phase was changed from the card // break; } } public void resumePlay(Game game, boolean wasPaused) { activePlayerId = game.getActivePlayerId(); UUID priorityPlayerId = game.getPriorityPlayerId(); TurnPhase phaseType = game.getPhase().getType(); PhaseStep stepType = game.getStep().getType(); Iterator it = phases.iterator(); Phase phase; do { phase = it.next(); currentPhase = phase; } while (phase.type != phaseType); if (phase.resumePlay(game, stepType, wasPaused)) { //20091005 - 500.4/703.4n game.emptyManaPools(); //game.saveState(); //20091005 - 500.8 playExtraPhases(game, phase.getType()); } while (it.hasNext()) { phase = it.next(); if (game.isPaused() || game.gameOver(null)) { return; } currentPhase = phase; if (!game.getState().getTurnMods().skipPhase(activePlayerId, currentPhase.getType())) { if (phase.play(game, activePlayerId)) { //20091005 - 500.4/703.4n game.emptyManaPools(); //game.saveState(); //20091005 - 500.8 playExtraPhases(game, phase.getType()); } } if (!currentPhase.equals(phase)) { // phase was changed from the card game.fireEvent(new GameEvent(GameEvent.EventType.PHASE_CHANGED, activePlayerId, null, activePlayerId)); break; } } } 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(); } } private boolean playExtraPhases(Game game, TurnPhase afterPhase) { TurnMod extraPhaseTurnMod = game.getState().getTurnMods().extraPhase(activePlayerId, afterPhase); if (extraPhaseTurnMod == null) { return false; } TurnPhase extraPhase = extraPhaseTurnMod.getExtraPhase(); if (extraPhase == null) { return false; } Phase phase; switch(extraPhase) { case BEGINNING: phase = new BeginningPhase(); break; case PRECOMBAT_MAIN: phase = new PreCombatMainPhase(); break; case COMBAT: phase = new CombatPhase(); break; case POSTCOMBAT_MAIN: phase = new PostCombatMainPhase(); break; default: phase = new EndPhase(); } currentPhase = phase; game.fireEvent(new GameEvent(GameEvent.EventType.PHASE_CHANGED, activePlayerId, extraPhaseTurnMod.getId(), activePlayerId)); Player activePlayer = game.getPlayer(activePlayerId); if (activePlayer != null) { game.informPlayers(new StringBuilder(activePlayer.getName()).append(" starts an additional ").append(phase.getType().toString()).append(" phase").toString()); } phase.play(game, activePlayerId); return true; } /*protected void playExtraTurns(Game game) { while (game.getState().getTurnMods().extraTurn(activePlayerId)) { this.play(game, activePlayerId); } }*/ /** * Used for some spells with end turn effect (e.g. Time Stop). * * @param game * @param activePlayerId */ public void endTurn(Game game, UUID activePlayerId) { // Exile all spells and abilities on the stack game.getStack().clear(); // Discard down to your maximum hand size. Player activePlayer = game.getPlayer(activePlayerId); game.getState().setPriorityPlayerId(activePlayer.getId()); //20091005 - 514.1 if (!activePlayer.hasLeft() && !activePlayer.hasLost()) { activePlayer.discardToMax(game); activePlayer.setGameUnderYourControl(true); } // Damage wears off. //20100423 - 514.2 game.getBattlefield().endOfTurn(activePlayerId, game); game.getState().removeEotEffects(game); Phase phase = new EndPhase(); phase.setStep(new CleanupStep()); currentPhase = phase; game.fireEvent(new GameEvent(GameEvent.EventType.PHASE_CHANGED, activePlayerId, null, activePlayerId)); //phase.play(game, activePlayerId); } public boolean isDeclareAttackersStepStarted() { return declareAttackersStepStarted; } public void setDeclareAttackersStepStarted(boolean declareAttackersStepStarted) { this.declareAttackersStepStarted = declareAttackersStepStarted; } public Turn copy() { return new Turn(this); } }