use of soc.game.SOCFortress 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.SOCFortress in project JSettlers2 by jdmonin.
the class SOCBoardAtServer method startGame_putInitPieces.
/**
* For scenario game option {@link SOCGameOption#K_SC_PIRI _SC_PIRI},
* place each player's initial pieces. For {@link SOCGameOption#K_SC_FTRI _SC_FTRI},
* set aside some dev cards to be claimed later at Special Edges.
* Otherwise do nothing.
*<P>
* For {@code _SC_PIRI}, also calls each player's {@link SOCPlayer#addLegalSettlement(int, boolean)}
* for their Lone Settlement location (adds layout part "LS").
* Vacant player numbers get 0 for their {@code "LS"} element.
*<P>
* Called only at server. For a method called during game start
* at server and clients, see {@link SOCGame#updateAtBoardLayout()}.
*<P>
* Called from {@link SOCGameHandler#startGame(SOCGame)} for those
* scenario game options; if you need it called for your game, add
* a check there for your scenario's {@link SOCGameOption}.
*<P>
* This is called after {@link #makeNewBoard(Map)} and before
* {@link SOCGameHandler#getBoardLayoutMessage}. So if needed,
* it can call {@link SOCBoardLarge#setAddedLayoutPart(String, int[])}.
*<P>
* If ship placement is restricted by the scenario, please call each player's
* {@link SOCPlayer#setRestrictedLegalShips(int[])} before calling this method,
* so the legal and potential arrays will be initialized.
*
* @see #getLegalSeaEdges(SOCGame, int)
*/
public void startGame_putInitPieces(SOCGame ga) {
if (ga.isGameOptionSet(SOCGameOption.K_SC_FTRI)) {
// Set aside dev cards for players to be given when reaching "CE" Special Edges.
final int cpn = ga.getCurrentPlayerNumber();
// to call buyDevCard without giving it to a player
ga.setCurrentPlayerNumber(-1);
drawStack = new Stack<Integer>();
final int n = FOR_TRI_DEV_CARD_EDGES[(ga.maxPlayers > 4) ? 1 : 0].length;
for (int i = 0; i < n; ++i) drawStack.push(ga.buyDevCard());
ga.setCurrentPlayerNumber(cpn);
return;
}
if (!ga.isGameOptionSet(SOCGameOption.K_SC_PIRI))
return;
final int gstate = ga.getGameState();
// prevent ga.putPiece from advancing turn
ga.setGameState(SOCGame.READY);
final int[] inits = PIR_ISL_INIT_PIECES[(ga.maxPlayers > 4) ? 1 : 0];
// lone possible-settlement node on the way to the island.
int[] possiLoneSettles = new int[ga.maxPlayers];
// vacant players will get 0 here, will not get free settlement, ship, or pirate fortress.
// iterate i only when player present, to avoid spacing gaps from vacant players
int i = 0;
for (int pn = 0; pn < ga.maxPlayers; ++pn) {
if (ga.isSeatVacant(pn))
continue;
SOCPlayer pl = ga.getPlayer(pn);
ga.putPiece(new SOCSettlement(pl, inits[i], this));
++i;
ga.putPiece(new SOCShip(pl, inits[i], this));
++i;
ga.putPiece(new SOCFortress(pl, inits[i], this));
++i;
possiLoneSettles[pn] = inits[i];
ga.getPlayer(pn).addLegalSettlement(inits[i], false);
++i;
}
setAddedLayoutPart("LS", possiLoneSettles);
ga.setGameState(gstate);
}
use of soc.game.SOCFortress in project JSettlers2 by jdmonin.
the class SOCPlayerTracker method updateScenario_SC_PIRI_closestShipToFortress.
/**
* For scenario {@code _SC_PIRI}, update the player's ship closest to their Fortress.
* Assumes no ship will ever be west of the fortress (smaller column number).
* Must be called after adding or removing a ship from our player's {@link SOCPlayer#getRoads()}.
* @param ship Ship that was added or removed, or {@code null} to check all ships after removal
* @param shipAdded True if {@code ship} was added; false if {@code ship} or any other ship was removed
* or if we're updating Closest Ship without adding or removing a ship
* @throws IllegalArgumentException if {@code shipAdded} is true, but null {@code ship}
* @since 2.0.00
*/
void updateScenario_SC_PIRI_closestShipToFortress(final SOCShip ship, final boolean shipAdded) throws IllegalArgumentException {
if (shipAdded && (ship == null))
throw new IllegalArgumentException();
if ((scen_SC_PIRI_closestShipToFortress == null) && (ship != null)) {
if (shipAdded)
// closest by default
scen_SC_PIRI_closestShipToFortress = ship;
// <--- Early return: no other ships to compare ---
return;
}
if (!shipAdded) {
if ((ship != null) && (scen_SC_PIRI_closestShipToFortress != null) && (ship.getCoordinates() != scen_SC_PIRI_closestShipToFortress.getCoordinates()))
// <--- Early return: Not the closest ship ---
return;
}
// may be null towards end of game
final SOCFortress fort = player.getFortress();
// If fort's null, we can still compare columns, just not rows, of ship coordinates.
final int fortR = (fort != null) ? (fort.getCoordinates() >> 8) : -1;
if (shipAdded) {
final int shipEdge = ship.getCoordinates(), prevShipEdge = scen_SC_PIRI_closestShipToFortress.getCoordinates();
final int shipR = shipEdge >> 8, shipC = shipEdge & 0xFF, prevR = prevShipEdge >> 8, prevC = prevShipEdge & 0xFF;
if ((shipC < prevC) || ((shipC == prevC) && (fortR != -1) && (Math.abs(shipR - fortR) < Math.abs(prevR - fortR)))) {
scen_SC_PIRI_closestShipToFortress = ship;
}
} else {
// A ship has been removed. We don't know which one.
// So, check all ships for distance from fortress.
Enumeration<SOCRoad> roadAndShipEnum = player.getRoads().elements();
SOCShip closest = null;
int closeR = -1, closeC = -1;
while (roadAndShipEnum.hasMoreElements()) {
final SOCRoad rs = roadAndShipEnum.nextElement();
if (!(rs instanceof SOCShip))
continue;
final int shipEdge = rs.getCoordinates();
final int shipR = shipEdge >> 8, shipC = shipEdge & 0xFF;
if ((closest == null) || (shipC < closeC) || ((shipC == closeC) && (fortR != -1) && (Math.abs(shipR - fortR) < Math.abs(closeR - fortR)))) {
closest = (SOCShip) rs;
closeR = shipR;
closeC = shipC;
}
}
// null if no ships
scen_SC_PIRI_closestShipToFortress = closest;
}
}
use of soc.game.SOCFortress in project JSettlers2 by jdmonin.
the class SOCPlayerTracker method getScenario_SC_PIRI_shipDistanceToFortress.
/**
* For scenario {@code _SC_PIRI}, get the distance of this player's closest ship from their
* {@code SOCFortress}. Since ships aren't placed diagonally, this is the distance along rows + columns.
* The edge (r,c) has node (r,c) as its left end, at distance 0.
* @param ship Any ship, including {@link #getScenario_SC_PIRI_closestShipToFortress()}
* @return row distance + column distance based on piece coordinates;
* or 0 if no fortress which would mean the fortress was reached
* (distance 0) and defeated already.
* @since 2.0.00
*/
public int getScenario_SC_PIRI_shipDistanceToFortress(final SOCShip ship) {
// may be null towards end of game
final SOCFortress fort = player.getFortress();
if (fort == null)
return 0;
final int fortNode = fort.getCoordinates(), shipEdge = ship.getCoordinates();
final int fortR = fortNode >> 8, fortC = fortNode & 0xFF, shipR = shipEdge >> 8, shipC = shipEdge & 0xFF;
return Math.abs(fortR - shipR) + Math.abs(fortC - shipC);
}
use of soc.game.SOCFortress in project JSettlers2 by jdmonin.
the class SOCBoardPanel method drawBoard.
/**
* Draw the whole board, including pieces and tooltip ({@link #hilight}, {@link #hoverTip}) if applicable.
* The basic board without pieces is drawn just once, then buffered.
* If the board layout changes (at start of game, for example),
* call {@link #flushBoardLayoutAndRepaint()} to clear the buffered copy.
*
* @see #drawBoardEmpty(Graphics)
*/
private void drawBoard(Graphics g) {
Image ebb = emptyBoardBuffer;
if (scaledMissedImage || ebb == null) {
if (ebb == null) {
ebb = createImage(scaledPanelW, scaledPanelH);
emptyBoardBuffer = ebb;
}
drawnEmptyAt = System.currentTimeMillis();
// drawBoardEmpty, drawHex will set this flag if missed
scaledMissedImage = false;
drawBoardEmpty(ebb.getGraphics());
ebb.flush();
if (scaledMissedImage && (scaledAt != 0) && (RESCALE_MAX_RETRY_MS < (drawnEmptyAt - scaledAt)))
// eventually give up scaling it
scaledMissedImage = false;
}
// draw ebb from local variable, not emptyBoardBuffer field, to avoid occasional NPE
g.setPaintMode();
g.drawImage(ebb, 0, 0, this);
// ask for antialiasing if available
if (g instanceof Graphics2D)
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
final boolean xlat = (panelMarginX != 0) || (panelMarginY != 0);
if (xlat)
g.translate(panelMarginX, panelMarginY);
final int gameState = game.getGameState();
if (board.getRobberHex() != -1) {
drawRobber(g, board.getRobberHex(), (gameState != SOCGame.PLACING_ROBBER), true);
}
if (board.getPreviousRobberHex() != -1) {
drawRobber(g, board.getPreviousRobberHex(), (gameState != SOCGame.PLACING_ROBBER), false);
}
if (isLargeBoard) {
int hex = ((SOCBoardLarge) board).getPirateHex();
if (hex > 0) {
drawRoadOrShip(g, hex, -2, (gameState == SOCGame.PLACING_PIRATE), false, false);
}
hex = ((SOCBoardLarge) board).getPreviousPirateHex();
if (hex > 0) {
drawRoadOrShip(g, hex, -3, (gameState == SOCGame.PLACING_PIRATE), false, false);
}
}
/**
* draw the roads and ships
*/
if (!game.isGameOptionSet(SOCGameOption.K_SC_PIRI)) {
for (SOCRoad r : board.getRoads()) {
drawRoadOrShip(g, r.getCoordinates(), r.getPlayerNumber(), false, !(r instanceof SOCShip), false);
}
} else {
for (int pn = 0; pn < game.maxPlayers; ++pn) {
final SOCPlayer pl = game.getPlayer(pn);
// count warships here, for efficiency, instead of calling SOCGame.isShipWarship for each one
int numWarships = pl.getNumWarships();
for (SOCRoad r : pl.getRoads()) {
final boolean isShip = (r instanceof SOCShip);
final boolean isWarship = isShip && (numWarships > 0);
drawRoadOrShip(g, r.getCoordinates(), pn, false, !isShip, isWarship);
if (isWarship)
// this works since warships begin with player's 1st-placed ship in getRoads()
--numWarships;
}
/**
* draw the player's fortress, if any
*/
SOCFortress fo = pl.getFortress();
if (fo != null)
drawFortress(g, fo, pn, false);
}
}
/**
* draw the settlements
*/
for (SOCSettlement s : board.getSettlements()) {
drawSettlement(g, s.getCoordinates(), s.getPlayerNumber(), false, false);
}
/**
* draw the cities
*/
for (SOCCity c : board.getCities()) {
drawCity(g, c.getCoordinates(), c.getPlayerNumber(), false);
}
if (xlat)
g.translate(-panelMarginX, -panelMarginY);
/**
* draw the current-player arrow after ("above") pieces,
* but below any hilighted piece, in case of overlap at
* edge of board. More likely on 6-player board for the
* two players whose handpanels are vertically centered.
*/
if (gameState != SOCGame.NEW) {
drawArrow(g, game.getCurrentPlayerNumber(), game.getCurrentDice());
}
if (player != null) {
if (xlat)
g.translate(panelMarginX, panelMarginY);
/**
* Draw the hilight when in interactive mode;
* No hilight when null player (before game started).
* The "hovering" road/settlement/city are separately painted
* in {@link soc.client.SOCBoardPanel.BoardToolTip#paint()}.
*/
switch(mode) {
case MOVE_SHIP:
if (moveShip_fromEdge != 0)
drawRoadOrShip(g, moveShip_fromEdge, -1, false, false, moveShip_isWarship);
case PLACE_ROAD:
case PLACE_INIT_ROAD:
case PLACE_FREE_ROAD_OR_SHIP:
if (hilight != 0) {
drawRoadOrShip(g, hilight, playerNumber, true, !hilightIsShip, (moveShip_isWarship && (moveShip_fromEdge != 0)));
}
break;
case PLACE_SETTLEMENT:
case PLACE_INIT_SETTLEMENT:
if (hilight > 0) {
drawSettlement(g, hilight, playerNumber, true, false);
}
break;
case PLACE_CITY:
if (hilight > 0) {
drawCity(g, hilight, playerNumber, true);
}
break;
case PLACE_SHIP:
if (hilight > 0) {
drawRoadOrShip(g, hilight, playerNumber, true, false, false);
}
break;
case CONSIDER_LM_SETTLEMENT:
case CONSIDER_LT_SETTLEMENT:
if (hilight > 0) {
drawSettlement(g, hilight, otherPlayer.getPlayerNumber(), true, false);
}
break;
case CONSIDER_LM_ROAD:
case CONSIDER_LT_ROAD:
if (hilight != 0) {
drawRoadOrShip(g, hilight, otherPlayer.getPlayerNumber(), false, true, false);
}
break;
case CONSIDER_LM_CITY:
case CONSIDER_LT_CITY:
if (hilight > 0) {
drawCity(g, hilight, otherPlayer.getPlayerNumber(), true);
}
break;
case PLACE_ROBBER:
if (hilight > 0) {
drawRobber(g, hilight, true, true);
}
break;
case PLACE_PIRATE:
if (hilight > 0) {
drawRoadOrShip(g, hilight, -2, false, false, false);
}
break;
case SC_FTRI_PLACE_PORT:
drawBoard_SC_FTRI_placePort(g);
break;
}
if (xlat)
g.translate(-panelMarginX, -panelMarginY);
}
if (superText1 != null) {
drawSuperText(g);
}
if (superTextTop != null) {
drawSuperTextTop(g);
}
}
Aggregations