From: Erik V. <ev...@us...> - 2011-11-20 19:39:58
|
LocalisedText.properties | 3 rails/game/Portfolio.java | 62 ++++++++++---- rails/game/PublicCompany.java | 6 - rails/game/ShareSellingRound.java | 51 +++++------- rails/game/StockRound.java | 97 +++++++++++++---------- rails/game/TreasuryShareRound.java | 77 ++++++++---------- rails/game/action/SellShares.java | 72 ++++++++++------- rails/game/specific/_1856/CGRFormationRound.java | 64 +++++++-------- rails/ui/swing/GameStatus.java | 20 +++- 9 files changed, 260 insertions(+), 192 deletions(-) New commits: commit 554e75af4992262c38260eb28fc0a4ed8071d174 Merge: eaa0aa5 605008e Author: Erik Vos <eri...@xs...> Date: Sun Nov 20 19:41:35 2011 +0100 Merge branch 'master' of ssh://rails.git.sourceforge.net/gitroot/rails/rails commit eaa0aa5957c29448c317bcdec0edb0fc28bebdc8 Author: Erik Vos <eri...@xs...> Date: Sun Nov 20 17:37:39 2011 +0100 1835 fix: allow dumped president's share to be exchanged against a 20% share. diff --git a/LocalisedText.properties b/LocalisedText.properties index 6516a23..d957c20 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -560,7 +560,8 @@ SELL=Sell SELL_SHARE_LOG={0} sells a {1}% share of {2} to Pool for {3}. SELL_SHARES_LOG={0} sells {1} {2}% shares ({3}%) of {4} to Pool for {5}. SellHowManyShares=Sell how many shares? -SellShares=Sell {0} {1}% share(s) ({2}%) of {3} for {4} +SellShares=Sell {0} {1}% certificates(s) ({2}%) of {3} for {4} +SellSharesWithSwap=Sell {0} {1}% certificates(s) ({2}%) of {3} for {4}, swapping president for {5} {6}% certificate(s). SeparateSalesAtSamePrice=Allow separate sales at same price SET_REVENUE=Set Revenue SET_SCALE=Set Scale diff --git a/rails/game/Portfolio.java b/rails/game/Portfolio.java index 5630a8e..d2c7b23 100644 --- a/rails/game/Portfolio.java +++ b/rails/game/Portfolio.java @@ -75,7 +75,7 @@ public class Portfolio implements TokenHolder, MoveableHolder { protected String name; /** Unique name (including owner class name) */ protected String uniqueName; - + GameManagerI gameManager; /** Specific portfolio names */ @@ -199,8 +199,8 @@ public class Portfolio implements TokenHolder, MoveableHolder { ((Player)owner).updateWorth(); } } - - public ShareModel getShareModel(PublicCompanyI company) { + + public ShareModel getShareModel(PublicCompanyI company) { if (!shareModelPerCompany.containsKey(company)) { shareModelPerCompany.put(company, new ShareModel(this, company)); @@ -246,6 +246,26 @@ public class Portfolio implements TokenHolder, MoveableHolder { } } + /** Return an array of length 5 that contains:<br> + * - in element [0]: 1 if there is a presidency, 0 if not (but see below);<br> + * - in element [1]: number of non-president certificates of size 1 (number of share units);<br> + * - in element [2]: number of non-president certificates of size 2;<br> + * - etc. + * @param compName Company name + * @param includePresident True if the president certificate must also be included in the other counts. + * @return integer array + */ + public int[] getCertificateTypeCountsPerCompany (String compName, boolean includePresident) { + int[] uniqueCertCounts = new int[5]; + for (PublicCertificateI cert : getCertificatesPerCompany(compName)) { + if (!cert.isPresidentShare() || includePresident) { + ++uniqueCertCounts[cert.getShares()]; + } + if (cert.isPresidentShare()) uniqueCertCounts[0] = 1; + } + return uniqueCertCounts; + } + /** * Find a certificate for a given company. * @@ -371,17 +391,27 @@ public class Portfolio implements TokenHolder, MoveableHolder { */ public List<PublicCertificateI> swapPresidentCertificate( PublicCompanyI company, Portfolio other) { + return swapPresidentCertificate (company, other, 0); + } + + public List<PublicCertificateI> swapPresidentCertificate( + PublicCompanyI company, Portfolio other, int swapShareSize) { List<PublicCertificateI> swapped = new ArrayList<PublicCertificateI>(); PublicCertificateI swapCert; // Find the President's certificate - PublicCertificateI cert = this.findCertificate(company, true); - if (cert == null) return null; - int shares = cert.getShares(); + PublicCertificateI presCert = this.findCertificate(company, true); + if (presCert == null) return null; + int shares = presCert.getShares(); - // Check if counterparty has enough single certificates - if (other.ownsCertificates(company, 1, false) >= shares) { + // If a double cert is requested, try that first + if (swapShareSize > 1 && other.ownsCertificates(company, swapShareSize, false)*swapShareSize >= shares) { + swapCert = other.findCertificate(company, swapShareSize, false); + swapCert.moveTo(this); + swapped.add(swapCert); + } else if (other.ownsCertificates(company, 1, false) >= shares) { + // Check if counterparty has enough single certificates for (int i = 0; i < shares; i++) { swapCert = other.findCertificate(company, 1, false); swapCert.moveTo(this); @@ -395,7 +425,7 @@ public class Portfolio implements TokenHolder, MoveableHolder { } else { return null; } - cert.moveTo(other); + presCert.moveTo(other); // Make sure the old President is no longer marked as such getShareModel(company).setShare(); @@ -412,19 +442,19 @@ public class Portfolio implements TokenHolder, MoveableHolder { private void addTrain(TrainI train, int[] position) { Util.addToList(trains, train, position[0]); - + TrainType type = train.getType(); if (!trainsPerType.containsKey(type)) { trainsPerType.put(type, new ArrayList<TrainI>()); } Util.addToList(trainsPerType.get(type), train, position[1]); - + TrainCertificateType certType = train.getCertType(); if (!trainsPerCertType.containsKey(certType)) { trainsPerCertType.put(certType, new ArrayList<TrainI>()); } Util.addToList(trainsPerCertType.get(certType), train, position[2]); - + train.setHolder(this); trainsModel.update(); } @@ -674,9 +704,9 @@ public class Portfolio implements TokenHolder, MoveableHolder { if (object instanceof PublicCertificateI) { PublicCertificateI cert = (PublicCertificateI) object; return new int[] { - certificates.indexOf(object), - certPerCompany.get(cert.getCompany().getName()).indexOf(cert), - certsPerType.get(cert.getTypeId()).indexOf(cert) + certificates.indexOf(object), + certPerCompany.get(cert.getCompany().getName()).indexOf(cert), + certsPerType.get(cert.getTypeId()).indexOf(cert) }; } else if (object instanceof PrivateCompanyI) { return new int[] {privateCompanies.indexOf(object)}; @@ -685,7 +715,7 @@ public class Portfolio implements TokenHolder, MoveableHolder { return new int[] { trains.indexOf(train), train.getPreviousType() != null ? trainsPerType.get(train.getPreviousType()).indexOf(train) : -1, - trainsPerCertType.get(train.getCertType()).indexOf(train) + trainsPerCertType.get(train.getCertType()).indexOf(train) }; } else if (object instanceof SpecialPropertyI) { return new int[] {specialProperties.indexOf(object)}; diff --git a/rails/game/PublicCompany.java b/rails/game/PublicCompany.java index f4ff236..16c25ee 100644 --- a/rails/game/PublicCompany.java +++ b/rails/game/PublicCompany.java @@ -1507,7 +1507,7 @@ public class PublicCompany extends Company implements PublicCompanyI { int buyerShare = buyer.getPortfolio().getShare(this); if (buyerShare > presShare) { pres.getPortfolio().swapPresidentCertificate(this, - buyer.getPortfolio()); + buyer.getPortfolio(), 0); ReportBuffer.add(LocalText.getText("IS_NOW_PRES_OF", buyer.getName(), name )); @@ -1534,7 +1534,7 @@ public class PublicCompany extends Company implements PublicCompanyI { if (share > presShare) { // Presidency must be transferred seller.getPortfolio().swapPresidentCertificate(this, - player.getPortfolio()); + player.getPortfolio(), 0); ReportBuffer.add(LocalText.getText("IS_NOW_PRES_OF", player.getName(), name )); @@ -1560,7 +1560,7 @@ public class PublicCompany extends Company implements PublicCompanyI { if (share > presShare) { // Hand presidency to the first player with a higher share president.getPortfolio().swapPresidentCertificate(this, - player.getPortfolio()); + player.getPortfolio(), 0); ReportBuffer.add(LocalText.getText("IS_NOW_PRES_OF", player.getName(), name )); diff --git a/rails/game/ShareSellingRound.java b/rails/game/ShareSellingRound.java index 394a2e7..d8a015d 100644 --- a/rails/game/ShareSellingRound.java +++ b/rails/game/ShareSellingRound.java @@ -7,9 +7,7 @@ package rails.game; import java.util.*; -import rails.common.DisplayBuffer; -import rails.common.GuiDef; -import rails.common.LocalText; +import rails.common.*; import rails.common.parser.GameOption; import rails.game.action.PossibleAction; import rails.game.action.SellShares; @@ -120,9 +118,9 @@ public class ShareSellingRound extends StockRound { /* May not sell more than the Pool can accept */ maxShareToSell = - Math.min(maxShareToSell, - getGameParameterAsInt(GameDef.Parm.POOL_SHARE_LIMIT) - - pool.getShare(company)); + Math.min(maxShareToSell, + getGameParameterAsInt(GameDef.Parm.POOL_SHARE_LIMIT) + - pool.getShare(company)); if (maxShareToSell == 0) continue; /* @@ -212,22 +210,23 @@ public class ShareSellingRound extends StockRound { price = company.getMarketPrice(); } - for (int i = 1; i <= 4; i++) { - number = shareCountPerUnit[i]; + for (int shareSize = 1; shareSize <= 4; shareSize++) { + number = shareCountPerUnit[shareSize]; if (number == 0) continue; number = - Math.min(number, maxShareToSell - / (i * company.getShareUnit())); + Math.min(number, maxShareToSell + / (shareSize * company.getShareUnit())); if (number == 0) continue; // May not sell more than is needed to buy the train while (number > 0 - && ((number - 1) * price) > cashToRaise.intValue()) + && ((number - 1) * price) > cashToRaise.intValue()) number--; if (number > 0) { - sellableShares.add(new SellShares(compName, i, number, - price)); + for (int i=1; i<=number; i++) { + sellableShares.add(new SellShares(compName, shareSize, i, price)); + } } } } @@ -241,14 +240,14 @@ public class ShareSellingRound extends StockRound { String errMsg = null; String companyName = action.getCompanyName(); PublicCompanyI company = - companyManager.getPublicCompany(action.getCompanyName()); + companyManager.getPublicCompany(action.getCompanyName()); PublicCertificateI cert = null; PublicCertificateI presCert = null; List<PublicCertificateI> certsToSell = - new ArrayList<PublicCertificateI>(); + new ArrayList<PublicCertificateI>(); Player dumpedPlayer = null; int presSharesToSell = 0; - int numberToSell = action.getNumberSold(); + int numberToSell = action.getNumber(); int shareUnits = action.getShareUnits(); int currentIndex = getCurrentPlayerIndex(); @@ -269,8 +268,8 @@ public class ShareSellingRound extends StockRound { // May player sell this company if (!mayPlayerSellShareOfCompany(company)) { - errMsg = LocalText.getText("SaleNotAllowed", companyName); - break; + errMsg = LocalText.getText("SaleNotAllowed", companyName); + break; } // The player must have the share(s) @@ -288,7 +287,7 @@ public class ShareSellingRound extends StockRound { // Find the certificates to sell Iterator<PublicCertificateI> it = - portfolio.getCertificatesPerCompany(companyName).iterator(); + portfolio.getCertificatesPerCompany(companyName).iterator(); while (numberToSell > 0 && it.hasNext()) { cert = it.next(); if (cert.isPresidentShare()) { @@ -306,23 +305,23 @@ public class ShareSellingRound extends StockRound { if (numberToSell == 0) presCert = null; if (numberToSell > 0 && presCert != null - && numberToSell <= presCert.getShares()) { + && numberToSell <= presCert.getShares()) { // Not allowed to dump the company that needs the train if (company == cashNeedingCompany || !dumpOtherCompaniesAllowed) { errMsg = - LocalText.getText("CannotDumpTrainBuyingPresidency"); + LocalText.getText("CannotDumpTrainBuyingPresidency"); break; } // More to sell and we are President: see if we can dump it. Player otherPlayer; for (int i = currentIndex + 1; i < currentIndex - + numberOfPlayers; i++) { + + numberOfPlayers; i++) { otherPlayer = gameManager.getPlayerByIndex(i); if (otherPlayer.getPortfolio().getShare(company) >= presCert.getShare()) { // Check if he has the right kind of share if (numberToSell > 1 - || otherPlayer.getPortfolio().ownsCertificates( - company, 1, false) >= 1) { + || otherPlayer.getPortfolio().ownsCertificates( + company, 1, false) >= 1) { // The poor sod. dumpedPlayer = otherPlayer; presSharesToSell = numberToSell; @@ -345,7 +344,7 @@ public class ShareSellingRound extends StockRound { break; } - int numberSold = action.getNumberSold(); + int numberSold = action.getNumber(); if (errMsg != null) { DisplayBuffer.add(LocalText.getText("CantSell", playerName, @@ -388,7 +387,7 @@ public class ShareSellingRound extends StockRound { if (!company.isClosed()) { executeShareTransfer (company, certsToSell, - dumpedPlayer, presSharesToSell); + dumpedPlayer, presSharesToSell, action.getPresidentExchange()); } cashToRaise.add(-numberSold * price); diff --git a/rails/game/StockRound.java b/rails/game/StockRound.java index cafb86b..4ee9c7b 100644 --- a/rails/game/StockRound.java +++ b/rails/game/StockRound.java @@ -353,8 +353,9 @@ public class StockRound extends Round { String compName; int price; int number; - int share, maxShareToSell; - boolean dumpAllowed; + int share, shareUnit, maxShareToSell; + int dumpThreshold = 0; + boolean choiceOfPresidentExchangeCerts = false; Portfolio playerPortfolio = currentPlayer.getPortfolio(); /* @@ -367,6 +368,7 @@ public class StockRound extends Round { if (!mayPlayerSellShareOfCompany(company)) continue; share = maxShareToSell = playerPortfolio.getShare(company); + shareUnit = company.getShareUnit(); if (maxShareToSell == 0) continue; /* May not sell more than the Pool can accept */ @@ -378,23 +380,46 @@ public class StockRound extends Round { /* * If the current Player is president, check if he can dump the - * presidency onto someone else + * presidency onto someone else. */ if (company.getPresident() == currentPlayer) { int presidentShare = company.getCertificates().get(0).getShare(); if (maxShareToSell > share - presidentShare) { - dumpAllowed = false; int playerShare; - for (Player player : gameManager.getPlayers()) { - if (player == currentPlayer) continue; + // Check in correct player sequence, because we must also check + // whether we must offer a choice for the Pres.cert exchange + // (as may occur in 1835). + int currentPlayerIndex = getCurrentPlayerIndex(); + int playerIndex = currentPlayerIndex; + List<Player> players = gameManager.getPlayers(); + Player player; + int dumpedPlayerShare = 0; + dumpThreshold = 0; + + for (playerIndex = (currentPlayerIndex+1)%numberOfPlayers; + playerIndex != currentPlayerIndex; + playerIndex = (playerIndex+1)%numberOfPlayers) { + player = players.get(playerIndex); playerShare = player.getPortfolio().getShare(company); - if (playerShare >= presidentShare) { - dumpAllowed = true; - break; - } + if (playerShare <= dumpedPlayerShare) continue; + + if (playerShare < presidentShare) continue; // Cannot dump on him + + dumpedPlayerShare = playerShare; + // From what share sold are we dumping? + dumpThreshold = share - playerShare + shareUnit; + // Check if the potential dumpee has a choice of return certs + int[] uniqueCertsCount = + player.getPortfolio().getCertificateTypeCountsPerCompany(company.getName(), false); + // Let's keep it simple and only check for single + // and double shares for now. + choiceOfPresidentExchangeCerts = + uniqueCertsCount[1] > 1 && uniqueCertsCount[2] > 0; + } - if (!dumpAllowed) maxShareToSell = share - presidentShare; + // What number of shares can we sell if we cannot dump? + if (dumpThreshold == 0) maxShareToSell = share - presidentShare; } } @@ -405,30 +430,14 @@ public class StockRound extends Round { * of the smallest ordinary share unit type. */ // Take care for max. 4 share units per share - int[] shareCountPerUnit = new int[5]; compName = company.getName(); - for (PublicCertificateI c : playerPortfolio.getCertificatesPerCompany(compName)) { - if (c.isPresidentShare()) { - shareCountPerUnit[1] += c.getShares(); - } else { - ++shareCountPerUnit[c.getShares()]; - } - } - // TODO The above ignores that a dumped player must be - // able to exchange the president's share. - - /* - * Check the price. If a cert was sold before this turn, the - * original price is still valid - */ + int[] shareCountPerUnit = playerPortfolio.getCertificateTypeCountsPerCompany(compName, true); + // Check the price. If a cert was sold before this turn, the original price is still valid. price = getCurrentSellPrice(company); - // removed as this is done in getCurrentSellPrice - // price /= company.getShareUnitsForSharePrice(); - /* Allow for different share units (as in 1835) */ - for (int i = 1; i <= 4; i++) { - number = shareCountPerUnit[i]; + for (int shareSize = 1; shareSize <= 4; shareSize++) { + number = shareCountPerUnit[shareSize]; if (number == 0) continue; /* In some games (1856), a just bought share may not be sold */ @@ -442,11 +451,19 @@ public class StockRound extends Round { // Check against the share% already in the pool number = Math.min(number, maxShareToSell - / (i * company.getShareUnit())); + / (shareSize * company.getShareUnit())); if (number <= 0) continue; - possibleActions.add(new SellShares(compName, i, number, price)); - + for (int i=1; i<=number; i++) { + if (dumpThreshold > 0 && i*shareSize*shareUnit >= dumpThreshold + && choiceOfPresidentExchangeCerts) { + // Also offer the alternative president exchange for a double share + possibleActions.add(new SellShares(compName, shareSize, i, price, 1)); + possibleActions.add(new SellShares(compName, shareSize, i, price, 2)); + } else { + possibleActions.add(new SellShares(compName, shareSize, i, price, 0)); + } + } } } } @@ -934,7 +951,7 @@ public class StockRound extends Round { new ArrayList<PublicCertificateI>(); Player dumpedPlayer = null; int presSharesToSell = 0; - int numberToSell = action.getNumberSold(); + int numberToSell = action.getNumber(); int shareUnits = action.getShareUnits(); int currentIndex = getCurrentPlayerIndex(); @@ -1039,7 +1056,7 @@ public class StockRound extends Round { break; } - int numberSold = action.getNumberSold(); + int numberSold = action.getNumber(); if (errMsg != null) { DisplayBuffer.add(LocalText.getText("CantSell", playerName, @@ -1085,7 +1102,7 @@ public class StockRound extends Round { if (!company.isClosed()) { executeShareTransfer (company, certsToSell, - dumpedPlayer, presSharesToSell); + dumpedPlayer, presSharesToSell, action.getPresidentExchange()); } // Remember that the player has sold this company this round. @@ -1101,7 +1118,7 @@ public class StockRound extends Round { protected void executeShareTransfer (PublicCompanyI company, List<PublicCertificateI> certsToSell, - Player dumpedPlayer, int presSharesToSell) { + Player dumpedPlayer, int presSharesToSell, int swapShareSize) { Portfolio portfolio = currentPlayer.getPortfolio(); @@ -1113,7 +1130,7 @@ public class StockRound extends Round { // First swap the certificates Portfolio dumpedPortfolio = dumpedPlayer.getPortfolio(); List<PublicCertificateI> swapped = - portfolio.swapPresidentCertificate(company, dumpedPortfolio); + portfolio.swapPresidentCertificate(company, dumpedPortfolio, swapShareSize); for (int i = 0; i < presSharesToSell; i++) { certsToSell.add(swapped.get(i)); } @@ -1129,7 +1146,7 @@ public class StockRound extends Round { otherPlayer = gameManager.getPlayerByIndex(i); if (otherPlayer.getPortfolio().getShare(company) > portfolio.getShare(company)) { portfolio.swapPresidentCertificate(company, - otherPlayer.getPortfolio()); + otherPlayer.getPortfolio(), swapShareSize); ReportBuffer.add(LocalText.getText("IS_NOW_PRES_OF", otherPlayer.getName(), company.getName() )); diff --git a/rails/game/TreasuryShareRound.java b/rails/game/TreasuryShareRound.java index 5a08c14..030822e 100644 --- a/rails/game/TreasuryShareRound.java +++ b/rails/game/TreasuryShareRound.java @@ -7,9 +7,7 @@ package rails.game; import java.util.*; -import rails.common.DisplayBuffer; -import rails.common.GuiDef; -import rails.common.LocalText; +import rails.common.*; import rails.game.action.*; import rails.game.state.BooleanState; @@ -32,18 +30,18 @@ public class TreasuryShareRound extends StockRound { * */ public TreasuryShareRound(GameManagerI aGameManager, - RoundI parentRound) { + RoundI parentRound) { super (aGameManager); operatingCompany = ((OperatingRound)parentRound).getOperatingCompany(); sellingPlayer = operatingCompany.getPresident(); log.debug("Creating TreasuryShareRound"); hasBought = - new BooleanState(operatingCompany.getName() + "_boughtShares", - false); + new BooleanState(operatingCompany.getName() + "_boughtShares", + false); hasSold = - new BooleanState(operatingCompany.getName() + "_soldShares", - false); + new BooleanState(operatingCompany.getName() + "_soldShares", + false); setCurrentPlayerIndex(sellingPlayer.getIndex()); @@ -111,7 +109,7 @@ public class TreasuryShareRound extends StockRound { /* Get the unique Pool certificates and check which ones can be bought */ from = pool; Map<String, List<PublicCertificateI>> map = - from.getCertsPerCompanyMap(); + from.getCertsPerCompanyMap(); for (String compName : map.keySet()) { certs = map.get(compName); @@ -126,12 +124,12 @@ public class TreasuryShareRound extends StockRound { // Shares already owned int ownedShare = - operatingCompany.getPortfolio().getShare(operatingCompany); + operatingCompany.getPortfolio().getShare(operatingCompany); // Max share that may be owned int maxShare = getGameParameterAsInt(GameDef.Parm.TREASURY_SHARE_LIMIT); // Max number of shares to add int maxBuyable = - (maxShare - ownedShare) / operatingCompany.getShareUnit(); + (maxShare - ownedShare) / operatingCompany.getShareUnit(); // Max number of shares to buy number = Math.min(certs.size(), maxBuyable); if (number == 0) continue; @@ -180,12 +178,12 @@ public class TreasuryShareRound extends StockRound { /* May not sell more than the Pool can accept */ maxShareToSell = - Math.min(maxShareToSell, - getGameParameterAsInt(GameDef.Parm.POOL_SHARE_LIMIT) - - pool.getShare(company)); + Math.min(maxShareToSell, + getGameParameterAsInt(GameDef.Parm.POOL_SHARE_LIMIT) + - pool.getShare(company)); if (maxShareToSell == 0) continue; - /* + /* * Check what share units the player actually owns. In some games * (e.g. 1835) companies may have different ordinary shares: 5% and * 10%, or 10% and 20%. The president's share counts as a multiple @@ -214,17 +212,16 @@ public class TreasuryShareRound extends StockRound { price = company.getMarketPrice(); } - for (int i = 1; i <= 4; i++) { - number = shareCountPerUnit[i]; + for (int shareSize = 1; shareSize <= 4; shareSize++) { + number = shareCountPerUnit[shareSize]; if (number == 0) continue; number = - Math.min(number, maxShareToSell - / (i * company.getShareUnit())); + Math.min(number, maxShareToSell + / (shareSize * company.getShareUnit())); if (number == 0) continue; - if (number > 0) { - possibleActions.add(new SellShares(compName, i, number, - price)); + for (int i=1; i<=number; i++) { + possibleActions.add(new SellShares(compName, shareSize, i, price)); } } } @@ -275,9 +272,9 @@ public class TreasuryShareRound extends StockRound { } if (company != operatingCompany) { errMsg = - LocalText.getText("WrongCompany", - companyName, - operatingCompany.getName() ); + LocalText.getText("WrongCompany", + companyName, + operatingCompany.getName() ); } @@ -287,7 +284,7 @@ public class TreasuryShareRound extends StockRound { break; } if (company.mustHaveOperatedToTradeShares() - && !company.hasOperated()) { + && !company.hasOperated()) { errMsg = LocalText.getText("NotYetOperated", companyName); break; } @@ -301,9 +298,9 @@ public class TreasuryShareRound extends StockRound { // Check if that many shares are available if (share > from.getShare(company)) { errMsg = - LocalText.getText("NotAvailable", - companyName, - from.getName() ); + LocalText.getText("NotAvailable", + companyName, + from.getName() ); break; } @@ -313,8 +310,8 @@ public class TreasuryShareRound extends StockRound { int treasuryShareLimit = getGameParameterAsInt(GameDef.Parm.TREASURY_SHARE_LIMIT); if (portfolio.getShare(company) + share > treasuryShareLimit) { errMsg = - LocalText.getText("TreasuryOverHoldLimit", - String.valueOf(treasuryShareLimit)); + LocalText.getText("TreasuryOverHoldLimit", + String.valueOf(treasuryShareLimit)); break; } @@ -382,8 +379,8 @@ public class TreasuryShareRound extends StockRound { PublicCompanyI company = companyManager.getPublicCompany(companyName); PublicCertificateI cert = null; List<PublicCertificateI> certsToSell = - new ArrayList<PublicCertificateI>(); - int numberToSell = action.getNumberSold(); + new ArrayList<PublicCertificateI>(); + int numberToSell = action.getNumber(); int shareUnits = action.getShareUnits(); // Dummy loop to allow a quick jump out @@ -402,9 +399,9 @@ public class TreasuryShareRound extends StockRound { } if (company != operatingCompany) { errMsg = - LocalText.getText("WrongCompany", - companyName, - operatingCompany.getName() ); + LocalText.getText("WrongCompany", + companyName, + operatingCompany.getName() ); break; } @@ -414,7 +411,7 @@ public class TreasuryShareRound extends StockRound { break; } if (company.mustHaveOperatedToTradeShares() - && !company.hasOperated()) { + && !company.hasOperated()) { errMsg = LocalText.getText("NotYetOperated", companyName); break; } @@ -440,7 +437,7 @@ public class TreasuryShareRound extends StockRound { // Find the certificates to sell Iterator<PublicCertificateI> it = - portfolio.getCertificatesPerCompany(companyName).iterator(); + portfolio.getCertificatesPerCompany(companyName).iterator(); while (numberToSell > 0 && it.hasNext()) { cert = it.next(); if (shareUnits != cert.getShares()) { @@ -461,7 +458,7 @@ public class TreasuryShareRound extends StockRound { break; } - int numberSold = action.getNumberSold(); + int numberSold = action.getNumber(); if (errMsg != null) { DisplayBuffer.add(LocalText.getText("CantSell", companyName, @@ -504,7 +501,7 @@ public class TreasuryShareRound extends StockRound { transferCertificate (cert2, pool, cert2.getShares() * price); } } - */ + */ stockMarket.sell(company, numberSold); hasSold.set(true); diff --git a/rails/game/action/SellShares.java b/rails/game/action/SellShares.java index 00e552a..e266a7a 100644 --- a/rails/game/action/SellShares.java +++ b/rails/game/action/SellShares.java @@ -23,22 +23,29 @@ public class SellShares extends PossibleAction { private int shareUnits; private int share; private int price; - private int maximumNumber; - - // Client-side settings - private int numberSold = 0; + private int number; + /** Dump flag, indicates to which type of certificates the president's share must be exchanged.<br> + * 0 = no dump, or dump that does not require any choice of exchange certificates;<br> + * 1 = exchange against 1-share certificates (usually 10%);<br> + * 2 = exchange against a 2-share certificate (as can occur in 1835);<br> + * etc. + */ + private int presidentExchange = 0; public static final long serialVersionUID = 1L; - /** - * - */ - public SellShares(String companyName, int shareUnits, int maximumNumber, + public SellShares(String companyName, int shareUnits, int number, int price) { + this (companyName, shareUnits, number, price, 0); + } + + public SellShares(String companyName, int shareUnits, int number, + int price, int presidentExchange) { this.companyName = companyName; this.shareUnits = shareUnits; this.price = price; - this.maximumNumber = maximumNumber; + this.number = number; + this.presidentExchange = presidentExchange; company = getCompanyManager().getPublicCompany(companyName); shareUnit = company.getShareUnit(); @@ -48,8 +55,8 @@ public class SellShares extends PossibleAction { /** * @return Returns the maximumNumber. */ - public int getMaximumNumber() { - return maximumNumber; + public int getNumber() { + return number; } /** @@ -82,12 +89,8 @@ public class SellShares extends PossibleAction { return share; } - public int getNumberSold() { - return numberSold; - } - - public void setNumberSold(int numberSold) { - this.numberSold = numberSold; + public int getPresidentExchange() { + return presidentExchange; } @Override @@ -95,9 +98,9 @@ public class SellShares extends PossibleAction { if (!(action instanceof SellShares)) return false; SellShares a = (SellShares) action; return a.getCompanyName().equals(companyName) - && a.getShareUnits() == shareUnits - && a.getMaximumNumber() == maximumNumber - && a.getPrice() == price; + && a.getShareUnits() == shareUnits + && a.getNumber() == number + && a.getPrice() == price; } @Override @@ -105,28 +108,39 @@ public class SellShares extends PossibleAction { if (!(action instanceof SellShares)) return false; SellShares a = (SellShares) action; return a.companyName.equals(companyName) - && a.shareUnits == shareUnits - && a.numberSold == numberSold - && a.price == price; + && a.shareUnits == shareUnits + && a.number == number + && a.price == price; } @Override public String toString() { return "SellShares: " - + (numberSold > 0 ? numberSold : "max " + maximumNumber) - + " of " + share + "% " + companyName + " at " - + Bank.format(shareUnits * price) + " apiece"; + + number + " of " + share + "% " + companyName + + " at " + Bank.format(shareUnits * price) + " apiece" + + (presidentExchange > 0 ? " (pres.exch. for "+presidentExchange*shareUnit+"% share(s))" : ""); } /** Deserialize */ private void readObject(ObjectInputStream in) throws IOException, - ClassNotFoundException { + ClassNotFoundException { + + //in.defaultReadObject(); + // Custom reading for backwards compatibility + ObjectInputStream.GetField fields = in.readFields(); - in.defaultReadObject(); + companyName = (String) fields.get("companyName", null); + shareUnit = fields.get("shareUnit", shareUnit); + shareUnits = fields.get("shareUnits", shareUnits); + share = fields.get("share", share); + price = fields.get("price", price); + int numberSold = fields.get("numberSold", 0); // For backwards compatibility + number = fields.get("number", numberSold); + presidentExchange = fields.get("presidentExchange", 0); CompanyManagerI companyManager = getCompanyManager(); if (Util.hasValue(companyName)) companyName = companyManager.checkAlias(companyName); - company = companyManager.getPublicCompany(companyName); + company = companyManager.getPublicCompany(companyName); } } diff --git a/rails/game/specific/_1856/CGRFormationRound.java b/rails/game/specific/_1856/CGRFormationRound.java index 8ce4689..f7066e7 100644 --- a/rails/game/specific/_1856/CGRFormationRound.java +++ b/rails/game/specific/_1856/CGRFormationRound.java @@ -2,9 +2,7 @@ package rails.game.specific._1856; import java.util.*; -import rails.common.DisplayBuffer; -import rails.common.GuiDef; -import rails.common.LocalText; +import rails.common.*; import rails.game.*; import rails.game.action.*; import rails.game.move.CashMove; @@ -18,7 +16,7 @@ public class CGRFormationRound extends SwitchableUIRound { private Player startingPlayer; private int maxLoansToRepayByPresident = 0; private Map<Player, List<PublicCompanyI>> companiesToRepayLoans = null; - + private PublicCompanyI currentCompany = null; private List<PublicCompanyI> mergingCompanies = new ArrayList<PublicCompanyI>(); @@ -27,9 +25,9 @@ public class CGRFormationRound extends SwitchableUIRound { */ private String cgrName = PublicCompany_CGR.NAME; private PublicCompany_CGR cgr - = (PublicCompany_CGR)gameManager.getCompanyManager().getPublicCompany(cgrName); - - /* + = (PublicCompany_CGR)gameManager.getCompanyManager().getPublicCompany(cgrName); + + /* * effects from the merger, processed at the end * thus no need for state variables */ @@ -86,7 +84,7 @@ public class CGRFormationRound extends SwitchableUIRound { if (company.getCurrentNumberOfLoans() > 0) { if (companiesToRepayLoans == null) { companiesToRepayLoans - = new HashMap<Player, List<PublicCompanyI>>(); + = new HashMap<Player, List<PublicCompanyI>>(); } president = company.getPresident(); if (!companiesToRepayLoans.containsKey(president)) { @@ -192,22 +190,22 @@ public class CGRFormationRound extends SwitchableUIRound { player.getName(), maxNumber, currentCompany.getName()), - false); + false); } else { DisplayBuffer.add(LocalText.getText("YouCannotRepayAllLoans", player.getName(), maxNumber, numberOfLoans, currentCompany.getName()), - false); -// currentCompany.getLoanValueModel().setText(LocalText.getText("MERGE")); + false); + // currentCompany.getLoanValueModel().setText(LocalText.getText("MERGE")); } maxLoansToRepayByPresident = maxNumber; break; } else { // President cannot help, this company will merge into CGR anyway mergingCompanies.add(currentCompany); -// currentCompany.getLoanValueModel().setText(LocalText.getText("MERGE")); + // currentCompany.getLoanValueModel().setText(LocalText.getText("MERGE")); message = LocalText.getText("WillMergeInto", currentCompany.getName(), PublicCompany_CGR.NAME); @@ -241,7 +239,7 @@ public class CGRFormationRound extends SwitchableUIRound { trainsToDiscardFrom, forcedTrainDiscard); possibleActions.add(action); guiHints.setActivePanel(GuiDef.Panel.STATUS); - } + } return true; } @@ -266,10 +264,10 @@ public class CGRFormationRound extends SwitchableUIRound { new CashMove (company, bank, repaymentByCompany); ReportBuffer.add (LocalText.getText("CompanyRepaysLoans", company.getName(), - Bank.format(repaymentByCompany), - Bank.format(repayment), - numberRepaid, - Bank.format(company.getValuePerLoan()))); + Bank.format(repaymentByCompany), + Bank.format(repayment), + numberRepaid, + Bank.format(company.getValuePerLoan()))); } if (repaymentByPresident > 0) { Player president = company.getPresident(); @@ -282,11 +280,11 @@ public class CGRFormationRound extends SwitchableUIRound { Bank.format(company.getValuePerLoan()), president.getName())); } - } + } - if (action.getCompany().getCurrentNumberOfLoans() > 0) { + if (action.getCompany().getCurrentNumberOfLoans() > 0) { mergingCompanies.add(currentCompany); -// currentCompany.getLoanValueModel().setText(LocalText.getText("MERGE")); + // currentCompany.getLoanValueModel().setText(LocalText.getText("MERGE")); String message = LocalText.getText("WillMergeInto", currentCompany.getName(), PublicCompany_CGR.NAME); @@ -438,7 +436,7 @@ public class CGRFormationRound extends SwitchableUIRound { // Move the remaining CGR shares to the ipo. // Clone the shares list first certs = new ArrayList<PublicCertificateI> - (unavailable.getCertificatesPerCompany(PublicCompany_CGR.NAME)); + (unavailable.getCertificatesPerCompany(PublicCompany_CGR.NAME)); for (PublicCertificateI cert : certs) { cert.moveTo(ipo); } @@ -452,8 +450,8 @@ public class CGRFormationRound extends SwitchableUIRound { } else if (temporaryPresident != null && temporaryPresident != newPresident) { log.debug("Moving pres.share from "+temporaryPresident.getName() +" to "+newPresident.getName()); - temporaryPresident.getPortfolio().swapPresidentCertificate(cgr, - newPresident.getPortfolio()); + temporaryPresident.getPortfolio().swapPresidentCertificate(cgr, + newPresident.getPortfolio(), 1); } newPresident.getPortfolio().getShareModel(cgr).setShare(); @@ -522,7 +520,7 @@ public class CGRFormationRound extends SwitchableUIRound { DisplayBuffer.add(message); ReportBuffer.add(message); - // Collect the old token spots, and move cash and trains + // Collect the old token spots, and move cash and trains List<BaseToken> homeTokens = new ArrayList<BaseToken>(); nonHomeTokens = new ArrayList<BaseToken>(); BaseToken bt; @@ -561,7 +559,7 @@ public class CGRFormationRound extends SwitchableUIRound { // Move any still valid bonuses if (comp.getBonuses() != null) { List<Bonus> bonuses = new ArrayList<Bonus> (comp.getBonuses()); -bonuses: for (Bonus bonus : bonuses) { + bonuses: for (Bonus bonus : bonuses) { comp.removeBonus(bonus); // Only add if the CGR does not already have the same bonus if (cgr.getBonuses() != null) { @@ -645,7 +643,7 @@ bonuses: for (Bonus bonus : bonuses) { // Then create list of exchange spots. Sort it on hexname/city number tokensToExchangeFrom = new ArrayList<ExchangeableToken>(); for (String key : new TreeSet<String> (oldTokens.keySet())) { - tokensToExchangeFrom.add(new ExchangeableToken( + tokensToExchangeFrom.add(new ExchangeableToken( key, oldTokens.get(key))); } } else { @@ -658,7 +656,7 @@ bonuses: for (Bonus bonus : bonuses) { } // Check the trains, autodiscard any excess non-permanent trains -// int trainLimit = cgr.getTrainLimit(gameManager.getCurrentPlayerIndex()); + // int trainLimit = cgr.getTrainLimit(gameManager.getCurrentPlayerIndex()); int trainLimit = cgr.getCurrentTrainLimit(); List<TrainI> trains = cgr.getPortfolio().getTrainList(); if (cgr.getNumberOfTrains() > trainLimit) { @@ -680,7 +678,7 @@ bonuses: for (Bonus bonus : bonuses) { } - private void executeExchangeTokens (List<BaseToken> exchangedTokens) { + private void executeExchangeTokens (List<BaseToken> exchangedTokens) { Stop city; MapHex hex; ReportBuffer.add(""); @@ -765,7 +763,7 @@ bonuses: for (Bonus bonus : bonuses) { for (TrainI train : cgr.getPortfolio().getTrainList()) { if (!train.isPermanent()) { trainsToDiscardFrom.add(train); - } + } } if (!trainsToDiscardFrom.isEmpty()) { if (getStep() != STEP_DISCARD_TRAINS) { @@ -811,9 +809,9 @@ bonuses: for (Bonus bonus : bonuses) { if (train != null && !company.getPortfolio().getTrainList().contains(train)) { errMsg = - LocalText.getText("CompanyDoesNotOwnTrain", - company.getName(), - train.getName() ); + LocalText.getText("CompanyDoesNotOwnTrain", + company.getName(), + train.getName() ); break; } @@ -833,7 +831,7 @@ bonuses: for (Bonus bonus : bonuses) { if (train != null) { -// if (action.isForced()) moveStack.linkToPreviousMoveSet(); + // if (action.isForced()) moveStack.linkToPreviousMoveSet(); train.moveTo(pool); ReportBuffer.add(LocalText.getText("CompanyDiscardsTrain", companyName, diff --git a/rails/ui/swing/GameStatus.java b/rails/ui/swing/GameStatus.java index a41d730..6a3d460 100644 --- a/rails/ui/swing/GameStatus.java +++ b/rails/ui/swing/GameStatus.java @@ -587,7 +587,9 @@ public class GameStatus extends GridPanel implements ActionListener { for (PossibleAction action : actions) { sale = (SellShares) action; - for (int i = 1; i <= sale.getMaximumNumber(); i++) { + //for (int i = 1; i <= sale.getMaximumNumber(); i++) { + int i = sale.getNumber(); + if (sale.getPresidentExchange() == 0) { options.add(LocalText.getText("SellShares", i, sale.getShare(), @@ -595,9 +597,19 @@ public class GameStatus extends GridPanel implements ActionListener { sale.getCompanyName(), Bank.format(i * sale.getShareUnits() * sale.getPrice()) )); - sellActions.add(sale); - sellAmounts.add(i); + } else { + options.add(LocalText.getText("SellSharesWithSwap", + i, + sale.getShare(), + i * sale.getShare(), + sale.getCompanyName(), + Bank.format(i * sale.getShareUnits() * sale.getPrice()), + // disregard other than double pres.certs. This is for 1835 only. + 3 - sale.getPresidentExchange(), + sale.getPresidentExchange() * sale.getShareUnit())); } + sellActions.add(sale); + sellAmounts.add(i); } int index = 0; if (options.size() > 1) { @@ -620,7 +632,7 @@ public class GameStatus extends GridPanel implements ActionListener { // cancelled } else { chosenAction = sellActions.get(index); - ((SellShares) chosenAction).setNumberSold(sellAmounts.get(index)); + //((SellShares) chosenAction).setNumberSold(sellAmounts.get(index)); } } else if (actions.get(0) instanceof BuyCertificate) { boolean startCompany = false; commit 9f97d651984b68e5c9dd68ddfb7361a7151a083f Author: Erik Vos <eri...@xs...> Date: Sat Nov 19 09:35:58 2011 +0100 Fixes for 1835: Rewrote nationalisation to make it able to handle both 10% and 20% shares. The nationalisation code has also been refactored into setBuyableCerts(). Suppressed empty share field tooltips. Moved the SHARES update key from ShareModel to ViewUpdate, joining with the other keys. diff --git a/rails/game/model/ShareModel.java b/rails/game/model/ShareModel.java index 2dd9993..2c7f913 100644 --- a/rails/game/model/ShareModel.java +++ b/rails/game/model/ShareModel.java @@ -11,8 +11,6 @@ public class ShareModel extends ModelObject { private Portfolio portfolio; private PublicCompanyI company; - public static final String SHARES = "SHARES"; - public ShareModel(Portfolio portfolio, PublicCompanyI company) { this.portfolio = portfolio; this.company = company; @@ -55,7 +53,7 @@ public class ShareModel extends ModelObject { if (b.length() > 0) b.append(","); b.append(type).append(":").append(numberPerCertType.get(type)); } - u.addObject(SHARES, b.toString()); + u.addObject(ViewUpdate.SHARES, b.toString()); } return u; } diff --git a/rails/game/model/ViewUpdate.java b/rails/game/model/ViewUpdate.java index 3a99661..bc1b57d 100644 --- a/rails/game/model/ViewUpdate.java +++ b/rails/game/model/ViewUpdate.java @@ -9,7 +9,6 @@ import java.util.*; * <p> The current version has text, background colour and foreground colour. * Receiving view objects must be prepared to handle extensions. * @author VosE - * */ public class ViewUpdate implements Serializable { @@ -18,6 +17,7 @@ public class ViewUpdate implements Serializable { public static final String TEXT = "TEXT"; public static final String BGCOLOUR = "BGCOLOUR"; + public static final String SHARES = "SHARES"; public static final long serialVersionUID = 1L; diff --git a/rails/game/specific/_1835/StockRound_1835.java b/rails/game/specific/_1835/StockRound_1835.java index 8d27f76..ff8eea3 100644 --- a/rails/game/specific/_1835/StockRound_1835.java +++ b/rails/game/specific/_1835/StockRound_1835.java @@ -4,7 +4,6 @@ */ package rails.game.specific._1835; -import java.util.ArrayList; import java.util.List; import rails.common.LocalText; @@ -25,45 +24,68 @@ public class StockRound_1835 extends StockRound { /** Add nationalisations */ @Override - protected void setGameSpecificActions() { - if (!mayCurrentPlayerBuyAnything()) return; + public void setBuyableCerts() { + + super.setBuyableCerts(); if (companyBoughtThisTurnWrapper.get() != null) return; - List<Player> otherPlayers = new ArrayList<Player>(); - Portfolio holder; - CashHolder owner; - Player otherPlayer; int price; int cash = currentPlayer.getCash(); + List<PublicCertificateI> certs; + StockSpaceI stockSpace; + Portfolio from; + int unitsForPrice; - // Nationalization + // Nationalisation for (PublicCompanyI company : companyManager.getAllPublicCompanies()) { if (!company.getTypeName().equalsIgnoreCase("Major")) continue; if (!company.hasFloated()) continue; if (company.getPresident() != currentPlayer) continue; - if (currentPlayer.getPortfolio().getShare(company) >= 55) { - otherPlayers.clear(); - for (PublicCertificateI cert : company.getCertificates()) { - holder = (Portfolio)cert.getHolder(); - owner = holder.getOwner(); + if (currentPlayer.getPortfolio().getShare(company) < 55) continue; + if (isSaleRecorded(currentPlayer, company)) continue; + + for (Player otherPlayer : this.getPlayers()) { + if (otherPlayer == currentPlayer) continue; + + /* Get the unique player certificates and check which ones can be bought */ + from = otherPlayer.getPortfolio(); + certs = from.getCertificatesPerCompany(company.getName()); + if (certs == null || certs.isEmpty()) continue; + + /* Allow for multiple share unit certificates (e.g. 1835) */ + PublicCertificateI[] uniqueCerts; + int shares; + + stockSpace = company.getCurrentSpace(); + unitsForPrice = company.getShareUnitsForSharePrice(); + price = (int)(1.5 * stockSpace.getPrice() / unitsForPrice); + + /* Check what share multiples are available + * Normally only 1, but 1 and 2 in 1835. Allow up to 4. + */ + uniqueCerts = new PublicCertificateI[5]; + for (PublicCertificateI cert2 : certs) { + shares = cert2.getShares(); + if (uniqueCerts[shares] != null) continue; + uniqueCerts[shares] = cert2; + } + + /* Create a BuyCertificate action per share size */ + for (shares = 1; shares < 5; shares++) { + if (uniqueCerts[shares] == null) continue; + /* Would the player exceed the total certificate limit? */ - StockSpaceI stockSpace = company.getCurrentSpace(); - if ((stockSpace == null || !stockSpace.isNoCertLimit()) && !mayPlayerBuyCertificate( - currentPlayer, company, cert.getCertificateCount())) continue; - // only nationalize other players - if (owner instanceof Player && owner != currentPlayer) { - otherPlayer = (Player) owner; - if (!otherPlayers.contains(otherPlayer)) { - price = (int)(1.5 * company.getCurrentPriceModel().getPrice().getPrice()); - if (price <= cash) { - possibleActions.add(new BuyCertificate (company, cert.getShare(), - holder, - (int)(1.5 * company.getCurrentPriceModel().getPrice().getPrice()), - 1)); - } - otherPlayers.add(otherPlayer); - } - } + if (!stockSpace.isNoCertLimit() + && !mayPlayerBuyCertificate(currentPlayer, company, + uniqueCerts[shares].getCertificateCount())) + continue; + + // Does the player have enough cash? + if (cash < price * shares) continue; + + possibleActions.add(new BuyCertificate(company, + uniqueCerts[shares].getShare(), + from, price, 1)); } } } @@ -97,7 +119,7 @@ public class StockRound_1835 extends StockRound { } // stored price is the previous unadjusted price price = price / company.getShareUnitsForSharePrice(); - return price; + return price; } @@ -133,9 +155,9 @@ public class StockRound_1835 extends StockRound { // Check for group releases if (sharesInIPO == 0) { if (name.equals(GameManager_1835.SX_ID) && - ipo.getShare(companyManager.getPublicCompany(GameManager_1835.BY_ID)) == 0 - || name.equals(GameManager_1835.BY_ID) && - ipo.getShare(companyManager.getPublicCompany(GameManager_1835.SX_ID)) == 0) { + ipo.getShare(companyManager.getPublicCompany(GameManager_1835.BY_ID)) == 0 + || name.equals(GameManager_1835.BY_ID) && + ipo.getShare(companyManager.getPublicCompany(GameManager_1835.SX_ID)) == 0) { // Group 1 sold out: release Badische releaseCompanyShares (companyManager.getPublicCompany(GameManager_1835.BA_ID)); ReportBuffer.add (LocalText.getText("SharesReleased", @@ -163,7 +185,7 @@ public class StockRound_1835 extends StockRound { ... [truncated message content] |