use of soc.message.SOCPlayerElement 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()));
}
use of soc.message.SOCPlayerElement 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));
}
}
use of soc.message.SOCPlayerElement in project JSettlers2 by jdmonin.
the class SOCGameHandler method reportRsrcGainGold.
/**
* Report to game members what a player picked from the gold hex.
* Sends {@link SOCPlayerElement} for resources and to reset the
* {@link SOCPlayerElement#NUM_PICK_GOLD_HEX_RESOURCES} counter.
* Sends text "playername has picked ___ from the gold hex.".
* @param ga Game with gaining player
* @param player Player gaining
* @param pn <tt>player</tt>{@link SOCPlayer#getPlayerNumber() .getPlayerNumber()}
* @param rsrcs Resources picked
* @param isNews Is this element change notably good or an unexpected bad change or loss?
* Sets the {@link SOCPlayerElement#isNews()} flag in messages sent by this method.
* If there are multiple resource types, flag is set only for the first type sent
* to avoid several alert sounds at client.
* @param includeGoldHexText If true, text ends with "from the gold hex." after the resource name.
* @since 2.0.00
*/
void reportRsrcGainGold(final SOCGame ga, final SOCPlayer player, final int pn, final SOCResourceSet rsrcs, final boolean isNews, final boolean includeGoldHexText) {
final String gn = ga.getName();
// Send SOCPlayerElement messages
reportRsrcGainLoss(gn, rsrcs, false, isNews, pn, -1, null, null);
srv.messageToGameKeyedSpecial(ga, true, ((includeGoldHexText) ? "action.picked.rsrcs.goldhex" : "action.picked.rsrcs"), player.getName(), rsrcs);
srv.messageToGame(gn, new SOCPlayerElement(gn, pn, SOCPlayerElement.SET, SOCPlayerElement.NUM_PICK_GOLD_HEX_RESOURCES, 0));
}
use of soc.message.SOCPlayerElement 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);
}
use of soc.message.SOCPlayerElement in project JSettlers2 by jdmonin.
the class SOCGameHandler method sitDown_sendPrivateInfo.
// javadoc inherited from GameHandler
public void sitDown_sendPrivateInfo(final SOCGame ga, final Connection c, final int pn) {
final String gaName = ga.getName();
final SOCPlayer pl = ga.getPlayer(pn);
/**
* send all the private information
*/
SOCResourceSet resources = pl.getResources();
// CLAY, ORE, SHEEP, WHEAT, WOOD, UNKNOWN
final int[] counts = resources.getAmounts(true);
if (c.getVersion() >= SOCPlayerElements.MIN_VERSION)
srv.messageToPlayer(c, new SOCPlayerElements(gaName, pn, SOCPlayerElement.SET, ELEM_RESOURCES_WITH_UNKNOWN, counts));
else
for (int i = 0; i < counts.length; ++i) srv.messageToPlayer(c, new SOCPlayerElement(gaName, pn, SOCPlayerElement.SET, ELEM_RESOURCES_WITH_UNKNOWN[i], counts[i]));
SOCInventory cardsInv = pl.getInventory();
final boolean cliVersionNew = (c.getVersion() >= SOCDevCardConstants.VERSION_FOR_NEW_TYPES);
/**
* remove the unknown cards
*/
final SOCDevCardAction cardUnknown = (cliVersionNew) ? new SOCDevCardAction(gaName, pn, SOCDevCardAction.PLAY, SOCDevCardConstants.UNKNOWN) : new SOCDevCardAction(gaName, pn, SOCDevCardAction.PLAY, SOCDevCardConstants.UNKNOWN_FOR_VERS_1_X);
for (int i = cardsInv.getTotal(); i > 0; --i) {
srv.messageToPlayer(c, cardUnknown);
}
/**
* send all new dev cards first, then all playable, then all kept (VP cards)
*/
for (int dcState = SOCInventory.NEW; dcState <= SOCInventory.KEPT; ++dcState) {
final int dcAge = (dcState == SOCInventory.NEW) ? SOCInventory.NEW : SOCInventory.OLD;
final int addCmd = (dcAge == SOCInventory.NEW) ? SOCDevCardAction.ADD_NEW : SOCDevCardAction.ADD_OLD;
for (final SOCInventoryItem card : cardsInv.getByState(dcState)) {
final SOCMessage addMsg;
if (card instanceof SOCDevCard) {
final int dcType = card.itype;
if (cliVersionNew || (dcType != SOCDevCardConstants.KNIGHT))
addMsg = new SOCDevCardAction(gaName, pn, addCmd, dcType);
else
addMsg = new SOCDevCardAction(gaName, pn, addCmd, SOCDevCardConstants.KNIGHT_FOR_VERS_1_X);
} else {
// None yet
System.err.println("L1385: Unrecognized inventory item type " + card.getClass());
addMsg = null;
}
if (addMsg != null)
srv.messageToPlayer(c, addMsg);
}
// for (card)
}
// for (dcState)
/**
* send game state info such as requests for discards
*/
sendGameState(ga);
if ((ga.getCurrentDice() == 7) && pl.getNeedToDiscard()) {
srv.messageToPlayer(c, new SOCDiscardRequest(gaName, pl.getResources().getTotal() / 2));
} else if (ga.hasSeaBoard) {
final int numGoldRes = pl.getNeedToPickGoldHexResources();
if (numGoldRes > 0)
srv.messageToPlayer(c, new SOCSimpleRequest(gaName, pn, SOCSimpleRequest.PROMPT_PICK_RESOURCES, numGoldRes));
}
/**
* send what face this player is using
*/
srv.messageToGame(gaName, new SOCChangeFace(gaName, pn, pl.getFaceId()));
}
Aggregations