diff --git a/src/main/java/net/sf/rails/common/parser/Tag.java b/src/main/java/net/sf/rails/common/parser/Tag.java index f54e3bd7f..9011c0266 100644 --- a/src/main/java/net/sf/rails/common/parser/Tag.java +++ b/src/main/java/net/sf/rails/common/parser/Tag.java @@ -276,18 +276,24 @@ private void parseSubTags(Element element) throws ConfigurationException { value = attribute.getNodeValue(); attributes.put(name, value); } - } else if ( "IfOption".equalsIgnoreCase(childTagName)) { - Node nameAttr = nnp.getNamedItem("name"); - if (nameAttr == null) - throw new ConfigurationException( - "IfOption has no optionName attribute"); - name = nameAttr.getNodeValue(); - - Node parmAttr = nnp.getNamedItem("parm"); - if (parmAttr != null) { - value = parmAttr.getNodeValue(); - Iterable parameters = Splitter.on(XMLTags.VALUES_DELIM).split(value); - name = GameOption.constructParameterisedName(name, ImmutableList.copyOf(parameters)); + } else if ("IfOption".equalsIgnoreCase(childTagName) + || "IfVariant".equalsIgnoreCase(childTagName)) { + + if ("IfOption".equalsIgnoreCase(childTagName)) { + Node nameAttr = nnp.getNamedItem("name"); + if (nameAttr == null) + throw new ConfigurationException( + "IfOption has no optionName attribute"); + name = nameAttr.getNodeValue(); + + Node parmAttr = nnp.getNamedItem("parm"); + if (parmAttr != null) { + value = parmAttr.getNodeValue(); + Iterable parameters = Splitter.on(XMLTags.VALUES_DELIM).split(value); + name = GameOption.constructParameterisedName(name, ImmutableList.copyOf(parameters)); + } + } else { // IfVariant + name = "Variant"; } Node valueAttr = nnp.getNamedItem("value"); diff --git a/src/main/java/net/sf/rails/game/StartItem.java b/src/main/java/net/sf/rails/game/StartItem.java index 3ecae4193..463e2106f 100644 --- a/src/main/java/net/sf/rails/game/StartItem.java +++ b/src/main/java/net/sf/rails/game/StartItem.java @@ -37,6 +37,10 @@ public class StartItem extends RailsAbstractItem { protected int column = 0; protected int index; + // To allow the displayed name to include both primary and secondary. + // Default is the primary name (id) only. + protected String displayName = null; + // Bids protected final GenericState lastBidder = new GenericState<>(this, "lastBidder"); protected final Map bids = Maps.newHashMap(); @@ -271,6 +275,14 @@ public Certificate getSecondary() { return secondary; } + public String getDisplayName() { + return (displayName != null ? displayName : getId()); + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + /** * Get the start item base price. * diff --git a/src/main/java/net/sf/rails/game/StartPacket.java b/src/main/java/net/sf/rails/game/StartPacket.java index 55352d925..f24a16b73 100644 --- a/src/main/java/net/sf/rails/game/StartPacket.java +++ b/src/main/java/net/sf/rails/game/StartPacket.java @@ -30,6 +30,14 @@ public class StartPacket extends RailsAbstractItem { protected int minimumIncrement = 5; /** The modulus of all bids (i.e. of which value the bid must be a multiple) */ protected int modulus = 5; + /** Is multiple-column display enabled? + * If so, row and col attributes become mandatory for all start items + * (if the tag precedes all start items).*/ + protected boolean multipleColumns = false; + /** The number of columns. Will be derived from the column attributes. */ + protected int numberOfColumns = 1; + /** The number of rows. Will be derived from the row attributes, if multipleColumns is true. */ + protected int numberOfRows; /** Default name */ public static final String DEFAULT_ID = "Initial"; @@ -56,6 +64,12 @@ public static StartPacket create(RailsItem parent, String id, String roundClassN * @throws ConfigurationException if anything goes wrong. */ public void configureFromXML(Tag tag) throws ConfigurationException { + + // Multiple column display? + Tag columnsTag = tag.getChild("MultipleColumns"); + multipleColumns = columnsTag != null; + + // Bidding parameters, if applicable Tag biddingTag = tag.getChild("Bidding"); if (biddingTag != null) { minimumInitialIncrement = @@ -83,14 +97,27 @@ public void configureFromXML(Tag tag) throws ConfigurationException { int basePrice = itemTag.getAttributeAsInteger("basePrice", 0); boolean reduceable = itemTag.getAttributeAsBoolean("reduceable", false); - StartItem item = StartItem.create(this, itemName, itemType, basePrice, reduceable, index++, president); + StartItem item = StartItem.create(this, itemName, itemType, + basePrice, reduceable, index++, president); items.add(item); // Optional attributes int row = itemTag.getAttributeAsInteger("row", 0); - if (row > 0) item.setRow(row); + item.setRow(row); int column = itemTag.getAttributeAsInteger("column", 0); - if (column > 0) item.setColumn(column); + if (multipleColumns) { + if (!(row > 0 && column > 0)) { + throw new ConfigurationException( + "With multiple columns, both row and column attributes are required"); + } + item.setColumn(column); + numberOfRows = Math.max (numberOfRows, row); + numberOfColumns = Math.max (numberOfColumns, column); + } + + // Displayed name + String displayName = itemTag.getAttributeAsString("displayName", null); + if (displayName != null) item.setDisplayName(displayName); // Check if there is another certificate List subItemTags = itemTag.getChildren("SubItem"); @@ -241,4 +268,15 @@ public int getModulus() { return modulus; } + public boolean isMultipleColumns() { + return multipleColumns; + } + + public int getNumberOfColumns() { + return numberOfColumns; + } + + public int getNumberOfRows() { + return numberOfRows; + } } diff --git a/src/main/java/net/sf/rails/game/TileUpgrade.java b/src/main/java/net/sf/rails/game/TileUpgrade.java index bbe0e8269..72d424246 100644 --- a/src/main/java/net/sf/rails/game/TileUpgrade.java +++ b/src/main/java/net/sf/rails/game/TileUpgrade.java @@ -383,12 +383,13 @@ private Rotation processRotations(HexSide side) { log.debug("base={} target={}", base, target); } // check if there are stations to map - Map stationMapping = assignStations(base, target); + Map stationMapping = assignStations(base, target); // Try something else: match sides with old and new Stations in a simple way // Each pair of stations that matches with the same side is connected. // This finally appears to work for the 1837 green Vienna upgrade. // Though it may only work where both base and target tiles have a fixed orientation. + // (may be obsolete, now that automatic relay works better (see issue #341). if (stationMapping == null) { stationMapping = new HashMap<>(6); Station b, t; @@ -506,8 +507,11 @@ private Map assignStations(TrackConfig base, TrackConfig targe } } // check if all base and target stations are assigned - if (stationMap.keySet().size() != baseNb || - Sets.newHashSet(stationMap.values()).size() != targetNb) { + if (stationMap.keySet().size() != baseNb + /* Unclear why the all-stations-mapped check was applied to the new tile. + It inhibited upgrading 1837 Vienna to green (4 -> 6 stations). + || Sets.newHashSet(stationMap.values()).size() != targetNb*/ + ) { stationMap = null; log.debug("Mapping: Not all stations assigned, set stationMap to null"); } diff --git a/src/main/java/net/sf/rails/ui/swing/ORUIManager.java b/src/main/java/net/sf/rails/ui/swing/ORUIManager.java index c8349d122..0365cf276 100644 --- a/src/main/java/net/sf/rails/ui/swing/ORUIManager.java +++ b/src/main/java/net/sf/rails/ui/swing/ORUIManager.java @@ -788,8 +788,9 @@ private void relayBaseTokens (LayTile action) { Tile newTile = action.getLaidTile(); Tile oldTile = hex.getCurrentTile(); - // Why does that need to be configured? - // Shouldn't tokens always be relaid?? + // Check if manual token relay is required. + // This was an emergency measure in cases where automatic relay + // did not work (e.g. 1837 tile 427). Now probably obsolete. if (!action.isRelayBaseTokens() && !oldTile.relayBaseTokensOnUpgrade()) return; // is deprecated @@ -798,7 +799,6 @@ private void relayBaseTokens (LayTile action) { /* Check which tokens must be relaid, and in which sequence. * Ideally, the game engine should instruct the UI what to do * if there is more than one stop and more than one token. - * TODO LayTile does not yet allow that. * * For now, the only case that needs special handling is the 1835 BA home hex L6, * where it it possible to have two tokens laid before even one tile. diff --git a/src/main/java/net/sf/rails/ui/swing/StartRoundWindow.java b/src/main/java/net/sf/rails/ui/swing/StartRoundWindow.java index ff21f9440..64ec9db51 100644 --- a/src/main/java/net/sf/rails/ui/swing/StartRoundWindow.java +++ b/src/main/java/net/sf/rails/ui/swing/StartRoundWindow.java @@ -13,7 +13,6 @@ import net.sf.rails.game.*; import net.sf.rails.game.financial.*; import net.sf.rails.game.round.RoundFacade; -import net.sf.rails.game.special.SpecialProperty; import net.sf.rails.sound.SoundManager; import net.sf.rails.ui.swing.elements.*; import net.sf.rails.ui.swing.hexmap.HexHighlightMouseListener; @@ -64,26 +63,34 @@ public class StartRoundWindow extends JFrame implements ActionListener, KeyListe private GridBagConstraints gbc; // Grid elements per function - private Caption itemName[]; - private ClickField itemNameButton[]; - private int itemNameXOffset, itemNameYOffset; - private Field basePrice[]; - private int basePriceXOffset, basePriceYOffset; - private Field minBid[]; - private int minBidXOffset, minBidYOffset; - private Field bidPerPlayer[][]; - private int bidPerPlayerXOffset, bidPerPlayerYOffset; - private Field playerBids[]; - private int playerBidsXOffset, playerBidsYOffset; - private Field playerFree[]; - private int playerFreeCashXOffset, playerFreeCashYOffset; - private Field info[]; - private int infoXOffset, infoYOffset; - private Field itemStatus[]; // Remains invisible, only used for status tooltip - - private int playerCaptionXOffset, upperPlayerCaptionYOffset, lowerPlayerCaptionYOffset; - private Field upperPlayerCaption[]; - private Field lowerPlayerCaption[]; + private Caption[] itemName; + private ClickField[] itemNameButton; + private int[] itemNameXOffset; + private int itemNameYOffset; + private Field[] basePrice; + private int[] basePriceXOffset; + private int basePriceYOffset; + private Field[] minBid; + private int[] minBidXOffset; + private int minBidYOffset; + private Field[][] bidPerPlayer; + private int[] bidPerPlayerXOffset; + private int bidPerPlayerYOffset; + private Field[] playerBids; + private int[] playerBidsXOffset; + private int playerBidsYOffset; + private Field[] playerFree; + private int[] playerFreeCashXOffset; + private int playerFreeCashYOffset; + private Field[] info; + private int[] infoXOffset; + private int infoYOffset; + private Field[] itemStatus; // Remains invisible, only used for status tooltip + + private int[] playerCaptionXOffset; + private int upperPlayerCaptionYOffset, lowerPlayerCaptionYOffset; + private Field[][] upperPlayerCaption; + private Field[] lowerPlayerCaption; private JComponent[][] fields; private ActionButton bidButton; @@ -99,6 +106,11 @@ public class StartRoundWindow extends JFrame implements ActionListener, KeyListe private int[] crossIndex; protected StartRound round; private GameUIManager gameUIManager; + protected StartPacket startPacket; + protected boolean multipleColumns; + protected int numberOfColumns; + protected int numberOfRows; + protected int columnWidth = 0; // For the non-modal dialog to ask for a company starting share price. protected JDialog currentDialog; @@ -118,6 +130,15 @@ public class StartRoundWindow extends JFrame implements ActionListener, KeyListe public void init(StartRound round, GameUIManager parent) { //super(); this.round = round; + startPacket = round.getStartPacket(); + multipleColumns = startPacket.isMultipleColumns(); + if (multipleColumns) { + numberOfColumns = startPacket.getNumberOfColumns(); + numberOfRows = startPacket.getNumberOfRows(); + } else { + numberOfRows = round.getNumberOfStartItems(); + numberOfColumns = 1; + } includeBidding = round.hasBidding(); includeBuying = round.hasBuying(); showBasePrices = round.hasBasePrices(); @@ -227,6 +248,7 @@ private void initCells() { int np = players.getNumberOfPlayers(); int ni = round.getNumberOfStartItems(); + itemName = new Caption[ni]; itemNameButton = new ClickField[ni]; basePrice = new Field[ni]; @@ -234,91 +256,128 @@ private void initCells() { bidPerPlayer = new Field[ni][np]; info = new Field[ni]; itemStatus = new Field[ni]; - upperPlayerCaption = new Field[np]; + upperPlayerCaption = new Field[numberOfColumns][np]; lowerPlayerCaption = new Field[np]; playerBids = new Field[np]; playerFree = new Field[np]; + itemNameXOffset = new int[numberOfColumns]; + if (showBasePrices) basePriceXOffset = new int[numberOfColumns]; + if (includeBidding == StartRound.Bidding.ON_ITEMS) minBidXOffset = new int[numberOfColumns]; + bidPerPlayerXOffset = new int[numberOfColumns]; + playerCaptionXOffset = new int[numberOfColumns]; + infoXOffset = new int[numberOfColumns]; + if (includeBidding != StartRound.Bidding.NO) playerBidsXOffset = new int[numberOfColumns]; + playerFreeCashXOffset = new int[numberOfColumns]; + upperPlayerCaptionYOffset = ++lastY; - itemNameXOffset = ++lastX; - itemNameYOffset = ++lastY; - if (showBasePrices) { - basePriceXOffset = ++lastX; - basePriceYOffset = lastY; - } - if (includeBidding == StartRound.Bidding.ON_ITEMS) { - minBidXOffset = ++lastX; - minBidYOffset = lastY; - } - bidPerPlayerXOffset = playerCaptionXOffset = ++lastX; - bidPerPlayerYOffset = lastY; + for (int col = 0; col < numberOfColumns; col++) { + itemNameXOffset[col] = ++lastX; + if (col == 0) itemNameYOffset = ++lastY; + if (showBasePrices) { + basePriceXOffset[col] = ++lastX; + if (col == 0) basePriceYOffset = lastY; + } + if (includeBidding == StartRound.Bidding.ON_ITEMS) { + minBidXOffset[col] = ++lastX; + if (col == 0) minBidYOffset = lastY; + } + bidPerPlayerXOffset[col] = playerCaptionXOffset[col] = ++lastX; + if (col == 0) bidPerPlayerYOffset = lastY; + + infoXOffset[col] = bidPerPlayerXOffset[col] + np; + lastX += np; + if (col == 0) { + infoYOffset = lastY; + columnWidth = lastX + 1; + } - infoXOffset = bidPerPlayerXOffset + np; - infoYOffset = lastY; - // Bottom rows - lastY += (ni - 1); - if (includeBidding != StartRound.Bidding.NO) { - playerBidsXOffset = bidPerPlayerXOffset; - playerBidsYOffset = ++lastY; - } - playerFreeCashXOffset = bidPerPlayerXOffset; - playerFreeCashYOffset = ++lastY; + // Bottom rows + lastY += (numberOfRows - 1); + if (includeBidding != StartRound.Bidding.NO) { + playerBidsXOffset[col] = bidPerPlayerXOffset[col]; + if (col == 0) playerBidsYOffset = ++lastY; + } + playerFreeCashXOffset[col] = bidPerPlayerXOffset[col]; - lowerPlayerCaptionYOffset = ++lastY; + if (col == 0) { + playerFreeCashYOffset = ++lastY; + lowerPlayerCaptionYOffset = ++lastY; - fields = new JComponent[1 + infoXOffset][2 + lastY]; + fields = new JComponent[columnWidth * numberOfColumns][2 + lastY]; + log.debug("Columns={} (width/col={} nbOfCol={}) rows={}", columnWidth * numberOfColumns, + columnWidth, numberOfColumns, 2 + lastY); + } - addField(new Caption(LocalText.getText("ITEM")), 0, 0, 1, 2, - WIDE_RIGHT + WIDE_BOTTOM); - if (showBasePrices) { - addField(new Caption(LocalText.getText(includeBidding == StartRound.Bidding.ON_ITEMS - ? "BASE_PRICE" : "PRICE")), basePriceXOffset, 0, 1, 2, - WIDE_BOTTOM); - } - if (includeBidding == StartRound.Bidding.ON_ITEMS) { - addField(new Caption(LocalText.getText("MINIMUM_BID")), - minBidXOffset, 0, 1, 2, WIDE_BOTTOM + WIDE_RIGHT); - } - addField(new Caption(LocalText.getText("PLAYERS")), - playerCaptionXOffset, 0, np, 1, 0); - for (int i = 0; i < np; i++) { - upperPlayerCaption[i] = new Field(players.getPlayerByPosition(i).getPlayerNameModel()); - addField(upperPlayerCaption[i], playerCaptionXOffset + i, upperPlayerCaptionYOffset, 1, 1, WIDE_BOTTOM); + addField(new Caption(LocalText.getText("ITEM")), + itemNameXOffset[col], 0, 1, 2, + WIDE_LEFT + WIDE_RIGHT + WIDE_BOTTOM); + + if (showBasePrices) { + addField(new Caption(LocalText.getText(includeBidding == StartRound.Bidding.ON_ITEMS + ? "BASE_PRICE" : "PRICE")), basePriceXOffset[col], 0, 1, 2, + WIDE_BOTTOM); + } + if (includeBidding == StartRound.Bidding.ON_ITEMS) { + addField(new Caption(LocalText.getText("MINIMUM_BID")), + minBidXOffset[col], 0, 1, 2, WIDE_BOTTOM + WIDE_RIGHT); + } + addField(new Caption(LocalText.getText("PLAYERS")), + playerCaptionXOffset[col], 0, np, 1, 0); + for (int i = 0; i < np; i++) { + upperPlayerCaption[col][i] = new Field(players.getPlayerByPosition(i).getPlayerNameModel()); + addField(upperPlayerCaption[col][i], playerCaptionXOffset[col] + i, + upperPlayerCaptionYOffset, 1, 1, WIDE_BOTTOM); + } } + int row, col; for (int i = 0; i < ni; i++) { final StartItem si = round.getStartItem(i); - itemName[i] = new Caption(si.getId()); + if (multipleColumns) { + row = si.getRow() - 1; + col = si.getColumn() - 1; + } else { + row = i; + col = 0; + } + + itemName[i] = new Caption(si.getDisplayName()); HexHighlightMouseListener.addMouseListener(itemName[i], gameUIManager.getORUIManager(), si); - addField(itemName[i], itemNameXOffset, itemNameYOffset + i, 1, 1, WIDE_RIGHT); + addField(itemName[i], itemNameXOffset[col], itemNameYOffset + row, + 1, 1, WIDE_LEFT + WIDE_RIGHT); - itemNameButton[i] = new ClickField(si.getId(), "", "", this, itemGroup); + itemNameButton[i] = new ClickField(si.getDisplayName(), "", "", this, itemGroup); HexHighlightMouseListener.addMouseListener(itemNameButton[i], gameUIManager.getORUIManager(), si); - addField(itemNameButton[i], itemNameXOffset, itemNameYOffset + i, 1, 1, WIDE_RIGHT); + addField(itemNameButton[i], itemNameXOffset[col], itemNameYOffset + row, + 1, 1, WIDE_LEFT + WIDE_RIGHT); // Prevent row height resizing after every buy action itemName[i].setPreferredSize(itemNameButton[i].getPreferredSize()); if (showBasePrices) { basePrice[i] = new Field(si.getBasePriceModel()); - addField(basePrice[i], basePriceXOffset, basePriceYOffset + i, 1, 1, 0); + addField(basePrice[i], basePriceXOffset[col], basePriceYOffset + row, + 1, 1, 0); } if (includeBidding == StartRound.Bidding.ON_ITEMS) { minBid[i] = new Field(round.getMinimumBidModel(i)); - addField(minBid[i], minBidXOffset, minBidYOffset + i, 1, 1, WIDE_RIGHT); + addField(minBid[i], minBidXOffset[col], minBidYOffset + row, + 1, 1, WIDE_RIGHT); } for (int j = 0; j < np; j++) { bidPerPlayer[i][j] = new Field(round.getBidModel(i, players.getPlayerByPosition(j))); - addField(bidPerPlayer[i][j], bidPerPlayerXOffset + j, bidPerPlayerYOffset + i, 1, 1, 0); + addField(bidPerPlayer[i][j], bidPerPlayerXOffset[col] + j, bidPerPlayerYOffset + row, + 1, 1, 0); } info[i] = new Field(infoIcon); - //info[i].setToolTipText(getStartItemDescription(si)); + Certificate cert = si.getPrimary(); Company comp = null; if (cert instanceof PublicCertificate) { @@ -330,7 +389,7 @@ private void initCells() { "" + comp.getType().getId() + " company: "); info[i].setToolTipText(infoText); HexHighlightMouseListener.addMouseListener(info[i], gameUIManager.getORUIManager(), si); - addField(info[i], infoXOffset, infoYOffset + i, 1, 1, WIDE_LEFT); + addField(info[i], infoXOffset[col], infoYOffset + row, 1, 1, WIDE_LEFT + WIDE_RIGHT); // Invisible field, only used to hold current item status. itemStatus[i] = new Field(si.getStatusModel()); @@ -339,11 +398,13 @@ private void initCells() { // Player money boolean firstBelowTable = true; if (includeBidding != StartRound.Bidding.NO) { - addField(new Caption(LocalText.getText("BID")), playerBidsXOffset - 1, playerBidsYOffset, 1, 1, WIDE_TOP + WIDE_RIGHT); + addField(new Caption(LocalText.getText("BID")), playerBidsXOffset[0] - 1, playerBidsYOffset, + 1, 1, WIDE_TOP + WIDE_RIGHT); for (int i = 0; i < np; i++) { playerBids[i] = new Field(round.getBlockedCashModel(players.getPlayerByPosition(i))); - addField(playerBids[i], playerBidsXOffset + i, playerBidsYOffset, 1, 1, WIDE_TOP); + addField(playerBids[i], playerBidsXOffset[0] + i, playerBidsYOffset, + 1, 1, WIDE_TOP); } firstBelowTable = false; @@ -351,18 +412,18 @@ private void initCells() { addField(new Caption( LocalText.getText(includeBidding != StartRound.Bidding.NO ? "FREE" : "CASH")), - playerFreeCashXOffset - 1, playerFreeCashYOffset, 1, 1, + playerFreeCashXOffset[0] - 1, playerFreeCashYOffset, 1, 1, WIDE_RIGHT + (firstBelowTable ? WIDE_TOP : 0)); for (int i = 0; i < np; i++) { playerFree[i] = new Field(includeBidding != StartRound.Bidding.NO ? round.getFreeCashModel(players.getPlayerByPosition(i)) : players.getPlayerByPosition(i).getWallet()); - addField(playerFree[i], playerFreeCashXOffset + i, playerFreeCashYOffset, 1, 1, firstBelowTable ? WIDE_TOP : 0); + addField(playerFree[i], playerFreeCashXOffset[0] + i, playerFreeCashYOffset, 1, 1, firstBelowTable ? WIDE_TOP : 0); } for (int i = 0; i < np; i++) { lowerPlayerCaption[i] = new Field(players.getPlayerByPosition(i).getPlayerNameModel()); - addField(lowerPlayerCaption[i], playerFreeCashXOffset + i, playerFreeCashYOffset + 1, 1, 1, WIDE_TOP); + addField(lowerPlayerCaption[i], playerFreeCashXOffset[0] + i, playerFreeCashYOffset + 1, 1, 1, WIDE_TOP); } dummyButton = new ClickField("", "", "", this, itemGroup); @@ -722,13 +783,13 @@ public void close() { } public void setSRPlayerTurn() { + int playerIndex = players.getCurrentPlayer().getIndex(); for (int i = 0; i < players.getNumberOfPlayers(); i++) { - upperPlayerCaption[i].setHighlight(false); - lowerPlayerCaption[i].setHighlight(false); + for (int j = 0; j < numberOfColumns; j++) { + upperPlayerCaption[j][i].setHighlight(i == playerIndex); + } + lowerPlayerCaption[i].setHighlight(i == playerIndex); } - - upperPlayerCaption[players.getCurrentPlayer().getIndex()].setHighlight(true); - lowerPlayerCaption[players.getCurrentPlayer().getIndex()].setHighlight(true); } private void setItemNameButton(int i, boolean clickable) { @@ -807,6 +868,9 @@ public boolean process(PossibleAction action) { } public void updatePlayerOrder(List newPlayerNames) { + + // Multiple columns are here ignored for now. + // When is this called? int np = players.getNumberOfPlayers(); int[] xref = new int[np]; @@ -822,18 +886,20 @@ public void updatePlayerOrder(List newPlayerNames) { GridBagConstraints[] constraints = new GridBagConstraints[np]; JComponent f; for (int y = upperPlayerCaptionYOffset; y <= lowerPlayerCaptionYOffset; y++) { - for (int i = 0, x = playerCaptionXOffset; i < np; i++, x++) { + for (int i = 0, x = playerCaptionXOffset[0]; i < np; i++, x++) { cells[i] = fields[x][y]; constraints[i] = gb.getConstraints(cells[i]); statusPanel.remove(cells[i]); } - for (int i = 0, x = playerCaptionXOffset; i < np; i++, x++) { + for (int i = 0, x = playerCaptionXOffset[0]; i < np; i++, x++) { f = fields[x][y] = cells[xref[i]]; statusPanel.add(f, constraints[i]); } } - for (int i = 0, x = playerCaptionXOffset; i < np; i++, x++) { - upperPlayerCaption[i] = (Field) fields[x][upperPlayerCaptionYOffset]; + for (int i = 0, x = playerCaptionXOffset[0]; i < np; i++, x++) { + for (int col = 0; col < numberOfColumns; col++) { + upperPlayerCaption[col][i] = (Field) fields[x][upperPlayerCaptionYOffset]; + } lowerPlayerCaption[i] = (Field) fields[x][lowerPlayerCaptionYOffset]; } diff --git a/src/main/resources/data/1835/CompanyManager.xml b/src/main/resources/data/1835/CompanyManager.xml index a8b7405c4..1e29c0a34 100644 --- a/src/main/resources/data/1835/CompanyManager.xml +++ b/src/main/resources/data/1835/CompanyManager.xml @@ -230,25 +230,26 @@ - + + - - + + - - - - - - - - - + + + + + + + + + - + diff --git a/src/main/resources/data/1837/CompanyManager.xml b/src/main/resources/data/1837/CompanyManager.xml index db4bf1202..f88c67aae 100644 --- a/src/main/resources/data/1837/CompanyManager.xml +++ b/src/main/resources/data/1837/CompanyManager.xml @@ -401,31 +401,32 @@ + - + - + - + - + - + @@ -460,26 +461,26 @@ - + - + - + - + - + diff --git a/src/main/resources/data/1837/Game.xml b/src/main/resources/data/1837/Game.xml index 6f7c7feca..950929304 100644 --- a/src/main/resources/data/1837/Game.xml +++ b/src/main/resources/data/1837/Game.xml @@ -1,225 +1,220 @@ - - - - - - - - - - - - - - - - - --> - - - --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/data/1837/TileSet.xml b/src/main/resources/data/1837/TileSet.xml index 46bd368e1..2f7d82c2f 100644 --- a/src/main/resources/data/1837/TileSet.xml +++ b/src/main/resources/data/1837/TileSet.xml @@ -49,13 +49,13 @@ - + - + diff --git a/src/main/resources/data/GamesList.xml b/src/main/resources/data/GamesList.xml index 737477047..8bc01bbca 100644 --- a/src/main/resources/data/GamesList.xml +++ b/src/main/resources/data/GamesList.xml @@ -222,8 +222,7 @@ Published 2004 by Deep Thought Games, LLC Known limitations: - Buying the KK and Ug minors in subsequent Start rounds does not work well. These rounds should be changed to Stock Rounds. - - Multiple-city green upgrades often need tokens to be replaced manually. - - Not yet tested after the 3-train phase. + - Not yet tested beyond the 3-train phase.