Search in sources :

Example 1 with SOCPlayerElement

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

the class SOCGameHandler method sendGameState_sendGoldPickAnnounceText.

/**
 * Send a game text message "x, y, and z need to pick resources from the gold hex."
 * and, for each picking player, a {@link SOCPlayerElement}({@link SOCPlayerElement#NUM_PICK_GOLD_HEX_RESOURCES NUM_PICK_GOLD_HEX_RESOURCES}).
 * To prompt the specific players to choose a resource, also sends their clients a
 * {@link SOCSimpleRequest}({@link SOCSimpleRequest#PROMPT_PICK_RESOURCES PROMPT_PICK_RESOURCES}).
 *<P>
 * Used in game state {@link SOCGame#STARTS_WAITING_FOR_PICK_GOLD_RESOURCE}
 * and {@link SOCGame#WAITING_FOR_PICK_GOLD_RESOURCE}.
 *<P>
 * The text and SOCPlayerElement messages are sent to the entire game.
 * Any {@code PROMPT_PICK_RESOURCES} are sent to those player clients only.
 * If you know that only 1 player will pick gold, pass their <tt>playerCon</tt> for efficiency.
 *<P>
 * This is separate from {@link #sendGameState(SOCGame)} because when the dice are rolled,
 * <tt>sendGameState</tt> is called, then resource distribution messages are sent out,
 * then this method is called.
 *
 * @param ga  Game object
 * @param gname  Game name
 * @param playerCon  <tt>null</tt>, or current player's client connection to send the
 *                   {@code PROMPT_PICK_RESOURCES} if they are the only one to pick gold.
 *                   If more than 1 player has {@link SOCPlayer#getNeedToPickGoldHexResources()},
 *                   no message will be sent to <tt>playerCon</tt>.
 * @param roll  For gold gained from dice rolls, the roll details, otherwise null.
 *                   In scenario SC_PIRI, is used to avoid announcing twice for a pick from victory against pirate fleet.
 * @since 2.0.00
 */
final void sendGameState_sendGoldPickAnnounceText(SOCGame ga, final String gname, Connection playerCon, SOCGame.RollResult roll) {
    final int ignoreRollPirateVictory;
    if ((roll != null) && ga.isGameOptionSet(SOCGameOption.K_SC_PIRI) && (roll.sc_piri_fleetAttackRsrcs != null))
        ignoreRollPirateVictory = roll.sc_piri_fleetAttackRsrcs.getAmount(SOCResourceConstants.GOLD_LOCAL);
    else
        ignoreRollPirateVictory = 0;
    int count = 0, amount = 0, firstPN = -1;
    ArrayList<String> names = new ArrayList<String>();
    int[] num = new int[ga.maxPlayers];
    for (int pn = 0; pn < ga.maxPlayers; ++pn) {
        final SOCPlayer pp = ga.getPlayer(pn);
        int numGoldRes = pp.getNeedToPickGoldHexResources();
        if (numGoldRes > 0) {
            num[pn] = numGoldRes;
            if ((ignoreRollPirateVictory > 0) && (pp == roll.sc_piri_fleetAttackVictim))
                numGoldRes -= ignoreRollPirateVictory;
            if (numGoldRes > 0) {
                names.add(pp.getName());
                count++;
                if (count == 1) {
                    amount = numGoldRes;
                    firstPN = pn;
                }
            }
        }
    }
    if (count > 1)
        srv.messageToGameKeyedSpecial(ga, true, "prompt.pick.gold.n", names);
    else // "... need to pick resources from the gold hex."
    if (count == 1)
        srv.messageToGameKeyed(ga, true, "prompt.pick.gold.1", names.get(0));
    // "Joe needs to pick resources from the gold hex."
    final boolean singlePlayerGetsPickRequest = ((playerCon != null) && (count == 1));
    for (int pn = 0; pn < ga.maxPlayers; ++pn) {
        if (num[pn] > 0) {
            srv.messageToGame(gname, new SOCPlayerElement(gname, pn, SOCPlayerElement.SET, SOCPlayerElement.NUM_PICK_GOLD_HEX_RESOURCES, num[pn]));
            if (!singlePlayerGetsPickRequest) {
                Connection plCon = srv.getConnection(ga.getPlayer(pn).getName());
                if (plCon != null)
                    srv.messageToPlayer(plCon, new SOCSimpleRequest(gname, pn, SOCSimpleRequest.PROMPT_PICK_RESOURCES, num[pn]));
            }
        }
    }
    if (singlePlayerGetsPickRequest)
        srv.messageToPlayer(playerCon, new SOCSimpleRequest(gname, firstPN, SOCSimpleRequest.PROMPT_PICK_RESOURCES, amount));
}
Also used : SOCSimpleRequest(soc.message.SOCSimpleRequest) ArrayList(java.util.ArrayList) Connection(soc.server.genericServer.Connection) SOCPlayerElement(soc.message.SOCPlayerElement)

Example 2 with SOCPlayerElement

use of soc.message.SOCPlayerElement 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 3 with SOCPlayerElement

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

the class SOCGameHandler method sendTurn.

/**
 * At start of a new turn, send new {@link SOCGame#getGameState()} and {@link SOCTurn} with whose turn it is.
 * Optionally also send a prompt to roll. If the client is too old (1.0.6), it will ignore the prompt.
 *<P>
 * The {@link SOCTurn} sent will have a field for the Game State unless
 * {@link SOCGame#clientVersionLowest} &lt; 2.0.00 ({@link SOCGameState#VERSION_FOR_GAME_STATE_AS_FIELD}),
 * in which case a separate {@link SOCGameState} message will be sent first.
 * Calls {@link #sendGameState(SOCGame, boolean, boolean)} in either case,
 * to send any text prompts or other gamestate-related messages.
 *<P>
 * sendTurn should be called whenever the current player changes, including
 * during and after initial placement.
 *
 * @param ga  the game
 * @param sendRollPrompt  whether to send a RollDicePrompt message afterwards
 */
void sendTurn(final SOCGame ga, boolean sendRollPrompt) {
    if (ga == null)
        return;
    final boolean useGSField = (ga.clientVersionLowest >= SOCGameState.VERSION_FOR_GAME_STATE_AS_FIELD);
    sendRollPrompt |= sendGameState(ga, useGSField, false);
    String gname = ga.getName();
    final int gs = ga.getGameState(), cpn = ga.getCurrentPlayerNumber();
    if (ga.clientVersionLowest >= SOCPlayerElement.VERSION_FOR_CARD_ELEMENTS)
        srv.messageToGame(gname, new SOCPlayerElement(gname, cpn, SOCPlayerElement.SET, SOCPlayerElement.PLAYED_DEV_CARD_FLAG, 0));
    else
        srv.messageToGame(gname, new SOCSetPlayedDevCard(gname, cpn, false));
    final SOCTurn turnMessage = new SOCTurn(gname, cpn, (useGSField) ? gs : 0);
    srv.messageToGame(gname, turnMessage);
    srv.recordGameEvent(gname, turnMessage);
    if (sendRollPrompt)
        srv.messageToGame(gname, new SOCRollDicePrompt(gname, cpn));
}
Also used : SOCTurn(soc.message.SOCTurn) SOCRollDicePrompt(soc.message.SOCRollDicePrompt) SOCPlayerElement(soc.message.SOCPlayerElement) SOCSetPlayedDevCard(soc.message.SOCSetPlayedDevCard)

Example 4 with SOCPlayerElement

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

the class SOCGameHandler method reportRobbery.

/**
 * The current player is stealing from another player.
 * Send messages saying what was stolen.
 *
 * @param ga  the game
 * @param pe  the perpetrator
 * @param vi  the victim
 * @param rsrc  type of resource stolen, as in {@link SOCResourceConstants#SHEEP},
 *              or {@link SOCResourceConstants#CLOTH_STOLEN_LOCAL} for cloth
 *              (scenario option {@link SOCGameOption#K_SC_CLVI _SC_CLVI}).
 */
void reportRobbery(SOCGame ga, SOCPlayer pe, SOCPlayer vi, final int rsrc) {
    if (ga == null)
        return;
    final String gaName = ga.getName();
    final String peName = pe.getName();
    final String viName = vi.getName();
    final int pePN = pe.getPlayerNumber();
    final int viPN = vi.getPlayerNumber();
    if (rsrc == SOCResourceConstants.CLOTH_STOLEN_LOCAL) {
        // Send players' cloth counts and text.
        // Client's game will recalculate players' VP based on
        // the cloth counts, so we don't need to also send VP.
        srv.messageToGame(gaName, new SOCPlayerElement(gaName, viPN, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_CLOTH_COUNT, vi.getCloth(), true));
        srv.messageToGame(gaName, new SOCPlayerElement(gaName, pePN, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_CLOTH_COUNT, pe.getCloth()));
        // "{0} stole a cloth from {1}."
        srv.messageToGameKeyed(ga, true, "robber.stole.cloth.from", peName, viName);
        // <--- early return: cloth is announced to entire game ---
        return;
    }
    SOCPlayerElement gainRsrc = null;
    SOCPlayerElement loseRsrc = null;
    SOCPlayerElement gainUnknown;
    SOCPlayerElement loseUnknown;
    // This works because SOCPlayerElement.SHEEP == SOCResourceConstants.SHEEP.
    gainRsrc = new SOCPlayerElement(gaName, pePN, SOCPlayerElement.GAIN, rsrc, 1);
    loseRsrc = new SOCPlayerElement(gaName, viPN, SOCPlayerElement.LOSE, rsrc, 1, true);
    /**
     * send the game data messages
     */
    Connection peCon = srv.getConnection(peName);
    Connection viCon = srv.getConnection(viName);
    srv.messageToPlayer(peCon, gainRsrc);
    srv.messageToPlayer(peCon, loseRsrc);
    srv.messageToPlayer(viCon, gainRsrc);
    srv.messageToPlayer(viCon, loseRsrc);
    // Don't send generic message to pe or vi
    List<Connection> sendNotTo = new ArrayList<Connection>(2);
    sendNotTo.add(peCon);
    sendNotTo.add(viCon);
    gainUnknown = new SOCPlayerElement(gaName, pePN, SOCPlayerElement.GAIN, SOCPlayerElement.UNKNOWN, 1);
    loseUnknown = new SOCPlayerElement(gaName, viPN, SOCPlayerElement.LOSE, SOCPlayerElement.UNKNOWN, 1);
    srv.messageToGameExcept(gaName, sendNotTo, gainUnknown, true);
    srv.messageToGameExcept(gaName, sendNotTo, loseUnknown, true);
    /**
     * send the text messages:
     * "You stole a sheep from viName."  [In v1.x.xx, "stole a sheep resource"]
     * "peName stole a sheep from you."
     * "peName stole a resource from viName."
     */
    // "You stole {0,rsrcs} from {2}."
    srv.messageToPlayerKeyedSpecial(peCon, ga, "robber.you.stole.resource.from", -1, rsrc, viName);
    // "{0} stole {1,rsrcs} from you."
    srv.messageToPlayerKeyedSpecial(viCon, ga, "robber.stole.resource.from.you", peName, -1, rsrc);
    // "{0} stole a resource from {1}."
    srv.messageToGameKeyedSpecialExcept(ga, true, sendNotTo, "robber.stole.resource.from", peName, viName);
}
Also used : Connection(soc.server.genericServer.Connection) ArrayList(java.util.ArrayList) SOCPlayerElement(soc.message.SOCPlayerElement)

Example 5 with SOCPlayerElement

use of soc.message.SOCPlayerElement 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)

Aggregations

SOCPlayerElement (soc.message.SOCPlayerElement)12 Connection (soc.server.genericServer.Connection)5 ArrayList (java.util.ArrayList)3 SOCDevCardAction (soc.message.SOCDevCardAction)3 SOCGameElements (soc.message.SOCGameElements)3 SOCPlayerElements (soc.message.SOCPlayerElements)3 HashSet (java.util.HashSet)2 SOCInventoryItemAction (soc.message.SOCInventoryItemAction)2 SOCMessage (soc.message.SOCMessage)2 SOCPieceValue (soc.message.SOCPieceValue)2 SOCRollDicePrompt (soc.message.SOCRollDicePrompt)2 SOCSetPlayedDevCard (soc.message.SOCSetPlayedDevCard)2 SOCSimpleRequest (soc.message.SOCSimpleRequest)2 SOCTurn (soc.message.SOCTurn)2 Date (java.util.Date)1 NoSuchElementException (java.util.NoSuchElementException)1 StringTokenizer (java.util.StringTokenizer)1 SOCChangeFace (soc.message.SOCChangeFace)1 SOCClearOffer (soc.message.SOCClearOffer)1 SOCDevCardCount (soc.message.SOCDevCardCount)1