Search in sources :

Example 1 with IntPair

use of soc.util.IntPair in project JSettlers2 by jdmonin.

the class SOCGameHandler method playerEvent.

/**
 * Listener callback for per-player scenario events on the large sea board.
 * For example, there might be an SVP awarded for settlements.
 * Server sends messages to the game to announce it (PLAYERELEMENT,
 * {@link #updatePlayerSVPPendingMessage(SOCGame, SOCPlayer, int, String)}, etc).
 *<P>
 * <em>Threads:</em> The game's treater thread handles incoming client messages and calls
 * game methods that change state. Those same game methods will trigger the scenario events;
 * so, the treater thread will also run this <tt>playerEvent</tt> callback.
 *
 * @param ga  Game
 * @param pl  Player
 * @param evt  Event code
 * @see #gameEvent(SOCGame, SOCScenarioGameEvent, Object)
 * @param flagsChanged  True if this event changed {@link SOCPlayer#getScenarioPlayerEvents()},
 *             {@link SOCPlayer#getSpecialVP()}, or another flag documented for <tt>evt</tt> in
 *             {@link SOCScenarioPlayerEvent}
 * @param obj  Object related to the event, or null; documented for <tt>evt</tt> in {@link SOCScenarioPlayerEvent}.
 *             Example: The {@link SOCVillage} for {@link SOCScenarioPlayerEvent#CLOTH_TRADE_ESTABLISHED_VILLAGE}.
 * @since 2.0.00
 */
public void playerEvent(final SOCGame ga, final SOCPlayer pl, final SOCScenarioPlayerEvent evt, final boolean flagsChanged, final Object obj) {
    // Note: Some SOCGameHandler code assumes that player events are fired only during
    // SOCGameMessageHandler.handlePUTPIECE and handleMOVEPIECE.
    // Most handle* methods don't check pendingMessagesOut before sending game state.
    // If a new player event breaks this assumption, adjust SOCGameHandler.playerEvent(...)
    // and related code; search where SOCGame.pendingMessagesOut is used.
    final String gaName = ga.getName(), plName = pl.getName();
    final int pn = pl.getPlayerNumber();
    boolean sendSVP = true;
    boolean sendPlayerEventsBitmask = true;
    switch(evt) {
        case SVP_SETTLED_ANY_NEW_LANDAREA:
            {
                final String newSettleEventStr = (playerEvent_newSettlementIsByShip(ga, (SOCSettlement) obj)) ? // "growing past the main island"
                "event.svp.sc_sany.island" : // "growing to a new area"
                "event.svp.sc_sany.area";
                updatePlayerSVPPendingMessage(ga, pl, 1, newSettleEventStr);
            }
            break;
        case SVP_SETTLED_EACH_NEW_LANDAREA:
            {
                final String newSettleEventStr = (playerEvent_newSettlementIsByShip(ga, (SOCSettlement) obj)) ? // "settling a new island"
                "event.svp.sc_seac.island" : // "settling a new area"
                "event.svp.sc_seac.area";
                updatePlayerSVPPendingMessage(ga, pl, 2, newSettleEventStr);
                sendPlayerEventsBitmask = false;
                final int las = pl.getScenarioSVPLandAreas();
                if (las != 0)
                    ga.pendingMessagesOut.add(new SOCPlayerElement(gaName, pn, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_SVP_LANDAREAS_BITMASK, las));
            }
            break;
        case CLOTH_TRADE_ESTABLISHED_VILLAGE:
            {
                sendSVP = false;
                if (!flagsChanged)
                    sendPlayerEventsBitmask = false;
                ga.pendingMessagesOut.add(new UnlocalizedString("event.sc_clvi.established", // "{0} established a trade route with a village."
                plName));
                if (flagsChanged)
                    srv.messageToPlayerPendingKeyed(pl, gaName, "event.sc_clvi.not.prevented.pirate");
                // "You are no longer prevented from moving the pirate ship."
                // Player gets 1 cloth for establishing trade
                SOCVillage vi = (SOCVillage) obj;
                srv.messageToGame(gaName, new SOCPieceValue(gaName, vi.getCoordinates(), vi.getCloth(), 0));
                srv.messageToGame(gaName, new SOCPlayerElement(gaName, pn, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_CLOTH_COUNT, pl.getCloth()));
            }
            break;
        case DEV_CARD_REACHED_SPECIAL_EDGE:
            {
                sendPlayerEventsBitmask = false;
                sendSVP = false;
                IntPair edge_cardType = (IntPair) obj;
                Connection c = srv.getConnection(plName);
                ga.pendingMessagesOut.add(new UnlocalizedString("action.built.sc_ftri.dev", // "{0} gets a Development Card as a gift from the Lost Tribe."
                plName));
                srv.messageToPlayer(c, new SOCDevCardAction(gaName, pn, SOCDevCardAction.DRAW, edge_cardType.getB()));
                srv.messageToGameExcept(gaName, c, new SOCDevCardAction(gaName, pn, SOCDevCardAction.DRAW, SOCDevCardConstants.UNKNOWN), true);
                srv.messageToGame(gaName, new SOCSimpleAction(gaName, -1, SOCSimpleAction.BOARD_EDGE_SET_SPECIAL, edge_cardType.getA(), 0));
            }
            break;
        case SVP_REACHED_SPECIAL_EDGE:
            {
                // "a gift from the Lost Tribe"
                updatePlayerSVPPendingMessage(ga, pl, 1, "event.svp.sc_ftri.gift");
                sendPlayerEventsBitmask = false;
                srv.messageToGame(gaName, new SOCSimpleAction(gaName, -1, SOCSimpleAction.BOARD_EDGE_SET_SPECIAL, ((Integer) obj).intValue(), 0));
            }
            break;
        case REMOVED_TRADE_PORT:
            {
                sendPlayerEventsBitmask = false;
                sendSVP = false;
                IntPair edge_portType = (IntPair) obj;
                final int edge = edge_portType.getA(), portType = edge_portType.getB();
                if ((edge & 0xFF) <= ga.getBoard().getBoardWidth())
                    // announce removal from board, unless (for debugging)
                    // this port wasn't really on the board at clients
                    srv.messageToGame(gaName, new SOCSimpleAction(gaName, pn, SOCSimpleAction.TRADE_PORT_REMOVED, edge, portType));
                if (ga.getGameState() == SOCGame.PLACING_INV_ITEM) {
                    // Removal happens during ship piece placement, which is followed at server with sendGameState.
                    // When sendGameState gives the new state, client will prompt current player to place now.
                    // We just need to send the client PLACING_EXTRA, for the port type and not-cancelable flag.
                    Connection c = srv.getConnection(plName);
                    srv.messageToPlayer(c, new SOCInventoryItemAction(gaName, pn, SOCInventoryItemAction.PLACING_EXTRA, -portType, false, false, false));
                } else {
                    // port was added to player's inventory;
                    // if this message changes, also update SOCGameHandler.processDebugCommand_scenario
                    srv.messageToGame(gaName, new SOCInventoryItemAction(gaName, pn, SOCInventoryItemAction.ADD_PLAYABLE, -portType, false, false, true));
                }
            }
            break;
        default:
            // Suppress warning; not all enum values need a handler here
            break;
    }
    if (sendSVP)
        ga.pendingMessagesOut.add(new SOCPlayerElement(gaName, pn, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_SVP, pl.getSpecialVP()));
    if (sendPlayerEventsBitmask)
        ga.pendingMessagesOut.add(new SOCPlayerElement(gaName, pn, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_PLAYEREVENTS_BITMASK, pl.getScenarioPlayerEvents()));
}
Also used : SOCPieceValue(soc.message.SOCPieceValue) SOCInventoryItemAction(soc.message.SOCInventoryItemAction) Connection(soc.server.genericServer.Connection) SOCSimpleAction(soc.message.SOCSimpleAction) IntPair(soc.util.IntPair) SOCPlayerElement(soc.message.SOCPlayerElement) SOCDevCardAction(soc.message.SOCDevCardAction)

Example 2 with IntPair

use of soc.util.IntPair in project JSettlers2 by jdmonin.

the class SOCGame method removePort.

/**
 * For scenario option {@link SOCGameOption#K_SC_FTRI _SC_FTRI}, remove a "gift" port
 * at this edge to be placed elsewhere. Assumes {@link #canRemovePort(SOCPlayer, int)} has already
 * been called to validate player, edge, and game state.
 *<P>
 * This method will remove the port from the board.  At server it will also either add it to the
 * player's inventory or set the game's placingItem field; change the game state if placing
 * it immediately; and then fire {@link SOCScenarioPlayerEvent#REMOVED_TRADE_PORT}.
 *<P>
 * <b>At the server:</b> Not called directly; called only from other game/player methods.
 * Ports are currently removed only by a player's adjacent ship placement, so
 * {@link SOCPlayer#putPiece(SOCPlayingPiece, boolean)} would eventually call this
 * method if {@code canRemovePort(..)}.  The server calls
 * {@link SOCPlayer#getPortMovePotentialLocations(boolean) pl.getPortMovePotentialLocations(false)}
 * to determine if immediate placement is possible and thus required.
 *<P>
 * In the PlayerEvent handler or after this method returns, check
 * {@link #getGameState()} == {@link #PLACING_INV_ITEM} to see whether the port must immediately
 * be placed, or was instead added to the player's inventory.
 *<P>
 * <b>At the client:</b> Call this method to update the board data and player port flags.
 * The server will send other messages about game state and player inventory.  If those set
 * {@link #getGameState()} to {@link #PLACING_INV_ITEM}, the current player must choose a location for
 * port placement: Call
 * {@link SOCPlayer#getPortMovePotentialLocations(boolean) SOCPlayer.getPortMovePotentialLocations(true)}
 * to present options to the user.  The user will choose an edge and send a request to the server. The server
 * will validate and if valid call {@link #placePort(int)} and send updated status to the game's clients.
 *
 * @param pl  Player who is removing the port: Must be current player. Ignored at client, {@code null} is okay there.
 * @param edge  Port's edge coordinate
 * @throws UnsupportedOperationException if ! {@link #hasSeaBoard}
 * @throws NullPointerException if {@code pl} is null at server
 * @return  The port removed, with its {@link SOCInventoryItem#itype} in range
 *      -{@link SOCBoard#WOOD_PORT WOOD_PORT} to -{@link SOCBoard#MISC_PORT MISC_PORT}
 */
public SOCInventoryItem removePort(SOCPlayer pl, final int edge) throws UnsupportedOperationException, NullPointerException {
    if (!hasSeaBoard)
        throw new UnsupportedOperationException();
    final int ptype = ((SOCBoardLarge) board).removePort(edge);
    for (int pn = 0; pn < maxPlayers; ++pn) players[pn].updatePortFlagsAfterRemove(ptype, true);
    if ((pl == null) || !isAtServer)
        pl = players[currentPlayerNumber];
    // note: if this logic changes, also update SOCGameHandler.processDebugCommand_scenario
    final boolean placeNow = (pl.getPortMovePotentialLocations(false) != null);
    final SOCInventoryItem port = SOCInventoryItem.createForScenario(this, -ptype, true, false, false, !placeNow);
    if (isAtServer) {
        if (!placeNow) {
            pl.getInventory().addItem(port);
        } else {
            placingItem = port;
            oldGameState = (gameState == SPECIAL_BUILDING) ? SPECIAL_BUILDING : PLAY1;
            gameState = PLACING_INV_ITEM;
        }
        // Fire the scenario player event, with the removed port's edge coord and type
        if (scenarioEventListener != null) {
            scenarioEventListener.playerEvent(this, pl, SOCScenarioPlayerEvent.REMOVED_TRADE_PORT, false, new IntPair(edge, ptype));
        }
    }
    return port;
}
Also used : IntPair(soc.util.IntPair)

Example 3 with IntPair

use of soc.util.IntPair in project JSettlers2 by jdmonin.

the class SOCPlayer method calcLongestRoad2.

/**
 * Calculates the longest road / longest trade route for this player
 *
 * @return the length of the longest road for this player
 */
public int calcLongestRoad2() {
    // Date startTime = new Date();
    // 
    // clear the lr paths vector so that we have an accurate
    // representation.  if someone cut our longest path in two
    // we won't catch it unless we clear the vector
    // 
    // D.ebugPrintln("CLEARING PATH DATA");
    lrPaths.removeAllElements();
    /**
     * we're doing a depth first search of all possible road paths.
     * For similar code, see soc.robot.SOCRobotDM.recalcLongestRoadETAAux.
     * Both methods rely on a stack holding NodeLenVis (pop to curNode in loop);
     * they differ in actual element type within the stack because they are
     * gathering slightly different results (length or a stack of edges).
     */
    SOCBoard board = game.getBoard();
    Stack<NodeLenVis<IntPair>> pending = new Stack<NodeLenVis<IntPair>>();
    int longest = 0;
    for (Integer rn : roadNodes) {
        final int pathStartNodeCoord = rn.intValue();
        pending.push(new NodeLenVis<IntPair>(pathStartNodeCoord, 0, new Vector<IntPair>()));
        while (!pending.isEmpty()) {
            NodeLenVis<IntPair> curNode = pending.pop();
            final int coord = curNode.node;
            final int len = curNode.len;
            Vector<IntPair> visited = curNode.vis;
            boolean pathEnd = false;
            final SOCPlayingPiece settlementAtNodeCoord;
            /**
             * check for road blocks
             */
            if (len > 0) {
                settlementAtNodeCoord = board.settlementAtNode(coord);
                if ((settlementAtNodeCoord != null) && (settlementAtNodeCoord.getPlayerNumber() != playerNumber)) {
                    pathEnd = true;
                // D.ebugPrintln("^^^ path end at "+Integer.toHexString(coord));
                }
            } else {
                settlementAtNodeCoord = null;
            }
            if (!pathEnd) {
                /**
                 * Check if this road path continues to adjacent connected nodes.
                 */
                // may be set false in loop
                pathEnd = true;
                final int[] adjacNodes = board.getAdjacentNodesToNode_arr(coord);
                for (int ni = adjacNodes.length - 1; ni >= 0; --ni) {
                    final int j = adjacNodes[ni];
                    if (j == -9)
                        continue;
                    if (isConnectedByRoad(coord, j)) {
                        // sea board: road/ship from node to j
                        final SOCRoad roadFromNode;
                        if (game.hasSeaBoard) {
                            // Check for road<->ship transitions,
                            // which require a settlement/city at node.
                            // If len==0, inboundRoad is null because we're just starting.
                            roadFromNode = getRoadOrShip(board.getEdgeBetweenAdjacentNodes(coord, j));
                            if (len > 0) {
                                if (// shouldn't happen
                                roadFromNode == null)
                                    continue;
                                if ((roadFromNode.isRoadNotShip() != curNode.inboundRoad.isRoadNotShip()) && (settlementAtNodeCoord == null)) {
                                    // Requires settlement/city to connect road to ship
                                    continue;
                                }
                            }
                        } else {
                            roadFromNode = null;
                        }
                        IntPair pair = new IntPair(coord, j);
                        boolean match = false;
                        for (IntPair vis : visited) {
                            if (vis.equals(pair)) {
                                match = true;
                                break;
                            }
                        }
                        if (!match) {
                            Vector<IntPair> newVis = new Vector<IntPair>(visited);
                            newVis.addElement(pair);
                            pending.push(new NodeLenVis<IntPair>(j, len + 1, newVis, roadFromNode));
                            pathEnd = false;
                        }
                    }
                }
            // foreach(adjacNodes)
            }
            if (pathEnd) {
                if (len > longest) {
                    longest = len;
                }
                // 
                // we want to store the longest path for a single set of nodes
                // check to make sure that we don't save two paths that share a node
                // 
                boolean intersection;
                boolean addNewPath = true;
                Vector<SOCLRPathData> trash = new Vector<SOCLRPathData>();
                for (SOCLRPathData oldPathData : lrPaths) {
                    // D.ebugPrintln("oldPathData = " + oldPathData);
                    Vector<IntPair> nodePairs = oldPathData.getNodePairs();
                    intersection = false;
                    for (IntPair vis : visited) {
                        for (IntPair np : nodePairs) {
                            if (np.equals(vis)) {
                                // D.ebugPrintln("oldPathData.nodePairs.contains(vis)");
                                intersection = true;
                                break;
                            }
                        }
                        if (intersection) {
                            break;
                        }
                    }
                    if (intersection) {
                        // 
                        if (oldPathData.getLength() < len) {
                            // D.ebugPrintln("REMOVING OLDPATHDATA");
                            trash.addElement(oldPathData);
                        } else {
                            addNewPath = false;
                        // D.ebugPrintln("NOT ADDING NEW PATH");
                        }
                    }
                }
                if (!trash.isEmpty()) {
                    for (SOCLRPathData oldPathData : trash) {
                        lrPaths.removeElement(oldPathData);
                    }
                }
                if (addNewPath) {
                    SOCLRPathData newPathData = new SOCLRPathData(pathStartNodeCoord, coord, len, visited);
                    // D.ebugPrintln("ADDING PATH: " + newPathData);
                    lrPaths.addElement(newPathData);
                }
            }
        }
    }
    longestRoadLength = longest;
    // System.out.println("LONGEST FOR "+name+" IS "+longest+" TIME = "+elapsed+"ms");
    return longest;
}
Also used : NodeLenVis(soc.util.NodeLenVis) IntPair(soc.util.IntPair) Stack(java.util.Stack) Vector(java.util.Vector)

Example 4 with IntPair

use of soc.util.IntPair in project JSettlers2 by jdmonin.

the class SOCPlayerNumbers method undoAddNumberForResource.

/**
 * remove a number for a resource
 * do this when you take back a piece
 *
 * @param number    the dice-roll number
 * @param resource  the resource, in range {@link SOCResourceConstants#CLAY} to {@link SOCResourceConstants#WOOD},
 *                    from {@link SOCBoard#getHexTypeFromCoord(int)}.
 *                    If {@link #hasSeaBoard}, can be {@link SOCBoardLarge#GOLD_HEX}.
 * @param hex       the hex coordinate ID
 */
public void undoAddNumberForResource(int number, int resource, int hex) {
    if ((resource >= SOCResourceConstants.CLAY) && (resource <= SOCResourceConstants.WOOD)) {
        for (Integer num : numbersForResource[resource]) {
            if (num.intValue() == number) {
                numbersForResource[resource].removeElement(num);
                break;
            }
        }
        for (Integer resourceInt : resourcesForNumber[number]) {
            if (resourceInt.intValue() == resource) {
                resourcesForNumber[number].removeElement(resourceInt);
                break;
            }
        }
    } else {
        if (!(hasSeaBoard && (resource == SOCBoardLarge.GOLD_HEX))) {
            // <--- Ignore all other resource/hex types ---
            return;
        }
        for (int res = SOCResourceConstants.CLAY; res <= SOCResourceConstants.WOOD; ++res) {
            Iterator<Integer> numIter = numbersForResource[res].iterator();
            while (numIter.hasNext()) {
                final int num = numIter.next().intValue();
                if (num == number) {
                    numIter.remove();
                    break;
                }
            }
        }
        // range CLAY to WOOD
        boolean[] removed = new boolean[SOCResourceConstants.UNKNOWN];
        Iterator<Integer> resIter = resourcesForNumber[number].iterator();
        while (resIter.hasNext()) {
            final int res = resIter.next().intValue();
            if (!removed[res]) {
                resIter.remove();
                removed[res] = true;
            }
        }
    // GOLD_HEX will be in numberAndResourceForHex.
    }
    Vector<IntPair> pairs = numberAndResourceForHex.get(Integer.valueOf(hex));
    if (pairs != null) {
        for (IntPair numAndResource : pairs) {
            if ((numAndResource.getA() == number) && (numAndResource.getB() == resource)) {
                pairs.removeElement(numAndResource);
                break;
            }
        }
    }
}
Also used : IntPair(soc.util.IntPair)

Example 5 with IntPair

use of soc.util.IntPair in project JSettlers2 by jdmonin.

the class SOCPlayerNumbers method addNumberForResource.

/**
 * add a number to the list of dice numbers for a resource
 *
 * @param diceNum    the dice-roll number
 * @param resource  the resource, in range {@link SOCResourceConstants#CLAY} to {@link SOCResourceConstants#WOOD};
 *                   resources outside this range are ignored.
 *                   If {@link #hasSeaBoard}, can be {@link SOCBoardLarge#GOLD_HEX}
 *                   as returned from {@link SOCBoardLarge#getHexTypeFromCoord(int)}.
 * @param hex       the hex coordinate ID
 */
public void addNumberForResource(final int diceNum, final int resource, final int hex) {
    if ((resource >= SOCResourceConstants.CLAY) && (resource <= SOCResourceConstants.WOOD)) {
        numbersForResource[resource].addElement(new Integer(diceNum));
        Integer resourceInt = new Integer(resource);
        // if (!resourcesForNumber[number].contains(resourceInt)) {
        resourcesForNumber[diceNum].addElement(resourceInt);
    // }
    } else {
        if (!(hasSeaBoard && (resource == SOCBoardLarge.GOLD_HEX))) {
            // <--- Ignore all other resource/hex types ---
            return;
        }
        // GOLD_HEX: Add all 5 resource types
        final Integer diceNumInt = new Integer(diceNum);
        for (int res = SOCResourceConstants.CLAY; res <= SOCResourceConstants.WOOD; ++res) {
            numbersForResource[res].addElement(diceNumInt);
            resourcesForNumber[diceNum].addElement(new Integer(res));
        }
    // GOLD_HEX is okay in numberAndResourceForHex.
    }
    final Integer hexInt = new Integer(hex);
    Vector<IntPair> pairs = numberAndResourceForHex.get(hexInt);
    if (pairs == null) {
        pairs = new Vector<IntPair>();
        numberAndResourceForHex.put(hexInt, pairs);
    }
    pairs.addElement(new IntPair(diceNum, resource));
}
Also used : IntPair(soc.util.IntPair)

Aggregations

IntPair (soc.util.IntPair)5 Stack (java.util.Stack)1 Vector (java.util.Vector)1 SOCDevCardAction (soc.message.SOCDevCardAction)1 SOCInventoryItemAction (soc.message.SOCInventoryItemAction)1 SOCPieceValue (soc.message.SOCPieceValue)1 SOCPlayerElement (soc.message.SOCPlayerElement)1 SOCSimpleAction (soc.message.SOCSimpleAction)1 Connection (soc.server.genericServer.Connection)1 NodeLenVis (soc.util.NodeLenVis)1