foul-magics/Mage/src/main/java/mage/game/turn/Phase.java

281 lines
9.2 KiB
Java

package mage.game.turn;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.players.Player;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com
*/
public abstract class Phase implements Serializable {
protected TurnPhase type;
protected List<Step> steps = new ArrayList<>();
protected EventType event;
protected EventType preEvent;
protected EventType postEvent;
protected UUID activePlayerId;
protected Step currentStep;
protected int count;
public abstract Phase copy();
public Phase() {
}
protected Phase(final Phase phase) {
this.type = phase.type;
this.event = phase.event;
this.preEvent = phase.preEvent;
this.postEvent = phase.postEvent;
this.activePlayerId = phase.activePlayerId;
if (phase.currentStep != null) {
this.currentStep = phase.currentStep.copy();
}
this.count = phase.count;
for (Step step : phase.steps) {
this.steps.add(step.copy());
}
}
public TurnPhase getType() {
return type;
}
public Step getStep() {
return currentStep;
}
public void setStep(Step step) {
this.currentStep = step;
}
public void resetCount() {
count = 0;
}
public int getCount() {
return count;
}
public boolean play(Game game, UUID activePlayerId) {
if (game.isPaused() || game.checkIfGameIsOver()) {
return false;
}
this.activePlayerId = activePlayerId;
if (beginPhase(game, activePlayerId)) {
for (Step step : steps) {
if (game.isPaused() || game.checkIfGameIsOver()) {
return false;
}
if (game.getTurn().isEndTurnRequested() && step.getType() != PhaseStep.CLEANUP) {
continue;
}
currentStep = step;
TurnMod skipStepMod = game.getState().getTurnMods().useNextSkipStep(activePlayerId, getStep().getType());
if (skipStepMod == null) {
playStep(game);
if (game.executingRollback()) {
return true;
}
} else {
Player player = game.getPlayer(skipStepMod.getPlayerId());
if (player != null) {
game.informPlayers(String.format("%s skips %s step%s",
player.getLogName(),
skipStepMod.getSkipStep().toString(),
skipStepMod.getInfo()
));
}
}
if (!game.isSimulation() && checkStopOnStepOption(game)) {
return false;
}
}
if (game.isPaused() || game.checkIfGameIsOver()) {
return false;
}
count++;
endPhase(game, activePlayerId);
return true;
}
return false;
}
private boolean checkStopOnStepOption(Game game) {
if (game.getOptions().stopOnTurn != null
&& game.getOptions().stopOnTurn <= game.getState().getTurnNum()
&& game.getOptions().stopAtStep == getStep().getType()) {
game.pause();
return true;
}
return false;
}
public boolean resumePlay(Game game, PhaseStep stepType, boolean wasPaused) {
if (game.isPaused() || game.checkIfGameIsOver()) {
return false;
}
this.activePlayerId = game.getActivePlayerId();
Iterator<Step> it = steps.iterator();
Step step;
do {
step = it.next();
currentStep = step;
} while (step.getType() != stepType);
resumeStep(game, wasPaused);
while (it.hasNext()) {
step = it.next();
if (game.isPaused() || game.checkIfGameIsOver()) {
return false;
}
currentStep = step;
TurnMod skipStepMod = game.getState().getTurnMods().useNextSkipStep(activePlayerId, currentStep.getType());
if (skipStepMod == null) {
playStep(game);
if (game.executingRollback()) {
return true;
}
} else {
Player player = game.getPlayer(skipStepMod.getPlayerId());
if (player != null) {
game.informPlayers(String.format("%s skips %s step%s",
player.getLogName(),
skipStepMod.getSkipStep().toString(),
skipStepMod.getInfo()
));
}
}
}
if (game.isPaused() || game.checkIfGameIsOver()) {
return false;
}
count++;
endPhase(game, activePlayerId);
return true;
}
public boolean beginPhase(Game game, UUID activePlayerId) {
if (!game.replaceEvent(new GameEvent(event, null, null, activePlayerId))) {
game.fireEvent(new GameEvent(preEvent, null, null, activePlayerId));
return true;
}
return false;
}
public void endPhase(Game game, UUID activePlayerId) {
game.fireEvent(new GameEvent(postEvent, null, null, activePlayerId));
game.getState().getTriggers().removeAbilitiesOfNonExistingSources(game); // e.g. tokens that left the battlefield
}
public void prePriority(Game game, UUID activePlayerId) {
currentStep.beginStep(game, activePlayerId);
}
public void postPriority(Game game, UUID activePlayerId) {
currentStep.endStep(game, activePlayerId);
//20091005 - 500.4/703.4n
game.emptyManaPools(null);
//20091005 - 500.9
playExtraSteps(game, currentStep.getType());
}
protected void playStep(Game game) {
if (!currentStep.skipStep(game, activePlayerId)) {
game.getState().increaseStepNum();
prePriority(game, activePlayerId);
if (!game.isPaused() && !game.checkIfGameIsOver() && !game.executingRollback()) {
currentStep.priority(game, activePlayerId, false);
if (game.executingRollback()) {
return;
}
}
if (!game.isPaused() && !game.checkIfGameIsOver() && !game.executingRollback()) {
postPriority(game, activePlayerId);
}
}
}
protected void resumeStep(Game game, boolean wasPaused) {
boolean resuming = true;
if (currentStep == null || currentStep.getStepPart() == null) {
game.end();
return;
}
switch (currentStep.getStepPart()) {
case PRE:
if (wasPaused) {
currentStep.resumeBeginStep(game, activePlayerId);
resuming = false;
} else {
prePriority(game, activePlayerId);
}
case PRIORITY:
if (!game.isPaused() && !game.checkIfGameIsOver()) {
currentStep.priority(game, activePlayerId, resuming);
}
case POST:
if (!game.isPaused() && !game.checkIfGameIsOver()) {
postPriority(game, activePlayerId);
}
}
}
private void playExtraSteps(Game game, PhaseStep afterStep) {
while (true) {
TurnMod extraStepMod = game.getState().getTurnMods().useNextExtraStep(activePlayerId, afterStep);
if (extraStepMod == null) {
return;
}
currentStep = extraStepMod.getExtraStep();
Player player = game.getPlayer(extraStepMod.getPlayerId());
if (player != null && player.canRespond()) {
game.informPlayers(String.format("%s takes an extra %s step%s",
player.getLogName(),
extraStepMod.getExtraStep().toString(),
extraStepMod.getInfo()
));
playStep(game);
} else {
return;
}
}
}
/**
* One card [[Okea, Splitter of Seconds]], adds extra beginning phases with
* all but upkeep steps skipped.
* To achieve that, this function is called right after creating the extra Phase,
* before running it.
*/
public void keepOnlyStep(PhaseStep step) {
if (count != 0) {
throw new IllegalStateException("Wrong code usage: illegal Phase modification once it started running");
}
this.steps = this.steps.stream().filter(s -> s.getType().equals(step)).collect(Collectors.toList());
if (this.steps.isEmpty()) {
throw new IllegalStateException("Wrong code usage: keepOnlyStep should not remove all the steps in a phase - " + step);
}
}
public String toString() {
return type.toString();
}
}