Search in sources :

Example 1 with SOCLeaveGame

use of soc.message.SOCLeaveGame in project JSettlers2 by jdmonin.

the class SOCGameHandler method leaveGame.

// javadoc inherited from GameHandler. Return true if game is empty and should be ended.
public boolean leaveGame(SOCGame ga, Connection c) {
    final String gm = ga.getName();
    // Retain name, since will become null within game obj.
    final String plName = c.getData();
    boolean gameHasHumanPlayer = false;
    boolean gameHasObserver = false;
    @SuppressWarnings("unused") boolean // TODO checks/messages; added in v1.1.01, TODO not used yet
    gameVotingActiveDuringStart = false;
    final int gameState = ga.getGameState();
    boolean isPlayer = false;
    // removing this player number
    int playerNumber;
    for (playerNumber = 0; playerNumber < ga.maxPlayers; playerNumber++) {
        SOCPlayer player = ga.getPlayer(playerNumber);
        if ((player != null) && (player.getName() != null) && (player.getName().equals(plName))) {
            isPlayer = true;
            /**
             * About to remove this player from the game. Before doing so:
             * If a board-reset vote is in progress, they cannot vote
             * once they have left. So to keep the game moving,
             * fabricate their response: vote No.
             */
            if (ga.getResetVoteActive()) {
                if (gameState <= SOCGame.STARTS_WAITING_FOR_PICK_GOLD_RESOURCE)
                    gameVotingActiveDuringStart = true;
                if (ga.getResetPlayerVote(playerNumber) == SOCGame.VOTE_NONE) {
                    srv.gameList.releaseMonitorForGame(gm);
                    ga.takeMonitor();
                    srv.resetBoardVoteNotifyOne(ga, playerNumber, plName, false);
                    ga.releaseMonitor();
                    srv.gameList.takeMonitorForGame(gm);
                }
            }
            /**
             * Remove the player.
             */
            // player obj name becomes null
            ga.removePlayer(plName);
            // broadcastGameStats(cg);
            break;
        }
    }
    SOCLeaveGame leaveMessage = new SOCLeaveGame(plName, "-", gm);
    srv.messageToGameWithMon(gm, leaveMessage);
    srv.recordGameEvent(gm, leaveMessage);
    if (D.ebugOn)
        D.ebugPrintln("*** " + plName + " left the game " + gm + " at " + DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date()));
    // "{0} left the game"
    srv.messageToGameKeyed(ga, false, "member.left.game", plName);
    /**
     * check if there is at least one person playing the game
     */
    for (int pn = 0; pn < ga.maxPlayers; pn++) {
        SOCPlayer player = ga.getPlayer(pn);
        if ((player != null) && (player.getName() != null) && (!ga.isSeatVacant(pn)) && (!player.isRobot())) {
            gameHasHumanPlayer = true;
            break;
        }
    }
    /**
     * if no human players, check if there is at least one person watching the game (observing).
     * Even with observers, end it unless ga.isBotsOnly or PROP_JSETTLERS_BOTS_BOTGAMES_TOTAL != 0.
     */
    if ((!gameHasHumanPlayer) && !srv.gameList.isGameEmpty(gm)) {
        Enumeration<Connection> membersEnum = srv.gameList.getMembers(gm).elements();
        while (membersEnum.hasMoreElements()) {
            Connection member = membersEnum.nextElement();
            // D.ebugPrintln("*** "+member.data+" is a member of "+gm);
            boolean nameMatch = false;
            for (int pn = 0; pn < ga.maxPlayers; pn++) {
                SOCPlayer player = ga.getPlayer(pn);
                if ((player != null) && (player.getName() != null) && (player.getName().equals(member.getData()))) {
                    nameMatch = true;
                    break;
                }
            }
            if (!nameMatch) {
                gameHasObserver = true;
                break;
            }
        }
        if (gameHasObserver && !ga.isBotsOnly) {
            if (0 == srv.getConfigIntProperty(SOCServer.PROP_JSETTLERS_BOTS_BOTGAMES_TOTAL, 0))
                gameHasObserver = false;
        }
    }
    /**
     * if the leaving member was playing the game, and
     * the game isn't over, then decide:
     * - Do we need to force-end the current turn?
     * - Do we need to cancel their initial settlement placement?
     * - Should we replace the leaving player with a robot?
     */
    if (isPlayer && (gameHasHumanPlayer || gameHasObserver) && ((ga.getPlayer(playerNumber).getPublicVP() > 0) || (gameState == SOCGame.START1A) || (gameState == SOCGame.START1B)) && (gameState < SOCGame.OVER) && !(gameState < SOCGame.START1A)) {
        boolean foundNoRobots;
        if (ga.getPlayer(playerNumber).isRobot()) {
            /**
             * don't replace bot with bot; force end-turn instead.
             */
            foundNoRobots = true;
        } else {
            /**
             * get a robot to replace this human player;
             * just in case, check game-version vs robots-version,
             * like at new-game (readyGameAskRobotsJoin).
             */
            foundNoRobots = !findRobotAskJoinGame(ga, Integer.valueOf(playerNumber), true);
        }
        /**
         * What to do if no robot was found to fill their spot?
         * Must keep the game going, might need to force-end current turn.
         */
        if (foundNoRobots) {
            final boolean stillActive = endGameTurnOrForce(ga, playerNumber, plName, c, true);
            if (!stillActive) {
                // force game destruction below
                gameHasHumanPlayer = false;
                gameHasObserver = false;
            }
        }
    } else {
        // observer leaving: If game is bot-only, don't end the game despite no human players/observers
        if (ga.isBotsOnly && (ga.getGameState() < SOCGame.OVER))
            gameHasObserver = true;
    }
    return !(gameHasHumanPlayer || gameHasObserver);
}
Also used : SOCLeaveGame(soc.message.SOCLeaveGame) Connection(soc.server.genericServer.Connection) Date(java.util.Date)

Aggregations

Date (java.util.Date)1 SOCLeaveGame (soc.message.SOCLeaveGame)1 Connection (soc.server.genericServer.Connection)1