use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class SOCBoardAtServer method makeNewBoard.
// //////////////////////////////////////////
//
// Make New Board
//
// To add a new board layout, see the class javadoc.
//
/**
* Shuffle the hex tiles and layout a board.
* Sets up land hex types, water, ports, dice numbers, Land Areas' contents, starting Land Area if any,
* and the legal/potential node sets ({@link SOCBoardLarge#getLegalSettlements()}).
* Sets up any Added Layout Parts such as {@code "PP", "CE", "VE", "N1"}, etc.
*<P>
* This is called at server, but not at client;
* client instead calls methods such as {@link #setLandHexLayout(int[])}
* and {@link #setLegalSettlements(Collection, int, HashSet[])},
* see {@link SOCBoardLarge} class javadoc.
* @param opts {@link SOCGameOption Game options}, which may affect
* tile placement on board, or null. <tt>opts</tt> must be
* the same as passed to constructor, and thus give the same size and layout
* (same {@link #getBoardEncodingFormat()}).
*/
@SuppressWarnings("unchecked")
@Override
public void makeNewBoard(final Map<String, SOCGameOption> opts) {
final SOCGameOption opt_breakClumps = (opts != null ? opts.get("BC") : null);
SOCGameOption opt = (opts != null ? opts.get(SOCGameOption.K_SC_FOG) : null);
final boolean hasScenarioFog = (opt != null) && opt.getBoolValue();
// scenario key, such as SOCScenario.K_SC_4ISL, or empty string
final String scen;
{
final SOCGameOption optSC = (opts != null ? opts.get("SC") : null);
if (optSC != null) {
final String ostr = optSC.getStringValue();
scen = (ostr != null) ? ostr : "";
} else {
scen = "";
}
}
/**
* _SC_4ISL doesn't require startingLandArea, it remains 0; all other scenarios require it.
*/
final boolean hasScenario4ISL = scen.equals(SOCScenario.K_SC_4ISL);
// For scenario boards, use 3-player or 4-player or 6-player layout?
// Always test maxPl for ==6 or < 4 ; actual value may be 6, 4, 3, or 2.
// Same maxPl initialization as in getBoardShift(opts) and getBoardSize(..).
final int maxPl;
if (maxPlayers == 6) {
maxPl = 6;
} else {
opt = (opts != null ? opts.get("PL") : null);
if (opt == null)
maxPl = 4;
else if (opt.getIntValue() > 4)
maxPl = 6;
else
maxPl = opt.getIntValue();
}
// unless hasScenario4ISL. Set that field now, in case a board-setup method wants it.
if (!hasScenario4ISL)
startingLandArea = 1;
// shuffle and place the land hexes, numbers, and robber:
// sets robberHex, contents of hexLayout[] and numberLayout[].
// Adds to landHexLayout and nodesOnLand.
// Clears cachedGetlandHexCoords.
// Also checks vs game option BC: Break up clumps of # or more same-type hexes/ports
// port types, or null if none
final int[] PORTS_TYPES_MAINLAND, PORTS_TYPES_ISLANDS;
// port edge locations and facings
final int[] PORT_LOC_FACING_MAINLAND, PORT_LOC_FACING_ISLANDS;
if (hasScenario4ISL) {
if (maxPl < 4) {
landAreasLegalNodes = new HashSet[5];
makeNewBoard_placeHexes(FOUR_ISL_LANDHEX_TYPE_3PL, FOUR_ISL_LANDHEX_COORD_3PL, FOUR_ISL_DICENUM_3PL, true, true, FOUR_ISL_LANDHEX_LANDAREA_RANGES_3PL, false, maxPl, opt_breakClumps, scen);
PORTS_TYPES_MAINLAND = FOUR_ISL_PORT_TYPE_3PL;
PORT_LOC_FACING_MAINLAND = FOUR_ISL_PORT_EDGE_FACING_3PL;
pirateHex = FOUR_ISL_PIRATE_HEX[0];
} else if (maxPl != 6) {
landAreasLegalNodes = new HashSet[5];
makeNewBoard_placeHexes(FOUR_ISL_LANDHEX_TYPE_4PL, FOUR_ISL_LANDHEX_COORD_4PL, FOUR_ISL_DICENUM_4PL, true, true, FOUR_ISL_LANDHEX_LANDAREA_RANGES_4PL, false, maxPl, opt_breakClumps, scen);
PORTS_TYPES_MAINLAND = FOUR_ISL_PORT_TYPE_4PL;
PORT_LOC_FACING_MAINLAND = FOUR_ISL_PORT_EDGE_FACING_4PL;
pirateHex = FOUR_ISL_PIRATE_HEX[1];
} else {
// Six Islands
landAreasLegalNodes = new HashSet[7];
makeNewBoard_placeHexes(FOUR_ISL_LANDHEX_TYPE_6PL, FOUR_ISL_LANDHEX_COORD_6PL, FOUR_ISL_DICENUM_6PL, true, true, FOUR_ISL_LANDHEX_LANDAREA_RANGES_6PL, false, maxPl, opt_breakClumps, scen);
PORTS_TYPES_MAINLAND = FOUR_ISL_PORT_TYPE_6PL;
PORT_LOC_FACING_MAINLAND = FOUR_ISL_PORT_EDGE_FACING_6PL;
pirateHex = FOUR_ISL_PIRATE_HEX[2];
}
PORT_LOC_FACING_ISLANDS = null;
PORTS_TYPES_ISLANDS = null;
} else if (scen.equals(SOCScenario.K_SC_TTD)) {
// Through The Desert
// 6-player, 4, or 3-player board
final int idx = (maxPl > 4) ? 2 : (maxPl > 3) ? 1 : 0;
// Land Area count varies by number of players;
// 2 + number of small islands. Array length has + 1 for unused landAreasLegalNodes[0].
landAreasLegalNodes = new HashSet[1 + 2 + (TTDESERT_LANDHEX_RANGES_SMALL[idx].length / 2)];
// - Desert strip (not part of any landarea)
{
final int[] desertLandHexCoords = TTDESERT_LANDHEX_COORD_DESERT[idx];
// all 0
final int[] desertDiceNum = new int[desertLandHexCoords.length];
final int[] desertLandhexType = new int[desertLandHexCoords.length];
Arrays.fill(desertLandhexType, DESERT_HEX);
makeNewBoard_placeHexes(desertLandhexType, desertLandHexCoords, desertDiceNum, false, false, 0, false, maxPl, null, scen);
}
// - Main island (landarea 1 and 2)
makeNewBoard_placeHexes(TTDESERT_LANDHEX_TYPE_MAIN[idx], TTDESERT_LANDHEX_COORD_MAIN[idx], TTDESERT_DICENUM_MAIN[idx], true, true, TTDESERT_LANDHEX_RANGES_MAIN[idx], false, maxPl, opt_breakClumps, scen);
// - Small islands (LA 3 to n)
makeNewBoard_placeHexes(TTDESERT_LANDHEX_TYPE_SMALL[idx], TTDESERT_LANDHEX_COORD_SMALL[idx], TTDESERT_DICENUM_SMALL[idx], true, true, TTDESERT_LANDHEX_RANGES_SMALL[idx], false, maxPl, null, scen);
pirateHex = TTDESERT_PIRATE_HEX[idx];
PORTS_TYPES_MAINLAND = TTDESERT_PORT_TYPE[idx];
PORTS_TYPES_ISLANDS = null;
PORT_LOC_FACING_MAINLAND = TTDESERT_PORT_EDGE_FACING[idx];
PORT_LOC_FACING_ISLANDS = null;
} else if (scen.equals(SOCScenario.K_SC_PIRI)) {
// Pirate Islands
landAreasLegalNodes = new HashSet[2];
// 4-player or 6-player board
final int idx = (maxPl > 4) ? 1 : 0;
// - Large starting island
makeNewBoard_placeHexes(PIR_ISL_LANDHEX_TYPE_MAIN[idx], PIR_ISL_LANDHEX_COORD_MAIN[idx], PIR_ISL_DICENUM_MAIN[idx], false, false, 1, false, maxPl, opt_breakClumps, scen);
// - Pirate islands
// (LA # 0: Player can't place there except at their Lone Settlement coordinate within "LS".)
makeNewBoard_placeHexes(PIR_ISL_LANDHEX_TYPE_PIRI[idx], PIR_ISL_LANDHEX_COORD_PIRI[idx], PIR_ISL_DICENUM_PIRI[idx], false, false, 0, false, maxPl, opt_breakClumps, scen);
pirateHex = PIR_ISL_PIRATE_HEX[idx];
PORTS_TYPES_MAINLAND = PIR_ISL_PORT_TYPE[idx];
PORTS_TYPES_ISLANDS = null;
PORT_LOC_FACING_MAINLAND = PIR_ISL_PORT_EDGE_FACING[idx];
PORT_LOC_FACING_ISLANDS = null;
setAddedLayoutPart("PP", PIR_ISL_PPATH[idx]);
} else if (scen.equals(SOCScenario.K_SC_FTRI)) {
// Forgotten Tribe
landAreasLegalNodes = new HashSet[2];
// 4-player or 6-player board
final int idx = (maxPl > 4) ? 1 : 0;
// - Larger main island
makeNewBoard_placeHexes(FOR_TRI_LANDHEX_TYPE_MAIN[idx], FOR_TRI_LANDHEX_COORD_MAIN[idx], FOR_TRI_DICENUM_MAIN[idx], true, true, 1, false, maxPl, opt_breakClumps, scen);
// - Small outlying islands for tribe
// (LA # 0; Player can't place there)
makeNewBoard_placeHexes(FOR_TRI_LANDHEX_TYPE_ISL[idx], FOR_TRI_LANDHEX_COORD_ISL[idx], null, false, false, 0, false, maxPl, null, scen);
pirateHex = FOR_TRI_PIRATE_HEX[idx];
// The 4-player board doesn't have enough 3-for-1 ports for that to work.
if (maxPl > 4) {
// PORTS_TYPES_MAINLAND breaks clumps
PORTS_TYPES_MAINLAND = FOR_TRI_PORT_TYPE[idx];
PORTS_TYPES_ISLANDS = null;
PORT_LOC_FACING_MAINLAND = FOR_TRI_PORT_EDGE_FACING[idx];
PORT_LOC_FACING_ISLANDS = null;
} else {
PORTS_TYPES_MAINLAND = null;
// PORTS_TYPES_ISLAND doesn't break clumps
PORTS_TYPES_ISLANDS = FOR_TRI_PORT_TYPE[idx];
PORT_LOC_FACING_MAINLAND = null;
PORT_LOC_FACING_ISLANDS = FOR_TRI_PORT_EDGE_FACING[idx];
}
setAddedLayoutPart("CE", FOR_TRI_DEV_CARD_EDGES[idx]);
setAddedLayoutPart("VE", FOR_TRI_SVP_EDGES[idx]);
// startGame_putInitPieces will set aside dev cards for players to reach "CE" special edges.
} else if (scen.equals(SOCScenario.K_SC_CLVI)) {
// Cloth Villages
landAreasLegalNodes = new HashSet[2];
// 4-player or 6-player board
final int idx = (maxPl > 4) ? 1 : 0;
// - Larger main islands
makeNewBoard_placeHexes(CLVI_LANDHEX_TYPE_MAIN[idx], CLVI_LANDHEX_COORD_MAIN[idx], CLVI_DICENUM_MAIN[idx], true, true, 1, false, maxPl, opt_breakClumps, scen);
// - Small middle islands for villages
// (LA # 0; Players can't place there)
makeNewBoard_placeHexes(CLVI_LANDHEX_TYPE_ISL[idx], CLVI_LANDHEX_COORD_ISL[idx], null, false, false, 0, false, maxPl, null, scen);
pirateHex = CLVI_PIRATE_HEX[idx];
// The 4-player board doesn't have enough 3-for-1 ports for that to work.
if (maxPl > 4) {
// PORTS_TYPES_MAINLAND breaks clumps
PORTS_TYPES_MAINLAND = CLVI_PORT_TYPE[idx];
PORTS_TYPES_ISLANDS = null;
PORT_LOC_FACING_MAINLAND = CLVI_PORT_EDGE_FACING[idx];
PORT_LOC_FACING_ISLANDS = null;
} else {
PORTS_TYPES_MAINLAND = null;
// PORTS_TYPES_ISLAND doesn't break clumps
PORTS_TYPES_ISLANDS = CLVI_PORT_TYPE[idx];
PORT_LOC_FACING_MAINLAND = null;
PORT_LOC_FACING_ISLANDS = CLVI_PORT_EDGE_FACING[idx];
}
final int[] cl = CLVI_CLOTH_VILLAGE_AMOUNTS_NODES_DICE[idx];
// also sets board's "general supply"
setVillageAndClothLayout(cl);
setAddedLayoutPart("CV", cl);
} else if (scen.equals(SOCScenario.K_SC_WOND)) {
// Wonders
landAreasLegalNodes = new HashSet[3];
// 4-player or 6-player board
final int idx = (maxPl > 4) ? 1 : 0;
// - Large main island
makeNewBoard_placeHexes(WOND_LANDHEX_TYPE_MAIN[idx], WOND_LANDHEX_COORD_MAIN[idx], WOND_DICENUM_MAIN[idx], true, true, 1, false, maxPl, opt_breakClumps, scen);
// - Desert on main island (not shuffled with other hexes)
int[] desert = new int[WOND_LANDHEX_COORD_DESERT[idx].length];
Arrays.fill(desert, DESERT_HEX);
makeNewBoard_placeHexes(desert, WOND_LANDHEX_COORD_DESERT[idx], null, false, false, 1, true, maxPl, null, scen);
// - Small outlying islands (LA #2)
makeNewBoard_placeHexes(WOND_LANDHEX_TYPE_ISL[idx], WOND_LANDHEX_COORD_ISL[idx], WOND_DICENUM_ISL[idx], false, false, 2, false, maxPl, null, scen);
pirateHex = 0;
// ports
// PORTS_TYPES_MAINLAND breaks clumps
PORTS_TYPES_MAINLAND = WOND_PORT_TYPE[idx];
PORTS_TYPES_ISLANDS = null;
PORT_LOC_FACING_MAINLAND = WOND_PORT_EDGE_FACING[idx];
PORT_LOC_FACING_ISLANDS = null;
// Will have to re-add after initial placement, via addLegalNodes from SOCGame.updateAtGameFirstTurn().
for (int i = 0; i <= 2; ++i) makeNewBoard_removeLegalNodes(WOND_SPECIAL_NODES[idx][i], startingLandArea, i + 1, (i == 2));
} else if (// _SC_FOG
hasScenarioFog) {
// for pirate: 3, 4, or 6-player board
final int idx;
landAreasLegalNodes = new HashSet[((maxPl == 6) ? 4 : 3)];
if (maxPl < 4) {
// - East and West islands:
makeNewBoard_placeHexes(FOG_ISL_LANDHEX_TYPE_MAIN_3PL, FOG_ISL_LANDHEX_COORD_MAIN_3PL, FOG_ISL_DICENUM_MAIN_3PL, true, true, 1, false, maxPl, opt_breakClumps, scen);
// - "Fog Island" in the middle:
makeNewBoard_placeHexes(FOG_ISL_LANDHEX_TYPE_FOG, FOG_ISL_LANDHEX_COORD_FOG_3PL, FOG_ISL_DICENUM_FOG_3PL, true, true, 2, false, maxPl, null, scen);
PORTS_TYPES_MAINLAND = FOG_ISL_PORT_TYPE_3PL;
PORT_LOC_FACING_MAINLAND = FOG_ISL_PORT_EDGE_FACING_3PL;
idx = 0;
} else if (maxPl == 4) {
// - East and West islands:
makeNewBoard_placeHexes(FOG_ISL_LANDHEX_TYPE_MAIN_4PL, FOG_ISL_LANDHEX_COORD_MAIN_4PL, FOG_ISL_DICENUM_MAIN_4PL, true, true, 1, false, maxPl, opt_breakClumps, scen);
// - "Fog Island" in the middle:
makeNewBoard_placeHexes(FOG_ISL_LANDHEX_TYPE_FOG, FOG_ISL_LANDHEX_COORD_FOG_4PL, FOG_ISL_DICENUM_FOG_4PL, true, true, 2, false, maxPl, null, scen);
PORTS_TYPES_MAINLAND = FOG_ISL_PORT_TYPE_4PL;
PORT_LOC_FACING_MAINLAND = FOG_ISL_PORT_EDGE_FACING_4PL;
idx = 1;
} else // maxPl == 6
{
// - Northern main island:
makeNewBoard_placeHexes(FOG_ISL_LANDHEX_TYPE_MAIN_6PL, FOG_ISL_LANDHEX_COORD_MAIN_6PL, FOG_ISL_DICENUM_MAIN_6PL, true, true, 1, false, maxPl, opt_breakClumps, scen);
// - "Fog Island" in an arc from southwest to southeast:
makeNewBoard_placeHexes(FOG_ISL_LANDHEX_TYPE_FOG_6PL, FOG_ISL_LANDHEX_COORD_FOG_6PL, FOG_ISL_DICENUM_FOG_6PL, true, true, 2, false, maxPl, opt_breakClumps, scen);
// - Gold Corners in southwest, southeast
makeNewBoard_placeHexes(FOG_ISL_LANDHEX_TYPE_GC, FOG_ISL_LANDHEX_COORD_GC, FOG_ISL_DICENUM_GC, false, false, 3, false, maxPl, null, scen);
PORTS_TYPES_MAINLAND = FOG_ISL_PORT_TYPE_6PL;
PORT_LOC_FACING_MAINLAND = FOG_ISL_PORT_EDGE_FACING_6PL;
idx = 2;
}
// no ports inside fog island's random layout
PORTS_TYPES_ISLANDS = null;
PORT_LOC_FACING_ISLANDS = null;
pirateHex = FOG_ISL_PIRATE_HEX[idx];
// Fog hex hiding is done below after some other steps; search for hasScenarioFog
} else if (scen.equals(SOCScenario.K_SC_NSHO)) {
// New Shores: Uses original 4- or 6-player board like fallback layout does, + outlying islands.
// 3pl has 4 LAs, 4pl has 4, 6pl has 7
landAreasLegalNodes = new HashSet[(maxPl == 6) ? 8 : 5];
// 3-player, 4-player, or 6-player board
final int idx = (maxPl == 6) ? 2 : (maxPl == 4) ? 1 : 0;
// - Main island:
makeNewBoard_placeHexes(NSHO_LANDHEX_TYPE_MAIN[idx], NSHO_LANDHEX_COORD_MAIN[idx], NSHO_DICENUM_MAIN[idx], (maxPl < 4), true, 1, false, maxPl, opt_breakClumps, scen);
// - Outlying islands:
makeNewBoard_placeHexes(NSHO_LANDHEX_TYPE_ISL[idx], NSHO_LANDHEX_COORD_ISL[idx], NSHO_DICENUM_ISL[idx], true, true, NSHO_LANDHEX_LANDAREA_RANGES[idx], false, maxPl, null, scen);
pirateHex = NSHO_PIRATE_HEX[idx];
// ports
PORTS_TYPES_MAINLAND = NSHO_PORT_TYPE[idx];
PORTS_TYPES_ISLANDS = null;
PORT_LOC_FACING_MAINLAND = NSHO_PORT_EDGE_FACING[idx];
PORT_LOC_FACING_ISLANDS = null;
} else {
// This is the fallback layout, the large sea board used when no scenario is chosen.
// Size is BOARDHEIGHT_LARGE by BOARDWIDTH_LARGE for 4 players.
// For 6 players, there's an extra row of hexes: BOARDHEIGHT_LARGE + 3.
// hardcoded max number of land areas
landAreasLegalNodes = new HashSet[5];
// - Mainland:
makeNewBoard_placeHexes((maxPl > 4) ? SOCBoard6p.makeNewBoard_landHexTypes_v2 : SOCBoard4p.makeNewBoard_landHexTypes_v1, (maxPl > 4) ? LANDHEX_DICEPATH_MAINLAND_6PL : LANDHEX_DICEPATH_MAINLAND_4PL, (maxPl > 4) ? SOCBoard6p.makeNewBoard_diceNums_v2 : SOCBoard4p.makeNewBoard_diceNums_v1, false, true, 1, false, maxPl, opt_breakClumps, scen);
// - Outlying islands:
makeNewBoard_placeHexes((maxPl > 4) ? LANDHEX_TYPE_ISLANDS_6PL : LANDHEX_TYPE_ISLANDS_4PL, (maxPl > 4) ? LANDHEX_COORD_ISLANDS_ALL_6PL : LANDHEX_COORD_ISLANDS_ALL_4PL, (maxPl > 4) ? LANDHEX_DICENUM_ISLANDS_6PL : LANDHEX_DICENUM_ISLANDS_4PL, true, true, (maxPl > 4) ? LANDHEX_LANDAREA_RANGES_ISLANDS_6PL : LANDHEX_LANDAREA_RANGES_ISLANDS_4PL, false, maxPl, null, scen);
PORTS_TYPES_MAINLAND = (maxPl > 4) ? SOCBoard6p.PORTS_TYPE_V2 : SOCBoard4p.PORTS_TYPE_V1;
PORTS_TYPES_ISLANDS = (maxPl > 4) ? PORT_TYPE_ISLANDS_6PL : PORT_TYPE_ISLANDS_4PL;
PORT_LOC_FACING_MAINLAND = (maxPl > 4) ? PORT_EDGE_FACING_MAINLAND_6PL : PORT_EDGE_FACING_MAINLAND_4PL;
PORT_LOC_FACING_ISLANDS = (maxPl > 4) ? PORT_EDGE_FACING_ISLANDS_6PL : PORT_EDGE_FACING_ISLANDS_4PL;
}
// Set up legalRoadEdges:
initLegalRoadsFromLandNodes();
initLegalShipEdges();
// consistency-check land areas
if (landAreasLegalNodes != null) {
for (int i = 1; i < landAreasLegalNodes.length; ++i) if (landAreasLegalNodes[i] == null)
throw new IllegalStateException("inconsistent landAreasLegalNodes: null idx " + i);
}
// Hide some land hexes behind fog, if the scenario does that
if (hasScenarioFog) {
final int[] FOGHEXES = (maxPl == 6) ? FOG_ISL_LANDHEX_COORD_FOG_6PL : ((maxPl < 4) ? FOG_ISL_LANDHEX_COORD_FOG_3PL : FOG_ISL_LANDHEX_COORD_FOG_4PL);
makeNewBoard_hideHexesInFog(FOGHEXES);
} else if (null != System.getProperty(PROP_JSETTLERS_DEBUG_BOARD_FOG)) {
// Select n random hexes (20% of landHexLayout):
// Knuth, "The Art of Computer Programming" Vol 2 Seminumerical Algorithms, Algorithm 3.4.2 S
int d = landHexLayout.size();
int n = (int) (d * .20f);
if (n == 0)
// round up
n = 1;
final int[] hideCoord = new int[n];
for (int hexcoord : landHexLayout) {
if (rand.nextFloat() <= (n / (float) d)) {
hideCoord[hideCoord.length - n] = hexcoord;
n -= 1;
if (n == 0)
break;
}
d -= 1;
}
makeNewBoard_hideHexesInFog(hideCoord);
}
if ((PORTS_TYPES_MAINLAND == null) && (PORTS_TYPES_ISLANDS == null)) {
// <--- Early return: No ports to place ---
return;
}
// check port locations & facings, make sure no overlap with land hexes
if (PORTS_TYPES_MAINLAND != null)
makeNewBoard_checkPortLocationsConsistent(PORT_LOC_FACING_MAINLAND);
if (PORT_LOC_FACING_ISLANDS != null)
makeNewBoard_checkPortLocationsConsistent(PORT_LOC_FACING_ISLANDS);
// copy and shuffle the ports, and check vs game option BC
int[] portTypes_main;
int[] portTypes_islands;
if (PORTS_TYPES_MAINLAND != null) {
final int ptL = PORTS_TYPES_MAINLAND.length, plfL = PORT_LOC_FACING_MAINLAND.length;
if ((2 * ptL) != plfL)
throw new IllegalArgumentException("Mismatched port-array lengths: PORT_LOC_FACING_MAINLAND (" + plfL + ") should be 2 x PORTS_TYPES_MAINLAND (" + ptL + ")");
portTypes_main = new int[ptL];
System.arraycopy(PORTS_TYPES_MAINLAND, 0, portTypes_main, 0, ptL);
if ((maxPl == 6) || !hasScenarioFog)
makeNewBoard_shufflePorts(portTypes_main, opt_breakClumps);
} else {
portTypes_main = null;
}
if (PORTS_TYPES_ISLANDS != null) {
final int ptL = PORTS_TYPES_ISLANDS.length, plfL = PORT_LOC_FACING_ISLANDS.length;
if ((2 * ptL) != plfL)
throw new IllegalArgumentException("Mismatched port-array lengths: PORT_LOC_FACING_ISLANDS (" + plfL + ") should be 2 x PORTS_TYPES_ISLANDS (" + ptL + ")");
portTypes_islands = new int[ptL];
System.arraycopy(PORTS_TYPES_ISLANDS, 0, portTypes_islands, 0, ptL);
makeNewBoard_shufflePorts(portTypes_islands, null);
} else {
portTypes_islands = null;
}
// copy port types to beginning of portsLayout[]
final int pcountMain = (PORTS_TYPES_MAINLAND != null) ? portTypes_main.length : 0;
portsCount = pcountMain;
if (PORTS_TYPES_ISLANDS != null)
portsCount += PORTS_TYPES_ISLANDS.length;
if ((portsLayout == null) || (portsLayout.length != (3 * portsCount)))
portsLayout = new int[3 * portsCount];
if (PORTS_TYPES_MAINLAND != null)
System.arraycopy(portTypes_main, 0, portsLayout, 0, pcountMain);
if (PORTS_TYPES_ISLANDS != null)
System.arraycopy(portTypes_islands, 0, portsLayout, pcountMain, portTypes_islands.length);
// place the ports (hex numbers and facing) within portsLayout[] and nodeIDtoPortType.
// fill out the ports[] vectors with node coordinates where a trade port can be placed.
nodeIDtoPortType = new HashMap<Integer, Integer>();
// - main island(s):
// i == port type array index
// j == port edge & facing array index
final int L = (portTypes_main != null) ? portTypes_main.length : 0;
if (L > 0) {
for (int i = 0, j = 0; i < L; ++i) {
// also == portsLayout[i]
final int ptype = portTypes_main[i];
final int edge = PORT_LOC_FACING_MAINLAND[j];
++j;
final int facing = PORT_LOC_FACING_MAINLAND[j];
++j;
final int[] nodes = getAdjacentNodesToEdge_arr(edge);
placePort(ptype, -1, facing, nodes[0], nodes[1]);
// portsLayout[i] is set already, from portTypes_main[i]
portsLayout[i + portsCount] = edge;
portsLayout[i + (2 * portsCount)] = facing;
}
}
// j == port edge & facing array index
if (PORTS_TYPES_ISLANDS != null) {
for (int i = 0, j = 0; i < PORTS_TYPES_ISLANDS.length; ++i) {
// also == portsLayout[i+L]
final int ptype = portTypes_islands[i];
final int edge = PORT_LOC_FACING_ISLANDS[j];
++j;
final int facing = PORT_LOC_FACING_ISLANDS[j];
++j;
final int[] nodes = getAdjacentNodesToEdge_arr(edge);
placePort(ptype, -1, facing, nodes[0], nodes[1]);
// portsLayout[L+i] is set already, from portTypes_islands[i]
portsLayout[L + i + portsCount] = edge;
portsLayout[L + i + (2 * portsCount)] = facing;
}
}
}
use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class NewGameOptionsFrame method clickScenarioInfo.
/**
* The "Scenario Info" button was clicked.
* Reads the current scenario, if any, from {@link #scenDropdown}.
* Calls {@link #showScenarioInfoDialog(SOCScenario, Map, int, SOCPlayerClient.GameAwtDisplay, Frame)}.
* @since 2.0.00
*/
private void clickScenarioInfo() {
if (scenDropdown == null)
// should not happen, scenDropdown is created before scenInfo
return;
final Object scObj = scenDropdown.getSelectedItem();
if ((scObj == null) || !(scObj instanceof SOCScenario))
// "(none)" item is a String, not a scenario
return;
final SOCScenario scen = (SOCScenario) scObj;
// find game's vp_winner
int vpWinner = SOCGame.VP_WINNER_STANDARD;
boolean vpKnown = false;
if (opts != null) {
SOCGameOption vp = opts.get("VP");
if (vp.getBoolValue()) {
vpWinner = vp.getIntValue();
vpKnown = true;
}
}
if (forNewGame && (!vpKnown) && scen.scOpts.contains("VP=")) {
final Map<String, SOCGameOption> scenOpts = SOCGameOption.parseOptionsToMap(scen.scOpts);
final SOCGameOption scOptVP = (scenOpts != null) ? scenOpts.get("VP") : null;
if (scOptVP != null)
vpWinner = scOptVP.getIntValue();
}
showScenarioInfoDialog(scen, null, vpWinner, gameDisplay, this);
}
use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class NewGameOptionsFrame method itemStateChanged.
/**
* Called when a Choice or Checkbox value changes (ItemListener).
* Used for these things:
*<UL>
* <LI>
* Set {@link SOCGameOption#userChanged}
* <LI>
* Check Choices or Checkboxes to see if their game option has a {@link SOCGameOption.ChangeListener ChangeListener}.
* <LI>
* Set the checkbox when the popup-menu Choice value is changed for a
* {@link SOCGameOption#OTYPE_INTBOOL} or {@link SOCGameOption#OTYPE_ENUMBOOL}.
* <LI>
* Update game option {@code "SC"} and the {@link #scenInfo} button when a scenario is picked
* from {@link #scenDropdown}. Other scenario-related updates are handled by this method calling
* {@link SOCGameOption.ChangeListener#valueChanged(SOCGameOption, Object, Object, Map)}.
*</UL>
* @param e itemevent from a Choice or Checkbox in {@link #controlsOpts}
*/
public void itemStateChanged(ItemEvent e) {
final Object ctrl = e.getSource();
SOCGameOption opt = controlsOpts.get(ctrl);
if (opt == null)
return;
boolean wasCBEvent = false, choiceSetCB = false;
Checkbox cb = boolOptCheckboxes.get(opt.key);
if ((cb != null) && (cb != ctrl)) {
// If the user picked a choice, also set the checkbox
// any item sets it
boolean wantsSet = true;
if (wantsSet != cb.getState()) {
cb.setState(wantsSet);
choiceSetCB = true;
}
} else if (ctrl instanceof Checkbox) {
wasCBEvent = true;
choiceSetCB = (e.getStateChange() == ItemEvent.SELECTED);
}
fireUserChangedOptListeners(opt, ctrl, choiceSetCB, wasCBEvent);
}
use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class NewGameOptionsFrame method initInterface_Options.
/**
* Interface setup: {@link SOCGameOption}s, user's client preferences, per-game local preferences.
* One row per option, except for 3-letter options which group with 2-letter ones.
* Boolean checkboxes go on the left edge; text and int/enum values are to right of checkboxes.
*<P>
* When showing options to create a new game, option keys starting with '_' are hidden
* unless the player nickname is "debug". This prevents unwanted changes to those options,
* which are set at the server during game creation. When the options are shown read-only
* during a game, these options are shown and not hidden.
*<P>
* Options which have {@link SOCGameOption#FLAG_INTERNAL_GAME_PROPERTY} are always hidden.
* If not {@link #readOnly}, they're removed from opts. Unknown opts are always removed.
*<P>
* This is called from constructor, so this is a new NGOF being shown.
* If not read-only, clear {@link SOCGameOption#userChanged} flag for
* each option in {@link #opts}.
*<P>
* If options are null, put a label with "This server version does not support game options" (localized).
*<P>
* Sets up local preferences for the client by calling
* {@link #initInterface_UserPrefs(JPanel, GridBagLayout, GridBagConstraints)}.
*/
private void initInterface_Options(JPanel bp, GridBagLayout gbl, GridBagConstraints gbc) {
final boolean hideUnderscoreOpts = (!readOnly) && (!gameDisplay.nick.getText().equalsIgnoreCase("debug"));
Label L;
if (opts == null) {
// "This server version does not support game options."
L = new Label(strings.get("game.options.not"));
L.setForeground(LABEL_TXT_COLOR);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbl.setConstraints(L, gbc);
bp.add(L);
initInterface_UserPrefs(bp, gbl, gbc);
// <---- Early return: no options ----
return;
} else if (!readOnly) {
for (SOCGameOption opt : opts.values()) // clear flag from any previously shown NGOF
opt.userChanged = false;
}
if (opts.containsKey("SC"))
allSc = SOCScenario.getAllKnownScenarios();
gbc.anchor = GridBagConstraints.WEST;
// Look for options that should be on the same
// line as other options (based on key length)
// instead of at the start of a line.
// TODO: for now these are on subsequent lines
// instead of sharing the same line.
// key=on-same-line opt, value=opt to start line
HashMap<String, String> sameLineOpts = new HashMap<String, String>();
for (final String kf3 : opts.keySet()) {
if (kf3.length() <= 2)
continue;
final String kf2 = kf3.substring(0, 2);
if (opts.containsKey(kf2))
sameLineOpts.put(kf3, kf2);
}
// Sort and lay out options; remove unknowns and internal-onlys from opts.
// TreeSet sorts game options by description, using gameopt.compareTo.
// The array lets us remove from opts without disrupting an iterator.
SOCGameOption[] optArr = new TreeSet<SOCGameOption>(opts.values()).toArray(new SOCGameOption[0]);
for (int i = 0; i < optArr.length; ++i) {
SOCGameOption op = optArr[i];
if (op.optType == SOCGameOption.OTYPE_UNKNOWN) {
opts.remove(op.key);
// <-- Removed, Go to next entry --
continue;
}
if (op.hasFlag(SOCGameOption.FLAG_INTERNAL_GAME_PROPERTY)) {
if (!readOnly)
// ignore internal-property options when requesting new game from client
opts.remove(op.key);
// <-- Don't show internal-property options
continue;
}
if (op.key.charAt(0) == '_') {
if (hideUnderscoreOpts)
// <-- Don't show options starting with '_'
continue;
if ((allSc != null) && allSc.containsKey(op.key.substring(1)))
// <-- Don't show options which are scenario names (use SC dropdown to pick at most one)
continue;
}
if (sameLineOpts.containsKey(op.key))
// <-- Shares a line, Go to next entry --
continue;
final boolean sharesLine = sameLineOpts.containsValue(op.key);
initInterface_OptLine(op, bp, gbl, gbc);
if (sharesLine) {
// TODO group on same line, not following lines, if there's only 1.
for (final String kf3 : sameLineOpts.keySet()) {
final String kf2 = sameLineOpts.get(kf3);
if ((kf2 == null) || !kf2.equals(op.key))
// <-- Goes with a a different option --
continue;
final SOCGameOption op3 = opts.get(kf3);
if (op3 != null)
initInterface_OptLine(op3, bp, gbl, gbc);
}
}
}
// for(opts)
initInterface_UserPrefs(bp, gbl, gbc);
}
use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class NewGameOptionsFrame method mouseClicked.
/**
* when an option with a boolValue's label is clicked, toggle its checkbox
*/
public void mouseClicked(MouseEvent e) {
SOCGameOption opt = controlsOpts.get(e.getSource());
if (opt == null)
return;
Checkbox cb = boolOptCheckboxes.get(opt.key);
if (cb == null)
return;
final boolean becameChecked = !cb.getState();
cb.setState(becameChecked);
opt.setBoolValue(becameChecked);
if (!opt.userChanged)
opt.userChanged = true;
SOCGameOption.ChangeListener cl = opt.getChangeListener();
if (cl == null)
return;
final Boolean newValue = (becameChecked) ? Boolean.TRUE : Boolean.FALSE;
final Boolean oldValue = (becameChecked) ? Boolean.FALSE : Boolean.TRUE;
fireOptionChangeListener(cl, opt, oldValue, newValue);
}
Aggregations