diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java index 5a54960e65..b0c645f25f 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java @@ -71,10 +71,12 @@ public class NewTournamentDialog extends MageDialog { private TableView table; private UUID playerId; private UUID roomId; - private Session session; + private final Session session; private String lastSessionId; private final List players = new ArrayList<>(); private final List packs = new ArrayList<>(); + private final int CONSTRUCTION_TIME_MIN = 6; + private final int CONSTRUCTION_TIME_MAX = 30; /** Creates new form NewTournamentDialog */ public NewTournamentDialog() { @@ -84,7 +86,7 @@ public class NewTournamentDialog extends MageDialog { txtName.setText("Tournament"); this.spnNumWins.setModel(new SpinnerNumberModel(2, 1, 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)); } @@ -427,9 +429,8 @@ public class NewTournamentDialog extends MageDialog { if (tournamentType.isLimited()) { if (tOptions.getLimitedOptions() == null) { 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()) { tOptions.getLimitedOptions().setDraftCubeName(this.cbDraftCube.getSelectedItem().toString()); } else { @@ -646,7 +647,11 @@ public class NewTournamentDialog extends MageDialog { 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"); for (TournamentTypeView tournamentTypeView : session.getTournamentTypes()) { if (tournamentTypeView.getName().equals(tournamentTypeName)) { diff --git a/Mage.Common/src/mage/interfaces/Action.java b/Mage.Common/src/mage/interfaces/Action.java index 7ab3bca44e..d7fc3fbe89 100644 --- a/Mage.Common/src/mage/interfaces/Action.java +++ b/Mage.Common/src/mage/interfaces/Action.java @@ -12,6 +12,7 @@ public interface Action { /** * Executes action. + * @throws mage.MageException */ void execute() throws MageException; } diff --git a/Mage.Common/src/mage/utils/timer/PriorityTimer.java b/Mage.Common/src/mage/utils/timer/PriorityTimer.java index 73c0d9ff72..31dd52276f 100644 --- a/Mage.Common/src/mage/utils/timer/PriorityTimer.java +++ b/Mage.Common/src/mage/utils/timer/PriorityTimer.java @@ -1,11 +1,10 @@ package mage.utils.timer; -import mage.MageException; -import mage.interfaces.Action; -import org.apache.log4j.Logger; - import java.util.Timer; import java.util.TimerTask; +import mage.MageException; +import mage.interfaces.Action; +import org.apache.log4j.Logger; /** * @author noxx @@ -14,14 +13,11 @@ public class PriorityTimer extends TimerTask { private static final Logger logger = Logger.getLogger(PriorityTimer.class); + private final long delay; + private final Action taskOnTimeout; + private int count; - - private long delay; - - private Action taskOnTimeout; - private Action taskOnTick; - private States state = States.NONE; enum States { diff --git a/Mage.Common/src/mage/view/MatchView.java b/Mage.Common/src/mage/view/MatchView.java index 86bd43c2bb..5bb8f0fca5 100644 --- a/Mage.Common/src/mage/view/MatchView.java +++ b/Mage.Common/src/mage/view/MatchView.java @@ -72,14 +72,18 @@ public class MatchView implements Serializable { } StringBuilder sb1 = new StringBuilder(); StringBuilder sb2 = new StringBuilder(); - for (MatchPlayer player: match.getPlayers()) { - sb1.append(player.getName()); - if(player.hasQuit()) { - sb1.append(" [quit] "); + for (MatchPlayer matchPlayer: match.getPlayers()) { + sb1.append(matchPlayer.getName()); + if(matchPlayer.hasQuit()) { + if (matchPlayer.hasTimerTimeout()) { + sb1.append(" [timer] "); + } else { + sb1.append(" [quit] "); + } } sb1.append(", "); - sb2.append(player.getName()).append(" "); - sb2.append(player.getWins()).append("-").append(player.getLoses()).append(", "); + sb2.append(matchPlayer.getName()).append(" "); + sb2.append(matchPlayer.getWins()).append("-").append(matchPlayer.getLoses()).append(", "); } players = sb1.substring(0, sb1.length() - 2); result = sb2.substring(0, sb2.length() - 2); diff --git a/Mage.Common/src/mage/view/TableView.java b/Mage.Common/src/mage/view/TableView.java index 6c52f6332f..86a814a2b3 100644 --- a/Mage.Common/src/mage/view/TableView.java +++ b/Mage.Common/src/mage/view/TableView.java @@ -39,7 +39,6 @@ import mage.game.Seat; import mage.game.Table; import mage.game.match.MatchPlayer; import mage.game.tournament.TournamentPlayer; -import org.jboss.logging.Logger; /** * diff --git a/Mage.Common/src/mage/view/TournamentGameView.java b/Mage.Common/src/mage/view/TournamentGameView.java index 201771e75e..2ec4a74aa4 100644 --- a/Mage.Common/src/mage/view/TournamentGameView.java +++ b/Mage.Common/src/mage/view/TournamentGameView.java @@ -54,7 +54,7 @@ public class TournamentGameView implements Serializable { this.matchId = pair.getMatch().getId(); this.gameId = game.getId(); this.players = pair.getPlayer1().getPlayer().getName() + " - " + pair.getPlayer2().getPlayer().getName(); - if (game.isGameOver()) { + if (game.hasEnded()) { this.state = "Finished"; this.result = game.getWinner(); } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index ce79182fe1..29d0ee5449 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -467,7 +467,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements logger.trace("interrupted - " + 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); val = GameStateEvaluator2.evaluate(playerId, game); UUID currentPlayerId = node.getGame().getPlayerList().get(); @@ -488,7 +488,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements } } - if (game.isGameOver()) { + if (game.gameOver(null)) { val = GameStateEvaluator2.evaluate(playerId, game); } else if (node.getChildren().size() > 0) { //declared attackers or blockers or triggered abilities @@ -534,7 +534,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements logger.debug("Sim Prio [" + depth + "] -- repeated action: " + action.toString()); continue; } - if (!sim.isGameOver() && action.isUsesStack()) { + if (!sim.gameOver(null) && action.isUsesStack()) { // only pass if the last action uses the stack sim.getPlayer(currentPlayer.getId()).pass(game); sim.getPlayerList().getNext(); @@ -797,7 +797,7 @@ public class ComputerPlayer6 extends ComputerPlayer implements break; case CLEANUP: 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.getTurn().setPhase(new BeginningPhase()); game.getPhase().setStep(new UntapStep()); diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index 8252532655..ad485a9e62 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -229,7 +229,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { return GameStateEvaluator2.evaluate(playerId, game); } // 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); if (logger.isTraceEnabled()) { 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); } 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())); Combat simCombat = sim.getCombat().copy(); finishCombat(sim); - if (sim.isGameOver()) { + if (sim.gameOver(null)) { val = GameStateEvaluator2.evaluate(playerId, sim); } else if (!counter) { @@ -568,7 +568,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { logger.debug("interrupted"); return; } - if (!game.isGameOver()) { + if (!game.gameOver(null)) { game.getPhase().setStep(step); if (!step.skipStep(game, game.getActivePlayerId())) { step.beginStep(game, game.getActivePlayerId()); @@ -617,7 +617,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { logger.debug("interrupted"); return; } - if (!game.isGameOver()) { + if (!game.gameOver(null)) { game.getTurn().getPhase().endPhase(game, game.getActivePlayerId()); game.getTurn().setPhase(new EndPhase()); if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) { diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java index 27a1abbd81..52b99359a6 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/GameStateEvaluator2.java @@ -33,7 +33,7 @@ public class GameStateEvaluator2 { public static int evaluate(UUID playerId, Game game) { Player player = game.getPlayer(playerId); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); - if (game.isGameOver()) { + if (game.gameOver(null)) { if (player.hasLost() || opponent.hasWon()) { return LOSE_GAME_SCORE; } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java index 27438f7cbc..54368cc841 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/simulators/ActionSimulator.java @@ -60,11 +60,13 @@ public class ActionSimulator { public int evaluateState() { Player opponent = game.getPlayer(game.getOpponents(player.getId()).iterator().next()); - if (game.isGameOver()) { - if (player.hasLost() || opponent.hasWon()) + if (game.gameOver(null)) { + if (player.hasLost() || opponent.hasWon()) { return Integer.MIN_VALUE; - if (opponent.hasLost() || player.hasWon()) + } + if (opponent.hasLost() || player.hasWon()) { return Integer.MAX_VALUE; + } } int value = player.getLife(); value -= opponent.getLife(); diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java index 5ac55f69c8..3705b35e61 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/MCTSNode.java @@ -58,11 +58,11 @@ public class MCTSNode { private int visits = 0; private int wins = 0; private MCTSNode parent; - private List children = new ArrayList(); + private final List children = new ArrayList(); private Ability action; private Game game; private Combat combat; - private String stateValue; + private final String stateValue; private UUID playerId; private boolean terminal = false; @@ -71,7 +71,7 @@ public class MCTSNode { public MCTSNode(Game game) { this.game = game; this.stateValue = game.getState().getValue(false, game); - this.terminal = game.isGameOver(); + this.terminal = game.gameOver(null); setPlayer(); nodeCount = 1; } @@ -79,7 +79,7 @@ public class MCTSNode { protected MCTSNode(MCTSNode parent, Game game, Ability action) { this.game = game; this.stateValue = game.getState().getValue(false, game); - this.terminal = game.isGameOver(); + this.terminal = game.gameOver(null); this.parent = parent; this.action = action; setPlayer(); @@ -90,20 +90,21 @@ public class MCTSNode { this.game = game; this.combat = combat; this.stateValue = game.getState().getValue(false, game); - this.terminal = game.isGameOver(); + this.terminal = game.gameOver(null); this.parent = parent; setPlayer(); nodeCount++; } private void setPlayer() { - if (game.getStep().getStepPart() == StepPart.PRIORITY) + if (game.getStep().getStepPart() == StepPart.PRIORITY) { playerId = game.getPriorityPlayerId(); - else { - if (game.getStep().getType() == PhaseStep.DECLARE_BLOCKERS) + } else { + if (game.getStep().getType() == PhaseStep.DECLARE_BLOCKERS) { playerId = game.getCombat().getDefenders().iterator().next(); - else + } else { playerId = game.getActivePlayerId(); + } } } diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java index 881130ca1f..bbdafd26c2 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java @@ -330,7 +330,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements return GameStateEvaluator.evaluate(playerId, game); } int val; - if (node.depth > maxDepth || game.isGameOver()) { + if (node.depth > maxDepth || game.gameOver(null)) { logger.debug(indent(node.depth) + "simulating -- reached end state"); val = GameStateEvaluator.evaluate(playerId, game); } @@ -357,7 +357,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements } } - if (game.isGameOver()) { + if (game.gameOver(null)) { val = GameStateEvaluator.evaluate(playerId, game); } else if (node.getChildren().size() > 0) { @@ -403,7 +403,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements logger.debug(indent(node.depth) + "found useless action: " + action); continue; } - if (!sim.isGameOver() && action.isUsesStack()) { + if (!sim.gameOver(null) && action.isUsesStack()) { // only pass if the last action uses the stack sim.getPlayer(currentPlayer.getId()).pass(game); sim.getPlayerList().getNext(); @@ -587,7 +587,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements break; case CLEANUP: 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.getTurn().setPhase(new BeginningPhase()); game.getPhase().setStep(new UntapStep()); diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java index ee3e42d261..2046f08005 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java @@ -185,7 +185,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { logger.debug(indent(node.depth) + "interrupted"); 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"); 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); } 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())); Combat simCombat = sim.getCombat().copy(); finishCombat(sim); - if (sim.isGameOver()) { + if (sim.gameOver(null)) { val = GameStateEvaluator.evaluate(playerId, sim); } else if (!counter) { @@ -448,7 +448,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { return GameStateEvaluator.evaluate(playerId, game); } Integer val = null; - if (!game.isGameOver()) { + if (!game.gameOver(null)) { logger.debug(indent(node.depth) + "simulating -- ending turn"); simulateToEnd(game); game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext()); @@ -476,7 +476,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { logger.debug("interrupted"); return; } - if (!game.isGameOver()) { + if (!game.gameOver(null)) { game.getPhase().setStep(step); if (!step.skipStep(game, game.getActivePlayerId())) { step.beginStep(game, game.getActivePlayerId()); @@ -524,7 +524,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player { logger.debug("interrupted"); return; } - if (!game.isGameOver()) { + if (!game.gameOver(null)) { game.getTurn().getPhase().endPhase(game, game.getActivePlayerId()); game.getTurn().setPhase(new EndPhase()); if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) { diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java index 88c590ba20..920b00d252 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java @@ -70,7 +70,7 @@ public class GameStateEvaluator { public static int evaluate(UUID playerId, Game game, boolean ignoreTapped) { Player player = game.getPlayer(playerId); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); - if (game.isGameOver()) { + if (game.gameOver(null)) { if (player.hasLost() || opponent.hasWon()) return LOSE_SCORE; if (opponent.hasLost() || player.hasWon()) diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 99faf99cf4..7008d09336 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -593,7 +593,6 @@ public class TableController { * @return true if table can be closed */ public boolean endGameAndStartNextGame() { - boolean matchIsOver = false; // get player that chooses who goes first UUID choosingPlayerId = match.getChooser(); match.endGame(); @@ -604,27 +603,24 @@ public class TableController { } GameManager.getInstance().removeGame(match.getGame().getId()); try { - if (!match.isMatchOver()) { + if (!match.hasEnded()) { table.sideboard(); setupTimeout(Match.SIDEBOARD_TIME); match.sideboard(); cancelTimeout(); - if (!match.isMatchOver()) { + if (!match.hasEnded()) { startGame(choosingPlayerId); } else { - matchIsOver = true; closeTable(); } } else { - // if match has only one game - matchIsOver = true; closeTable(); } } catch (GameException ex) { logger.fatal(null, ex); } - return matchIsOver; + return match.hasEnded(); } /** diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index d924e8a39a..dcbbd1bdf3 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -240,8 +240,8 @@ public class GameController implements GameCallback { PriorityTimer timer = new PriorityTimer(count, delay, new Action() { @Override public void execute() throws MageException { - game.concede(initPlayerId); - logger.debug("Game timeout for player: " + initPlayerId + ". Conceding."); + game.timerTimeout(initPlayerId); + logger.debug(new StringBuilder("Game timeout for player: ").append(initPlayerId).append(". Conceding.")); } }); timers.put(playerId, timer); @@ -399,7 +399,7 @@ public class GameController implements GameCallback { .append(ConfigSettings.getInstance().getMaxSecondsIdle()) .append(" seconds ) - Auto concede."); ChatManager.getInstance().broadcast(chatId, "", sb.toString() , MessageColor.BLACK, true, MessageType.STATUS); - concede(userId); + game.idleTimeout(getPlayerId(userId)); } } diff --git a/Mage/src/mage/constants/TableState.java b/Mage/src/mage/constants/TableState.java index 3d8a21bf6d..2c0e45bb5e 100644 --- a/Mage/src/mage/constants/TableState.java +++ b/Mage/src/mage/constants/TableState.java @@ -13,7 +13,7 @@ public enum TableState { CONSTRUCTING ("Constructing"), FINISHED ("Finished"); - private String text; + private final String text; TableState(String text) { this.text = text; diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index 55fd6455d4..9a4b052c1f 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -122,7 +122,8 @@ public interface Game extends MageItem, Serializable { UUID getActivePlayerId(); UUID getPriorityPlayerId(); void leave(UUID playerId); - boolean isGameOver(); + boolean gameOver(UUID playerId); + boolean hasEnded(); Battlefield getBattlefield(); SpellStack getStack(); Exile getExile(); @@ -218,6 +219,8 @@ public interface Game extends MageItem, Serializable { void mulligan(UUID playerId); void endMulligan(UUID playerId); void quit(UUID playerId); + void timerTimeout(UUID playerId); + void idleTimeout(UUID playerId); void concede(UUID playerId); void undo(UUID playerId); void emptyManaPools(); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 129962b033..ef68f7e469 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -418,8 +418,26 @@ public abstract class GameImpl> implements Game, Serializa } } + /** + * Starts check if game over or if playerId is given + * let the player concede. + * + * @param playerId + * @return + */ @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()) { return true; } @@ -447,6 +465,11 @@ public abstract class GameImpl> implements Game, Serializa return false; } + @Override + public boolean hasEnded() { + return endTime != null; + } + @Override public String getWinner() { if (winnerId == null) { @@ -546,13 +569,13 @@ public abstract class GameImpl> implements Game, Serializa Player player = getPlayer(players.get()); boolean wasPaused = state.isPaused(); state.resume(); - if (!isGameOver()) { + if (!gameOver(null)) { fireInformEvent(new StringBuilder("Turn ").append(state.getTurnNum()).toString()); if (checkStopOnTurnOption()) { return; } state.getTurn().resumePlay(this, wasPaused); - if (!isPaused() && !isGameOver()) { + if (!isPaused() && !gameOver(null)) { endOfTurn(); player = players.getNext(this); state.setTurnNum(state.getTurnNum() + 1); @@ -562,10 +585,10 @@ public abstract class GameImpl> implements Game, Serializa } protected void play(UUID nextPlayerId) { - if (!isPaused() && !isGameOver()) { + if (!isPaused() && !gameOver(null)) { PlayerList players = state.getPlayerList(nextPlayerId); Player player = getPlayer(players.get()); - while (!isPaused() && !isGameOver()) { + while (!isPaused() && !gameOver(null)) { if (!playTurn(player)) { break; @@ -583,7 +606,7 @@ public abstract class GameImpl> implements Game, Serializa player = players.getNext(this); } } - if (isGameOver()) { + if (gameOver(null)) { winnerId = findWinnersAndLosers(); logger.info(new StringBuilder("Game with gameId ").append(this.getId()).append(" ended.")); } @@ -597,7 +620,7 @@ public abstract class GameImpl> implements Game, Serializa state.setActivePlayerId(player.getId()); player.becomesActivePlayer(); state.getTurn().play(this, player.getId()); - if (isPaused() || isGameOver()) { + if (isPaused() || gameOver(null)) { return false; } endOfTurn(); @@ -865,9 +888,30 @@ public abstract class GameImpl> implements Game, Serializa @Override public synchronized void quit(UUID playerId) { Player player = state.getPlayer(playerId); - if (player != null) { - fireInformEvent(player.getName() + " quits the match."); + if (player != null) { 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> implements Game, Serializa int bookmark = 0; clearAllBookmarks(); try { - while (!isPaused() && !isGameOver()) { + while (!isPaused() && !gameOver(null)) { if (!resuming) { state.getPlayers().resetPassed(); state.getPlayerList().setCurrent(activePlayerId); @@ -933,13 +977,13 @@ public abstract class GameImpl> implements Game, Serializa } fireUpdatePlayersEvent(); Player player; - while (!isPaused() && !isGameOver()) { + while (!isPaused() && !gameOver(null)) { try { //if (bookmark == 0) //bookmark = bookmarkState(); player = getPlayer(state.getPlayerList().get()); state.setPriorityPlayerId(player.getId()); - while (!player.isPassed() && player.isInGame() && !isPaused() && !isGameOver()) { + while (!player.isPassed() && player.isInGame() && !isPaused() && !gameOver(null)) { if (!resuming) { if (checkStateAndTriggered()) { applyEffects(); @@ -947,7 +991,7 @@ public abstract class GameImpl> implements Game, Serializa //resetLKI(); applyEffects(); saveState(false); - if (isPaused() || isGameOver()) { + if (isPaused() || gameOver(null)) { return; } // resetPassed should be called if player performs any action @@ -962,7 +1006,7 @@ public abstract class GameImpl> implements Game, Serializa } resetShortLivingLKI(); resuming = false; - if (isPaused() || isGameOver()) { + if (isPaused() || gameOver(null)) { return; } if (allPassed()) { @@ -1164,9 +1208,9 @@ public abstract class GameImpl> implements Game, Serializa public boolean checkStateAndTriggered() { boolean somethingHappened = false; //20091005 - 115.5 - while (!isPaused() && !this.isGameOver()) { + while (!isPaused() && !gameOver(null)) { if (!checkStateBasedActions() ) { - if (isPaused() || this.isGameOver() || !checkTriggered()) { + if (isPaused() || gameOver(null) || !checkTriggered()) { break; } } @@ -1729,7 +1773,7 @@ public abstract class GameImpl> implements Game, Serializa return; } player.leave(); - if (this.isGameOver()) { + if (gameOver(null)) { // no need to remove objects if only one player is left so the game is over return; } diff --git a/Mage/src/mage/game/Table.java b/Mage/src/mage/game/Table.java index e6dabdbb89..4aa4490122 100644 --- a/Mage/src/mage/game/Table.java +++ b/Mage/src/mage/game/Table.java @@ -112,8 +112,8 @@ public class Table implements Serializable { } public void initTournament() { - setState(TableState.DUELING); - + setState(TableState.DUELING); + tournament.setStepStartTime(new Date()); } public void endTournament() { @@ -122,10 +122,12 @@ public class Table implements Serializable { public void initDraft() { setState(TableState.DRAFTING); + tournament.setStepStartTime(new Date()); } public void construct() { setState(TableState.CONSTRUCTING); + tournament.setStepStartTime(new Date()); } /** diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java index fa41efc01c..b5624938e8 100644 --- a/Mage/src/mage/game/combat/Combat.java +++ b/Mage/src/mage/game/combat/Combat.java @@ -191,7 +191,7 @@ public class Combat implements Serializable, Copyable { //20101001 - 508.1d checkAttackRequirements(player, game); player.selectAttackers(game, attackerId); - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return; } checkAttackRestrictions(player, game); @@ -316,7 +316,7 @@ public class Combat implements Serializable, Copyable { } while (choose) { blockController.selectBlockers(game, defenderId); - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return; } if (!this.checkBlockRestrictions(defender, game)) { diff --git a/Mage/src/mage/game/match/Match.java b/Mage/src/mage/game/match/Match.java index 2e5493c895..a9917638de 100644 --- a/Mage/src/mage/game/match/Match.java +++ b/Mage/src/mage/game/match/Match.java @@ -48,7 +48,8 @@ public interface Match { UUID getId(); String getName(); - boolean isMatchOver(); + boolean hasEnded(); + boolean checkIfMatchEnds(); List getPlayers(); MatchPlayer getPlayer(UUID playerId); diff --git a/Mage/src/mage/game/match/MatchImpl.java b/Mage/src/mage/game/match/MatchImpl.java index cc95c09506..b4caf5e9b8 100644 --- a/Mage/src/mage/game/match/MatchImpl.java +++ b/Mage/src/mage/game/match/MatchImpl.java @@ -126,20 +126,31 @@ public abstract class MatchImpl implements Match { } @Override - public boolean isMatchOver() { + public boolean hasEnded() { + return endTime != null; + }; + + @Override + public boolean checkIfMatchEnds() { int activePlayers = 0; - for (MatchPlayer player: players) { - if (!player.hasQuit()) { + MatchPlayer matchWinner = null; + for (MatchPlayer matchPlayer: players) { + if (!matchPlayer.hasQuit()) { activePlayers++; + matchWinner = matchPlayer; } - if (player.getWins() >= options.getWinsNeeded()) { + if (matchPlayer.getWins() >= options.getWinsNeeded()) { + matchPlayer.setMatchWinner(true); endTime = new Date(); return true; } } if (activePlayers < 2) { - endTime = new Date(); - return true; + if (matchWinner != null) { + matchWinner.setMatchWinner(true); + } + endTime = new Date(); + return true; } return false; } @@ -200,24 +211,28 @@ public abstract class MatchImpl implements Match { @Override public void endGame() { Game game = getGame(); - for (MatchPlayer player: this.players) { - Player p = game.getPlayer(player.getPlayer().getId()); - if (p != null) { + for (MatchPlayer matchPlayer: this.players) { + Player player = game.getPlayer(matchPlayer.getPlayer().getId()); + if (player != null) { // get the left time from player priority timer if (game.getPriorityTime() > 0) { - player.setPriorityTimeLeft(p.getPriorityTimeLeft()); + matchPlayer.setPriorityTimeLeft(player.getPriorityTimeLeft()); } - if (p.hasQuit()) { - player.setQuit(true); + if (player.hasQuit()) { + matchPlayer.setQuit(true); } - if (p.hasWon()) { - player.addWin(); + if (player.hasTimerTimeout()) { + matchPlayer.setTimerTimeout(true); } - if (p.hasLost()) { - player.addLose(); + if (player.hasWon()) { + matchPlayer.addWin(); + } + if (player.hasLost()) { + matchPlayer.addLose(); } } } + checkIfMatchEnds(); game.fireGameEndInfo(); } diff --git a/Mage/src/mage/game/match/MatchPlayer.java b/Mage/src/mage/game/match/MatchPlayer.java index 01dc95f7ab..b9a5438227 100644 --- a/Mage/src/mage/game/match/MatchPlayer.java +++ b/Mage/src/mage/game/match/MatchPlayer.java @@ -39,12 +39,14 @@ import mage.players.Player; public class MatchPlayer { private int wins; private int loses; - + private boolean matchWinner; + private Deck deck; private Player player; private final String name; private boolean quit; + private boolean timerTimeout; private boolean doneSideboarding; private int priorityTimeLeft; @@ -55,7 +57,9 @@ public class MatchPlayer { this.loses = 0; this.doneSideboarding = true; this.quit = false; + this.timerTimeout = false; this.name = player.getName(); + this.matchWinner = false; } public int getPriorityTimeLeft() { @@ -125,7 +129,23 @@ public class MatchPlayer { this.doneSideboarding = true; 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() { // Free resources that are not needed after match end this.deck = null; diff --git a/Mage/src/mage/game/tournament/Round.java b/Mage/src/mage/game/tournament/Round.java index 2b107cde0d..5f2e539521 100644 --- a/Mage/src/mage/game/tournament/Round.java +++ b/Mage/src/mage/game/tournament/Round.java @@ -72,7 +72,7 @@ public class Round { public boolean isRoundOver() { boolean roundIsOver = true; for (TournamentPairing pair: pairs) { - if (pair.getMatch() != null && !pair.getMatch().isMatchOver()) { + if (pair.getMatch() != null && !pair.getMatch().hasEnded()) { roundIsOver = false; } else { if (!pair.isAlreadyPublished()) { diff --git a/Mage/src/mage/game/tournament/Tournament.java b/Mage/src/mage/game/tournament/Tournament.java index 84b8438a49..046afbe0a9 100644 --- a/Mage/src/mage/game/tournament/Tournament.java +++ b/Mage/src/mage/game/tournament/Tournament.java @@ -78,6 +78,10 @@ public interface Tournament { // tournament times Date getStartTime(); Date getEndTime(); + + Date getStepStartTime(); + void setStepStartTime(Date date); + // tournament type TournamentType getTournamentType(); void setTournamentType(TournamentType tournamentType); diff --git a/Mage/src/mage/game/tournament/TournamentImpl.java b/Mage/src/mage/game/tournament/TournamentImpl.java index e49d61880b..26941faa59 100644 --- a/Mage/src/mage/game/tournament/TournamentImpl.java +++ b/Mage/src/mage/game/tournament/TournamentImpl.java @@ -74,6 +74,7 @@ public abstract class TournamentImpl implements Tournament { protected Date startTime; protected Date endTime; + protected Date stepStartTime; protected boolean abort; protected String tournamentState; @@ -244,7 +245,7 @@ public abstract class TournamentImpl implements Tournament { for (Round round: rounds) { for (TournamentPairing pair: round.getPairs()) { Match match = pair.getMatch(); - if (match != null && match.isMatchOver()) { + if (match != null && match.hasEnded()) { TournamentPlayer tp1 = pair.getPlayer1(); TournamentPlayer tp2 = pair.getPlayer2(); 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(" (").append(mp1.getWins()); if (mp1.hasQuit()) { - matchResult.append("Q"); + matchResult.append(mp1.hasTimerTimeout()?"T":"Q"); } matchResult.append("-").append(mp2.getWins()); if (mp2.hasQuit()) { - matchResult.append("Q"); + matchResult.append(mp2.hasTimerTimeout()?"T":"Q"); } matchResult.append(") "); return matchResult.toString(); @@ -479,4 +480,18 @@ public abstract class TournamentImpl implements Tournament { 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; + } + + } diff --git a/Mage/src/mage/game/tournament/TournamentPairing.java b/Mage/src/mage/game/tournament/TournamentPairing.java index ccdd1f90da..41abf20b43 100644 --- a/Mage/src/mage/game/tournament/TournamentPairing.java +++ b/Mage/src/mage/game/tournament/TournamentPairing.java @@ -72,7 +72,7 @@ public class TournamentPairing { } public void eliminatePlayers() { - if (match.isMatchOver()) { + if (match.hasEnded()) { MatchPlayer mPlayer1 = match.getPlayer(player1.getPlayer().getId()); MatchPlayer mPlayer2 = match.getPlayer(player2.getPlayer().getId()); if (mPlayer1.hasQuit() || (!mPlayer2.hasQuit() && mPlayer1.getWins() < match.getWinsNeeded())) { diff --git a/Mage/src/mage/game/turn/Phase.java b/Mage/src/mage/game/turn/Phase.java index 545854fb56..916351fd83 100644 --- a/Mage/src/mage/game/turn/Phase.java +++ b/Mage/src/mage/game/turn/Phase.java @@ -95,7 +95,7 @@ public abstract class Phase> implements Serializable { } public boolean play(Game game, UUID activePlayerId) { - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return false; } @@ -104,7 +104,7 @@ public abstract class Phase> implements Serializable { if (beginPhase(game, activePlayerId)) { for (Step step: steps) { - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return false; } currentStep = step; @@ -115,7 +115,7 @@ public abstract class Phase> implements Serializable { playStep(game); } } - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return false; } count++; @@ -136,7 +136,7 @@ public abstract class Phase> implements Serializable { } public boolean resumePlay(Game game, PhaseStep stepType, boolean wasPaused) { - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return false; } @@ -150,7 +150,7 @@ public abstract class Phase> implements Serializable { resumeStep(game, wasPaused); while (it.hasNext()) { step = it.next(); - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return false; } currentStep = step; @@ -159,7 +159,7 @@ public abstract class Phase> implements Serializable { } } - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return false; } count++; @@ -194,10 +194,10 @@ public abstract class Phase> implements Serializable { protected void playStep(Game game) { if (!currentStep.skipStep(game, activePlayerId)) { prePriority(game, activePlayerId); - if (!game.isPaused() && !game.isGameOver()) { + if (!game.isPaused() && !game.gameOver(null)) { currentStep.priority(game, activePlayerId, false); } - if (!game.isPaused() && !game.isGameOver()) { + if (!game.isPaused() && !game.gameOver(null)) { postPriority(game, activePlayerId); } } @@ -219,11 +219,11 @@ public abstract class Phase> implements Serializable { prePriority(game, activePlayerId); } case PRIORITY: - if (!game.isPaused() && !game.isGameOver()) { + if (!game.isPaused() && !game.gameOver(null)) { currentStep.priority(game, activePlayerId, resuming); } case POST: - if (!game.isPaused() && !game.isGameOver()) { + if (!game.isPaused() && !game.gameOver(null)) { postPriority(game, activePlayerId); } } diff --git a/Mage/src/mage/game/turn/Turn.java b/Mage/src/mage/game/turn/Turn.java index 40395bd82e..b00e44eda6 100644 --- a/Mage/src/mage/game/turn/Turn.java +++ b/Mage/src/mage/game/turn/Turn.java @@ -47,7 +47,7 @@ public class Turn implements Serializable { private Phase currentPhase; private UUID activePlayerId; - private List phases = new ArrayList(); + private final List phases = new ArrayList<>(); private boolean declareAttackersStepStarted = false; public Turn() { @@ -109,7 +109,7 @@ public class Turn implements Serializable { public void play(Game game, UUID activePlayerId) { this.setDeclareAttackersStepStarted(false); - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return; } @@ -123,7 +123,7 @@ public class Turn implements Serializable { resetCounts(); game.getPlayer(activePlayerId).beginTurn(game); for (Phase phase: phases) { - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return; } currentPhase = phase; @@ -168,7 +168,7 @@ public class Turn implements Serializable { } while (it.hasNext()) { phase = it.next(); - if (game.isPaused() || game.isGameOver()) { + if (game.isPaused() || game.gameOver(null)) { return; } currentPhase = phase; diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index ae9f9d5c84..3fd0486aab 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -129,6 +129,10 @@ public interface Player extends MageItem, Copyable { boolean hasWon(); boolean hasQuit(); void quit(Game game); + boolean hasTimerTimeout(); + void timerTimeout(Game game); + boolean hasIdleTimeout(); + void idleTimeout(Game game); boolean hasLeft(); /** * Player is still active in game (has not left, lost or won the game). diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index dc4cfd8ff1..c5b5b1698d 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -114,7 +114,10 @@ import mage.target.common.TargetDiscard; import mage.watchers.common.BloodthirstWatcher; import org.apache.log4j.Logger; - +/** + * + * * @param + */ public abstract class PlayerImpl> implements Player, Serializable { private static final transient Logger log = Logger.getLogger(PlayerImpl.class); @@ -160,6 +163,10 @@ public abstract class PlayerImpl> implements Player, Ser protected boolean left; // set if the player quits the complete match 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 Set inRange = new HashSet<>(); @@ -234,6 +241,8 @@ public abstract class PlayerImpl> implements Player, Ser this.left = player.left; this.quit = player.quit; + this.timerTimeout = player.timerTimeout; + this.idleTimeout = player.idleTimeout; this.range = player.range; this.canGainLife = player.canGainLife; this.canLoseLife = player.canLoseLife; @@ -288,6 +297,8 @@ public abstract class PlayerImpl> implements Player, Ser this.left = player.hasLeft(); this.quit = player.hasQuit(); + this.timerTimeout = player.hasTimerTimeout(); + this.idleTimeout = player.hasIdleTimeout(); this.range = player.getRange(); this.canGainLife = player.isCanGainLife(); this.canLoseLife = player.isCanLoseLife(); @@ -343,7 +354,11 @@ public abstract class PlayerImpl> implements Player, Ser this.wins = false; this.loses = 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.passedTurn = false; this.passedAllTurns = false; @@ -732,7 +747,7 @@ public abstract class PlayerImpl> implements Player, Ser resetStoredBookmark(game); 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); } } @@ -1475,13 +1490,30 @@ public abstract class PlayerImpl> implements Player, Ser @Override public void quit(Game game) { + game.informPlayers(new StringBuilder(getName()).append(" quits the match.").toString()); quit = true; 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 public void concede(Game game) { - game.leave(playerId); + game.gameOver(playerId); lost(game); this.left = true; } @@ -2117,6 +2149,16 @@ public abstract class PlayerImpl> implements Player, Ser return quit; } + @Override + public boolean hasTimerTimeout() { + return timerTimeout; + } + + @Override + public boolean hasIdleTimeout() { + return idleTimeout; + } + @Override public void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving) { this.reachedNextTurnAfterLeaving = reachedNextTurnAfterLeaving;