Search in sources :

Example 1 with SOCResetBoardReject

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."
}
Also used : SOCClearOffer(soc.message.SOCClearOffer) SOCPlayerElement(soc.message.SOCPlayerElement) SOCResetBoardReject(soc.message.SOCResetBoardReject)

Example 2 with SOCResetBoardReject

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

Aggregations

SOCResetBoardReject (soc.message.SOCResetBoardReject)2 SOCCancelBuildRequest (soc.message.SOCCancelBuildRequest)1 SOCClearOffer (soc.message.SOCClearOffer)1 SOCPlayerElement (soc.message.SOCPlayerElement)1