use of soc.game.SOCPlayer in project JSettlers2 by jdmonin.
the class SOCGameMessageHandler method handleSETSPECIALITEM.
/**
* Handle Special Item requests from a player.
* Calls {@link SOCSpecialItem#playerPickItem(String, SOCGame, SOCPlayer, int, int)}
* or {@link SOCSpecialItem#playerSetItem(String, SOCGame, SOCPlayer, int, int, boolean)}
* which provide scenario-specific responses or decline the request.
* @param c the connection that sent the message
* @param mes the message
*/
private void handleSETSPECIALITEM(SOCGame ga, Connection c, final SOCSetSpecialItem mes) {
final String gaName = ga.getName();
final SOCPlayer pl = ga.getPlayer(c.getData());
final String typeKey = mes.typeKey;
final int op = mes.op, gi = mes.gameItemIndex, pi = mes.playerItemIndex;
// don't trust mes.playerNumber
final int pn = (pl != null) ? pl.getPlayerNumber() : -1;
boolean sendDenyReply = false;
try {
SOCSpecialItem itm = null;
// if true, itm's cost was paid by player to PICK or SET or CLEAR
final boolean paidCost;
ga.takeMonitor();
if ((pl == null) || (op < SOCSetSpecialItem.OP_SET) || (op > SOCSetSpecialItem.OP_PICK)) {
sendDenyReply = true;
paidCost = false;
} else {
final int prevState = ga.getGameState();
if (op == SOCSetSpecialItem.OP_PICK) {
// field values to send in reply/announcement
int pickCoord = -1, pickLevel = 0;
// sv field value to send
String pickSV = null;
// When game index and player index are both given,
// compare items before and after PICK in case they change
final SOCSpecialItem gBefore, pBefore;
if ((gi != -1) && (pi != -1)) {
gBefore = ga.getSpecialItem(typeKey, gi);
pBefore = pl.getSpecialItem(typeKey, pi);
} else {
gBefore = null;
pBefore = null;
}
// Before pick, get item as per playerPickItem javadoc for cost, coord, level,
// in case it's cleared by the pick. If not cleared, will get it again afterwards.
itm = ga.getSpecialItem(typeKey, gi, pi, pn);
if (itm != null) {
pickCoord = itm.getCoordinates();
pickLevel = itm.getLevel();
pickSV = itm.getStringValue();
}
// perform the PICK in game
paidCost = SOCSpecialItem.playerPickItem(typeKey, ga, pl, gi, pi);
// if cost paid, send resource-loss first
if (paidCost && (itm != null))
handler.reportRsrcGainLoss(gaName, itm.getCost(), true, false, pn, -1, null, null);
if ((gi == -1) || (pi == -1)) {
// request didn't specify both gi and pi: only 1 SET/CLEAR message to send
final SOCSpecialItem itmAfter = ga.getSpecialItem(typeKey, gi, pi, pn);
final SOCSetSpecialItem msg;
if (itmAfter != null) {
msg = new SOCSetSpecialItem(ga, SOCSetSpecialItem.OP_SET, typeKey, gi, pi, itmAfter);
pickCoord = itmAfter.getCoordinates();
pickLevel = itmAfter.getLevel();
pickSV = itmAfter.getStringValue();
} else {
msg = new SOCSetSpecialItem(gaName, SOCSetSpecialItem.OP_CLEAR, typeKey, gi, pi, pn);
}
srv.messageToGame(gaName, msg);
} else {
// request specified both gi and pi: might need to send 1 SET/CLEAR message if shared,
// or 2 messages if not the same object for both
final SOCSpecialItem gAfter, pAfter;
gAfter = ga.getSpecialItem(typeKey, gi);
pAfter = pl.getSpecialItem(typeKey, pi);
if (gAfter == pAfter) {
final SOCSetSpecialItem msg;
if (gAfter != null) {
msg = new SOCSetSpecialItem(ga, SOCSetSpecialItem.OP_SET, typeKey, gi, pi, gAfter);
pickCoord = gAfter.getCoordinates();
pickLevel = gAfter.getLevel();
pickSV = gAfter.getStringValue();
} else {
msg = new SOCSetSpecialItem(gaName, SOCSetSpecialItem.OP_CLEAR, typeKey, gi, pi, pn);
}
srv.messageToGame(gaName, msg);
} else {
// gi and pi don't share the same object; might need to send 2 messages out if both changed.
boolean hasgAfterCoordLevel = false;
if (gAfter == null) {
if (gBefore != null)
srv.messageToGame(gaName, new SOCSetSpecialItem(gaName, SOCSetSpecialItem.OP_CLEAR, typeKey, gi, -1, -1));
} else {
srv.messageToGame(gaName, new SOCSetSpecialItem(ga, SOCSetSpecialItem.OP_SET, typeKey, gi, -1, gAfter));
pickCoord = gAfter.getCoordinates();
pickLevel = gAfter.getLevel();
pickSV = gAfter.getStringValue();
hasgAfterCoordLevel = true;
}
if (pAfter == null) {
if (pBefore != null)
srv.messageToGame(gaName, new SOCSetSpecialItem(gaName, SOCSetSpecialItem.OP_CLEAR, typeKey, -1, pi, pn));
} else {
srv.messageToGame(gaName, new SOCSetSpecialItem(ga, SOCSetSpecialItem.OP_SET, typeKey, -1, pi, pAfter));
if (!hasgAfterCoordLevel) {
pickCoord = pAfter.getCoordinates();
pickLevel = pAfter.getLevel();
pickSV = pAfter.getStringValue();
}
}
}
}
srv.messageToGame(gaName, new SOCSetSpecialItem(gaName, SOCSetSpecialItem.OP_PICK, typeKey, gi, pi, pn, pickCoord, pickLevel, pickSV));
} else {
if (op == SOCSetSpecialItem.OP_CLEAR)
// get item before CLEAR
itm = ga.getSpecialItem(typeKey, gi, pi, pn);
paidCost = SOCSpecialItem.playerSetItem(typeKey, ga, pl, gi, pi, (op == SOCSetSpecialItem.OP_SET));
// if cost paid, send resource-loss first
if (paidCost && (itm != null))
handler.reportRsrcGainLoss(gaName, itm.getCost(), true, false, pn, -1, null, null);
// get item after SET, in case it's changed
if (op != SOCSetSpecialItem.OP_CLEAR)
itm = ga.getSpecialItem(typeKey, gi, pi, pn);
if ((op == SOCSetSpecialItem.OP_CLEAR) || (itm == null))
srv.messageToGame(gaName, new SOCSetSpecialItem(gaName, SOCSetSpecialItem.OP_CLEAR, typeKey, gi, pi, pn));
else
srv.messageToGame(gaName, new SOCSetSpecialItem(ga, op, typeKey, gi, pi, itm));
}
// check game state, check for winner
final int gstate = ga.getGameState();
if (gstate != prevState)
// might be OVER, if player won
handler.sendGameState(ga);
}
} catch (IllegalStateException e) {
sendDenyReply = true;
} catch (Exception e) {
D.ebugPrintStackTrace(e, "Exception caught");
} finally {
ga.releaseMonitor();
}
if (sendDenyReply)
c.put(new SOCSetSpecialItem(gaName, SOCSetSpecialItem.OP_DECLINE, typeKey, gi, pi, mes.playerNumber).toCmd());
}
use of soc.game.SOCPlayer in project JSettlers2 by jdmonin.
the class SOCGameMessageHandler method handleDISCARD.
/**
* handle "discard" message.
*
* @param c the connection that sent the message
* @param mes the message
* @since 1.0.0
*/
private void handleDISCARD(SOCGame ga, Connection c, final SOCDiscard mes) {
final String gn = ga.getName();
final SOCPlayer player = ga.getPlayer(c.getData());
final int pn;
if (player != null)
pn = player.getPlayerNumber();
else
// c's client no longer in the game
pn = -1;
ga.takeMonitor();
try {
if (player == null) {
// The catch block will print this out semi-nicely
throw new IllegalArgumentException("player not found in game");
}
if (ga.canDiscard(pn, mes.getResources())) {
// discard, change gameState
ga.discard(pn, mes.getResources());
// Same resource-loss messages are sent in handleROLLDICE after a pirate fleet attack (_SC_PIRI).
/**
* tell the player client that the player discarded the resources
*/
handler.reportRsrcGainLoss(gn, mes.getResources(), true, false, pn, -1, null, c);
/**
* tell everyone else that the player discarded unknown resources
*/
srv.messageToGameExcept(gn, c, new SOCPlayerElement(gn, pn, SOCPlayerElement.LOSE, SOCPlayerElement.UNKNOWN, mes.getResources().getTotal(), true), true);
srv.messageToGameKeyed(ga, true, "action.discarded", c.getData(), mes.getResources().getTotal());
/**
* send the new state, or end turn if was marked earlier as forced
*/
if ((ga.getGameState() != SOCGame.PLAY1) || !ga.isForcingEndTurn()) {
handler.sendGameState(ga);
// if state is WAITING_FOR_ROB_CHOOSE_PLAYER (_SC_PIRI), also sends CHOOSEPLAYERREQUEST
} else {
// already did ga.takeMonitor()
handler.endGameTurn(ga, player, true);
}
} else {
/**
* (TODO) there could be a better feedback message here
*/
srv.messageToPlayer(c, gn, "You can't discard that many cards.");
}
} catch (Throwable e) {
D.ebugPrintStackTrace(e, "Exception caught");
}
ga.releaseMonitor();
}
use of soc.game.SOCPlayer in project JSettlers2 by jdmonin.
the class SOCGameMessageHandler method handleREJECTOFFER.
/**
* handle "reject offer" message.
*
* @param c the connection that sent the message
* @param mes the message
* @since 1.0.0
*/
private void handleREJECTOFFER(SOCGame ga, Connection c, final SOCRejectOffer mes) {
SOCPlayer player = ga.getPlayer(c.getData());
if (player == null)
return;
final String gaName = ga.getName();
SOCRejectOffer rejectMessage = new SOCRejectOffer(gaName, player.getPlayerNumber());
srv.messageToGame(gaName, rejectMessage);
srv.recordGameEvent(gaName, rejectMessage);
}
use of soc.game.SOCPlayer in project JSettlers2 by jdmonin.
the class SOCGameMessageHandler method handleSIMPLEREQUEST.
/**
* Handle the "simple request" message.
* @param c the connection
* @param mes the message
* @since 1.1.18
*/
private void handleSIMPLEREQUEST(SOCGame ga, Connection c, final SOCSimpleRequest mes) {
final String gaName = ga.getName();
SOCPlayer clientPl = ga.getPlayer(c.getData());
if (clientPl == null)
return;
final int pn = mes.getPlayerNumber();
// probably required for most request types
final boolean clientIsPN = (pn == clientPl.getPlayerNumber());
final int reqtype = mes.getRequestType();
final int cpn = ga.getCurrentPlayerNumber();
// if true, reply with generic decline (pn = -1, reqtype, 0, 0)
boolean replyDecline = false;
switch(reqtype) {
case SOCSimpleRequest.SC_PIRI_FORT_ATTACK:
{
final SOCShip adjac = ga.canAttackPirateFortress();
if ((!clientIsPN) || (pn != cpn) || (adjac == null) || (adjac.getPlayerNumber() != cpn)) {
c.put(SOCSimpleRequest.toCmd(gaName, -1, reqtype, 0, 0));
// <--- early return: deny ---
return;
}
final int prevState = ga.getGameState();
final SOCPlayer cp = ga.getPlayer(cpn);
// in case some are lost, we'll announce that
final int prevNumWarships = cp.getNumWarships();
final SOCFortress fort = cp.getFortress();
final int[] res = ga.attackPirateFortress(adjac);
if (res.length > 1) {
// lost 1 or 2 ships adjacent to fortress. res[1] == adjac.coordinate
srv.messageToGame(gaName, new SOCRemovePiece(gaName, adjac));
if (res.length > 2)
srv.messageToGame(gaName, new SOCRemovePiece(gaName, cpn, SOCPlayingPiece.SHIP, res[2]));
final int n = cp.getNumWarships();
if (n != prevNumWarships)
srv.messageToGame(gaName, new SOCPlayerElement(gaName, cpn, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_WARSHIP_COUNT, n));
} else {
// player won
final int fortStrength = fort.getStrength();
srv.messageToGame(gaName, new SOCPieceValue(gaName, fort.getCoordinates(), fortStrength, 0));
if (0 == fortStrength)
srv.messageToGame(gaName, new SOCPutPiece(gaName, cpn, SOCPlayingPiece.SETTLEMENT, fort.getCoordinates()));
}
srv.messageToGame(gaName, new SOCSimpleAction(gaName, cpn, SOCSimpleAction.SC_PIRI_FORT_ATTACK_RESULT, res[0], res.length - 1));
// check for end of player's turn
if (!handler.checkTurn(c, ga)) {
handler.endGameTurn(ga, cp, false);
} else {
// still player's turn, even if they won
final int gstate = ga.getGameState();
if (gstate != prevState)
// might be OVER, if player won
handler.sendGameState(ga);
}
}
break;
case SOCSimpleRequest.TRADE_PORT_PLACE:
{
if (clientIsPN && (pn == cpn)) {
final int edge = mes.getValue1();
if ((ga.getGameState() == SOCGame.PLACING_INV_ITEM) && ga.canPlacePort(clientPl, edge)) {
final int ptype = ga.placePort(edge);
// PLAY1 or SPECIAL_BUILDING
handler.sendGameState(ga);
srv.messageToGame(gaName, new SOCSimpleRequest(gaName, cpn, SOCSimpleRequest.TRADE_PORT_PLACE, edge, ptype));
} else {
// client will print a text message, no need to send one
replyDecline = true;
}
} else {
srv.messageToPlayerKeyed(c, gaName, "reply.not.your.turn");
replyDecline = true;
}
}
break;
default:
// deny unknown types
replyDecline = true;
System.err.println("handleSIMPLEREQUEST: Unknown type " + reqtype + " from " + c.getData() + " in game " + ga);
}
if (replyDecline)
c.put(SOCSimpleRequest.toCmd(gaName, -1, reqtype, 0, 0));
}
use of soc.game.SOCPlayer in project JSettlers2 by jdmonin.
the class SOCGameMessageHandler method handlePICKRESOURCES.
/**
* handle "discovery pick" (while playing Discovery/Year of Plenty card) / Gold Hex resource pick message.
*
* @param c the connection that sent the message
* @param mes the message
* @since 1.0.0
*/
private void handlePICKRESOURCES(SOCGame ga, Connection c, final SOCPickResources mes) {
final String gaName = ga.getName();
final SOCResourceSet rsrcs = mes.getResources();
ga.takeMonitor();
final SOCPlayer player = ga.getPlayer(c.getData());
final int pn;
if (player != null)
pn = player.getPlayerNumber();
else
// c's client no longer in the game
pn = -1;
try {
if (player == null) {
// The catch block will print this out semi-nicely
throw new IllegalArgumentException("player not found in game");
}
final int gstate = ga.getGameState();
if (gstate == SOCGame.WAITING_FOR_DISCOVERY) {
if (handler.checkTurn(c, ga)) {
if (ga.canDoDiscoveryAction(rsrcs)) {
ga.doDiscoveryAction(rsrcs);
handler.reportRsrcGainLoss(gaName, rsrcs, false, false, pn, -1, null, null);
srv.messageToGameKeyedSpecial(ga, true, "action.card.discov.received", player.getName(), rsrcs);
// "{0} received {1,rsrcs} from the bank."
handler.sendGameState(ga);
} else {
// "That is not a legal Year of Plenty pick."
srv.messageToPlayerKeyed(c, gaName, "action.card.discov.notlegal");
}
} else {
// "It's not your turn."
srv.messageToPlayerKeyed(c, gaName, "reply.not.your.turn");
}
} else {
if (ga.canPickGoldHexResources(pn, rsrcs)) {
final boolean fromInitPlace = ga.isInitialPlacement();
final boolean fromPirateFleet = ga.isPickResourceIncludingPirateFleet(pn);
final int prevState = ga.pickGoldHexResources(pn, rsrcs);
final int newState = ga.getGameState();
/**
* tell everyone what the player gained
*/
handler.reportRsrcGainGold(ga, player, pn, rsrcs, false, !fromPirateFleet);
/**
* send the new state, or end turn if was marked earlier as forced
* -- for gold during initial placement, current player might also change.
*/
if ((gstate != SOCGame.PLAY1) || (newState == SOCGame.WAITING_FOR_DISCARDS) || !ga.isForcingEndTurn()) {
if (!fromInitPlace) {
handler.sendGameState(ga);
if (newState == SOCGame.WAITING_FOR_DISCARDS) {
// happens only in scenario _SC_PIRI, when 7 is rolled, player wins against pirate fleet
// and has picked their won resource, and then someone must discard
handler.sendGameState_sendDiscardRequests(ga, gaName);
}
} else {
switch(newState) {
case SOCGame.START1B:
case SOCGame.START2B:
case SOCGame.START3B:
// pl not changed: previously placed settlement, now placing road or ship
handler.sendGameState(ga);
break;
case SOCGame.START1A:
case SOCGame.START2A:
case SOCGame.START3A:
case SOCGame.ROLL_OR_CARD:
// Current player probably changed, announce new player if so
// with sendTurn and/or SOCRollDicePrompt
handler.sendTurnStateAtInitialPlacement(ga, player, c, prevState);
break;
}
}
} else {
// force-end game turn
// locking: already did ga.takeMonitor()
handler.endGameTurn(ga, player, true);
}
} else {
srv.messageToPlayer(c, gaName, "You can't pick that many resources.");
final int npick = player.getNeedToPickGoldHexResources();
if ((npick > 0) && (gstate < SOCGame.OVER))
srv.messageToPlayer(c, new SOCSimpleRequest(gaName, pn, SOCSimpleRequest.PROMPT_PICK_RESOURCES, npick));
else
srv.messageToPlayer(c, new SOCPlayerElement(gaName, pn, SOCPlayerElement.SET, SOCPlayerElement.NUM_PICK_GOLD_HEX_RESOURCES, 0));
}
}
} catch (Exception e) {
D.ebugPrintStackTrace(e, "Exception caught");
}
ga.releaseMonitor();
}
Aggregations