Search in sources :

Example 1 with SOCRollDicePrompt

use of soc.message.SOCRollDicePrompt 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 2 with SOCRollDicePrompt

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

the class SOCGameHandler method sendGameState.

/**
 * Send all game members the current state of the game with a message.
 * May also send other messages to the current player.
 * Note that the current (or new) player number is not sent here.
 * If game is now OVER, sends appropriate messages.
 *<P>
 * State {@link SOCGame#WAITING_FOR_DISCARDS}:
 * If a 7 is rolled, will also say who must discard (in a GAMETEXTMSG).
 *<P>
 * State {@link SOCGame#WAITING_FOR_ROB_CHOOSE_PLAYER}:
 * If current player must choose which player to rob,
 * will also prompt their client to choose (in a CHOOSEPLAYERREQUEST).
 *<P>
 * State {@link SOCGame#STARTS_WAITING_FOR_PICK_GOLD_RESOURCE}:
 * To announce the player must pick a resource to gain from the gold hex initial placement,
 * please call {@link #sendGameState_sendGoldPickAnnounceText(SOCGame, String, Connection, SOCGame.RollResult)}.
 *<P>
 * State {@link SOCGame#WAITING_FOR_PICK_GOLD_RESOURCE}:
 * If a gold hex is rolled, does not say who
 * must pick resources to gain (because of timing).  Please call
 * {@link #sendGameState_sendGoldPickAnnounceText(SOCGame, String, Connection, SOCGame.RollResult)}
 * after sending the resource gain text ("x gets 1 sheep").
 *<P>
 * <b>Note:</b> If game is now {@link SOCGame#OVER OVER} and the {@link SOCGame#isBotsOnly} flag is set,
 * {@link #sendGameStateOVER(SOCGame)} will call {@link SOCServer#destroyGameAndBroadcast(String, String)}.
 * Be sure that callers to {@code sendGameState} don't assume the game will still exist after calling this method.
 * Also, {@code destroyGame} might create more {@link SOCGame#isBotsOnly} games, depending on server settings.
 *<P>
 * <b>Locks:</b> Does not hold {@link SOCGameList#takeMonitor()} or
 * {@link SOCGameList#takeMonitorForGame}<tt>(gaName)</tt> when called.
 * Some callers call {@link SOCGame#takeMonitor()} before calling; not important here.
 *
 * @see #sendTurn(SOCGame, boolean)
 * @see #sendGameState(SOCGame)
 * @see #sendGameStateOVER(SOCGame)
 *
 * @param ga  the game
 * @param omitGameStateMessage  if true, don't send the {@link SOCGameState} message itself
 *    but do send any other messages as described above. For use just after sending a message which
 *    includes a Game State field.
 * @param sendRollPrompt  If true, and if we send a text message to prompt
 *    the player to roll, send a RollDicePrompt data message.
 *    If the client is too old (1.0.6), it will ignore the prompt.
 *
 * @return    did we send a text message to prompt the player to roll?
 *    If so, sendTurn can also send a RollDicePrompt data message.
 * @since 1.1.00
 */
boolean sendGameState(SOCGame ga, final boolean omitGameStateMessage, final boolean sendRollPrompt) {
    if (ga == null)
        return false;
    final int gaState = ga.getGameState();
    final int cpn = ga.getCurrentPlayerNumber();
    final String gname = ga.getName();
    boolean promptedRoll = false;
    if (gaState == SOCGame.OVER) {
        /**
         * Before sending state "OVER", enforce current player number.
         * This helps the client's copy of game recognize winning condition.
         */
        srv.messageToGame(gname, (ga.clientVersionLowest >= SOCGameElements.MIN_VERSION) ? new SOCGameElements(gname, SOCGameElements.CURRENT_PLAYER, cpn) : new SOCSetTurn(gname, cpn));
    }
    if (!omitGameStateMessage)
        srv.messageToGame(gname, new SOCGameState(gname, gaState));
    SOCPlayer player = null;
    if (cpn != -1)
        player = ga.getPlayer(cpn);
    switch(gaState) {
        case SOCGame.START1A:
        case SOCGame.START2A:
        case SOCGame.START3A:
            // "It's Joe's turn to build a settlement."
            srv.messageToGameKeyed(ga, true, "prompt.turn.to.build.stlmt", player.getName());
            if ((gaState >= SOCGame.START2A) && ga.isGameOptionSet(SOCGameOption.K_SC_3IP)) {
                // reminder to player before their 2nd, 3rd settlements
                Connection con = srv.getConnection(player.getName());
                if (con != null) {
                    srv.messageToPlayerKeyed(con, gname, "prompt.gameopt._SC_3IP.part1");
                    // "This game gives you 3 initial settlements and roads."
                    srv.messageToPlayerKeyed(con, gname, "prompt.gameopt._SC_3IP.part2");
                // "Your free resources will be from the third settlement."
                }
            }
            break;
        case SOCGame.START1B:
        case SOCGame.START2B:
        case SOCGame.START3B:
            srv.messageToGameKeyed(ga, true, (// "It's Joe's turn to build a road or ship."
            (ga.hasSeaBoard) ? // "It's Joe's turn to build a road or ship."
            "prompt.turn.to.build.road.or.ship" : "prompt.turn.to.build.road"), player.getName());
            break;
        case SOCGame.ROLL_OR_CARD:
            // "It's Joe's turn to roll the dice."
            srv.messageToGameKeyed(ga, true, "prompt.turn.to.roll.dice", player.getName());
            promptedRoll = true;
            if (sendRollPrompt)
                srv.messageToGame(gname, new SOCRollDicePrompt(gname, player.getPlayerNumber()));
            break;
        case SOCGame.WAITING_FOR_DISCARDS:
            {
                ArrayList<String> names = new ArrayList<String>();
                for (int i = 0; i < ga.maxPlayers; i++) if (ga.getPlayer(i).getNeedToDiscard())
                    names.add(ga.getPlayer(i).getName());
                if (names.size() == 1)
                    // "Joe needs to discard"
                    srv.messageToGameKeyed(ga, true, "prompt.discard.1", names.get(0));
                else
                    // "Joe and Ed need to discard"
                    srv.messageToGameKeyedSpecial(ga, true, "prompt.discard.n", names);
            }
            break;
        case SOCGame.WAITING_FOR_ROBBER_OR_PIRATE:
            // "{0} must choose to move the robber or the pirate."
            srv.messageToGameKeyed(ga, true, "robber.willmove.choose", player.getName());
            break;
        case SOCGame.PLACING_ROBBER:
            // "{0} will move the robber."
            srv.messageToGameKeyed(ga, true, "robber.willmove", player.getName());
            break;
        case SOCGame.PLACING_PIRATE:
            // "{0} will move the pirate ship."
            srv.messageToGameKeyed(ga, true, "robber.willmove.pirate", player.getName());
            break;
        case SOCGame.WAITING_FOR_ROB_CHOOSE_PLAYER:
            /**
             * get the choices from the game
             */
            final boolean canStealNone = ga.isGameOptionSet(SOCGameOption.K_SC_PIRI);
            boolean[] choices = new boolean[ga.maxPlayers + (canStealNone ? 1 : 0)];
            Arrays.fill(choices, false);
            if (canStealNone)
                choices[ga.maxPlayers] = true;
            for (SOCPlayer pl : ga.getPossibleVictims()) choices[pl.getPlayerNumber()] = true;
            /**
             * ask the current player to choose a player to steal from
             */
            Connection con = srv.getConnection(ga.getPlayer(cpn).getName());
            if (con != null) {
                con.put(SOCChoosePlayerRequest.toCmd(gname, choices));
            }
            break;
        case SOCGame.OVER:
            sendGameStateOVER(ga);
            break;
    }
    return promptedRoll;
}
Also used : SOCGameState(soc.message.SOCGameState) Connection(soc.server.genericServer.Connection) ArrayList(java.util.ArrayList) SOCRollDicePrompt(soc.message.SOCRollDicePrompt) SOCGameElements(soc.message.SOCGameElements) SOCSetTurn(soc.message.SOCSetTurn)

Example 3 with SOCRollDicePrompt

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

the class SOCGameHandler method startGame.

// javadoc inherited from GameHandler
/**
 * {@inheritDoc}
 *<P>
 * If {@link SOCGame#hasSeaBoard}: Once the board is made, send the updated
 * {@link SOCPotentialSettlements potential settlements}.
 *<P>
 * If this code changes, must also update {@link soctest.TestBoardLayouts#testSingleLayout(SOCScenario, int)}.
 */
public void startGame(SOCGame ga) {
    if (ga == null)
        return;
    final String gaName = ga.getName();
    // TODO once multiple handler threads, encapsulate this
    srv.numberOfGamesStarted++;
    /**
     * start the game, place any initial pieces.
     * If anything is added to this game object setup code,
     * update soctest.TestBoardLayouts.testSingleLayout(..).
     */
    // for playerEvent, gameEvent callbacks (since 2.0.00)
    ga.setScenarioEventListener(this);
    ga.startGame();
    // used on sea board; if null, all are legal
    final int[][] legalSeaEdges;
    if (ga.hasSeaBoard) {
        legalSeaEdges = SOCBoardAtServer.getLegalSeaEdges(ga, -1);
        if (legalSeaEdges != null)
            for (int pn = 0; pn < ga.maxPlayers; ++pn) ga.getPlayer(pn).setRestrictedLegalShips(legalSeaEdges[pn]);
        if (ga.isGameOptionSet(SOCGameOption.K_SC_FTRI) || ga.isGameOptionSet(SOCGameOption.K_SC_PIRI)) {
            // scenario has initial pieces
            ((SOCBoardAtServer) (ga.getBoard())).startGame_putInitPieces(ga);
        }
    } else {
        legalSeaEdges = null;
    }
    srv.gameList.takeMonitorForGame(gaName);
    try {
        /**
         * send the board layout
         */
        try {
            srv.messageToGameWithMon(gaName, getBoardLayoutMessage(ga));
        // For scenario option _SC_CLVI, the board layout message
        // includes villages and the general supply cloth count.
        // For _SC_PIRI, it includes the Pirate Path (additional layout part "PP").
        } catch (IllegalArgumentException e) {
            System.err.println("startGame: Cannot send board for " + gaName + ": " + e.getMessage());
            // the enclosing try-finally will releaseMonitorForGame(gaName) before returning
            return;
        }
        if (ga.hasSeaBoard) {
            // See also joinGame which has very similar code.
            // Send the updated Potential/Legal Settlement node list
            // Note: Assumes all players have same potential settlements
            // (sends with playerNumber -1 == all)
            final HashSet<Integer> psList = ga.getPlayer(0).getPotentialSettlements();
            // Some boards may have multiple land areas.
            final HashSet<Integer>[] lan;
            final int pan;
            boolean addedPsList = false;
            final SOCBoardLarge bl = (SOCBoardLarge) ga.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;
            }
            if (lan == null)
                srv.messageToGameWithMon(gaName, new SOCPotentialSettlements(gaName, -1, new ArrayList<Integer>(psList)));
            else
                srv.messageToGameWithMon(gaName, new SOCPotentialSettlements(gaName, -1, pan, lan, legalSeaEdges));
            if (addedPsList)
                // Undo change to game's copy of landAreasLegalNodes
                lan[0] = null;
        }
        /**
         * send the player info
         */
        boolean sentInitPiecesState = false;
        for (int i = 0; i < ga.maxPlayers; i++) {
            if (ga.isSeatVacant(i))
                continue;
            final SOCPlayer pl = ga.getPlayer(i);
            final int[] counts = new int[(ga.hasSeaBoard) ? 4 : 3];
            counts[0] = pl.getNumPieces(SOCPlayingPiece.ROAD);
            counts[1] = pl.getNumPieces(SOCPlayingPiece.SETTLEMENT);
            counts[2] = pl.getNumPieces(SOCPlayingPiece.CITY);
            if (ga.hasSeaBoard) {
                // Some scenarios like SC_PIRI may place initial pieces at fixed locations.
                // Usually, pieces will be empty.
                final Vector<SOCPlayingPiece> pieces = pl.getPieces();
                if (!pieces.isEmpty()) {
                    if (!sentInitPiecesState) {
                        // Temporary state change, to avoid initial-piece placement actions.
                        // The actual game state will be sent soon.
                        srv.messageToGameWithMon(gaName, new SOCGameState(gaName, SOCGame.READY));
                        sentInitPiecesState = true;
                    }
                    for (SOCPlayingPiece pp : pieces) srv.messageToGameWithMon(gaName, new SOCPutPiece(gaName, i, pp.getType(), pp.getCoordinates()));
                    SOCPlayingPiece pp = pl.getFortress();
                    if (pp != null)
                        srv.messageToGameWithMon(gaName, new SOCPutPiece(gaName, i, pp.getType(), pp.getCoordinates()));
                }
                counts[3] = pl.getNumPieces(SOCPlayingPiece.SHIP);
            }
            if (ga.clientVersionLowest >= SOCPlayerElements.MIN_VERSION)
                srv.messageToGameWithMon(gaName, new SOCPlayerElements(gaName, i, SOCPlayerElement.SET, (ga.hasSeaBoard) ? ELEM_PIECETYPES_SEA : ELEM_PIECETYPES_CLASSIC, counts));
            else
                for (int j = 0; j < counts.length; ++j) srv.messageToGameWithMon(gaName, new SOCPlayerElement(gaName, i, SOCPlayerElement.SET, ELEM_PIECETYPES_SEA[j], counts[j]));
            if (ga.clientVersionLowest < SOCPlayerElement.VERSION_FOR_CARD_ELEMENTS)
                srv.messageToGameWithMon(gaName, new SOCSetPlayedDevCard(gaName, i, false));
        }
        if (ga.clientVersionLowest >= SOCPlayerElement.VERSION_FOR_CARD_ELEMENTS)
            srv.messageToGameWithMon(gaName, new SOCPlayerElement(gaName, -1, SOCPlayerElement.SET, SOCPlayerElement.PLAYED_DEV_CARD_FLAG, 0));
        /**
         * send the number of dev cards
         */
        srv.messageToGameWithMon(gaName, (ga.clientVersionLowest >= SOCGameElements.MIN_VERSION) ? new SOCGameElements(gaName, SOCGameElements.DEV_CARD_COUNT, ga.getNumDevCards()) : new SOCDevCardCount(gaName, ga.getNumDevCards()));
        /**
         * ga.startGame() picks who goes first, but feedback is nice
         */
        srv.messageToGameKeyed(ga, false, // "Randomly picking a starting player..."
        "start.picking.random.starting.player");
    } finally {
        srv.gameList.releaseMonitorForGame(gaName);
    }
    /**
     * send the game state and start the game.
     * send game state and whose turn it is.
     */
    if (ga.clientVersionLowest >= SOCGameState.VERSION_FOR_GAME_STATE_AS_FIELD) {
        srv.messageToGame(gaName, new SOCStartGame(gaName, ga.getGameState()));
        sendTurn(ga, false);
    } else {
        final int cpn = ga.getCurrentPlayerNumber();
        final boolean sendRoll = sendGameState(ga, false, false);
        srv.messageToGame(gaName, new SOCStartGame(gaName, 0));
        srv.messageToGame(gaName, new SOCTurn(gaName, cpn, 0));
        if (sendRoll)
            srv.messageToGame(gaName, new SOCRollDicePrompt(gaName, cpn));
    }
}
Also used : SOCGameState(soc.message.SOCGameState) SOCPotentialSettlements(soc.message.SOCPotentialSettlements) SOCTurn(soc.message.SOCTurn) SOCRollDicePrompt(soc.message.SOCRollDicePrompt) SOCPlayerElement(soc.message.SOCPlayerElement) SOCSetPlayedDevCard(soc.message.SOCSetPlayedDevCard) HashSet(java.util.HashSet) SOCStartGame(soc.message.SOCStartGame) SOCPlayerElements(soc.message.SOCPlayerElements) SOCPutPiece(soc.message.SOCPutPiece) SOCGameElements(soc.message.SOCGameElements) SOCDevCardCount(soc.message.SOCDevCardCount)

Aggregations

SOCRollDicePrompt (soc.message.SOCRollDicePrompt)3 SOCGameElements (soc.message.SOCGameElements)2 SOCGameState (soc.message.SOCGameState)2 SOCPlayerElement (soc.message.SOCPlayerElement)2 SOCSetPlayedDevCard (soc.message.SOCSetPlayedDevCard)2 SOCTurn (soc.message.SOCTurn)2 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 SOCDevCardCount (soc.message.SOCDevCardCount)1 SOCPlayerElements (soc.message.SOCPlayerElements)1 SOCPotentialSettlements (soc.message.SOCPotentialSettlements)1 SOCPutPiece (soc.message.SOCPutPiece)1 SOCSetTurn (soc.message.SOCSetTurn)1 SOCStartGame (soc.message.SOCStartGame)1 Connection (soc.server.genericServer.Connection)1