Search in sources :

Example 1 with SOCFirstPlayer

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

the class SOCGameHandler method forceEndGameTurn.

/**
 * Try to force-end the current player's turn in this game.
 * Alter game state and send messages to players.
 * Will call {@link #endGameTurn(SOCGame, SOCPlayer, boolean)} if appropriate.
 * Will send gameState and current player (turn) to clients.
 *<P>
 * If the current player has lost connection, send the {@link SOCLeaveGame LEAVEGAME}
 * message out <b>before</b> calling this method.
 *<P>
 * Assumes, as {@link #endGameTurn(SOCGame, SOCPlayer, boolean)} does:
 * <UL>
 * <LI> ga.canEndTurn already called, returned false
 * <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>
 * @param ga Game to force end turn
 * @param plName Current player's name. Needed because if they have been disconnected by
 *               {@link #leaveGame(SOCGame, Connection)},
 *               their name within game object is already null.
 * @return true if the turn was ended and game is still active;
 *          false if we find that all players have left and
 *          the gamestate has been changed here to {@link SOCGame#OVER}.
 *
 * @see #endGameTurnOrForce(SOCGame, int, String, Connection, boolean)
 * @see SOCGame#forceEndTurn()
 */
private final boolean forceEndGameTurn(SOCGame ga, final String plName) {
    final String gaName = ga.getName();
    final int cpn = ga.getCurrentPlayerNumber();
    final int endFromGameState = ga.getGameState();
    SOCPlayer cp = ga.getPlayer(cpn);
    if (cp.hasAskedSpecialBuild()) {
        cp.setAskedSpecialBuild(false);
        srv.messageToGame(gaName, new SOCPlayerElement(gaName, cpn, SOCPlayerElement.SET, SOCPlayerElement.ASK_SPECIAL_BUILD, 0));
    }
    final SOCForceEndTurnResult res = ga.forceEndTurn();
    // also could be initial placement (START1A or START2A or START3A).
    if (SOCGame.OVER == ga.getGameState())
        // <--- Early return: All players have left ---
        return false;
    /**
     * Report any resources lost or gained.
     * See also forceGamePlayerDiscardOrGain for same reporting code.
     */
    SOCResourceSet resGainLoss = res.getResourcesGainedLost();
    if (resGainLoss != null) {
        /**
         * If gold hex or returning resources to player (not discarding), report actual types/amounts.
         * For discard, tell the discarding player's client that they discarded the resources,
         * tell everyone else that the player discarded unknown resources.
         */
        if (!res.isLoss()) {
            if ((endFromGameState == SOCGame.WAITING_FOR_PICK_GOLD_RESOURCE) || (endFromGameState == SOCGame.STARTS_WAITING_FOR_PICK_GOLD_RESOURCE)) {
                // Send SOCPlayerElement messages, "gains" text
                reportRsrcGainGold(ga, cp, cpn, resGainLoss, true, false);
            } else {
                // Send SOCPlayerElement messages
                reportRsrcGainLoss(gaName, resGainLoss, false, false, cpn, -1, null, null);
            }
        } else {
            Connection c = srv.getConnection(plName);
            if ((c != null) && c.isConnected())
                reportRsrcGainLoss(gaName, resGainLoss, true, true, cpn, -1, null, c);
            int totalRes = resGainLoss.getTotal();
            srv.messageToGameExcept(gaName, c, new SOCPlayerElement(gaName, cpn, SOCPlayerElement.LOSE, SOCPlayerElement.UNKNOWN, totalRes, true), true);
            // "{0} discarded {1} resources."
            srv.messageToGameKeyed(ga, true, "action.discarded", plName, totalRes);
        }
    }
    /**
     * report any dev-card or item returned to player's hand
     */
    final SOCInventoryItem itemCard = res.getReturnedInvItem();
    SOCInventoryItemAction retItemActionMsg = null;
    if (itemCard != null) {
        Connection c = srv.getConnection(plName);
        if ((c != null) && c.isConnected()) {
            if (itemCard instanceof SOCDevCard) {
                int card = itemCard.itype;
                if ((card == SOCDevCardConstants.KNIGHT) && (c.getVersion() < SOCDevCardConstants.VERSION_FOR_NEW_TYPES))
                    card = SOCDevCardConstants.KNIGHT_FOR_VERS_1_X;
                srv.messageToPlayer(c, new SOCDevCardAction(gaName, cpn, SOCDevCardAction.ADD_OLD, card));
            } else {
                retItemActionMsg = new SOCInventoryItemAction(gaName, cpn, (itemCard.isPlayable() ? SOCInventoryItemAction.ADD_PLAYABLE : SOCInventoryItemAction.ADD_OTHER), itemCard.itype, itemCard.isKept(), itemCard.isVPItem(), itemCard.canCancelPlay);
                srv.messageToPlayer(c, retItemActionMsg);
            }
        }
        // Announce item to game with same retItemActionMsg sent to player?
        boolean announceAsInvItemAction = false;
        // Announce this item to game as an unknown dev card type?
        boolean announceAsUnknown = true;
        if (!(itemCard instanceof SOCDevCard)) {
            // SOCInventoryItem: Add any new kinds here, to announce to all players.
            // If it needs a special message, do so and set announceAsUnknown = false
            // If it's private and doesn't need a special message, set handled = true and let it announce as unknown
            boolean handled = false;
            if (ga.isGameOptionSet(SOCGameOption.K_SC_FTRI)) {
                // endFromGameState is PLACING_INV_ITEM.
                // "Gift port" item details are public, send return message to whole game:
                handled = true;
                announceAsInvItemAction = true;
                announceAsUnknown = false;
            }
            // Fallback:
            if (!handled)
                System.err.println("forceEndGameTurn: Unhandled inventory item type " + itemCard.itype + " class " + itemCard.getClass());
        }
        if (announceAsInvItemAction) {
            srv.messageToGameExcept(gaName, c, retItemActionMsg, true);
        } else if (announceAsUnknown) {
            if (ga.clientVersionLowest >= SOCDevCardConstants.VERSION_FOR_NEW_TYPES) {
                srv.messageToGameExcept(gaName, c, new SOCDevCardAction(gaName, cpn, SOCDevCardAction.ADD_OLD, SOCDevCardConstants.UNKNOWN), true);
            } else {
                srv.messageToGameForVersionsExcept(ga, -1, SOCDevCardConstants.VERSION_FOR_NEW_TYPES - 1, c, new SOCDevCardAction(gaName, cpn, SOCDevCardAction.ADD_OLD, SOCDevCardConstants.UNKNOWN_FOR_VERS_1_X), true);
                srv.messageToGameForVersionsExcept(ga, SOCDevCardConstants.VERSION_FOR_NEW_TYPES, Integer.MAX_VALUE, c, new SOCDevCardAction(gaName, cpn, SOCDevCardAction.ADD_OLD, SOCDevCardConstants.UNKNOWN), true);
            }
            srv.messageToGameKeyed(ga, true, "forceend.devcard.returned", plName);
        // "{0}''s just-played development card was returned."
        }
    }
    /**
     * For initial placements, we don't end turns as normal.
     * (Player number may go forward or backwards, new state isn't ROLL_OR_CARD, etc.)
     * Update clients' gamestate, but don't call endGameTurn.
     */
    final int forceRes = res.getResult();
    if ((forceRes == SOCForceEndTurnResult.FORCE_ENDTURN_SKIP_START_ADV) || (forceRes == SOCForceEndTurnResult.FORCE_ENDTURN_SKIP_START_ADVBACK)) {
        if (res.didUpdateFP() || res.didUpdateLP()) {
            final int fpn = ga.getFirstPlayer();
            final SOCMessage msg = (ga.clientVersionLowest >= SOCGameElements.MIN_VERSION) ? new SOCGameElements(gaName, SOCGameElements.FIRST_PLAYER, fpn) : new SOCFirstPlayer(gaName, fpn);
            // will cause clients to recalculate lastPlayer too
            srv.messageToGame(gaName, msg);
        }
        sendTurn(ga, false);
        // <--- Early return ---
        return true;
    }
    /**
     * If the turn can now end, proceed as if player requested it.
     * Otherwise, send current gamestate.  We'll all wait for other
     * players to send discard messages, and afterwards this turn can end.
     */
    if (ga.canEndTurn(cpn))
        // could force gamestate to OVER, if a client leaves
        endGameTurn(ga, null, true);
    else
        sendGameState(ga, false, false);
    return (ga.getGameState() != SOCGame.OVER);
}
Also used : SOCMessage(soc.message.SOCMessage) SOCInventoryItemAction(soc.message.SOCInventoryItemAction) Connection(soc.server.genericServer.Connection) SOCPlayerElement(soc.message.SOCPlayerElement) SOCGameElements(soc.message.SOCGameElements) SOCFirstPlayer(soc.message.SOCFirstPlayer) SOCDevCardAction(soc.message.SOCDevCardAction)

Aggregations

SOCDevCardAction (soc.message.SOCDevCardAction)1 SOCFirstPlayer (soc.message.SOCFirstPlayer)1 SOCGameElements (soc.message.SOCGameElements)1 SOCInventoryItemAction (soc.message.SOCInventoryItemAction)1 SOCMessage (soc.message.SOCMessage)1 SOCPlayerElement (soc.message.SOCPlayerElement)1 Connection (soc.server.genericServer.Connection)1