Fixed (probably) the player1 concedes but other player2 wins. Fixed that if player runs out of timer time or player lose of beeing idle, the match will end correctly.

This commit is contained in:
LevelX2 2014-05-01 19:34:52 +02:00
parent 6d039e4262
commit 473c9e207b
32 changed files with 286 additions and 132 deletions

View file

@ -71,10 +71,12 @@ public class NewTournamentDialog extends MageDialog {
private TableView table; private TableView table;
private UUID playerId; private UUID playerId;
private UUID roomId; private UUID roomId;
private Session session; private final Session session;
private String lastSessionId; private String lastSessionId;
private final List<TournamentPlayerPanel> players = new ArrayList<>(); private final List<TournamentPlayerPanel> players = new ArrayList<>();
private final List<JComboBox> packs = new ArrayList<>(); private final List<JComboBox> packs = new ArrayList<>();
private final int CONSTRUCTION_TIME_MIN = 6;
private final int CONSTRUCTION_TIME_MAX = 30;
/** Creates new form NewTournamentDialog */ /** Creates new form NewTournamentDialog */
public NewTournamentDialog() { public NewTournamentDialog() {
@ -84,7 +86,7 @@ public class NewTournamentDialog extends MageDialog {
txtName.setText("Tournament"); txtName.setText("Tournament");
this.spnNumWins.setModel(new SpinnerNumberModel(2, 1, 5, 1)); this.spnNumWins.setModel(new SpinnerNumberModel(2, 1, 5, 1));
this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1)); this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1));
this.spnConstructTime.setModel(new SpinnerNumberModel(10, 10, 30, 5)); this.spnConstructTime.setModel(new SpinnerNumberModel(10, CONSTRUCTION_TIME_MIN, CONSTRUCTION_TIME_MAX, 2));
this.spnNumRounds.setModel(new SpinnerNumberModel(2, 2, 10, 1)); this.spnNumRounds.setModel(new SpinnerNumberModel(2, 2, 10, 1));
} }
@ -428,8 +430,7 @@ public class NewTournamentDialog extends MageDialog {
if (tOptions.getLimitedOptions() == null) { if (tOptions.getLimitedOptions() == null) {
tOptions.setLimitedOptions(new LimitedOptions()); tOptions.setLimitedOptions(new LimitedOptions());
} }
tOptions.getLimitedOptions().setConstructionTime(60); tOptions.getLimitedOptions().setConstructionTime((Integer)this.spnConstructTime.getValue() * 60);
// tOptions.getLimitedOptions().setConstructionTime((Integer)this.spnConstructTime.getValue() * 60);
if (tournamentType.isCubeBooster()) { if (tournamentType.isCubeBooster()) {
tOptions.getLimitedOptions().setDraftCubeName(this.cbDraftCube.getSelectedItem().toString()); tOptions.getLimitedOptions().setDraftCubeName(this.cbDraftCube.getSelectedItem().toString());
} else { } else {
@ -646,7 +647,11 @@ public class NewTournamentDialog extends MageDialog {
break; break;
} }
} }
this.spnConstructTime.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_CONSTR_TIME, "600"))/60); int constructionTime = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_CONSTR_TIME, "600")) / 60;
if (constructionTime < CONSTRUCTION_TIME_MIN || constructionTime > CONSTRUCTION_TIME_MAX) {
constructionTime = CONSTRUCTION_TIME_MIN;
}
this.spnConstructTime.setValue(constructionTime);
String tournamentTypeName = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_TYPE, "Sealed Elimination"); String tournamentTypeName = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_TYPE, "Sealed Elimination");
for (TournamentTypeView tournamentTypeView : session.getTournamentTypes()) { for (TournamentTypeView tournamentTypeView : session.getTournamentTypes()) {
if (tournamentTypeView.getName().equals(tournamentTypeName)) { if (tournamentTypeView.getName().equals(tournamentTypeName)) {

View file

@ -12,6 +12,7 @@ public interface Action {
/** /**
* Executes action. * Executes action.
* @throws mage.MageException
*/ */
void execute() throws MageException; void execute() throws MageException;
} }

View file

@ -1,11 +1,10 @@
package mage.utils.timer; package mage.utils.timer;
import mage.MageException;
import mage.interfaces.Action;
import org.apache.log4j.Logger;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import mage.MageException;
import mage.interfaces.Action;
import org.apache.log4j.Logger;
/** /**
* @author noxx * @author noxx
@ -14,14 +13,11 @@ public class PriorityTimer extends TimerTask {
private static final Logger logger = Logger.getLogger(PriorityTimer.class); private static final Logger logger = Logger.getLogger(PriorityTimer.class);
private final long delay;
private final Action taskOnTimeout;
private int count; private int count;
private long delay;
private Action taskOnTimeout;
private Action taskOnTick; private Action taskOnTick;
private States state = States.NONE; private States state = States.NONE;
enum States { enum States {

View file

@ -72,14 +72,18 @@ public class MatchView implements Serializable {
} }
StringBuilder sb1 = new StringBuilder(); StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder(); StringBuilder sb2 = new StringBuilder();
for (MatchPlayer player: match.getPlayers()) { for (MatchPlayer matchPlayer: match.getPlayers()) {
sb1.append(player.getName()); sb1.append(matchPlayer.getName());
if(player.hasQuit()) { if(matchPlayer.hasQuit()) {
if (matchPlayer.hasTimerTimeout()) {
sb1.append(" [timer] ");
} else {
sb1.append(" [quit] "); sb1.append(" [quit] ");
} }
}
sb1.append(", "); sb1.append(", ");
sb2.append(player.getName()).append(" "); sb2.append(matchPlayer.getName()).append(" ");
sb2.append(player.getWins()).append("-").append(player.getLoses()).append(", "); sb2.append(matchPlayer.getWins()).append("-").append(matchPlayer.getLoses()).append(", ");
} }
players = sb1.substring(0, sb1.length() - 2); players = sb1.substring(0, sb1.length() - 2);
result = sb2.substring(0, sb2.length() - 2); result = sb2.substring(0, sb2.length() - 2);

View file

@ -39,7 +39,6 @@ import mage.game.Seat;
import mage.game.Table; import mage.game.Table;
import mage.game.match.MatchPlayer; import mage.game.match.MatchPlayer;
import mage.game.tournament.TournamentPlayer; import mage.game.tournament.TournamentPlayer;
import org.jboss.logging.Logger;
/** /**
* *

View file

@ -54,7 +54,7 @@ public class TournamentGameView implements Serializable {
this.matchId = pair.getMatch().getId(); this.matchId = pair.getMatch().getId();
this.gameId = game.getId(); this.gameId = game.getId();
this.players = pair.getPlayer1().getPlayer().getName() + " - " + pair.getPlayer2().getPlayer().getName(); this.players = pair.getPlayer1().getPlayer().getName() + " - " + pair.getPlayer2().getPlayer().getName();
if (game.isGameOver()) { if (game.hasEnded()) {
this.state = "Finished"; this.state = "Finished";
this.result = game.getWinner(); this.result = game.getWinner();
} }

View file

@ -467,7 +467,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
logger.trace("interrupted - " + val); logger.trace("interrupted - " + val);
return val; return val;
} }
if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.isGameOver()) { if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.gameOver(null)) {
logger.trace("Add actions -- reached end state, node count=" + SimulationNode2.nodeCount + ", depth=" + depth); logger.trace("Add actions -- reached end state, node count=" + SimulationNode2.nodeCount + ", depth=" + depth);
val = GameStateEvaluator2.evaluate(playerId, game); val = GameStateEvaluator2.evaluate(playerId, game);
UUID currentPlayerId = node.getGame().getPlayerList().get(); UUID currentPlayerId = node.getGame().getPlayerList().get();
@ -488,7 +488,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
} }
} }
if (game.isGameOver()) { if (game.gameOver(null)) {
val = GameStateEvaluator2.evaluate(playerId, game); val = GameStateEvaluator2.evaluate(playerId, game);
} else if (node.getChildren().size() > 0) { } else if (node.getChildren().size() > 0) {
//declared attackers or blockers or triggered abilities //declared attackers or blockers or triggered abilities
@ -534,7 +534,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
logger.debug("Sim Prio [" + depth + "] -- repeated action: " + action.toString()); logger.debug("Sim Prio [" + depth + "] -- repeated action: " + action.toString());
continue; continue;
} }
if (!sim.isGameOver() && action.isUsesStack()) { if (!sim.gameOver(null) && action.isUsesStack()) {
// only pass if the last action uses the stack // only pass if the last action uses the stack
sim.getPlayer(currentPlayer.getId()).pass(game); sim.getPlayer(currentPlayer.getId()).pass(game);
sim.getPlayerList().getNext(); sim.getPlayerList().getNext();
@ -797,7 +797,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
break; break;
case CLEANUP: case CLEANUP:
game.getPhase().getStep().beginStep(game, activePlayerId); game.getPhase().getStep().beginStep(game, activePlayerId);
if (!game.checkStateAndTriggered() && !game.isGameOver()) { if (!game.checkStateAndTriggered() && !game.gameOver(null)) {
game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext());
game.getTurn().setPhase(new BeginningPhase()); game.getTurn().setPhase(new BeginningPhase());
game.getPhase().setStep(new UntapStep()); game.getPhase().setStep(new UntapStep());

View file

@ -229,7 +229,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
return GameStateEvaluator2.evaluate(playerId, game); return GameStateEvaluator2.evaluate(playerId, game);
} }
// Condition to stop deeper simulation // Condition to stop deeper simulation
if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.isGameOver()) { if (depth <= 0 || SimulationNode2.nodeCount > maxNodes || game.gameOver(null)) {
val = GameStateEvaluator2.evaluate(playerId, game); val = GameStateEvaluator2.evaluate(playerId, game);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder("Add Actions -- reached end state <").append(val).append(">"); StringBuilder sb = new StringBuilder("Add Actions -- reached end state <").append(val).append(">");
@ -265,7 +265,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
} }
} }
if (game.isGameOver()) { if (game.gameOver(null)) {
val = GameStateEvaluator2.evaluate(playerId, game); val = GameStateEvaluator2.evaluate(playerId, game);
} }
else if (stepFinished) { else if (stepFinished) {
@ -494,7 +494,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId()));
Combat simCombat = sim.getCombat().copy(); Combat simCombat = sim.getCombat().copy();
finishCombat(sim); finishCombat(sim);
if (sim.isGameOver()) { if (sim.gameOver(null)) {
val = GameStateEvaluator2.evaluate(playerId, sim); val = GameStateEvaluator2.evaluate(playerId, sim);
} }
else if (!counter) { else if (!counter) {
@ -568,7 +568,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
logger.debug("interrupted"); logger.debug("interrupted");
return; return;
} }
if (!game.isGameOver()) { if (!game.gameOver(null)) {
game.getPhase().setStep(step); game.getPhase().setStep(step);
if (!step.skipStep(game, game.getActivePlayerId())) { if (!step.skipStep(game, game.getActivePlayerId())) {
step.beginStep(game, game.getActivePlayerId()); step.beginStep(game, game.getActivePlayerId());
@ -617,7 +617,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
logger.debug("interrupted"); logger.debug("interrupted");
return; return;
} }
if (!game.isGameOver()) { if (!game.gameOver(null)) {
game.getTurn().getPhase().endPhase(game, game.getActivePlayerId()); game.getTurn().getPhase().endPhase(game, game.getActivePlayerId());
game.getTurn().setPhase(new EndPhase()); game.getTurn().setPhase(new EndPhase());
if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) { if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) {

View file

@ -33,7 +33,7 @@ public class GameStateEvaluator2 {
public static int evaluate(UUID playerId, Game game) { public static int evaluate(UUID playerId, Game game) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next());
if (game.isGameOver()) { if (game.gameOver(null)) {
if (player.hasLost() || opponent.hasWon()) { if (player.hasLost() || opponent.hasWon()) {
return LOSE_GAME_SCORE; return LOSE_GAME_SCORE;
} }

View file

@ -60,12 +60,14 @@ public class ActionSimulator {
public int evaluateState() { public int evaluateState() {
Player opponent = game.getPlayer(game.getOpponents(player.getId()).iterator().next()); Player opponent = game.getPlayer(game.getOpponents(player.getId()).iterator().next());
if (game.isGameOver()) { if (game.gameOver(null)) {
if (player.hasLost() || opponent.hasWon()) if (player.hasLost() || opponent.hasWon()) {
return Integer.MIN_VALUE; return Integer.MIN_VALUE;
if (opponent.hasLost() || player.hasWon()) }
if (opponent.hasLost() || player.hasWon()) {
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
} }
}
int value = player.getLife(); int value = player.getLife();
value -= opponent.getLife(); value -= opponent.getLife();
PermanentEvaluator evaluator = new PermanentEvaluator(); PermanentEvaluator evaluator = new PermanentEvaluator();

View file

@ -58,11 +58,11 @@ public class MCTSNode {
private int visits = 0; private int visits = 0;
private int wins = 0; private int wins = 0;
private MCTSNode parent; private MCTSNode parent;
private List<MCTSNode> children = new ArrayList<MCTSNode>(); private final List<MCTSNode> children = new ArrayList<MCTSNode>();
private Ability action; private Ability action;
private Game game; private Game game;
private Combat combat; private Combat combat;
private String stateValue; private final String stateValue;
private UUID playerId; private UUID playerId;
private boolean terminal = false; private boolean terminal = false;
@ -71,7 +71,7 @@ public class MCTSNode {
public MCTSNode(Game game) { public MCTSNode(Game game) {
this.game = game; this.game = game;
this.stateValue = game.getState().getValue(false, game); this.stateValue = game.getState().getValue(false, game);
this.terminal = game.isGameOver(); this.terminal = game.gameOver(null);
setPlayer(); setPlayer();
nodeCount = 1; nodeCount = 1;
} }
@ -79,7 +79,7 @@ public class MCTSNode {
protected MCTSNode(MCTSNode parent, Game game, Ability action) { protected MCTSNode(MCTSNode parent, Game game, Ability action) {
this.game = game; this.game = game;
this.stateValue = game.getState().getValue(false, game); this.stateValue = game.getState().getValue(false, game);
this.terminal = game.isGameOver(); this.terminal = game.gameOver(null);
this.parent = parent; this.parent = parent;
this.action = action; this.action = action;
setPlayer(); setPlayer();
@ -90,22 +90,23 @@ public class MCTSNode {
this.game = game; this.game = game;
this.combat = combat; this.combat = combat;
this.stateValue = game.getState().getValue(false, game); this.stateValue = game.getState().getValue(false, game);
this.terminal = game.isGameOver(); this.terminal = game.gameOver(null);
this.parent = parent; this.parent = parent;
setPlayer(); setPlayer();
nodeCount++; nodeCount++;
} }
private void setPlayer() { private void setPlayer() {
if (game.getStep().getStepPart() == StepPart.PRIORITY) if (game.getStep().getStepPart() == StepPart.PRIORITY) {
playerId = game.getPriorityPlayerId(); playerId = game.getPriorityPlayerId();
else { } else {
if (game.getStep().getType() == PhaseStep.DECLARE_BLOCKERS) if (game.getStep().getType() == PhaseStep.DECLARE_BLOCKERS) {
playerId = game.getCombat().getDefenders().iterator().next(); playerId = game.getCombat().getDefenders().iterator().next();
else } else {
playerId = game.getActivePlayerId(); playerId = game.getActivePlayerId();
} }
} }
}
public MCTSNode select(UUID targetPlayerId) { public MCTSNode select(UUID targetPlayerId) {
double bestValue = Double.NEGATIVE_INFINITY; double bestValue = Double.NEGATIVE_INFINITY;

View file

@ -330,7 +330,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
return GameStateEvaluator.evaluate(playerId, game); return GameStateEvaluator.evaluate(playerId, game);
} }
int val; int val;
if (node.depth > maxDepth || game.isGameOver()) { if (node.depth > maxDepth || game.gameOver(null)) {
logger.debug(indent(node.depth) + "simulating -- reached end state"); logger.debug(indent(node.depth) + "simulating -- reached end state");
val = GameStateEvaluator.evaluate(playerId, game); val = GameStateEvaluator.evaluate(playerId, game);
} }
@ -357,7 +357,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
} }
} }
if (game.isGameOver()) { if (game.gameOver(null)) {
val = GameStateEvaluator.evaluate(playerId, game); val = GameStateEvaluator.evaluate(playerId, game);
} }
else if (node.getChildren().size() > 0) { else if (node.getChildren().size() > 0) {
@ -403,7 +403,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
logger.debug(indent(node.depth) + "found useless action: " + action); logger.debug(indent(node.depth) + "found useless action: " + action);
continue; continue;
} }
if (!sim.isGameOver() && action.isUsesStack()) { if (!sim.gameOver(null) && action.isUsesStack()) {
// only pass if the last action uses the stack // only pass if the last action uses the stack
sim.getPlayer(currentPlayer.getId()).pass(game); sim.getPlayer(currentPlayer.getId()).pass(game);
sim.getPlayerList().getNext(); sim.getPlayerList().getNext();
@ -587,7 +587,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
break; break;
case CLEANUP: case CLEANUP:
game.getPhase().getStep().beginStep(game, activePlayerId); game.getPhase().getStep().beginStep(game, activePlayerId);
if (!game.checkStateAndTriggered() && !game.isGameOver()) { if (!game.checkStateAndTriggered() && !game.gameOver(null)) {
game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext());
game.getTurn().setPhase(new BeginningPhase()); game.getTurn().setPhase(new BeginningPhase());
game.getPhase().setStep(new UntapStep()); game.getPhase().setStep(new UntapStep());

View file

@ -185,7 +185,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
logger.debug(indent(node.depth) + "interrupted"); logger.debug(indent(node.depth) + "interrupted");
return GameStateEvaluator.evaluate(playerId, game); return GameStateEvaluator.evaluate(playerId, game);
} }
if (node.depth > maxDepth || game.isGameOver()) { if (node.depth > maxDepth || game.gameOver(null)) {
logger.debug(indent(node.depth) + "simulating -- reached end state"); logger.debug(indent(node.depth) + "simulating -- reached end state");
val = GameStateEvaluator.evaluate(playerId, game); val = GameStateEvaluator.evaluate(playerId, game);
} }
@ -205,7 +205,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
} }
} }
if (game.isGameOver()) { if (game.gameOver(null)) {
val = GameStateEvaluator.evaluate(playerId, game); val = GameStateEvaluator.evaluate(playerId, game);
} }
else if (stepFinished) { else if (stepFinished) {
@ -406,7 +406,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId()));
Combat simCombat = sim.getCombat().copy(); Combat simCombat = sim.getCombat().copy();
finishCombat(sim); finishCombat(sim);
if (sim.isGameOver()) { if (sim.gameOver(null)) {
val = GameStateEvaluator.evaluate(playerId, sim); val = GameStateEvaluator.evaluate(playerId, sim);
} }
else if (!counter) { else if (!counter) {
@ -448,7 +448,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
return GameStateEvaluator.evaluate(playerId, game); return GameStateEvaluator.evaluate(playerId, game);
} }
Integer val = null; Integer val = null;
if (!game.isGameOver()) { if (!game.gameOver(null)) {
logger.debug(indent(node.depth) + "simulating -- ending turn"); logger.debug(indent(node.depth) + "simulating -- ending turn");
simulateToEnd(game); simulateToEnd(game);
game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext());
@ -476,7 +476,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
logger.debug("interrupted"); logger.debug("interrupted");
return; return;
} }
if (!game.isGameOver()) { if (!game.gameOver(null)) {
game.getPhase().setStep(step); game.getPhase().setStep(step);
if (!step.skipStep(game, game.getActivePlayerId())) { if (!step.skipStep(game, game.getActivePlayerId())) {
step.beginStep(game, game.getActivePlayerId()); step.beginStep(game, game.getActivePlayerId());
@ -524,7 +524,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
logger.debug("interrupted"); logger.debug("interrupted");
return; return;
} }
if (!game.isGameOver()) { if (!game.gameOver(null)) {
game.getTurn().getPhase().endPhase(game, game.getActivePlayerId()); game.getTurn().getPhase().endPhase(game, game.getActivePlayerId());
game.getTurn().setPhase(new EndPhase()); game.getTurn().setPhase(new EndPhase());
if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) { if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) {

View file

@ -70,7 +70,7 @@ public class GameStateEvaluator {
public static int evaluate(UUID playerId, Game game, boolean ignoreTapped) { public static int evaluate(UUID playerId, Game game, boolean ignoreTapped) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next());
if (game.isGameOver()) { if (game.gameOver(null)) {
if (player.hasLost() || opponent.hasWon()) if (player.hasLost() || opponent.hasWon())
return LOSE_SCORE; return LOSE_SCORE;
if (opponent.hasLost() || player.hasWon()) if (opponent.hasLost() || player.hasWon())

View file

@ -593,7 +593,6 @@ public class TableController {
* @return true if table can be closed * @return true if table can be closed
*/ */
public boolean endGameAndStartNextGame() { public boolean endGameAndStartNextGame() {
boolean matchIsOver = false;
// get player that chooses who goes first // get player that chooses who goes first
UUID choosingPlayerId = match.getChooser(); UUID choosingPlayerId = match.getChooser();
match.endGame(); match.endGame();
@ -604,27 +603,24 @@ public class TableController {
} }
GameManager.getInstance().removeGame(match.getGame().getId()); GameManager.getInstance().removeGame(match.getGame().getId());
try { try {
if (!match.isMatchOver()) { if (!match.hasEnded()) {
table.sideboard(); table.sideboard();
setupTimeout(Match.SIDEBOARD_TIME); setupTimeout(Match.SIDEBOARD_TIME);
match.sideboard(); match.sideboard();
cancelTimeout(); cancelTimeout();
if (!match.isMatchOver()) { if (!match.hasEnded()) {
startGame(choosingPlayerId); startGame(choosingPlayerId);
} else { } else {
matchIsOver = true;
closeTable(); closeTable();
} }
} }
else { else {
// if match has only one game
matchIsOver = true;
closeTable(); closeTable();
} }
} catch (GameException ex) { } catch (GameException ex) {
logger.fatal(null, ex); logger.fatal(null, ex);
} }
return matchIsOver; return match.hasEnded();
} }
/** /**

View file

@ -240,8 +240,8 @@ public class GameController implements GameCallback {
PriorityTimer timer = new PriorityTimer(count, delay, new Action() { PriorityTimer timer = new PriorityTimer(count, delay, new Action() {
@Override @Override
public void execute() throws MageException { public void execute() throws MageException {
game.concede(initPlayerId); game.timerTimeout(initPlayerId);
logger.debug("Game timeout for player: " + initPlayerId + ". Conceding."); logger.debug(new StringBuilder("Game timeout for player: ").append(initPlayerId).append(". Conceding."));
} }
}); });
timers.put(playerId, timer); timers.put(playerId, timer);
@ -399,7 +399,7 @@ public class GameController implements GameCallback {
.append(ConfigSettings.getInstance().getMaxSecondsIdle()) .append(ConfigSettings.getInstance().getMaxSecondsIdle())
.append(" seconds ) - Auto concede."); .append(" seconds ) - Auto concede.");
ChatManager.getInstance().broadcast(chatId, "", sb.toString() , MessageColor.BLACK, true, MessageType.STATUS); ChatManager.getInstance().broadcast(chatId, "", sb.toString() , MessageColor.BLACK, true, MessageType.STATUS);
concede(userId); game.idleTimeout(getPlayerId(userId));
} }
} }

View file

@ -13,7 +13,7 @@ public enum TableState {
CONSTRUCTING ("Constructing"), CONSTRUCTING ("Constructing"),
FINISHED ("Finished"); FINISHED ("Finished");
private String text; private final String text;
TableState(String text) { TableState(String text) {
this.text = text; this.text = text;

View file

@ -122,7 +122,8 @@ public interface Game extends MageItem, Serializable {
UUID getActivePlayerId(); UUID getActivePlayerId();
UUID getPriorityPlayerId(); UUID getPriorityPlayerId();
void leave(UUID playerId); void leave(UUID playerId);
boolean isGameOver(); boolean gameOver(UUID playerId);
boolean hasEnded();
Battlefield getBattlefield(); Battlefield getBattlefield();
SpellStack getStack(); SpellStack getStack();
Exile getExile(); Exile getExile();
@ -218,6 +219,8 @@ public interface Game extends MageItem, Serializable {
void mulligan(UUID playerId); void mulligan(UUID playerId);
void endMulligan(UUID playerId); void endMulligan(UUID playerId);
void quit(UUID playerId); void quit(UUID playerId);
void timerTimeout(UUID playerId);
void idleTimeout(UUID playerId);
void concede(UUID playerId); void concede(UUID playerId);
void undo(UUID playerId); void undo(UUID playerId);
void emptyManaPools(); void emptyManaPools();

View file

@ -418,8 +418,26 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
} }
} }
/**
* Starts check if game over or if playerId is given
* let the player concede.
*
* @param playerId
* @return
*/
@Override @Override
public synchronized boolean isGameOver() { public synchronized boolean gameOver(UUID playerId) {
if (playerId == null) {
boolean result = checkIfGameIsOver();
return result;
} else {
leave(playerId);
return true;
}
}
private boolean checkIfGameIsOver() {
if (state.isGameOver()) { if (state.isGameOver()) {
return true; return true;
} }
@ -447,6 +465,11 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
return false; return false;
} }
@Override
public boolean hasEnded() {
return endTime != null;
}
@Override @Override
public String getWinner() { public String getWinner() {
if (winnerId == null) { if (winnerId == null) {
@ -546,13 +569,13 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
Player player = getPlayer(players.get()); Player player = getPlayer(players.get());
boolean wasPaused = state.isPaused(); boolean wasPaused = state.isPaused();
state.resume(); state.resume();
if (!isGameOver()) { if (!gameOver(null)) {
fireInformEvent(new StringBuilder("Turn ").append(state.getTurnNum()).toString()); fireInformEvent(new StringBuilder("Turn ").append(state.getTurnNum()).toString());
if (checkStopOnTurnOption()) { if (checkStopOnTurnOption()) {
return; return;
} }
state.getTurn().resumePlay(this, wasPaused); state.getTurn().resumePlay(this, wasPaused);
if (!isPaused() && !isGameOver()) { if (!isPaused() && !gameOver(null)) {
endOfTurn(); endOfTurn();
player = players.getNext(this); player = players.getNext(this);
state.setTurnNum(state.getTurnNum() + 1); state.setTurnNum(state.getTurnNum() + 1);
@ -562,10 +585,10 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
} }
protected void play(UUID nextPlayerId) { protected void play(UUID nextPlayerId) {
if (!isPaused() && !isGameOver()) { if (!isPaused() && !gameOver(null)) {
PlayerList players = state.getPlayerList(nextPlayerId); PlayerList players = state.getPlayerList(nextPlayerId);
Player player = getPlayer(players.get()); Player player = getPlayer(players.get());
while (!isPaused() && !isGameOver()) { while (!isPaused() && !gameOver(null)) {
if (!playTurn(player)) { if (!playTurn(player)) {
break; break;
@ -583,7 +606,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
player = players.getNext(this); player = players.getNext(this);
} }
} }
if (isGameOver()) { if (gameOver(null)) {
winnerId = findWinnersAndLosers(); winnerId = findWinnersAndLosers();
logger.info(new StringBuilder("Game with gameId ").append(this.getId()).append(" ended.")); logger.info(new StringBuilder("Game with gameId ").append(this.getId()).append(" ended."));
} }
@ -597,7 +620,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
state.setActivePlayerId(player.getId()); state.setActivePlayerId(player.getId());
player.becomesActivePlayer(); player.becomesActivePlayer();
state.getTurn().play(this, player.getId()); state.getTurn().play(this, player.getId());
if (isPaused() || isGameOver()) { if (isPaused() || gameOver(null)) {
return false; return false;
} }
endOfTurn(); endOfTurn();
@ -866,8 +889,29 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
public synchronized void quit(UUID playerId) { public synchronized void quit(UUID playerId) {
Player player = state.getPlayer(playerId); Player player = state.getPlayer(playerId);
if (player != null) { if (player != null) {
fireInformEvent(player.getName() + " quits the match.");
player.quit(this); player.quit(this);
}else {
logger.error(new StringBuilder("player not found - playerId: ").append(playerId));
}
}
@Override
public synchronized void timerTimeout(UUID playerId) {
Player player = state.getPlayer(playerId);
if (player != null) {
player.timerTimeout(this);
} else {
logger.error(new StringBuilder("player not found - playerId: ").append(playerId));
}
}
@Override
public synchronized void idleTimeout(UUID playerId) {
Player player = state.getPlayer(playerId);
if (player != null) {
player.idleTimeout(this);
} else {
logger.error(new StringBuilder("player not found - playerId: ").append(playerId));
} }
} }
@ -923,7 +967,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
int bookmark = 0; int bookmark = 0;
clearAllBookmarks(); clearAllBookmarks();
try { try {
while (!isPaused() && !isGameOver()) { while (!isPaused() && !gameOver(null)) {
if (!resuming) { if (!resuming) {
state.getPlayers().resetPassed(); state.getPlayers().resetPassed();
state.getPlayerList().setCurrent(activePlayerId); state.getPlayerList().setCurrent(activePlayerId);
@ -933,13 +977,13 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
} }
fireUpdatePlayersEvent(); fireUpdatePlayersEvent();
Player player; Player player;
while (!isPaused() && !isGameOver()) { while (!isPaused() && !gameOver(null)) {
try { try {
//if (bookmark == 0) //if (bookmark == 0)
//bookmark = bookmarkState(); //bookmark = bookmarkState();
player = getPlayer(state.getPlayerList().get()); player = getPlayer(state.getPlayerList().get());
state.setPriorityPlayerId(player.getId()); state.setPriorityPlayerId(player.getId());
while (!player.isPassed() && player.isInGame() && !isPaused() && !isGameOver()) { while (!player.isPassed() && player.isInGame() && !isPaused() && !gameOver(null)) {
if (!resuming) { if (!resuming) {
if (checkStateAndTriggered()) { if (checkStateAndTriggered()) {
applyEffects(); applyEffects();
@ -947,7 +991,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
//resetLKI(); //resetLKI();
applyEffects(); applyEffects();
saveState(false); saveState(false);
if (isPaused() || isGameOver()) { if (isPaused() || gameOver(null)) {
return; return;
} }
// resetPassed should be called if player performs any action // resetPassed should be called if player performs any action
@ -962,7 +1006,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
} }
resetShortLivingLKI(); resetShortLivingLKI();
resuming = false; resuming = false;
if (isPaused() || isGameOver()) { if (isPaused() || gameOver(null)) {
return; return;
} }
if (allPassed()) { if (allPassed()) {
@ -1164,9 +1208,9 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
public boolean checkStateAndTriggered() { public boolean checkStateAndTriggered() {
boolean somethingHappened = false; boolean somethingHappened = false;
//20091005 - 115.5 //20091005 - 115.5
while (!isPaused() && !this.isGameOver()) { while (!isPaused() && !gameOver(null)) {
if (!checkStateBasedActions() ) { if (!checkStateBasedActions() ) {
if (isPaused() || this.isGameOver() || !checkTriggered()) { if (isPaused() || gameOver(null) || !checkTriggered()) {
break; break;
} }
} }
@ -1729,7 +1773,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
return; return;
} }
player.leave(); player.leave();
if (this.isGameOver()) { if (gameOver(null)) {
// no need to remove objects if only one player is left so the game is over // no need to remove objects if only one player is left so the game is over
return; return;
} }

View file

@ -113,7 +113,7 @@ public class Table implements Serializable {
public void initTournament() { public void initTournament() {
setState(TableState.DUELING); setState(TableState.DUELING);
tournament.setStepStartTime(new Date());
} }
public void endTournament() { public void endTournament() {
@ -122,10 +122,12 @@ public class Table implements Serializable {
public void initDraft() { public void initDraft() {
setState(TableState.DRAFTING); setState(TableState.DRAFTING);
tournament.setStepStartTime(new Date());
} }
public void construct() { public void construct() {
setState(TableState.CONSTRUCTING); setState(TableState.CONSTRUCTING);
tournament.setStepStartTime(new Date());
} }
/** /**

View file

@ -191,7 +191,7 @@ public class Combat implements Serializable, Copyable<Combat> {
//20101001 - 508.1d //20101001 - 508.1d
checkAttackRequirements(player, game); checkAttackRequirements(player, game);
player.selectAttackers(game, attackerId); player.selectAttackers(game, attackerId);
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return; return;
} }
checkAttackRestrictions(player, game); checkAttackRestrictions(player, game);
@ -316,7 +316,7 @@ public class Combat implements Serializable, Copyable<Combat> {
} }
while (choose) { while (choose) {
blockController.selectBlockers(game, defenderId); blockController.selectBlockers(game, defenderId);
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return; return;
} }
if (!this.checkBlockRestrictions(defender, game)) { if (!this.checkBlockRestrictions(defender, game)) {

View file

@ -48,7 +48,8 @@ public interface Match {
UUID getId(); UUID getId();
String getName(); String getName();
boolean isMatchOver(); boolean hasEnded();
boolean checkIfMatchEnds();
List<MatchPlayer> getPlayers(); List<MatchPlayer> getPlayers();
MatchPlayer getPlayer(UUID playerId); MatchPlayer getPlayer(UUID playerId);

View file

@ -126,18 +126,29 @@ public abstract class MatchImpl implements Match {
} }
@Override @Override
public boolean isMatchOver() { public boolean hasEnded() {
return endTime != null;
};
@Override
public boolean checkIfMatchEnds() {
int activePlayers = 0; int activePlayers = 0;
for (MatchPlayer player: players) { MatchPlayer matchWinner = null;
if (!player.hasQuit()) { for (MatchPlayer matchPlayer: players) {
if (!matchPlayer.hasQuit()) {
activePlayers++; activePlayers++;
matchWinner = matchPlayer;
} }
if (player.getWins() >= options.getWinsNeeded()) { if (matchPlayer.getWins() >= options.getWinsNeeded()) {
matchPlayer.setMatchWinner(true);
endTime = new Date(); endTime = new Date();
return true; return true;
} }
} }
if (activePlayers < 2) { if (activePlayers < 2) {
if (matchWinner != null) {
matchWinner.setMatchWinner(true);
}
endTime = new Date(); endTime = new Date();
return true; return true;
} }
@ -200,24 +211,28 @@ public abstract class MatchImpl implements Match {
@Override @Override
public void endGame() { public void endGame() {
Game game = getGame(); Game game = getGame();
for (MatchPlayer player: this.players) { for (MatchPlayer matchPlayer: this.players) {
Player p = game.getPlayer(player.getPlayer().getId()); Player player = game.getPlayer(matchPlayer.getPlayer().getId());
if (p != null) { if (player != null) {
// get the left time from player priority timer // get the left time from player priority timer
if (game.getPriorityTime() > 0) { if (game.getPriorityTime() > 0) {
player.setPriorityTimeLeft(p.getPriorityTimeLeft()); matchPlayer.setPriorityTimeLeft(player.getPriorityTimeLeft());
} }
if (p.hasQuit()) { if (player.hasQuit()) {
player.setQuit(true); matchPlayer.setQuit(true);
} }
if (p.hasWon()) { if (player.hasTimerTimeout()) {
player.addWin(); matchPlayer.setTimerTimeout(true);
} }
if (p.hasLost()) { if (player.hasWon()) {
player.addLose(); matchPlayer.addWin();
}
if (player.hasLost()) {
matchPlayer.addLose();
} }
} }
} }
checkIfMatchEnds();
game.fireGameEndInfo(); game.fireGameEndInfo();
} }

View file

@ -39,12 +39,14 @@ import mage.players.Player;
public class MatchPlayer { public class MatchPlayer {
private int wins; private int wins;
private int loses; private int loses;
private boolean matchWinner;
private Deck deck; private Deck deck;
private Player player; private Player player;
private final String name; private final String name;
private boolean quit; private boolean quit;
private boolean timerTimeout;
private boolean doneSideboarding; private boolean doneSideboarding;
private int priorityTimeLeft; private int priorityTimeLeft;
@ -55,7 +57,9 @@ public class MatchPlayer {
this.loses = 0; this.loses = 0;
this.doneSideboarding = true; this.doneSideboarding = true;
this.quit = false; this.quit = false;
this.timerTimeout = false;
this.name = player.getName(); this.name = player.getName();
this.matchWinner = false;
} }
public int getPriorityTimeLeft() { public int getPriorityTimeLeft() {
@ -126,6 +130,22 @@ public class MatchPlayer {
this.quit = quit; this.quit = quit;
} }
public boolean hasTimerTimeout() {
return timerTimeout;
}
public void setTimerTimeout(boolean timerTimeout) {
this.timerTimeout = timerTimeout;
}
public boolean isMatchWinner() {
return matchWinner;
}
public void setMatchWinner(boolean matchWinner) {
this.matchWinner = matchWinner;
}
public void cleanUpOnMatchEnd() { public void cleanUpOnMatchEnd() {
// Free resources that are not needed after match end // Free resources that are not needed after match end
this.deck = null; this.deck = null;

View file

@ -72,7 +72,7 @@ public class Round {
public boolean isRoundOver() { public boolean isRoundOver() {
boolean roundIsOver = true; boolean roundIsOver = true;
for (TournamentPairing pair: pairs) { for (TournamentPairing pair: pairs) {
if (pair.getMatch() != null && !pair.getMatch().isMatchOver()) { if (pair.getMatch() != null && !pair.getMatch().hasEnded()) {
roundIsOver = false; roundIsOver = false;
} else { } else {
if (!pair.isAlreadyPublished()) { if (!pair.isAlreadyPublished()) {

View file

@ -78,6 +78,10 @@ public interface Tournament {
// tournament times // tournament times
Date getStartTime(); Date getStartTime();
Date getEndTime(); Date getEndTime();
Date getStepStartTime();
void setStepStartTime(Date date);
// tournament type // tournament type
TournamentType getTournamentType(); TournamentType getTournamentType();
void setTournamentType(TournamentType tournamentType); void setTournamentType(TournamentType tournamentType);

View file

@ -74,6 +74,7 @@ public abstract class TournamentImpl implements Tournament {
protected Date startTime; protected Date startTime;
protected Date endTime; protected Date endTime;
protected Date stepStartTime;
protected boolean abort; protected boolean abort;
protected String tournamentState; protected String tournamentState;
@ -244,7 +245,7 @@ public abstract class TournamentImpl implements Tournament {
for (Round round: rounds) { for (Round round: rounds) {
for (TournamentPairing pair: round.getPairs()) { for (TournamentPairing pair: round.getPairs()) {
Match match = pair.getMatch(); Match match = pair.getMatch();
if (match != null && match.isMatchOver()) { if (match != null && match.hasEnded()) {
TournamentPlayer tp1 = pair.getPlayer1(); TournamentPlayer tp1 = pair.getPlayer1();
TournamentPlayer tp2 = pair.getPlayer2(); TournamentPlayer tp2 = pair.getPlayer2();
MatchPlayer mp1 = match.getPlayer(pair.getPlayer1().getPlayer().getId()); MatchPlayer mp1 = match.getPlayer(pair.getPlayer1().getPlayer().getId());
@ -302,11 +303,11 @@ public abstract class TournamentImpl implements Tournament {
matchResult.append(p2.getPlayer().getName()); matchResult.append(p2.getPlayer().getName());
matchResult.append(" (").append(mp1.getWins()); matchResult.append(" (").append(mp1.getWins());
if (mp1.hasQuit()) { if (mp1.hasQuit()) {
matchResult.append("Q"); matchResult.append(mp1.hasTimerTimeout()?"T":"Q");
} }
matchResult.append("-").append(mp2.getWins()); matchResult.append("-").append(mp2.getWins());
if (mp2.hasQuit()) { if (mp2.hasQuit()) {
matchResult.append("Q"); matchResult.append(mp2.hasTimerTimeout()?"T":"Q");
} }
matchResult.append(") "); matchResult.append(") ");
return matchResult.toString(); return matchResult.toString();
@ -479,4 +480,18 @@ public abstract class TournamentImpl implements Tournament {
this.tournamentState = tournamentState; this.tournamentState = tournamentState;
} }
@Override
public Date getStepStartTime() {
if (stepStartTime != null) {
return new Date(stepStartTime.getTime());
}
return null;
}
@Override
public void setStepStartTime(Date stepStartTime) {
this.stepStartTime = stepStartTime;
}
} }

View file

@ -72,7 +72,7 @@ public class TournamentPairing {
} }
public void eliminatePlayers() { public void eliminatePlayers() {
if (match.isMatchOver()) { if (match.hasEnded()) {
MatchPlayer mPlayer1 = match.getPlayer(player1.getPlayer().getId()); MatchPlayer mPlayer1 = match.getPlayer(player1.getPlayer().getId());
MatchPlayer mPlayer2 = match.getPlayer(player2.getPlayer().getId()); MatchPlayer mPlayer2 = match.getPlayer(player2.getPlayer().getId());
if (mPlayer1.hasQuit() || (!mPlayer2.hasQuit() && mPlayer1.getWins() < match.getWinsNeeded())) { if (mPlayer1.hasQuit() || (!mPlayer2.hasQuit() && mPlayer1.getWins() < match.getWinsNeeded())) {

View file

@ -95,7 +95,7 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
} }
public boolean play(Game game, UUID activePlayerId) { public boolean play(Game game, UUID activePlayerId) {
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return false; return false;
} }
@ -104,7 +104,7 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
if (beginPhase(game, activePlayerId)) { if (beginPhase(game, activePlayerId)) {
for (Step step: steps) { for (Step step: steps) {
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return false; return false;
} }
currentStep = step; currentStep = step;
@ -115,7 +115,7 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
playStep(game); playStep(game);
} }
} }
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return false; return false;
} }
count++; count++;
@ -136,7 +136,7 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
} }
public boolean resumePlay(Game game, PhaseStep stepType, boolean wasPaused) { public boolean resumePlay(Game game, PhaseStep stepType, boolean wasPaused) {
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return false; return false;
} }
@ -150,7 +150,7 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
resumeStep(game, wasPaused); resumeStep(game, wasPaused);
while (it.hasNext()) { while (it.hasNext()) {
step = it.next(); step = it.next();
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return false; return false;
} }
currentStep = step; currentStep = step;
@ -159,7 +159,7 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
} }
} }
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return false; return false;
} }
count++; count++;
@ -194,10 +194,10 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
protected void playStep(Game game) { protected void playStep(Game game) {
if (!currentStep.skipStep(game, activePlayerId)) { if (!currentStep.skipStep(game, activePlayerId)) {
prePriority(game, activePlayerId); prePriority(game, activePlayerId);
if (!game.isPaused() && !game.isGameOver()) { if (!game.isPaused() && !game.gameOver(null)) {
currentStep.priority(game, activePlayerId, false); currentStep.priority(game, activePlayerId, false);
} }
if (!game.isPaused() && !game.isGameOver()) { if (!game.isPaused() && !game.gameOver(null)) {
postPriority(game, activePlayerId); postPriority(game, activePlayerId);
} }
} }
@ -219,11 +219,11 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
prePriority(game, activePlayerId); prePriority(game, activePlayerId);
} }
case PRIORITY: case PRIORITY:
if (!game.isPaused() && !game.isGameOver()) { if (!game.isPaused() && !game.gameOver(null)) {
currentStep.priority(game, activePlayerId, resuming); currentStep.priority(game, activePlayerId, resuming);
} }
case POST: case POST:
if (!game.isPaused() && !game.isGameOver()) { if (!game.isPaused() && !game.gameOver(null)) {
postPriority(game, activePlayerId); postPriority(game, activePlayerId);
} }
} }

View file

@ -47,7 +47,7 @@ public class Turn implements Serializable {
private Phase currentPhase; private Phase currentPhase;
private UUID activePlayerId; private UUID activePlayerId;
private List<Phase> phases = new ArrayList<Phase>(); private final List<Phase> phases = new ArrayList<>();
private boolean declareAttackersStepStarted = false; private boolean declareAttackersStepStarted = false;
public Turn() { public Turn() {
@ -109,7 +109,7 @@ public class Turn implements Serializable {
public void play(Game game, UUID activePlayerId) { public void play(Game game, UUID activePlayerId) {
this.setDeclareAttackersStepStarted(false); this.setDeclareAttackersStepStarted(false);
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return; return;
} }
@ -123,7 +123,7 @@ public class Turn implements Serializable {
resetCounts(); resetCounts();
game.getPlayer(activePlayerId).beginTurn(game); game.getPlayer(activePlayerId).beginTurn(game);
for (Phase phase: phases) { for (Phase phase: phases) {
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return; return;
} }
currentPhase = phase; currentPhase = phase;
@ -168,7 +168,7 @@ public class Turn implements Serializable {
} }
while (it.hasNext()) { while (it.hasNext()) {
phase = it.next(); phase = it.next();
if (game.isPaused() || game.isGameOver()) { if (game.isPaused() || game.gameOver(null)) {
return; return;
} }
currentPhase = phase; currentPhase = phase;

View file

@ -129,6 +129,10 @@ public interface Player extends MageItem, Copyable<Player> {
boolean hasWon(); boolean hasWon();
boolean hasQuit(); boolean hasQuit();
void quit(Game game); void quit(Game game);
boolean hasTimerTimeout();
void timerTimeout(Game game);
boolean hasIdleTimeout();
void idleTimeout(Game game);
boolean hasLeft(); boolean hasLeft();
/** /**
* Player is still active in game (has not left, lost or won the game). * Player is still active in game (has not left, lost or won the game).

View file

@ -114,7 +114,10 @@ import mage.target.common.TargetDiscard;
import mage.watchers.common.BloodthirstWatcher; import mage.watchers.common.BloodthirstWatcher;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
/**
*
* * @param <T>
*/
public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Serializable { public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Serializable {
private static final transient Logger log = Logger.getLogger(PlayerImpl.class); private static final transient Logger log = Logger.getLogger(PlayerImpl.class);
@ -160,6 +163,10 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
protected boolean left; protected boolean left;
// set if the player quits the complete match // set if the player quits the complete match
protected boolean quit; protected boolean quit;
// set if the player lost match because of priority timeout
protected boolean timerTimeout;
// set if the player lost match because of idle timeout
protected boolean idleTimeout;
protected RangeOfInfluence range; protected RangeOfInfluence range;
protected Set<UUID> inRange = new HashSet<>(); protected Set<UUID> inRange = new HashSet<>();
@ -234,6 +241,8 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.left = player.left; this.left = player.left;
this.quit = player.quit; this.quit = player.quit;
this.timerTimeout = player.timerTimeout;
this.idleTimeout = player.idleTimeout;
this.range = player.range; this.range = player.range;
this.canGainLife = player.canGainLife; this.canGainLife = player.canGainLife;
this.canLoseLife = player.canLoseLife; this.canLoseLife = player.canLoseLife;
@ -288,6 +297,8 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.left = player.hasLeft(); this.left = player.hasLeft();
this.quit = player.hasQuit(); this.quit = player.hasQuit();
this.timerTimeout = player.hasTimerTimeout();
this.idleTimeout = player.hasIdleTimeout();
this.range = player.getRange(); this.range = player.getRange();
this.canGainLife = player.isCanGainLife(); this.canGainLife = player.isCanGainLife();
this.canLoseLife = player.isCanLoseLife(); this.canLoseLife = player.isCanLoseLife();
@ -343,7 +354,11 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.wins = false; this.wins = false;
this.loses = false; this.loses = false;
this.left = false; this.left = false;
this.quit = false; // reset is neccessary because in tournament player will be used for each round // reset is neccessary because in tournament player will be used for each round
this.quit = false;
this.timerTimeout = false;
this.idleTimeout = false;
this.passed = false; this.passed = false;
this.passedTurn = false; this.passedTurn = false;
this.passedAllTurns = false; this.passedAllTurns = false;
@ -732,7 +747,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
resetStoredBookmark(game); resetStoredBookmark(game);
return true; return true;
} }
if (!game.isGameOver()) { // if player left or game is over no undo is possible - this could lead to wrong winner if (!game.hasEnded()) { // if player left or game is over no undo is possible - this could lead to wrong winner
game.restoreState(bookmark); game.restoreState(bookmark);
} }
} }
@ -1475,13 +1490,30 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
@Override @Override
public void quit(Game game) { public void quit(Game game) {
game.informPlayers(new StringBuilder(getName()).append(" quits the match.").toString());
quit = true; quit = true;
this.concede(game); this.concede(game);
} }
@Override
public void timerTimeout(Game game) {
game.informPlayers(new StringBuilder(getName()).append(" has run out of time. Loosing the Match.").toString());
quit = true;
timerTimeout = true;
this.concede(game);
}
@Override
public void idleTimeout(Game game) {
game.informPlayers(new StringBuilder(getName()).append(" has run out of time. Loosing the Match.").toString());
quit = true;
idleTimeout = true;
this.concede(game);
}
@Override @Override
public void concede(Game game) { public void concede(Game game) {
game.leave(playerId); game.gameOver(playerId);
lost(game); lost(game);
this.left = true; this.left = true;
} }
@ -2117,6 +2149,16 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
return quit; return quit;
} }
@Override
public boolean hasTimerTimeout() {
return timerTimeout;
}
@Override
public boolean hasIdleTimeout() {
return idleTimeout;
}
@Override @Override
public void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving) { public void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving) {
this.reachedNextTurnAfterLeaving = reachedNextTurnAfterLeaving; this.reachedNextTurnAfterLeaving = reachedNextTurnAfterLeaving;