Search in sources :

Example 1 with SOCSetSpecialItem

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

the class SOCGameHandler method joinGame.

/**
 * Client has been approved to join game; send JOINGAMEAUTH and the entire state of the game to client.
 * Unless <tt>isTakingOver</tt>, announce {@link SOCJoinGame} client join event to other players.
 *<P>
 * Does not add the client to the game's or server's list of players,
 * that should be done before calling this method.
 *<P>
 * Assumes NEWGAME (or NEWGAMEWITHOPTIONS) has already been sent out.
 * The game's first message<B>*</B> sent to the connecting client is JOINGAMEAUTH, unless isReset.
 *<P>
 * Among other messages, player names are sent via SITDOWN, and pieces on board
 * sent by PUTPIECE.  See comments here for further details.
 * If <tt>isTakingOver</tt>, some details are sent by calling
 * {@link #sitDown_sendPrivateInfo(SOCGame, Connection, int)}.
 * The group of messages sent here ends with GAMEMEMBERS, SETTURN and GAMESTATE.
 * Then, the entire game is sent a JOINGAME for the new game member.
 *<P>
 * *<B>I18N:</B> If the game has a {@link SOCScenario} and the client needs scenario info or localized strings
 * for the scenario name and description, {@link SOCScenarioInfo} or {@link SOCLocalizedStrings} is
 * sent before JOINGAMEAUTH.  This handles i18n and scenarios added or changed between the client's
 * and server's versions.
 *
 * @param gameData Game to join
 * @param c        The connection of joining client
 * @param isReset  Game is a board-reset of an existing game.  This is always false when
 *                 called from SOCServer instead of from inside the SOCGameHandler.
 * @param isTakingOver  Client is re-joining; this connection replaces an earlier one which
 *                      is defunct because of a network problem.
 *                      If <tt>isTakingOver</tt>, don't send anything to other players.
 *
 * @see SOCServer#connectToGame(Connection, String, Map)
 * @see SOCServer#createOrJoinGameIfUserOK(Connection, String, String, String, Map)
 */
@SuppressWarnings("unchecked")
public void joinGame(SOCGame gameData, Connection c, final boolean isReset, final boolean isTakingOver) {
    // If game's already started, true if any bot is seated (can be taken over)
    boolean hasRobot = false;
    String gameName = gameData.getName();
    final String cliName = c.getData();
    if (!isReset) {
        // First, send updated scenario info or localized strings if needed
        // (SOCScenarioInfo or SOCLocalizedStrings); checks c.getVersion(), scd.scenariosInfoSent etc.
        final String gameScen = gameData.getGameOptionStringValue("SC");
        if (gameScen != null)
            srv.sendGameScenarioInfo(gameScen, null, c, false);
        // Now, join game
        c.put(SOCJoinGameAuth.toCmd(gameName));
        c.put(SOCStatusMessage.toCmd(SOCStatusMessage.SV_OK, // "Welcome to Java Settlers of Catan!"
        c.getLocalized("member.welcome")));
    }
    // c.put(SOCGameState.toCmd(gameName, gameData.getGameState()));
    for (int i = 0; i < gameData.maxPlayers; i++) {
        /**
         * send them the already-seated player information;
         * if isReset, don't send, because sitDown will
         * be sent from resetBoardAndNotify.
         */
        if (!isReset) {
            SOCPlayer pl = gameData.getPlayer(i);
            String plName = pl.getName();
            if ((plName != null) && !gameData.isSeatVacant(i)) {
                final boolean isRobot = pl.isRobot();
                if (isRobot)
                    hasRobot = true;
                c.put(SOCSitDown.toCmd(gameName, plName, i, isRobot));
            }
        }
        /**
         * send the seat lock information
         */
        final SOCGame.SeatLockState sl = gameData.getSeatLock(i);
        if ((sl != SOCGame.SeatLockState.CLEAR_ON_RESET) || (c.getVersion() >= 2000))
            srv.messageToPlayer(c, new SOCSetSeatLock(gameName, i, sl));
        else
            // old client
            srv.messageToPlayer(c, new SOCSetSeatLock(gameName, i, SOCGame.SeatLockState.LOCKED));
    }
    c.put(getBoardLayoutMessage(gameData).toCmd());
    /**
     * if game hasn't started yet, each player's potentialSettlements are
     * identical, so send that info once for all players.
     * Otherwise send each player's unique potential settlement list,
     * to populate legal sets before sending any of their PutPieces.
     */
    if ((gameData.getGameState() < SOCGame.START1A) && (c.getVersion() >= SOCPotentialSettlements.VERSION_FOR_PLAYERNUM_ALL)) {
        final HashSet<Integer> psList = gameData.getPlayer(0).getPotentialSettlements();
        // Some boards may have multiple land areas.
        // See also below, and startGame which has very similar code.
        final HashSet<Integer>[] lan;
        final int pan;
        boolean addedPsList = false;
        if (gameData.hasSeaBoard) {
            final SOCBoardLarge bl = (SOCBoardLarge) gameData.getBoard();
            lan = bl.getLandAreasLegalNodes();
            pan = bl.getStartingLandArea();
            if ((lan != null) && (pan != 0) && !lan[pan].equals(psList)) {
                // If potentials != legals[startingLandArea], send as legals[0]
                lan[0] = psList;
                addedPsList = true;
            }
        } else {
            lan = null;
            pan = 0;
        }
        if (lan == null) {
            c.put(SOCPotentialSettlements.toCmd(gameName, -1, new ArrayList<Integer>(psList)));
        } else {
            c.put(SOCPotentialSettlements.toCmd(gameName, -1, pan, lan, SOCBoardAtServer.getLegalSeaEdges(gameData, -1)));
        }
        if (addedPsList)
            // Undo change to game's copy of landAreasLegalNodes
            lan[0] = null;
        if (gameData.isGameOptionSet(SOCGameOption.K_SC_CLVI))
            c.put(SOCPlayerElement.toCmd(gameName, -1, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_CLOTH_COUNT, ((SOCBoardLarge) (gameData.getBoard())).getCloth()));
    // individual villages' cloth counts are sent soon below
    } else {
        for (int pn = 0; pn < gameData.maxPlayers; ++pn) {
            final SOCPlayer pl = gameData.getPlayer(pn);
            final HashSet<Integer> psList = pl.getPotentialSettlements();
            // Some boards may have multiple land areas.
            // See also above, and startGame which has very similar code.
            final HashSet<Integer>[] lan;
            if (gameData.hasSeaBoard && (pn == 0)) {
                // send this info once, not per-player:
                // Note: Assumes all players have same legal nodes.
                final SOCBoardLarge bl = (SOCBoardLarge) gameData.getBoard();
                lan = bl.getLandAreasLegalNodes();
                if (lan != null)
                    lan[0] = psList;
            } else {
                lan = null;
            }
            if (lan == null) {
                c.put(SOCPotentialSettlements.toCmd(gameName, pn, new ArrayList<Integer>(psList)));
            } else {
                c.put(SOCPotentialSettlements.toCmd(gameName, pn, 0, lan, SOCBoardAtServer.getLegalSeaEdges(gameData, pn)));
                // Undo change to game's copy of landAreasLegalNodes
                lan[0] = null;
            }
        }
    }
    /**
     * If normal game play has started:
     * _SC_CLVI: Send updated Cloth counts for any changed villages.
     * _SC_FTRI: Send any changed Special Edges.
     */
    if (gameData.hasSeaBoard && (gameData.getGameState() >= SOCGame.ROLL_OR_CARD)) {
        final SOCBoardLarge bl = (SOCBoardLarge) gameData.getBoard();
        // SC_CLVI:
        final HashMap<Integer, SOCVillage> villages = bl.getVillages();
        if (villages != null)
            for (final SOCVillage vi : villages.values()) {
                final int cl = vi.getCloth();
                if (cl != SOCVillage.STARTING_CLOTH)
                    srv.messageToGame(gameName, new SOCPieceValue(gameName, vi.getCoordinates(), cl, 0));
            }
        // SC_FTRI:
        boolean sendEdgeChanges = bl.hasSpecialEdges();
        if (!sendEdgeChanges) {
            // check the board for any Special Edge layout part
            for (String ap : SOCBoardLarge.SPECIAL_EDGE_LAYOUT_PARTS) {
                if (bl.getAddedLayoutPart(ap) != null) {
                    sendEdgeChanges = true;
                    break;
                }
            }
        }
        if (sendEdgeChanges)
            joinGame_sendBoardSpecialEdgeChanges(gameData, bl, c);
    }
    /**
     * Send the current player number.
     * Before v2.0.00, this wasn't sent so early; was sent
     * just before SOCGameState and the "joined the game" text.
     * This earlier send has been tested against 1.1.07 (released 2009-10-31).
     */
    if (c.getVersion() >= SOCGameElements.MIN_VERSION)
        c.put(new SOCGameElements(gameName, SOCGameElements.CURRENT_PLAYER, gameData.getCurrentPlayerNumber()).toCmd());
    else
        c.put(SOCSetTurn.toCmd(gameName, gameData.getCurrentPlayerNumber()));
    /**
     * Send the game's Special Item info, if any, if game has started:
     */
    final String[] gameSITypes;
    if (gameData.getGameState() >= SOCGame.START1A) {
        Set<String> ty = gameData.getSpecialItemTypes();
        gameSITypes = (ty != null) ? ty.toArray(new String[ty.size()]) : null;
    } else {
        gameSITypes = null;
    }
    /**
     * Holds any special items shared between game and player. Those must be sent just once, not twice,
     * when per-game and then per-player special item info is sent. Per-player loop should check
     * {@code gameSItoPlayer.get(typeKey)[playerNumber].get(itemIndex)}; unused per-player lists
     * and typeKeys are null, so check each dereference; also check itemIndex versus list length.
     */
    final HashMap<String, ArrayList<SOCSpecialItem>[]> gameSItoPlayer;
    if (gameSITypes == null) {
        gameSItoPlayer = null;
    } else {
        gameSItoPlayer = new HashMap<String, ArrayList<SOCSpecialItem>[]>();
        for (int i = 0; i < gameSITypes.length; ++i) {
            final String tkey = gameSITypes[i];
            ArrayList<SOCSpecialItem> gsi = gameData.getSpecialItems(tkey);
            if (gsi == null)
                // shouldn't happen
                continue;
            final int L = gsi.size();
            for (// use this loop type to avoid ConcurrentModificationException if locking bug
            int gi = 0; // use this loop type to avoid ConcurrentModificationException if locking bug
            gi < L; // use this loop type to avoid ConcurrentModificationException if locking bug
            ++gi) {
                final SOCSpecialItem si = gsi.get(gi);
                if (si == null) {
                    c.put(new SOCSetSpecialItem(gameName, SOCSetSpecialItem.OP_CLEAR, tkey, gi, -1, -1).toCmd());
                    continue;
                }
                // player index, or -1: if pl != null, must search pl's items for a match
                int pi = -1;
                final SOCPlayer pl = si.getPlayer();
                if (pl != null) {
                    ArrayList<SOCSpecialItem> iList = pl.getSpecialItems(tkey);
                    if (iList != null) {
                        for (int k = 0; k < iList.size(); ++k) {
                            if (si == iList.get(k)) {
                                pi = k;
                                break;
                            }
                        }
                    }
                }
                c.put(new SOCSetSpecialItem(gameData, SOCSetSpecialItem.OP_SET, tkey, gi, pi, si).toCmd());
                if (pi != -1) {
                    // remember for use when sending per-player info
                    ArrayList<SOCSpecialItem>[] toAllPl = gameSItoPlayer.get(tkey);
                    if (toAllPl == null) {
                        toAllPl = new ArrayList[gameData.maxPlayers];
                        gameSItoPlayer.put(tkey, toAllPl);
                    }
                    ArrayList<SOCSpecialItem> iList = toAllPl[pl.getPlayerNumber()];
                    if (iList == null) {
                        iList = new ArrayList<SOCSpecialItem>();
                        toAllPl[pl.getPlayerNumber()] = iList;
                    }
                    int iLL = iList.size();
                    while (iLL <= pi) {
                        iList.add(null);
                        ++iLL;
                    }
                    iList.set(pi, si);
                }
            }
        }
    }
    /**
     * send the per-player information
     */
    for (int i = 0; i < gameData.maxPlayers; i++) {
        SOCPlayer pl = gameData.getPlayer(i);
        /**
         * send scenario info before any putpiece, so they know their
         * starting land areas and scenario events
         */
        int itm = pl.getSpecialVP();
        if (itm != 0) {
            srv.messageToPlayer(c, new SOCPlayerElement(gameName, i, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_SVP, itm));
            ArrayList<SOCPlayer.SpecialVPInfo> svpis = pl.getSpecialVPInfo();
            if (svpis != null)
                for (SOCPlayer.SpecialVPInfo svpi : svpis) srv.messageToPlayer(c, new SOCSVPTextMessage(gameName, i, svpi.svp, c.getLocalized(svpi.desc)));
        }
        itm = pl.getScenarioPlayerEvents();
        if (itm != 0)
            srv.messageToPlayer(c, new SOCPlayerElement(gameName, i, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_PLAYEREVENTS_BITMASK, itm));
        itm = pl.getScenarioSVPLandAreas();
        if (itm != 0)
            srv.messageToPlayer(c, new SOCPlayerElement(gameName, i, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_SVP_LANDAREAS_BITMASK, itm));
        itm = pl.getStartingLandAreasEncoded();
        if (itm != 0)
            srv.messageToPlayer(c, new SOCPlayerElement(gameName, i, SOCPlayerElement.SET, SOCPlayerElement.STARTING_LANDAREAS, itm));
        itm = pl.getCloth();
        if (itm != 0)
            srv.messageToPlayer(c, new SOCPlayerElement(gameName, i, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_CLOTH_COUNT, itm));
        // Send piece info even if player has left the game (pl.getName() == null).
        // This lets them see "their" pieces before srv.sitDown(), if they rejoin at same position.
        Enumeration<SOCPlayingPiece> piecesEnum = pl.getPieces().elements();
        while (piecesEnum.hasMoreElements()) {
            SOCPlayingPiece piece = piecesEnum.nextElement();
            if (piece.getType() == SOCPlayingPiece.CITY)
                c.put(SOCPutPiece.toCmd(gameName, i, SOCPlayingPiece.SETTLEMENT, piece.getCoordinates()));
            c.put(SOCPutPiece.toCmd(gameName, i, piece.getType(), piece.getCoordinates()));
        }
        // _SC_PIRI: special-case piece not part of getPieces
        {
            final SOCFortress piece = pl.getFortress();
            if (piece != null) {
                final int coord = piece.getCoordinates(), str = piece.getStrength();
                c.put(SOCPutPiece.toCmd(gameName, i, piece.getType(), coord));
                if (str != SOCFortress.STARTING_STRENGTH)
                    c.put(SOCPieceValue.toCmd(gameName, coord, str, 0));
            }
        }
        // _SC_PIRI: for display, send count of warships only after SOCShip pieces are sent
        itm = pl.getNumWarships();
        if (itm != 0)
            srv.messageToPlayer(c, new SOCPlayerElement(gameName, i, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_WARSHIP_COUNT, itm));
        /**
         * send node coord of the last settlement, resources,
         * knight cards played, number of playing pieces in hand
         */
        final int[] counts = new int[(gameData.hasSeaBoard) ? 7 : 6];
        counts[0] = pl.getLastSettlementCoord();
        // will send with SOCPlayerElement.UNKNOWN
        counts[1] = pl.getResources().getTotal();
        counts[2] = pl.getNumKnights();
        counts[3] = pl.getNumPieces(SOCPlayingPiece.ROAD);
        counts[4] = pl.getNumPieces(SOCPlayingPiece.SETTLEMENT);
        counts[5] = pl.getNumPieces(SOCPlayingPiece.CITY);
        if (gameData.hasSeaBoard)
            counts[6] = pl.getNumPieces(SOCPlayingPiece.SHIP);
        if (c.getVersion() >= SOCPlayerElements.MIN_VERSION) {
            c.put(new SOCPlayerElements(gameName, i, SOCPlayerElement.SET, (gameData.hasSeaBoard) ? ELEM_JOINGAME_WITH_PIECETYPES_SEA : ELEM_JOINGAME_WITH_PIECETYPES_CLASSIC, counts).toCmd());
        } else {
            c.put(SOCLastSettlement.toCmd(gameName, i, counts[0]));
            // client too old for SOCPlayerElement.LAST_SETTLEMENT_NODE
            for (int j = 1; j < counts.length; ++j) c.put(SOCPlayerElement.toCmd(gameName, i, SOCPlayerElement.SET, ELEM_JOINGAME_WITH_PIECETYPES_CLASSIC[j], counts[j]));
        }
        final int numDevCards = pl.getInventory().getTotal();
        final int unknownType;
        if (c.getVersion() >= SOCDevCardConstants.VERSION_FOR_NEW_TYPES)
            unknownType = SOCDevCardConstants.UNKNOWN;
        else
            unknownType = SOCDevCardConstants.UNKNOWN_FOR_VERS_1_X;
        final String cardUnknownCmd = SOCDevCardAction.toCmd(gameName, i, SOCDevCardAction.ADD_OLD, unknownType);
        for (int j = 0; j < numDevCards; j++) {
            c.put(cardUnknownCmd);
        }
        if (gameSITypes != null) {
            for (int j = 0; j < gameSITypes.length; ++j) {
                final String tkey = gameSITypes[j];
                ArrayList<SOCSpecialItem> plsi = pl.getSpecialItems(tkey);
                if (plsi == null)
                    // shouldn't happen
                    continue;
                // pi loop body checks gameSItoPlayer to see if already sent (object shared with game)
                final ArrayList<SOCSpecialItem>[] toAllPl = gameSItoPlayer.get(tkey);
                final ArrayList<SOCSpecialItem> iList = (toAllPl != null) ? toAllPl[i] : null;
                final int L = plsi.size();
                for (// use this loop type to avoid ConcurrentModificationException
                int pi = 0; // use this loop type to avoid ConcurrentModificationException
                pi < L; // use this loop type to avoid ConcurrentModificationException
                ++pi) {
                    final SOCSpecialItem si = plsi.get(pi);
                    if (si == null) {
                        c.put(new SOCSetSpecialItem(gameName, SOCSetSpecialItem.OP_CLEAR, tkey, -1, pi, i).toCmd());
                        continue;
                    }
                    if ((iList != null) && (iList.size() > pi) && (iList.get(pi) == si))
                        // already sent (shared with game)
                        continue;
                    c.put(new SOCSetSpecialItem(gameData, SOCSetSpecialItem.OP_SET, tkey, -1, pi, si).toCmd());
                }
            }
        }
        if ((i == 0) && (c.getVersion() < SOCGameElements.MIN_VERSION)) {
            // per-game data, send once; send here only if client is
            // too old to send together with other game elements,
            // otherwise send soon with longest road / largest army
            c.put(SOCFirstPlayer.toCmd(gameName, gameData.getFirstPlayer()));
            c.put(SOCDevCardCount.toCmd(gameName, gameData.getNumDevCards()));
        }
        c.put(SOCChangeFace.toCmd(gameName, i, pl.getFaceId()));
        if (i == 0) {
            // per-game data, send once
            c.put(SOCDiceResult.toCmd(gameName, gameData.getCurrentDice()));
        }
    }
    // /
    // / send dev card count, rounds count, first player, who has longest road and largest army
    // /
    final SOCPlayer lrPlayer = gameData.getPlayerWithLongestRoad(), laPlayer = gameData.getPlayerWithLargestArmy();
    final int lrPlayerNum = (lrPlayer != null) ? lrPlayer.getPlayerNumber() : -1, laPlayerNum = (laPlayer != null) ? laPlayer.getPlayerNumber() : -1;
    if (c.getVersion() < SOCGameElements.MIN_VERSION) {
        c.put(SOCLongestRoad.toCmd(gameName, lrPlayerNum));
        c.put(SOCLargestArmy.toCmd(gameName, laPlayerNum));
    } else {
        c.put(new SOCGameElements(gameName, ELEM_JOINGAME_DEVCARDS_ROUNDS_PLNUMS_FIRST_LONGEST_LARGEST, new int[] { gameData.getNumDevCards(), gameData.getRoundCount(), gameData.getFirstPlayer(), lrPlayerNum, laPlayerNum }).toCmd());
    }
    /**
     * If we're rejoining and taking over a seat after a network problem,
     * send our resource and hand information.
     */
    if (isTakingOver) {
        SOCPlayer cliPl = gameData.getPlayer(cliName);
        if (cliPl != null) {
            int pn = cliPl.getPlayerNumber();
            if ((pn != -1) && !gameData.isSeatVacant(pn))
                sitDown_sendPrivateInfo(gameData, c, pn);
        }
    }
    String membersCommand = null;
    srv.gameList.takeMonitorForGame(gameName);
    /**
     * Almost done; send GAMEMEMBERS as a hint to client that we're almost ready for its input.
     * There's no new data in GAMEMEMBERS, because player names have already been sent by
     * the SITDOWN messages above.
     */
    try {
        Vector<Connection> gameMembers = srv.gameList.getMembers(gameName);
        membersCommand = SOCGameMembers.toCmd(gameName, gameMembers);
    } catch (Exception e) {
        D.ebugPrintln("Exception in SGH.joinGame (gameMembers) - " + e);
    }
    srv.gameList.releaseMonitorForGame(gameName);
    if (membersCommand != null)
        c.put(membersCommand);
    // before v2.0.00, current player number (SETTURN) was sent here,
    // between membersCommand and GAMESTATE.
    c.put(SOCGameState.toCmd(gameName, gameData.getGameState()));
    if (D.ebugOn)
        D.ebugPrintln("*** " + cliName + " joined the game " + gameName + " at " + DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date()));
    /**
     * Let everyone else know about the change
     */
    if (isTakingOver) {
        return;
    }
    srv.messageToGame(gameName, new SOCJoinGame(cliName, "", "dummyhost", gameName));
    if ((!isReset) && gameData.getGameState() >= SOCGame.START2A) {
        srv.messageToPlayerKeyed(c, gameName, // "This game has started. To play, take over a robot."
        (hasRobot) ? // "This game has started. To play, take over a robot."
        "member.join.game.started.bots" : // "This game has started; no new players can sit down."
        "member.join.game.started");
    }
}
Also used : SOCSVPTextMessage(soc.message.SOCSVPTextMessage) SOCJoinGame(soc.message.SOCJoinGame) ArrayList(java.util.ArrayList) SOCPlayerElement(soc.message.SOCPlayerElement) HashSet(java.util.HashSet) SOCPieceValue(soc.message.SOCPieceValue) Connection(soc.server.genericServer.Connection) NoSuchElementException(java.util.NoSuchElementException) Date(java.util.Date) SOCSetSeatLock(soc.message.SOCSetSeatLock) SOCPlayerElements(soc.message.SOCPlayerElements) SOCSetSpecialItem(soc.message.SOCSetSpecialItem) SOCGameElements(soc.message.SOCGameElements)

Example 2 with SOCSetSpecialItem

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

the class SOCRobotBrain method run.

/**
 * Here is the run method.  Just keep receiving game events
 * through {@link #gameEventQ} and deal with each one.
 * Remember that we're sent a {@link SOCTimingPing} event once per second,
 * incrementing {@link #counter}.  That allows the bot to wait a certain
 * time for other players before it decides whether to do something.
 *<P>
 * Nearly all bot actions start in this method; the overview of bot structures
 * is in the {@link SOCRobotBrain class javadoc} for prominence.
 * See comments within <tt>run()</tt> for minor details.
 *<P>
 * The brain thread will run until {@link #kill()} has been called or its pinger stops,
 * or it receives a {@link SOCMessage#ROBOTDISMISS} request to exit the game.
 */
@Override
public void run() {
    // Thread name for debug
    try {
        Thread.currentThread().setName("robotBrain-" + client.getNickname() + "-" + game.getName());
    } catch (Throwable th) {
    }
    if (pinger != null) {
        pinger.start();
        while (alive) {
            try {
                // Sleeps until message received
                final SOCMessage mes = gameEventQ.get();
                final int mesType;
                if (mes != null) {
                    // Debug aid: When looking at message contents or setting a per-message breakpoint,
                    // skip the pings; note (mesType != SOCMessage.TIMINGPING) here.
                    mesType = mes.getType();
                    if (mesType != SOCMessage.TIMINGPING)
                        turnEventsCurrent.addElement(mes);
                    if (D.ebugOn)
                        D.ebugPrintln("mes - " + mes);
                } else {
                    mesType = -1;
                }
                if (waitingForTradeMsg && (counter > 10)) {
                    waitingForTradeMsg = false;
                    counter = 0;
                }
                if (waitingForTradeResponse && (counter > 100)) {
                    // Remember other players' responses, call client.clearOffer,
                    // clear waitingForTradeResponse and counter.
                    tradeStopWaitingClearOffer();
                }
                if (waitingForGameState && (counter > 10000)) {
                    // D.ebugPrintln("counter = "+counter);
                    // D.ebugPrintln("RESEND");
                    counter = 0;
                    client.resend();
                }
                if (mesType == SOCMessage.GAMESTATE) {
                    handleGAMESTATE(((SOCGameState) mes).getState());
                // clears waitingForGameState, updates oldGameState, calls ga.setGameState
                } else if (mesType == SOCMessage.STARTGAME) {
                    handleGAMESTATE(((SOCStartGame) mes).getGameState());
                // clears waitingForGameState, updates oldGameState, calls ga.setGameState
                } else if (mesType == SOCMessage.TURN) {
                    // Start of a new player's turn.
                    // Update game and reset most of our state fields.
                    // See also below: if ((mesType == SOCMessage.TURN) && ourTurn).
                    handleGAMESTATE(((SOCTurn) mes).getGameState());
                    // clears waitingForGameState, updates oldGameState, calls ga.setGameState
                    game.setCurrentPlayerNumber(((SOCTurn) mes).getPlayerNumber());
                    game.updateAtTurn();
                    // 
                    // remove any expected states
                    // 
                    expectROLL_OR_CARD = false;
                    expectPLAY1 = false;
                    expectPLACING_ROAD = false;
                    expectPLACING_SETTLEMENT = false;
                    expectPLACING_CITY = false;
                    expectPLACING_SHIP = false;
                    expectPLACING_ROBBER = false;
                    expectPLACING_FREE_ROAD1 = false;
                    expectPLACING_FREE_ROAD2 = false;
                    expectPLACING_INV_ITEM = false;
                    expectDICERESULT = false;
                    expectDISCARD = false;
                    expectMOVEROBBER = false;
                    expectWAITING_FOR_DISCOVERY = false;
                    expectWAITING_FOR_MONOPOLY = false;
                    // 
                    if (robotParameters.getTradeFlag() == 1) {
                        doneTrading = false;
                    } else {
                        doneTrading = true;
                    }
                    waitingForTradeMsg = false;
                    waitingForTradeResponse = false;
                    negotiator.resetIsSelling();
                    negotiator.resetOffersMade();
                    waitingForPickSpecialItem = null;
                    waitingForSC_PIRI_FortressRequest = false;
                    // 
                    // check or reset any special-building-phase decisions
                    // 
                    decidedIfSpecialBuild = false;
                    if (game.getGameState() == SOCGame.SPECIAL_BUILDING) {
                        if (waitingForSpecialBuild && !buildingPlan.isEmpty()) {
                        // Keep the building plan.
                        // Will ask during loop body to build.
                        } else {
                        // We have no plan, but will call planBuilding()
                        // during the loop body.  If buildingPlan still empty,
                        // bottom of loop will end our Special Building turn,
                        // just as it would in gamestate PLAY1.  Otherwise,
                        // will ask to build after planBuilding.
                        }
                    } else {
                        // 
                        // reset any plans we had
                        // 
                        buildingPlan.clear();
                    }
                    negotiator.resetTargetPieces();
                    // 
                    // swap the message-history queues
                    // 
                    {
                        Vector<SOCMessage> oldPrev = turnEventsPrev;
                        turnEventsPrev = turnEventsCurrent;
                        oldPrev.clear();
                        turnEventsCurrent = oldPrev;
                    }
                    turnExceptionCount = 0;
                }
                if (game.getCurrentPlayerNumber() == ourPlayerNumber) {
                    ourTurn = true;
                    waitingForSpecialBuild = false;
                } else {
                    ourTurn = false;
                }
                if ((mesType == SOCMessage.TURN) && ourTurn) {
                    waitingForOurTurn = false;
                    // Clear some per-turn variables.
                    // For others, see above: if (mesType == SOCMessage.TURN)
                    whatWeFailedToBuild = null;
                    failedBuildingAttempts = 0;
                    rejectedPlayDevCardType = -1;
                    rejectedPlayInvItem = null;
                }
                /**
                 * Handle some message types early.
                 *
                 * When reading the main flow of this method, skip past here;
                 * search for "it's time to decide to build or take other normal actions".
                 */
                switch(mesType) {
                    case SOCMessage.PLAYERELEMENT:
                        // If this during the ROLL_OR_CARD state, also updates the
                        // negotiator's is-selling flags.
                        // If our player is losing a resource needed for the buildingPlan,
                        // clear the plan if this is for the Special Building Phase (on the 6-player board).
                        // In normal game play, we clear the building plan at the start of each turn.
                        handlePLAYERELEMENT((SOCPlayerElement) mes);
                        break;
                    case SOCMessage.PLAYERELEMENTS:
                        // Multiple PLAYERELEMENT updates;
                        // see comment above for actions taken.
                        handlePLAYERELEMENTS((SOCPlayerElements) mes);
                        break;
                    case SOCMessage.RESOURCECOUNT:
                        handlePLAYERELEMENT(null, ((SOCResourceCount) mes).getPlayerNumber(), SOCPlayerElement.SET, SOCPlayerElement.RESOURCE_COUNT, ((SOCResourceCount) mes).getCount());
                        break;
                    case SOCMessage.DICERESULT:
                        game.setCurrentDice(((SOCDiceResult) mes).getResult());
                        break;
                    case SOCMessage.PUTPIECE:
                        handlePUTPIECE_updateGameData((SOCPutPiece) mes);
                        // For initial roads, also tracks their initial settlement in SOCPlayerTracker.
                        break;
                    case SOCMessage.MOVEPIECE:
                        {
                            SOCMovePiece mpm = (SOCMovePiece) mes;
                            SOCShip sh = new SOCShip(game.getPlayer(mpm.getPlayerNumber()), mpm.getFromCoord(), null);
                            game.moveShip(sh, mpm.getToCoord());
                        }
                        break;
                    case SOCMessage.CANCELBUILDREQUEST:
                        handleCANCELBUILDREQUEST((SOCCancelBuildRequest) mes);
                        break;
                    case SOCMessage.MOVEROBBER:
                        {
                            // 
                            // Note: Don't call ga.moveRobber() because that will call the
                            // functions to do the stealing.  We just want to set where
                            // the robber moved, without seeing if something was stolen.
                            // MOVEROBBER will be followed by PLAYERELEMENT messages to
                            // report the gain/loss of resources.
                            // 
                            moveRobberOnSeven = false;
                            final int newHex = ((SOCMoveRobber) mes).getCoordinates();
                            if (newHex >= 0)
                                game.getBoard().setRobberHex(newHex, true);
                            else
                                ((SOCBoardLarge) game.getBoard()).setPirateHex(-newHex, true);
                        }
                        break;
                    case SOCMessage.MAKEOFFER:
                        if (robotParameters.getTradeFlag() == 1)
                            handleMAKEOFFER((SOCMakeOffer) mes);
                        break;
                    case SOCMessage.CLEAROFFER:
                        if (robotParameters.getTradeFlag() == 1) {
                            final int pn = ((SOCClearOffer) mes).getPlayerNumber();
                            if (pn != -1) {
                                game.getPlayer(pn).setCurrentOffer(null);
                            } else {
                                for (int i = 0; i < game.maxPlayers; ++i) game.getPlayer(i).setCurrentOffer(null);
                            }
                        }
                        break;
                    case SOCMessage.ACCEPTOFFER:
                        if (waitingForTradeResponse && (robotParameters.getTradeFlag() == 1)) {
                            if ((ourPlayerNumber == (((SOCAcceptOffer) mes).getOfferingNumber())) || (ourPlayerNumber == ((SOCAcceptOffer) mes).getAcceptingNumber())) {
                                waitingForTradeResponse = false;
                            }
                        }
                        break;
                    case SOCMessage.REJECTOFFER:
                        if (robotParameters.getTradeFlag() == 1)
                            handleREJECTOFFER((SOCRejectOffer) mes);
                        break;
                    case SOCMessage.DEVCARDACTION:
                        {
                            SOCDevCardAction dcMes = (SOCDevCardAction) mes;
                            if (dcMes.getAction() != SOCDevCardAction.CANNOT_PLAY) {
                                handleDEVCARDACTION(dcMes);
                            } else {
                                // rejected by server, can't play our requested card
                                rejectedPlayDevCardType = dcMes.getCardType();
                                waitingForGameState = false;
                                expectPLACING_FREE_ROAD1 = false;
                                expectWAITING_FOR_DISCOVERY = false;
                                expectWAITING_FOR_MONOPOLY = false;
                                expectPLACING_ROBBER = false;
                            }
                        }
                        break;
                    case SOCMessage.SIMPLEREQUEST:
                        if (ourTurn && waitingForSC_PIRI_FortressRequest) {
                            final SOCSimpleRequest rqMes = (SOCSimpleRequest) mes;
                            if ((rqMes.getRequestType() == SOCSimpleRequest.SC_PIRI_FORT_ATTACK) && (rqMes.getPlayerNumber() == -1)) {
                                // Attack request was denied: End our turn now.
                                // Reset method sets waitingForGameState, which will bypass
                                // any further actions in the run() loop body.
                                waitingForSC_PIRI_FortressRequest = false;
                                resetFieldsAtEndTurn();
                                client.endTurn(game);
                            }
                        // else, from another player; we can ignore it
                        }
                        break;
                    case SOCMessage.SIMPLEACTION:
                        switch(((SOCSimpleAction) mes).getActionType()) {
                            case SOCSimpleAction.SC_PIRI_FORT_ATTACK_RESULT:
                                if (ourTurn && waitingForSC_PIRI_FortressRequest) {
                                    // Our player has won or lost an attack on a pirate fortress.
                                    // When we receive this message, other messages have already
                                    // been sent to update related game state. End our turn now.
                                    // Reset method sets waitingForGameState, which will bypass
                                    // any further actions in the run() loop body.
                                    waitingForSC_PIRI_FortressRequest = false;
                                    resetFieldsAtEndTurn();
                                // client.endTurn not needed; making the attack implies sending endTurn
                                }
                                break;
                        }
                        break;
                    case SOCMessage.INVENTORYITEMACTION:
                        if (((SOCInventoryItemAction) mes).action == SOCInventoryItemAction.CANNOT_PLAY) {
                            final List<SOCInventoryItem> itms = ourPlayerData.getInventory().getByStateAndType(SOCInventory.PLAYABLE, ((SOCInventoryItemAction) mes).itemType);
                            if (itms != null)
                                // any item of same type# is similar enough here
                                rejectedPlayInvItem = itms.get(0);
                            waitingForGameState = false;
                            // in case was rejected placement (SC_FTRI gift port, etc)
                            expectPLACING_INV_ITEM = false;
                        }
                        break;
                }
                // switch(mesType)
                debugInfo();
                if ((game.getGameState() == SOCGame.ROLL_OR_CARD) && !waitingForGameState) {
                    rollOrPlayKnightOrExpectDice();
                // On our turn, ask client to roll dice or play a knight;
                // on other turns, update flags to expect dice result.
                // Clears expectROLL_OR_CARD to false.
                // Sets either expectDICERESULT, or expectPLACING_ROBBER and waitingForGameState.
                }
                if (ourTurn && (game.getGameState() == SOCGame.WAITING_FOR_ROBBER_OR_PIRATE) && !waitingForGameState) {
                    // TODO handle moving the pirate too
                    // For now, always decide to move the robber.
                    // Once we move the robber, will also need to deal with state WAITING_FOR_ROB_CLOTH_OR_RESOURCE.
                    expectPLACING_ROBBER = true;
                    waitingForGameState = true;
                    counter = 0;
                    client.choosePlayer(game, SOCChoosePlayer.CHOICE_MOVE_ROBBER);
                    pause(200);
                } else if ((game.getGameState() == SOCGame.PLACING_ROBBER) && !waitingForGameState) {
                    expectPLACING_ROBBER = false;
                    if ((!waitingForOurTurn) && ourTurn) {
                        if (!((expectROLL_OR_CARD || expectPLAY1) && (counter < 4000))) {
                            if (moveRobberOnSeven) {
                                // robber moved because 7 rolled on dice
                                moveRobberOnSeven = false;
                                waitingForGameState = true;
                                counter = 0;
                                expectPLAY1 = true;
                            } else {
                                waitingForGameState = true;
                                counter = 0;
                                if (oldGameState == SOCGame.ROLL_OR_CARD) {
                                    // robber moved from playing knight card before dice roll
                                    expectROLL_OR_CARD = true;
                                } else if (oldGameState == SOCGame.PLAY1) {
                                    // robber moved from playing knight card after dice roll
                                    expectPLAY1 = true;
                                }
                            }
                            counter = 0;
                            moveRobber();
                        }
                    }
                }
                if ((game.getGameState() == SOCGame.WAITING_FOR_DISCOVERY) && !waitingForGameState) {
                    expectWAITING_FOR_DISCOVERY = false;
                    if ((!waitingForOurTurn) && ourTurn) {
                        if (!(expectPLAY1) && (counter < 4000)) {
                            waitingForGameState = true;
                            expectPLAY1 = true;
                            counter = 0;
                            client.pickResources(game, resourceChoices);
                            pause(1500);
                        }
                    }
                }
                if ((game.getGameState() == SOCGame.WAITING_FOR_MONOPOLY) && !waitingForGameState) {
                    expectWAITING_FOR_MONOPOLY = false;
                    if ((!waitingForOurTurn) && ourTurn) {
                        if (!(expectPLAY1) && (counter < 4000)) {
                            waitingForGameState = true;
                            expectPLAY1 = true;
                            counter = 0;
                            client.pickResourceType(game, monopolyStrategy.getMonopolyChoice());
                            pause(1500);
                        }
                    }
                }
                if (ourTurn && (!waitingForOurTurn) && (game.getGameState() == SOCGame.PLACING_INV_ITEM) && (!waitingForGameState)) {
                    // choose and send a placement location
                    planAndPlaceInvItem();
                }
                if (waitingForTradeMsg && (mesType == SOCMessage.BANKTRADE) && (((SOCBankTrade) mes).getPlayerNumber() == ourPlayerNumber)) {
                    // 
                    // This is the bank/port trade confirmation announcement we've been waiting for
                    // 
                    waitingForTradeMsg = false;
                }
                if (waitingForDevCard && (mesType == SOCMessage.SIMPLEACTION) && (((SOCSimpleAction) mes).getPlayerNumber() == ourPlayerNumber) && (((SOCSimpleAction) mes).getActionType() == SOCSimpleAction.DEVCARD_BOUGHT)) {
                    // 
                    // This is the "dev card bought" message we've been waiting for
                    // 
                    waitingForDevCard = false;
                }
                /**
                 * Planning: If our turn and not waiting for something,
                 * it's time to decide to build or take other normal actions.
                 */
                if (((game.getGameState() == SOCGame.PLAY1) || (game.getGameState() == SOCGame.SPECIAL_BUILDING)) && !(waitingForGameState || waitingForTradeMsg || waitingForTradeResponse || waitingForDevCard || expectPLACING_ROAD || expectPLACING_SETTLEMENT || expectPLACING_CITY || expectPLACING_SHIP || expectPLACING_FREE_ROAD1 || expectPLACING_FREE_ROAD2 || expectPLACING_ROBBER || expectWAITING_FOR_DISCOVERY || expectWAITING_FOR_MONOPOLY || waitingForSC_PIRI_FortressRequest || (waitingForPickSpecialItem != null))) {
                    expectPLAY1 = false;
                    // during other players' turns.
                    if ((!ourTurn) && waitingForOurTurn && gameIs6Player && (!decidedIfSpecialBuild) && (!expectPLACING_ROBBER)) {
                        decidedIfSpecialBuild = true;
                        if (buildingPlan.empty() && (ourPlayerData.getResources().getTotal() > 1) && (failedBuildingAttempts < MAX_DENIED_BUILDING_PER_TURN)) {
                            planBuilding();
                            if (!buildingPlan.empty()) {
                                // If we have the resources right now, ask to Special Build
                                final SOCPossiblePiece targetPiece = buildingPlan.peek();
                                final SOCResourceSet targetResources = targetPiece.getResourcesToBuild();
                                if ((ourPlayerData.getResources().contains(targetResources))) {
                                    // Ask server for the Special Building Phase.
                                    // (TODO) if FAST_STRATEGY: Maybe randomly don't ask, to lower opponent difficulty?
                                    waitingForSpecialBuild = true;
                                    client.buildRequest(game, -1);
                                    pause(100);
                                }
                            }
                        }
                    }
                    if ((!waitingForOurTurn) && ourTurn) {
                        if (!(expectROLL_OR_CARD && (counter < 4000))) {
                            counter = 0;
                            // D.ebugPrintln("DOING PLAY1");
                            if (D.ebugOn) {
                                client.sendText(game, "================================");
                                // for each player in game:
                                // sendText and debug-prn game.getPlayer(i).getResources()
                                printResources();
                            }
                            /**
                             * if we haven't played a dev card yet,
                             * and we have a knight, and we can get
                             * largest army, play the knight.
                             * If we're in SPECIAL_BUILDING (not PLAY1),
                             * can't trade or play development cards.
                             *
                             * In scenario _SC_PIRI (which has no robber and
                             * no largest army), play one whenever we have
                             * it, someone else has resources, and we can
                             * convert a ship to a warship.
                             */
                            if ((game.getGameState() == SOCGame.PLAY1) && !ourPlayerData.hasPlayedDevCard()) {
                                // might set expectPLACING_ROBBER and waitingForGameState
                                playKnightCardIfShould();
                            }
                            /**
                             * make a plan if we don't have one,
                             * and if we haven't given up building
                             * attempts this turn.
                             */
                            if ((!expectPLACING_ROBBER) && buildingPlan.empty() && (ourPlayerData.getResources().getTotal() > 1) && (failedBuildingAttempts < MAX_DENIED_BUILDING_PER_TURN)) {
                                planBuilding();
                            /*
                                         * planBuilding takes these actions, sets buildingPlan and other fields
                                         * (see its javadoc):
                                         *
                                        decisionMaker.planStuff(robotParameters.getStrategyType());

                                        if (! buildingPlan.empty())
                                        {
                                            lastTarget = (SOCPossiblePiece) buildingPlan.peek();
                                            negotiator.setTargetPiece(ourPlayerNumber, buildingPlan.peek());
                                        }
                                         */
                            }
                            // D.ebugPrintln("DONE PLANNING");
                            if ((!expectPLACING_ROBBER) && (!buildingPlan.empty())) {
                                // Time to build something.
                                // Either ask to build a piece, or use trading or development
                                // cards to get resources to build it.  See javadoc for flags set
                                // (expectPLACING_ROAD, etc).  In a future iteration of the run loop
                                // with the expected PLACING_ state, we'll build whatWeWantToBuild
                                // in placeIfExpectPlacing().
                                buildOrGetResourceByTradeOrCard();
                            }
                            /**
                             * see if we're done with our turn
                             */
                            if (!(expectPLACING_SETTLEMENT || expectPLACING_FREE_ROAD1 || expectPLACING_FREE_ROAD2 || expectPLACING_ROAD || expectPLACING_CITY || expectPLACING_SHIP || expectWAITING_FOR_DISCOVERY || expectWAITING_FOR_MONOPOLY || expectPLACING_ROBBER || waitingForTradeMsg || waitingForTradeResponse || waitingForDevCard || waitingForGameState || (waitingForPickSpecialItem != null))) {
                                // Any last things for turn from game's scenario?
                                boolean scenActionTaken = false;
                                if (game.isGameOptionSet(SOCGameOption.K_SC_FTRI) || game.isGameOptionSet(SOCGameOption.K_SC_PIRI)) {
                                    // possibly attack pirate fortress
                                    // or place a gift port for better bank trades
                                    scenActionTaken = considerScenarioTurnFinalActions();
                                }
                                if (!scenActionTaken) {
                                    resetFieldsAtEndTurn();
                                    /*
                                             * These state fields are reset:
                                             *
                                            waitingForGameState = true;
                                            counter = 0;
                                            expectROLL_OR_CARD = true;
                                            waitingForOurTurn = true;

                                            doneTrading = (robotParameters.getTradeFlag() != 1);

                                            //D.ebugPrintln("!!! ENDING TURN !!!");
                                            negotiator.resetIsSelling();
                                            negotiator.resetOffersMade();
                                            buildingPlan.clear();
                                            negotiator.resetTargetPieces();
                                             */
                                    pause(1500);
                                    client.endTurn(game);
                                }
                            }
                        }
                    }
                }
                /**
                 * Placement: Make various putPiece calls; server has told us it's OK to buy them.
                 * Call client.putPiece.
                 * Works when it's our turn and we have an expect flag set
                 * (such as expectPLACING_SETTLEMENT, in these game states:
                 * START1A - START2B or - START3B
                 * PLACING_SETTLEMENT, PLACING_ROAD, PLACING_CITY
                 * PLACING_FREE_ROAD1, PLACING_FREE_ROAD2
                 */
                if (!waitingForGameState) {
                    placeIfExpectPlacing();
                }
                /**
                 * Handle various message types here at bottom of loop.
                 */
                switch(mesType) {
                    case SOCMessage.PUTPIECE:
                        /**
                         * this is for player tracking
                         *
                         * For initial placement of our own pieces, also checks
                         * and clears expectPUTPIECE_FROM_START1A,
                         * and sets expectSTART1B, etc.  The final initial putpiece
                         * clears expectPUTPIECE_FROM_START2B and sets expectROLL_OR_CARD.
                         */
                        {
                            final SOCPutPiece mpp = (SOCPutPiece) mes;
                            final int pn = mpp.getPlayerNumber();
                            final int coord = mpp.getCoordinates();
                            final int pieceType = mpp.getPieceType();
                            handlePUTPIECE_updateTrackers(pn, coord, pieceType);
                        }
                        break;
                    case SOCMessage.MOVEPIECE:
                        /**
                         * this is for player tracking of moved ships
                         */
                        {
                            final SOCMovePiece mpp = (SOCMovePiece) mes;
                            final int pn = mpp.getPlayerNumber();
                            final int coord = mpp.getToCoord();
                            final int pieceType = mpp.getPieceType();
                            // TODO what about getFromCoord()?
                            handlePUTPIECE_updateTrackers(pn, coord, pieceType);
                        }
                        break;
                    case SOCMessage.DICERESULT:
                        if (expectDICERESULT) {
                            expectDICERESULT = false;
                            if (((SOCDiceResult) mes).getResult() == 7) {
                                final boolean robWithoutRobber = game.isGameOptionSet(SOCGameOption.K_SC_PIRI);
                                if (!robWithoutRobber)
                                    moveRobberOnSeven = true;
                                if (ourPlayerData.getResources().getTotal() > 7)
                                    expectDISCARD = true;
                                else if (ourTurn) {
                                    if (!robWithoutRobber)
                                        expectPLACING_ROBBER = true;
                                    else
                                        expectPLAY1 = true;
                                }
                            } else {
                                expectPLAY1 = true;
                            }
                        }
                        break;
                    case SOCMessage.SIMPLEREQUEST:
                        // These messages can almost always be ignored by bots.
                        // Some request types are handled at the top of the loop body;
                        // search for SOCMessage.SIMPLEREQUEST
                        {
                            final SOCSimpleRequest rqMes = (SOCSimpleRequest) mes;
                            switch(rqMes.getRequestType()) {
                                case SOCSimpleRequest.PROMPT_PICK_RESOURCES:
                                    // gold hex
                                    counter = 0;
                                    pickFreeResources(rqMes.getValue1());
                                    waitingForGameState = true;
                                    if (game.isInitialPlacement()) {
                                        if (game.isGameOptionSet(SOCGameOption.K_SC_3IP))
                                            expectSTART3B = true;
                                        else
                                            expectSTART2B = true;
                                    } else {
                                        expectPLAY1 = true;
                                    }
                                    break;
                            }
                        }
                        break;
                    case SOCMessage.DISCARDREQUEST:
                        expectDISCARD = false;
                        // {
                        if ((game.getCurrentDice() == 7) && ourTurn) {
                            if (!game.isGameOptionSet(SOCGameOption.K_SC_PIRI))
                                expectPLACING_ROBBER = true;
                            else
                                expectPLAY1 = true;
                        } else {
                            expectPLAY1 = true;
                        }
                        counter = 0;
                        client.discard(game, DiscardStrategy.discard(((SOCDiscardRequest) mes).getNumberOfDiscards(), buildingPlan, rand, ourPlayerData, robotParameters, decisionMaker, negotiator));
                        // }
                        break;
                    case SOCMessage.CHOOSEPLAYERREQUEST:
                        {
                            final int choicePl = RobberStrategy.chooseRobberVictim(((SOCChoosePlayerRequest) mes).getChoices(), game, playerTrackers);
                            counter = 0;
                            client.choosePlayer(game, choicePl);
                        }
                        break;
                    case SOCMessage.CHOOSEPLAYER:
                        {
                            final int vpn = ((SOCChoosePlayer) mes).getChoice();
                            // Cloth is more valuable.
                            // TODO decide when we should choose resources instead
                            client.choosePlayer(game, -(vpn + 1));
                        }
                        break;
                    case SOCMessage.SETSPECIALITEM:
                        if (waitingForPickSpecialItem != null) {
                            final SOCSetSpecialItem siMes = (SOCSetSpecialItem) mes;
                            if (siMes.typeKey.equals(waitingForPickSpecialItem)) {
                                switch(siMes.op) {
                                    case SOCSetSpecialItem.OP_PICK:
                                        waitingForPickSpecialItem = null;
                                        // Any specific action needed? Not for SC_WOND.
                                        break;
                                    case SOCSetSpecialItem.OP_DECLINE:
                                        waitingForPickSpecialItem = null;
                                        // TODO how to prevent asking again? (similar to whatWeFailedtoBuild)
                                        break;
                                }
                            }
                        }
                        break;
                    case SOCMessage.ROBOTDISMISS:
                        if ((!expectDISCARD) && (!expectPLACING_ROBBER)) {
                            client.leaveGame(game, "dismiss msg", false, false);
                            alive = false;
                        }
                        break;
                    case SOCMessage.TIMINGPING:
                        // Once-per-second message from the pinger thread
                        counter++;
                        break;
                }
                if (ourTurn && (counter > 15000)) {
                    // We've been waiting too long, must be a bug: Leave the game.
                    // This is a fallback, server has SOCForceEndTurnThread which
                    // should have already taken action.
                    // Before v1.1.20, would leave game even during other (human) players' turns.
                    client.leaveGame(game, "counter 15000", true, false);
                    alive = false;
                }
                if ((failedBuildingAttempts > (2 * MAX_DENIED_BUILDING_PER_TURN)) && game.isInitialPlacement()) {
                    // Apparently can't decide where we can initially place:
                    // Leave the game.
                    client.leaveGame(game, "failedBuildingAttempts at start", true, false);
                    alive = false;
                }
                /*
                       if (D.ebugOn) {
                       if (mes != null) {
                       debugInfo();
                       D.ebugPrintln("~~~~~~~~~~~~~~~~");
                       }
                       }
                     */
                yield();
            } catch (Exception e) {
                // Print exception; ignore errors due to game reset in another thread
                if (alive && ((game == null) || (game.getGameState() != SOCGame.RESET_OLD))) {
                    // TODO end our turn if too many
                    ++turnExceptionCount;
                    String eMsg = (turnExceptionCount == 1) ? "*** Robot caught an exception - " + e : "*** Robot caught an exception (" + turnExceptionCount + " this turn) - " + e;
                    D.ebugPrintln(eMsg);
                    System.out.println(eMsg);
                    e.printStackTrace();
                }
            }
        }
    } else {
        System.out.println("AGG! NO PINGER!");
    }
    // D.ebugPrintln("STOPPING AND DEALLOCATING");
    gameEventQ = null;
    client.addCleanKill();
    client = null;
    game = null;
    ourPlayerData = null;
    dummyCancelPlayerData = null;
    whatWeWantToBuild = null;
    whatWeFailedToBuild = null;
    rejectedPlayInvItem = null;
    resourceChoices = null;
    ourPlayerTracker = null;
    playerTrackers = null;
    pinger.stopPinger();
    pinger = null;
}
Also used : SOCShip(soc.game.SOCShip) SOCMakeOffer(soc.message.SOCMakeOffer) SOCInventoryItem(soc.game.SOCInventoryItem) SOCRejectOffer(soc.message.SOCRejectOffer) SOCResourceSet(soc.game.SOCResourceSet) SOCMovePiece(soc.message.SOCMovePiece) Vector(java.util.Vector) SOCAcceptOffer(soc.message.SOCAcceptOffer) SOCMessage(soc.message.SOCMessage) SOCBoardLarge(soc.game.SOCBoardLarge) SOCStartGame(soc.message.SOCStartGame) SOCDiscardRequest(soc.message.SOCDiscardRequest) SOCSimpleAction(soc.message.SOCSimpleAction) SOCSetSpecialItem(soc.message.SOCSetSpecialItem) SOCClearOffer(soc.message.SOCClearOffer) SOCSimpleRequest(soc.message.SOCSimpleRequest) SOCPutPiece(soc.message.SOCPutPiece) SOCChoosePlayerRequest(soc.message.SOCChoosePlayerRequest) SOCDevCardAction(soc.message.SOCDevCardAction)

Aggregations

SOCSetSpecialItem (soc.message.SOCSetSpecialItem)2 ArrayList (java.util.ArrayList)1 Date (java.util.Date)1 HashSet (java.util.HashSet)1 NoSuchElementException (java.util.NoSuchElementException)1 Vector (java.util.Vector)1 SOCBoardLarge (soc.game.SOCBoardLarge)1 SOCInventoryItem (soc.game.SOCInventoryItem)1 SOCResourceSet (soc.game.SOCResourceSet)1 SOCShip (soc.game.SOCShip)1 SOCAcceptOffer (soc.message.SOCAcceptOffer)1 SOCChoosePlayerRequest (soc.message.SOCChoosePlayerRequest)1 SOCClearOffer (soc.message.SOCClearOffer)1 SOCDevCardAction (soc.message.SOCDevCardAction)1 SOCDiscardRequest (soc.message.SOCDiscardRequest)1 SOCGameElements (soc.message.SOCGameElements)1 SOCJoinGame (soc.message.SOCJoinGame)1 SOCMakeOffer (soc.message.SOCMakeOffer)1 SOCMessage (soc.message.SOCMessage)1 SOCMovePiece (soc.message.SOCMovePiece)1