use of soc.message.SOCResetBoardReject in project JSettlers2 by jdmonin.
the class SOCGameHandler method endGameTurn.
/**
* Pre-checking already done, end the current player's turn in this game.
* Alter game state and send messages to players.
* (Clear all the Ask Special Building, Reset Board Request, and Trade Offer flags; send Game State; send Turn).
*<P>
* Calls {@link SOCGame#endTurn()}, which may also end the game.
* On the 6-player board, this may begin the {@link SOCGame#SPECIAL_BUILDING Special Building Phase},
* or end a player's placements during that phase.
* Otherwise, calls {@link #sendTurn(SOCGame, boolean)} and begins
* the next player's turn.
*<P>
* Assumes:
* <UL>
* <LI> ga.canEndTurn already called, to validate player
* <LI> ga.takeMonitor already called (not the same as {@link SOCGameList#takeMonitorForGame(String)})
* <LI> gamelist.takeMonitorForGame is NOT called, we do NOT have that monitor
* </UL>
*<P>
* As a special case, endTurn is used to begin the Special Building Phase during the
* start of a player's own turn, if permitted. (Added in 1.1.09)
*<P>
* A simplified version of this logic (during initial placement) is used in
* {@link SOCGameMessageHandler#handlePUTPIECE(SOCGame, Connection, SOCPutPiece)}.
*
* @param ga Game to end turn
* @param pl Current player in <tt>ga</tt>, or null. Not needed except in SPECIAL_BUILDING.
* If null, will be determined within this method.
* @param callEndTurn Almost always true; if false, don't call {@link SOCGame#endTurn()}
* because it was called before calling this method.
* If false, be sure to set {@code pl} to the player whose turn it was before {@code endTurn()} was called.
*/
void endGameTurn(SOCGame ga, SOCPlayer pl, final boolean callEndTurn) {
// Reminder: if this method's logic is changed or added to,
// please also look at SOCGameMessageHandler.handlePUTPIECE
// to see if the simplified version there should also be
// updated.
final String gname = ga.getName();
if (ga.getGameState() == SOCGame.SPECIAL_BUILDING) {
if (pl == null)
pl = ga.getPlayer(ga.getCurrentPlayerNumber());
pl.setAskedSpecialBuild(false);
srv.messageToGame(gname, new SOCPlayerElement(gname, pl.getPlayerNumber(), SOCPlayerElement.SET, SOCPlayerElement.ASK_SPECIAL_BUILD, 0));
}
final boolean hadBoardResetRequest = (-1 != ga.getResetVoteRequester());
/**
* End the Turn:
*/
if (callEndTurn) {
// May set state to OVER, if new player has enough points to win.
ga.endTurn();
// May begin or continue the Special Building Phase.
}
if (hadBoardResetRequest) {
// Cancel voting at end of turn
srv.messageToGame(gname, new SOCResetBoardReject(gname));
}
/**
* clear any trade offers
*/
srv.gameList.takeMonitorForGame(gname);
if (ga.clientVersionLowest >= SOCClearOffer.VERSION_FOR_CLEAR_ALL) {
srv.messageToGameWithMon(gname, new SOCClearOffer(gname, -1));
} else {
for (int i = 0; i < ga.maxPlayers; i++) srv.messageToGameWithMon(gname, new SOCClearOffer(gname, i));
}
srv.gameList.releaseMonitorForGame(gname);
/**
* send new state number; if game is now OVER,
* also send end-of-game messages.
* Send whose turn it is.
*/
sendTurn(ga, false);
if (ga.getGameState() == SOCGame.SPECIAL_BUILDING)
srv.messageToGameKeyed(ga, true, "action.sbp.turn.to.place", ga.getPlayer(ga.getCurrentPlayerNumber()).getName());
// "Special building phase: {0}''s turn to place."
}
use of soc.message.SOCResetBoardReject in project JSettlers2 by jdmonin.
the class SOCGameHandler method endGameTurnOrForce.
/**
* A bot is unresponsive, or a human player has left the game.
* End this player's turn cleanly, or force-end if needed.
*<P>
* Can be called for a player still in the game, or for a player
* who has left ({@link SOCGame#removePlayer(String)} has been called).
* Can be called for a player who isn't current player; in that case
* it takes action if the game was waiting for the player (picking random
* resources for discard or gold-hex picks) but won't end the current turn.
*<P>
* If they were placing an initial road, also cancels that road's
* initial settlement.
*<P>
* <b>Locks:</b> Must not have ga.takeMonitor() when calling this method.
* May or may not have <tt>gameList.takeMonitorForGame(ga)</tt>;
* use <tt>hasMonitorFromGameList</tt> to indicate.
*<P>
* Not public, but package visibility, for use by {@link SOCForceEndTurnThread} for {@link SOCGameTimeoutChecker}.
*
* @param ga The game to end turn if called for current player, or to otherwise stop waiting for a player
* @param plNumber player.getNumber; may or may not be current player
* @param plName player.getName
* @param plConn player's client connection
* @param hasMonitorFromGameList if false, have not yet called
* {@link SOCGameList#takeMonitorForGame(String) gameList.takeMonitorForGame(ga)};
* if false, this method will take this monitor at its start,
* and release it before returning.
* @return true if the turn was ended and game is still active;
* false if we find that all players have left and
* the gamestate has been changed here to {@link SOCGame#OVER OVER}.
*/
boolean endGameTurnOrForce(SOCGame ga, final int plNumber, final String plName, Connection plConn, final boolean hasMonitorFromGameList) {
boolean gameStillActive = true;
final String gaName = ga.getName();
if (!hasMonitorFromGameList) {
srv.gameList.takeMonitorForGame(gaName);
}
final int cpn = ga.getCurrentPlayerNumber();
final int gameState = ga.getGameState();
/**
* Is a board-reset vote is in progress?
* If they're still a sitting player, to keep the game
* moving, fabricate their response: vote No.
*/
boolean gameVotingActiveDuringStart = false;
if (ga.getResetVoteActive()) {
if (gameState <= SOCGame.STARTS_WAITING_FOR_PICK_GOLD_RESOURCE)
gameVotingActiveDuringStart = true;
if ((!ga.isSeatVacant(plNumber)) && (ga.getResetPlayerVote(plNumber) == SOCGame.VOTE_NONE)) {
srv.gameList.releaseMonitorForGame(gaName);
ga.takeMonitor();
srv.resetBoardVoteNotifyOne(ga, plNumber, plName, false);
ga.releaseMonitor();
srv.gameList.takeMonitorForGame(gaName);
}
}
/**
* Now end their turn, or handle any needed responses if not current player.
* Don't call forceEndGameTurn()/ga.forceEndTurn() unless we need to.
*/
if (plNumber == cpn) {
if ((gameState == SOCGame.START1B) || (gameState == SOCGame.START2B) || (gameState == SOCGame.START3B)) {
/**
* Leaving during initial road placement.
* Cancel the settlement they just placed,
* and send that cancel to the other players.
* Don't change gameState yet.
* Note that their most recent init settlement is removed here,
* but not earlier settlement(s). (That would impact the robots much more.)
*/
SOCPlayer pl = ga.getPlayer(plNumber);
SOCSettlement pp = new SOCSettlement(pl, pl.getLastSettlementCoord(), null);
ga.undoPutInitSettlement(pp);
// state was changed by undoPutInitSettlement
ga.setGameState(gameState);
srv.messageToGameWithMon(gaName, new SOCCancelBuildRequest(gaName, SOCSettlement.SETTLEMENT));
}
if (ga.canEndTurn(plNumber)) {
srv.gameList.releaseMonitorForGame(gaName);
ga.takeMonitor();
endGameTurn(ga, null, true);
ga.releaseMonitor();
srv.gameList.takeMonitorForGame(gaName);
} else {
/**
* Cannot easily end turn.
* Must back out something in progress.
* May or may not end turn; see javadocs
* of forceEndGameTurn and game.forceEndTurn.
* All start phases are covered here (START1A..START2B)
* because canEndTurn returns false in those gameStates.
*/
srv.gameList.releaseMonitorForGame(gaName);
ga.takeMonitor();
if (gameVotingActiveDuringStart) {
/**
* If anyone has requested a board-reset vote during
* game-start phases, we have to tell clients to cancel
* the vote request, because {@link soc.message.SOCTurn}
* isn't always sent during start phases. (Voting must
* end when the turn ends.)
*/
srv.messageToGame(gaName, new SOCResetBoardReject(gaName));
ga.resetVoteClear();
}
/**
* Force turn to end
*/
gameStillActive = forceEndGameTurn(ga, plName);
ga.releaseMonitor();
if (gameStillActive) {
srv.gameList.takeMonitorForGame(gaName);
}
}
} else {
/**
* Check if game is waiting for input from the player who
* is leaving, but who isn't current player.
* To keep the game moving, fabricate their response.
* - Board-reset voting: Handled above.
* - Waiting for discard: Handle here.
* - Waiting for gold-hex pick: Handle here.
*/
if (((gameState == SOCGame.WAITING_FOR_DISCARDS) && ga.getPlayer(plNumber).getNeedToDiscard()) || (((gameState == SOCGame.WAITING_FOR_PICK_GOLD_RESOURCE) || (gameState == SOCGame.STARTS_WAITING_FOR_PICK_GOLD_RESOURCE)) && (ga.getPlayer(plNumber).getNeedToPickGoldHexResources() > 0))) {
/**
* For discard, tell the discarding player's client that they discarded the resources,
* tell everyone else that the player discarded unknown resources.
* For gold pick, announce the picked resources.
*/
srv.gameList.releaseMonitorForGame(gaName);
System.err.println("L5789: Waiting too long for bot discard or gain: game=" + ga.getName() + ", pn=" + plNumber + " " + plName);
ga.takeMonitor();
forceGamePlayerDiscardOrGain(ga, cpn, plConn, plName, plNumber);
// WAITING_FOR_DISCARDS or MOVING_ROBBER for discard;
sendGameState(ga, false, false);
// PLAY1 or WAITING_FOR_PICK_GOLD_RESOURCE for gain
ga.releaseMonitor();
srv.gameList.takeMonitorForGame(gaName);
}
}
if (!hasMonitorFromGameList) {
srv.gameList.releaseMonitorForGame(gaName);
}
return gameStillActive;
}
Aggregations