Search in sources :

Example 1 with SOCCancelBuildRequest

use of soc.message.SOCCancelBuildRequest 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;
}
Also used : SOCCancelBuildRequest(soc.message.SOCCancelBuildRequest) SOCResetBoardReject(soc.message.SOCResetBoardReject)

Aggregations

SOCCancelBuildRequest (soc.message.SOCCancelBuildRequest)1 SOCResetBoardReject (soc.message.SOCResetBoardReject)1