From: Stefan F. <ste...@us...> - 2012-05-26 14:11:45
|
rails/algorithms/NetworkCompanyGraph.java | 2 rails/algorithms/NetworkGraphBuilder.java | 9 rails/algorithms/RevenueAdapter.java | 4 rails/algorithms/RevenueManager.java | 31 rails/common/GuiHints.java | 31 rails/common/ResourceLoader.java | 4 rails/game/AbstractRound.java | 544 +++++++++++++++ rails/game/Bank.java | 70 - rails/game/BankPortfolio.java | 38 + rails/game/BaseToken.java | 43 - rails/game/Bonus.java | 1 rails/game/BonusToken.java | 53 - rails/game/Certificate.java | 4 rails/game/Company.java | 53 - rails/game/CompanyManager.java | 2 rails/game/CompanyManagerI.java | 2 rails/game/CompanyType.java | 53 - rails/game/CompanyTypeI.java | 52 - rails/game/EndOfGameRound.java | 2 rails/game/Game.java | 3 rails/game/GameManager.java | 125 +-- rails/game/MapHex.java | 179 ++-- rails/game/MapManager.java | 3 rails/game/OperatingRound.java | 192 ++--- rails/game/Phase.java | 2 rails/game/PhaseManager.java | 11 rails/game/Player.java | 79 +- rails/game/PlayerManager.java | 9 rails/game/PrivateCompany.java | 143 +-- rails/game/PublicCertificate.java | 22 rails/game/PublicCompany.java | 496 ++++++------- rails/game/ReportBuffer.java | 6 rails/game/Round.java | 537 -------------- rails/game/RoundI.java | 34 rails/game/ShareSellingRound.java | 47 - rails/game/StartItem.java | 109 +-- rails/game/StartPacket.java | 6 rails/game/StartRound.java | 29 rails/game/StartRoundI.java | 28 rails/game/StartRound_1830.java | 8 rails/game/StartRound_1835.java | 30 rails/game/Station.java | 6 rails/game/StockMarket.java | 16 rails/game/StockRound.java | 109 +-- rails/game/StockSpace.java | 63 - rails/game/Stop.java | 106 +- rails/game/SwitchableUIRound.java | 2 rails/game/Tile.java | 56 - rails/game/TileI.java | 90 -- rails/game/TileManager.java | 2 rails/game/Token.java | 49 - rails/game/Train.java | 57 - rails/game/TrainCertificateType.java | 36 rails/game/TrainManager.java | 4 rails/game/TreasuryShareRound.java | 36 rails/game/action/BuyBonusToken.java | 4 rails/game/action/BuyCertificate.java | 14 rails/game/action/BuyTrain.java | 37 - rails/game/action/DiscardTrain.java | 4 rails/game/action/LayTile.java | 32 rails/game/action/PossibleORAction.java | 10 rails/game/action/UseSpecialProperty.java | 12 rails/game/correct/CashCorrectionManager.java | 6 rails/game/correct/CorrectionManager.java | 17 rails/game/correct/MapCorrectionAction.java | 22 rails/game/correct/MapCorrectionManager.java | 6 rails/game/model/BaseTokensModel.java | 71 + rails/game/model/BonusModel.java | 7 rails/game/model/CalculatedMoneyModel.java | 10 rails/game/model/CashMoneyModel.java | 5 rails/game/model/CashOwner.java | 8 rails/game/model/CertificateCountModel.java | 31 rails/game/model/CertificatesModel.java | 12 rails/game/model/MoneyModel.java | 7 rails/game/model/PortfolioModel.java | 119 +-- rails/game/model/PortfolioOwner.java | 10 rails/game/model/PresidentModel.java | 14 rails/game/model/PriceModel.java | 19 rails/game/model/PrivatesModel.java | 9 rails/game/model/TrainsModel.java | 11 rails/game/round/RoundContext.java | 10 rails/game/special/ExchangeForShare.java | 5 rails/game/special/SellBonusToken.java | 25 rails/game/special/SpecialProperty.java | 54 - rails/game/special/SpecialPropertyI.java | 70 - rails/game/special/SpecialRight.java | 6 rails/game/special/SpecialTileLay.java | 8 rails/game/specific/_1825/PublicCompany_1825.java | 16 rails/game/specific/_1825/StartRound_1825.java | 2 rails/game/specific/_1825/StockRound_1825.java | 2 rails/game/specific/_1835/GameManager_1835.java | 15 rails/game/specific/_1835/OperatingRound_1835.java | 29 rails/game/specific/_1835/PrussianFormationRound.java | 32 rails/game/specific/_1835/StockRound_1835.java | 12 rails/game/specific/_1856/CGRFormationRound.java | 82 +- rails/game/specific/_1856/GameManager_1856.java | 13 rails/game/specific/_1856/OperatingRound_1856.java | 28 rails/game/specific/_1856/PublicCompany_1856.java | 24 rails/game/specific/_1856/PublicCompany_CGR.java | 28 rails/game/specific/_1856/ShareSellingRound_1856.java | 26 rails/game/specific/_1856/StockRound_1856.java | 43 - rails/game/specific/_1880/StartRound_1880.java | 43 - rails/game/specific/_1889/OperatingRound_1889.java | 52 - rails/game/specific/_18AL/AssignNamedTrains.java | 6 rails/game/specific/_18AL/NameTrains.java | 3 rails/game/specific/_18AL/NameableTrain.java | 12 rails/game/specific/_18AL/NamedTrainRevenueModifier.java | 2 rails/game/specific/_18AL/NamedTrainToken.java | 7 rails/game/specific/_18AL/OperatingRound_18AL.java | 2 rails/game/specific/_18EU/GameManager_18EU.java | 32 rails/game/specific/_18EU/OperatingRound_18EU.java | 56 - rails/game/specific/_18EU/StartRound_18EU.java | 46 - rails/game/specific/_18EU/StockRound_18EU.java | 94 +- rails/game/specific/_18GA/OperatingRound_18GA.java | 4 rails/game/specific/_18TN/OperatingRound_18TN.java | 14 rails/game/specific/_18TN/PublicCompany_18TN.java | 15 rails/game/state/AbstractItem.java | 13 rails/game/state/ArrayListMultimapState.java | 6 rails/game/state/ArrayListState.java | 6 rails/game/state/BooleanState.java | 6 rails/game/state/ChangeStack.java | 2 rails/game/state/Context.java | 4 rails/game/state/GenericState.java | 8 rails/game/state/HashMapState.java | 6 rails/game/state/HashMultimapState.java | 5 rails/game/state/HashSetState.java | 6 rails/game/state/IntegerChange.java | 2 rails/game/state/IntegerState.java | 10 rails/game/state/Item.java | 2 rails/game/state/Ownable.java | 20 rails/game/state/OwnableItem.java | 22 rails/game/state/Owner.java | 13 rails/game/state/Portfolio.java | 36 rails/game/state/PortfolioChange.java | 2 rails/game/state/PortfolioHolder.java | 8 rails/game/state/PortfolioList.java | 10 rails/game/state/PortfolioManager.java | 12 rails/game/state/PortfolioMap.java | 10 rails/game/state/Root.java | 4 rails/game/state/State.java | 5 rails/game/state/StateManager.java | 8 rails/game/state/StringState.java | 6 rails/game/state/TileMove.java | 8 rails/game/state/Wallet.java | 6 rails/game/state/WalletManager.java | 6 rails/ui/swing/GameStatus.java | 21 rails/ui/swing/GameUIManager.java | 10 rails/ui/swing/GridPanel.java | 30 rails/ui/swing/ORPanel.java | 10 rails/ui/swing/ORUIManager.java | 36 rails/ui/swing/RemainingTilesWindow.java | 9 rails/ui/swing/StartRoundWindow.java | 4 rails/ui/swing/StatusWindow.java | 4 rails/ui/swing/UpgradesPanel.java | 48 - rails/ui/swing/gamespecific/_1835/StatusWindow_1835.java | 2 rails/ui/swing/gamespecific/_1856/StatusWindow_1856.java | 2 rails/ui/swing/hexmap/GUIHex.java | 51 - rails/ui/swing/hexmap/GUITile.java | 8 rails/ui/swing/hexmap/HexMap.java | 5 rails/ui/swing/hexmap/HexMapImage.java | 16 rails/util/Util.java | 28 161 files changed, 2799 insertions(+), 2880 deletions(-) New commits: commit f080601bedb11b14264515a41730fd62f30e0025 Author: Stefan Frey <ste...@we...> Date: Sun May 20 15:18:54 2012 +0200 further changes to the new defined elements diff --git a/rails/algorithms/NetworkGraphBuilder.java b/rails/algorithms/NetworkGraphBuilder.java index 0204793..a1a5d7f 100644 --- a/rails/algorithms/NetworkGraphBuilder.java +++ b/rails/algorithms/NetworkGraphBuilder.java @@ -32,7 +32,7 @@ import rails.game.MapHex; import rails.game.MapManager; import rails.game.PublicCompany; import rails.game.Station; -import rails.game.TileI; +import rails.game.Tile; import rails.game.Token; import rails.game.Track; import rails.game.state.Owner; @@ -64,7 +64,7 @@ public final class NetworkGraphBuilder implements Iterable<NetworkVertex> { for (MapHex hex:mapManager.getHexesAsList()) { // get Tile - TileI tile = hex.getCurrentTile(); + Tile tile = hex.getCurrentTile(); // then get stations List<Station> stations = tile.getStations(); @@ -89,7 +89,7 @@ public final class NetworkGraphBuilder implements Iterable<NetworkVertex> { // loop over all maps and add tracks for (MapHex hex:mapManager.getHexesAsList()) { // get Tile - TileI tile = hex.getCurrentTile(); + Tile tile = hex.getCurrentTile(); // get Tracks List<Track> tracks = tile.getTracks(); @@ -178,6 +178,7 @@ public final class NetworkGraphBuilder implements Iterable<NetworkVertex> { public NetworkVertex getVertex(Token token) { if (!(token instanceof BaseToken)) return null; Owner owner = token.getOwner(); + // TODO: Check if this still works if (!(owner instanceof Stop)) return null; Stop city = (Stop)owner; MapHex hex = city.getHolder(); diff --git a/rails/algorithms/RevenueManager.java b/rails/algorithms/RevenueManager.java index bfba854..a6e0cfc 100644 --- a/rails/algorithms/RevenueManager.java +++ b/rails/algorithms/RevenueManager.java @@ -14,6 +14,7 @@ import rails.common.parser.Tag; import rails.game.GameManager; import rails.game.state.AbstractItem; import rails.game.state.ArrayListState; +import rails.game.state.Item; /** * Coordinates and stores all elements related to revenue calulcation, @@ -30,25 +31,17 @@ public final class RevenueManager extends AbstractItem implements ConfigurableCo protected static Logger log = Logger.getLogger(RevenueManager.class.getPackage().getName()); - private final HashSet<ConfigurableComponentI> configurableModifiers; + private final HashSet<ConfigurableComponentI> configurableModifiers = new HashSet<ConfigurableComponentI>(); - private final ArrayListState<NetworkGraphModifier> graphModifiers; - private final ArrayListState<RevenueStaticModifier> staticModifiers; - private final ArrayListState<RevenueDynamicModifier> dynamicModifiers; + private final ArrayListState<NetworkGraphModifier> graphModifiers = ArrayListState.create(); + private final ArrayListState<RevenueStaticModifier> staticModifiers = ArrayListState.create(); + private final ArrayListState<RevenueDynamicModifier> dynamicModifiers = ArrayListState.create(); - private final ArrayList<RevenueStaticModifier> activeStaticModifiers; - private final ArrayList<RevenueDynamicModifier> activeDynamicModifiers; + private final ArrayList<RevenueStaticModifier> activeStaticModifiers = new ArrayList<RevenueStaticModifier>(); + private final ArrayList<RevenueDynamicModifier> activeDynamicModifiers = new ArrayList<RevenueDynamicModifier>(); private RevenueDynamicModifier activeCalculator; - public RevenueManager() { - graphModifiers = ArrayListState.create(this, "NetworkGraphModifiers"); - staticModifiers = ArrayListState.create(this, "RevenueStaticModifiers"); - dynamicModifiers = ArrayListState.create(this, "RevenueDynamicModifiers"); - configurableModifiers = new HashSet<ConfigurableComponentI>(); - - activeStaticModifiers = new ArrayList<RevenueStaticModifier>(); - activeDynamicModifiers = new ArrayList<RevenueDynamicModifier>(); - } + public RevenueManager() {} public void configureFromXML(Tag tag) throws ConfigurationException { @@ -100,6 +93,14 @@ public final class RevenueManager extends AbstractItem implements ConfigurableCo } + @Override + public void init(Item parent, String id) { + super.init(parent, id); + graphModifiers.init(this, "NetworkGraphModifiers"); + staticModifiers.init(this, "RevenueStaticModifiers"); + dynamicModifiers.init(this, "RevenueDynamicModifiers"); + } + public void finishConfiguration(GameManager parent) throws ConfigurationException { for (ConfigurableComponentI modifier:configurableModifiers) { diff --git a/rails/common/GuiHints.java b/rails/common/GuiHints.java index b386bc8..a40d4ac 100644 --- a/rails/common/GuiHints.java +++ b/rails/common/GuiHints.java @@ -4,9 +4,10 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import rails.game.RoundI; +import rails.game.Round; import rails.game.state.AbstractItem; import rails.game.state.GenericState; +import rails.game.state.Item; /** * This class contains hints from the server (game engine) to the client (GUI) @@ -21,25 +22,27 @@ public class GuiHints extends AbstractItem implements Serializable{ public static final long serialVersionUID = 1L; /** What round type is currently active in the engine? */ - private GenericState<Class<? extends RoundI>> currentRoundType = null; + private GenericState<Class<? extends Round>> currentRoundType = GenericState.create(); /** Which windows should be visible? */ private List<VisibilityHint> visibilityHints; /** Which window type is active and should be on top? */ - private GenericState<GuiDef.Panel> activePanel = null; + private GenericState<GuiDef.Panel> activePanel = GenericState.create(); - public Class<? extends RoundI> getCurrentRoundType() { + @Override + public void init(Item parent, String id){ + super.init(parent, id); + currentRoundType.init(this, "CurrentRoundType"); + activePanel.init(this, "ActivePanel"); + } + + public Class<? extends Round> getCurrentRoundType() { return currentRoundType.get(); } - public void setCurrentRoundType(Class<? extends RoundI> currentRoundType) { - if (this.currentRoundType == null) { - this.currentRoundType = GenericState.<Class<? extends RoundI>>create - (this, "CurrentRoundType", currentRoundType); - } else { - this.currentRoundType.set(currentRoundType); - } + public void setCurrentRoundType(Class<? extends Round> currentRoundType) { + this.currentRoundType.set(currentRoundType); } public List<VisibilityHint> getVisibilityHints() { @@ -66,11 +69,7 @@ public class GuiHints extends AbstractItem implements Serializable{ } public void setActivePanel(GuiDef.Panel activePanel) { - if (this.activePanel == null) { - this.activePanel = GenericState.create(this, "ActivePanel", activePanel); - } else { - this.activePanel.set(activePanel); - } + this.activePanel.set(activePanel); } public class VisibilityHint { diff --git a/rails/common/ResourceLoader.java b/rails/common/ResourceLoader.java index b064b9a..c31eebb 100644 --- a/rails/common/ResourceLoader.java +++ b/rails/common/ResourceLoader.java @@ -41,10 +41,6 @@ public final class ResourceLoader { super(parent); } - RailsClassLoader() { - super(); - } - @Override public Class<?> findClass(String className) throws ClassNotFoundException { diff --git a/rails/game/AbstractRound.java b/rails/game/AbstractRound.java new file mode 100644 index 0000000..ebdccfc --- /dev/null +++ b/rails/game/AbstractRound.java @@ -0,0 +1,544 @@ +package rails.game; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.log4j.Logger; + +import rails.common.*; +import rails.game.action.*; +import rails.game.model.CashOwner; +import rails.game.model.MoneyModel; +import rails.game.model.PortfolioModel; +import rails.game.special.SpecialProperty; +import rails.game.state.AbstractItem; +import rails.game.state.ArrayListState; +import rails.game.state.BooleanState; +import rails.game.state.ChangeStack; +import rails.game.state.Item; +import rails.game.state.Portfolio; + +/** + * @author Erik Vos + */ +public abstract class AbstractRound extends AbstractItem implements Round { + + protected PossibleActions possibleActions = PossibleActions.getInstance(); + protected GuiHints guiHints = null; + + protected static Logger log = + Logger.getLogger(AbstractRound.class.getPackage().getName()); + + protected GameManager gameManager = null; + protected CompanyManagerI companyManager = null; + protected PlayerManager playerManager = null; + protected Bank bank = null; + protected PortfolioModel ipo = null; + protected PortfolioModel pool = null; + protected PortfolioModel unavailable = null; + protected PortfolioModel scrapHeap = null; + protected StockMarket stockMarket = null; + protected MapManager mapManager = null; + + protected final BooleanState wasInterrupted = BooleanState.create(false); + + protected ChangeStack changeStack = null; + + + /** Autopasses */ + // TODO: Should this be moved to the StockRound classes? + // Only initialized if used + protected ArrayListState<Player> autopasses = null; + protected ArrayListState<Player> canRequestTurn = null; + protected ArrayListState<Player> hasRequestedTurn = null; + + /** + * Constructor with the GameManager, will call setGameManager with the parameter to initialize + * + * @param aGameManager The GameManager Object needed to initialize the Round Class + * + */ + public AbstractRound (GameManager aGameManager) { + + this.gameManager = aGameManager; + + if (gameManager == null) { + companyManager = null; + } else { + companyManager = gameManager.getCompanyManager(); + playerManager = gameManager.getPlayerManager(); + bank = gameManager.getBank(); + ipo = bank.getIpo(); + pool = bank.getPool(); + unavailable = bank.getUnavailable(); + scrapHeap = bank.getScrapHeap(); + stockMarket = gameManager.getStockMarket(); + mapManager = gameManager.getMapManager(); + + changeStack = gameManager.getChangeStack(); + } + + guiHints = gameManager.getUIHints(); + guiHints.setCurrentRoundType(getClass()); + } + + @Override + public void init(Item parent, String id) { + super.init(parent, id); + wasInterrupted.init(this, "RoundInterrupted"); + } + + public Player getCurrentPlayer() { + + if (gameManager != null) return gameManager.getCurrentPlayer(); + return null; + } + + /** + * @return Returns the currentPlayerIndex. + */ + public int getCurrentPlayerIndex() { + return getCurrentPlayer().getIndex(); + } + + public void setCurrentPlayerIndex(int newIndex) { + gameManager.setCurrentPlayerIndex(newIndex); + } + + public void setCurrentPlayer(Player player) { + gameManager.setCurrentPlayer(player); + } + + protected List<Player> getPlayers() { + return gameManager.getPlayers(); + } + + protected int getNumberOfPlayers() { + return gameManager.getNumberOfPlayers(); + } + + protected int getNumberOfActivePlayers () { + int number = 0; + for (Player player : getPlayers()) { + if (!player.isBankrupt()) number++; + } + return number; + } + + public Phase getCurrentPhase() { + return gameManager.getCurrentPhase(); + } + + /** Allows round instances to tell the UI what type of window to raise. + * Normally the type corresponds to the round type (e.g. OperatingRound + * needs ORWindow), but sometimes deviations occur (such as the + * CGRFormationRound, which isn't a StockRound type but needs StatusWindow). + * @return + */ + public Class<? extends Round> getRoundTypeForUI () { + return this.getClass(); + } + + public String getGameOption (String name) { + return gameManager.getGameOption(name); + } + + // TODO: Remove as this is abstract class? + public String getHelp() { + // TODO Auto-generated method stub + return null; + } + + // TODO: Remove as this is abstract class? + public List<SpecialProperty> getSpecialProperties() { + // TODO Auto-generated method stub + return null; + } + + public boolean process(PossibleAction action) { + return true; + } + + protected boolean exchangeTokens(ExchangeTokens action, boolean linkedMoveSet) { + + String errMsg = null; + + List<ExchangeableToken> tokens = action.getTokensToExchange(); + int min = action.getMinNumberToExchange(); + int max = action.getMaxNumberToExchange(); + int exchanged = 0; + + checks: { + + for (ExchangeableToken token : tokens) { + if (token.isSelected()) exchanged++; + } + if (exchanged < min || exchanged > max) { + errMsg = LocalText.getText("WrongNumberOfTokensExchanged", + action.getCompany(), + min, max, exchanged); + break checks; + } + } + + if (errMsg != null) { + DisplayBuffer.add(LocalText.getText("CannotExchangeTokens", + action.getCompany(), + action.toString(), + errMsg)); + + return false; + } + + // TODO: changeStack.start(true); + // FIMXE: if (linkedMoveSet) changeStack.linkToPreviousMoveSet(); + + if (exchanged > 0) { + MapHex hex; + Stop city; + String cityName, hexName; + int cityNumber; + String[] ct; + PublicCompany comp = action.getCompany(); + + ReportBuffer.add(""); + + for (ExchangeableToken token : tokens) { + cityName = token.getCityName(); + ct = cityName.split("/"); + hexName = ct[0]; + try { + cityNumber = Integer.parseInt(ct[1]); + } catch (NumberFormatException e) { + cityNumber = 1; + } + hex = mapManager.getHex(hexName); + city = hex.getStop(cityNumber); + + if (token.isSelected()) { + + // For now we'll assume that the old token(s) have already been removed. + // This is true in the 1856 CGR formation. + if (hex.layBaseToken(comp, city.getNumber())) { + /* TODO: the false return value must be impossible. */ + ReportBuffer.add(LocalText.getText("ExchangesBaseToken", + comp.getId(), + token.getOldCompanyName(), + city.getId())); + comp.layBaseToken(hex, 0); + } + } else { + ReportBuffer.add(LocalText.getText("NoBaseTokenExchange", + comp.getId(), + token.getOldCompanyName(), + city.getId())); + } + } + } + + return true; + } + + + /** + * Default version, does nothing. Subclasses should override this method + * with a real version. + */ + // TODO: Remove as this is abstract class? + public boolean setPossibleActions() { + return false; + } + + /** Set the operating companies in their current acting order */ + public List<PublicCompany> setOperatingCompanies() { + return setOperatingCompanies (null, null); + } + + public List<PublicCompany> setOperatingCompanies(List<PublicCompany> oldOperatingCompanies, + PublicCompany lastOperatingCompany) { + + Map<Integer, PublicCompany> operatingCompanies = + new TreeMap<Integer, PublicCompany>(); + List<PublicCompany> newOperatingCompanies; + StockSpace space; + int key; + int minorNo = 0; + boolean reorder = gameManager.isDynamicOperatingOrder() + && oldOperatingCompanies != null && lastOperatingCompany != null; + + int lastOperatingCompanyndex; + if (reorder) { + newOperatingCompanies = oldOperatingCompanies; + lastOperatingCompanyndex = oldOperatingCompanies.indexOf(lastOperatingCompany); + } else { + newOperatingCompanies = companyManager.getAllPublicCompanies(); + lastOperatingCompanyndex = -1; + } + + for (PublicCompany company : newOperatingCompanies) { + if (!reorder && !canCompanyOperateThisRound(company)) continue; + + if (reorder + && oldOperatingCompanies.indexOf(company) <= lastOperatingCompanyndex) { + // Companies that have operated this round get lowest keys + key = oldOperatingCompanies.indexOf(company); + } else if (company.hasStockPrice()) { + // Key must put companies in reverse operating order, because sort + // is ascending. + space = company.getCurrentSpace(); + key = 1000000 * (999 - space.getPrice()) + + 10000 * (99 - space.getColumn()) + + 100 * (space.getRow()+1) + + space.getStackPosition(company); + } else { + key = 50 + ++minorNo; + } + operatingCompanies.put(new Integer(key), company); + } + + return new ArrayList<PublicCompany>(operatingCompanies.values()); + } + + /** Can a public company operate? (Default version) */ + protected boolean canCompanyOperateThisRound (PublicCompany company) { + return company.hasFloated() && !company.isClosed(); + } + + /** + * Check if a company must be floated, and if so, do it. <p>This method is + * included here because it is used in various types of Round. + * + * @param company + */ + protected void checkFlotation(PublicCompany company) { + + if (!company.hasStarted() || company.hasFloated()) return; + + if (getSoldPercentage(company) >= company.getFloatPercentage()) { + // Company floats + floatCompany(company); + } + } + + /** Determine sold percentage for floating purposes */ + protected int getSoldPercentage (PublicCompany company) { + + int soldPercentage = 0; + for (PublicCertificate cert : company.getCertificates()) { + if (certCountsAsSold(cert)) { + soldPercentage += cert.getShare(); + } + } + return soldPercentage; + } + + /** Can be subclassed for games with special rules */ + protected boolean certCountsAsSold (PublicCertificate cert) { + Portfolio<PublicCertificate> portfolio = cert.getPortfolio(); + return portfolio.getOwner() instanceof Player || portfolio.getParent() == pool; + } + + /** + * Float a company, including a default implementation of moving cash and + * shares as a result of flotation. <p>Full capitalisation is implemented + * as in 1830. Partial capitalisation is implemented as in 1851. Other ways + * to process the consequences of company flotation must be handled in + * game-specific subclasses. + */ + protected void floatCompany(PublicCompany company) { + + // Move cash and shares where required + int soldPercentage = getSoldPercentage(company); + int cash = 0; + int capitalisationMode = company.getCapitalisation(); + if (company.hasStockPrice()) { + int capFactor = 0; + int shareUnit = company.getShareUnit(); + if (capitalisationMode == PublicCompany.CAPITALISE_FULL) { + // Full capitalisation as in 1830 + capFactor = 100 / shareUnit; + } else if (capitalisationMode == PublicCompany.CAPITALISE_INCREMENTAL) { + // Incremental capitalisation as in 1851 + capFactor = soldPercentage / shareUnit; + } else if (capitalisationMode == PublicCompany.CAPITALISE_WHEN_BOUGHT) { + // Cash goes directly to treasury at each buy (as in 1856 before phase 6) + capFactor = 0; + } + int price = company.getIPOPrice(); + cash = capFactor * price; + } else { + cash = company.getFixedPrice(); + } + + // Substract initial token cost (e.g. 1851, 18EU) + cash -= company.getBaseTokensBuyCost(); + + company.setFloated(); // After calculating cash (for 1851: price goes + // up) + + if (cash > 0) { + MoneyModel.cashMove(bank, company, cash); + ReportBuffer.add(LocalText.getText("FloatsWithCash", + company.getId(), + Bank.format(cash) )); + } else { + ReportBuffer.add(LocalText.getText("Floats", + company.getId())); + } + + if (capitalisationMode == PublicCompany.CAPITALISE_INCREMENTAL + && company.canHoldOwnShares()) { + // move all shares from ipo to the company portfolio + // FIXME: Is this correct? + // Should a company not have a Portfolio<Share> where it stores the certificates that it owns + Portfolio.moveAll(ipo.getShareModel(company).getPortfolio(), company.getPortfolioModel().getShareModel(company).getPortfolio()); + } + } + + protected void finishRound() { + // Report financials + ReportBuffer.add(""); + for (PublicCompany c : companyManager.getAllPublicCompanies()) { + if (c.hasFloated() && !c.isClosed()) { + ReportBuffer.add(LocalText.getText("Has", c.getId(), + Bank.format(c.getCash()))); + } + } + for (Player p : playerManager.getPlayers()) { + ReportBuffer.add(LocalText.getText("Has", p.getId(), + Bank.format(p.getCashValue()))); + } + // Inform GameManager + gameManager.nextRound(this); + } + + /** Generic stub to resume an interrupted round. + * Only valid if implemented in a subclass. + * + */ + public void resume() { + log.error("Calling Round.resume() is invalid"); + } + + public boolean wasInterrupted () { + return wasInterrupted.booleanValue(); + } + + @Override + public String toString() { + return getClass().getName().replaceAll(".*\\.", ""); + } + + protected void transferCertificate(Certificate cert, PortfolioModel newHolder) { + if (cert instanceof PublicCertificate) { + newHolder.addPublicCertificate((PublicCertificate)cert); + } else if (cert instanceof PrivateCompany) { + newHolder.addPrivateCompany((PrivateCompany)cert); + } + } + + // Note: all transferred shares must come from the same old shareholder. + // TODO: This is not very a very nice implementation + protected void transferCertificates(List<? extends Certificate> certs, + PortfolioModel newHolder) { + + for (Certificate cert : certs) { + if (cert != null) { + transferCertificate(cert, newHolder); + } + } + } + + protected void pay (CashOwner from, CashOwner to, int amount) { + if (to != null && amount != 0) { + MoneyModel.cashMove (from, to, amount); + } + } + + public GameManager getGameManager() { + return gameManager; + } + + protected Object getGameParameter (GameDef.Parm key) { + return gameManager.getGameParameter(key); + } + + public int getGameParameterAsInt (GameDef.Parm key) { + if (key.defaultValue() instanceof Integer) { + return (Integer) gameManager.getGameParameter(key); + } else { + return -1; + } + } + + public boolean getGameParameterAsBoolean (GameDef.Parm key) { + if (key.defaultValue() instanceof Boolean) { + return (Boolean) gameManager.getGameParameter(key); + } else { + return false; + } + } + + public String getRoundName() { + return this.getClass().getSimpleName(); + } + + public boolean requestTurn (Player player) { + if (canRequestTurn (player)) { + if (hasRequestedTurn == null) { + hasRequestedTurn = ArrayListState.create(); + hasRequestedTurn.init(this, "hasRequestedTurn"); + } + if (!hasRequestedTurn.contains(player)) hasRequestedTurn.add(player); + return true; + } + return false; + } + + public boolean canRequestTurn (Player player) { + return canRequestTurn != null && canRequestTurn.contains(player); + } + + public void setCanRequestTurn (Player player, boolean value) { + if (canRequestTurn == null) { + canRequestTurn = ArrayListState.create(); + canRequestTurn.init(this, "canRequestTurn"); + } + if (value && !canRequestTurn.contains(player)) { + canRequestTurn.add(player); + } else if (!value && canRequestTurn.contains(player)) { + canRequestTurn.remove(player); + } + } + + public void setAutopass (Player player, boolean value) { + if (autopasses == null) { + autopasses = ArrayListState.create(); + autopasses.init(this, "autopasses"); + } + if (value && !autopasses.contains(player)) { + autopasses.add(player); + } else if (!value && autopasses.contains(player)) { + autopasses.remove(player); + } + } + + public boolean hasAutopassed (Player player) { + return autopasses != null && autopasses.contains(player); + } + + public List<Player> getAutopasses() { + return autopasses.view(); + } + + /** A stub for processing actions triggered by a phase change. + * Must be overridden by subclasses that need to process such actions. + * @param name (required) The name of the action to be executed + * @param value (optional) The value of the action to be executed, if applicable + */ + public void processPhaseAction (String name, String value) { + + } +} diff --git a/rails/game/Bank.java b/rails/game/Bank.java index 5bebc7c..d5bf827 100644 --- a/rails/game/Bank.java +++ b/rails/game/Bank.java @@ -33,15 +33,15 @@ public class Bank extends AbstractItem implements CashOwner, ConfigurableCompone /** The Bank's amount of cash */ private final CashMoneyModel cash = CashMoneyModel.create(); - + /** The IPO */ - private final PortfolioModel ipo = PortfolioModel.create(); + private final BankPortfolio ipo = BankPortfolio.create(); /** The Bank Pool */ - private final PortfolioModel pool = PortfolioModel.create(); + private final BankPortfolio pool = BankPortfolio.create(); /** Collection of items that will (may) become available in the future */ - private final PortfolioModel unavailable = PortfolioModel.create(); + private final BankPortfolio unavailable = BankPortfolio.create(); /** Collection of items that have been discarded (but are kept to allow Undo) */ - private final PortfolioModel scrapHeap = PortfolioModel.create(); + private final BankPortfolio scrapHeap = BankPortfolio.create(); /** Is the bank broken */ private final BooleanState broken = BooleanState.create(); @@ -117,7 +117,7 @@ public class Bank extends AbstractItem implements CashOwner, ConfigurableCompone List<PrivateCompany> privates = gameManager.getCompanyManager().getAllPrivateCompanies(); for (PrivateCompany priv : privates) { - ipo.addPrivate(priv, -1); + ipo.getPortfolioModel().addPrivateCompany(priv); } // Add public companies @@ -126,9 +126,10 @@ public class Bank extends AbstractItem implements CashOwner, ConfigurableCompone for (PublicCompany comp : companies) { for (PublicCertificate cert : comp.getCertificates()) { if (cert.isInitiallyAvailable()) { - ipo.moveInto(cert); + // TODO: Make this shorter + ipo.getPortfolioModel().getShareModel(comp).getPortfolio().moveInto(cert); } else { - unavailable.moveInto(cert); + unavailable.getPortfolioModel().getShareModel(comp).getPortfolio().moveInto(cert); } } } @@ -138,11 +139,11 @@ public class Bank extends AbstractItem implements CashOwner, ConfigurableCompone * @return IPO Portfolio */ public PortfolioModel getIpo() { - return ipo; + return ipo.getPortfolioModel(); } public PortfolioModel getScrapHeap() { - return scrapHeap; + return scrapHeap.getPortfolioModel(); } /* FIXME: Add broken check somewhere @@ -159,14 +160,14 @@ public class Bank extends AbstractItem implements CashOwner, ConfigurableCompone * @return Portfolio of stock in Bank Pool */ public PortfolioModel getPool() { - return pool; + return pool.getPortfolioModel(); } /** * @return Portfolio of unavailable shares */ public PortfolioModel getUnavailable() { - return unavailable; + return unavailable.getPortfolioModel(); } public String getId() { @@ -174,8 +175,8 @@ public class Bank extends AbstractItem implements CashOwner, ConfigurableCompone } // CashOwner interface - public CashMoneyModel getCash() { - return cash; + public int getCash() { + return cash.value(); } public static String format(int amount) { @@ -194,5 +195,10 @@ public class Bank extends AbstractItem implements CashOwner, ConfigurableCompone } return result.toString(); } + + public CashMoneyModel getCashModel() { + // TODO Auto-generated method stub + return null; + } } diff --git a/rails/game/BankPortfolio.java b/rails/game/BankPortfolio.java new file mode 100644 index 0000000..ce62f23 --- /dev/null +++ b/rails/game/BankPortfolio.java @@ -0,0 +1,38 @@ +package rails.game; + +import rails.game.model.PortfolioModel; +import rails.game.model.PortfolioOwner; +import rails.game.state.AbstractItem; +import rails.game.state.Item; + +/** + * BankPortfolios + */ + +public class BankPortfolio extends AbstractItem implements PortfolioOwner { + + private final PortfolioModel portfolio = PortfolioModel.create(); + + private BankPortfolio() {} + + public static BankPortfolio create() { + BankPortfolio bp = new BankPortfolio(); + return bp; + } + + /** + * parent is restricted to Bank + */ + @Override + public void init(Item parent, String id) { + super.checkedInit(parent, id, Bank.class); + portfolio.init(this, "portfolio"); + } + + // PortfolioOwner methods + public PortfolioModel getPortfolioModel() { + return portfolio; + } + + +} diff --git a/rails/game/BaseToken.java b/rails/game/BaseToken.java index ce55773..253bad1 100644 --- a/rails/game/BaseToken.java +++ b/rails/game/BaseToken.java @@ -14,19 +14,18 @@ import rails.game.state.Item; */ public final class BaseToken extends Token { - /** - * Creates a non-initialized BaseToken - */ - public BaseToken() {}; + private BaseToken() {}; + + public static BaseToken create(PublicCompany company) { + BaseToken token = new BaseToken(); + token.init(company); + return token; + } @Override - public BaseToken init(Item parent) { + public void init(Item parent) { super.checkedInit(parent, null, PublicCompany.class); - // add token to the free tokens, this also intializes the portfolio - getParent().getBaseTokensModel().addFreeToken(this); - - return this; } @Override diff --git a/rails/game/BonusToken.java b/rails/game/BonusToken.java index 3f33613..9c8f871 100644 --- a/rails/game/BonusToken.java +++ b/rails/game/BonusToken.java @@ -23,16 +23,17 @@ public final class BonusToken extends Token implements Closeable, ConfigurableCo private Object removingObject = null; private PublicCompany user = null; - /** - * Creates a non-initialized BonusToken - */ - public BonusToken() {}; + private BonusToken() {}; + + public static BonusToken create(PublicCompany company) { + BonusToken token = new BonusToken(); + token.init(company); + return token; + } - // FIXME: Who is the parent of BonusToken? @Override - public BonusToken init(Item parent) { - super.checkedInit(parent, null, Item.class); - return this; + public void init(Item parent) { + super.checkedInit(parent, null, PublicCompany.class); } public void configureFromXML(Tag tag) throws ConfigurationException { diff --git a/rails/game/Certificate.java b/rails/game/Certificate.java index 638fe51..b4cf016 100644 --- a/rails/game/Certificate.java +++ b/rails/game/Certificate.java @@ -1,5 +1,7 @@ package rails.game; +import rails.game.state.Item; + /** * The superinterface of PrivateCompany and PublicCertificate, which allows * objects implementating these interfaces to be combined in start packets and @@ -8,7 +10,7 @@ package rails.game; * TODO: Check if this is still needed (or replaced by Ownable) or could be extended by * combining methods from both public and private certificates */ -public interface Certificate{ +public interface Certificate extends Item { } diff --git a/rails/game/Company.java b/rails/game/Company.java index 2ec211b..f628f88 100644 --- a/rails/game/Company.java +++ b/rails/game/Company.java @@ -12,6 +12,7 @@ import rails.common.parser.Tag; import rails.game.special.SpecialProperty; import rails.game.state.BooleanState; import rails.game.state.AbstractItem; +import rails.game.state.Item; import rails.game.state.PortfolioList; import rails.util.Util; @@ -27,10 +28,9 @@ Cloneable, Comparable<Company> { /** The name of the XML attribute for the company's type. */ public static final String COMPANY_TYPE_TAG = "type"; - protected String name; protected String longName; protected String alias = null; // To allow reloading files with old names after name changes - protected CompanyTypeI type; + protected CompanyType type; protected int companyNumber; // For internal use protected String infoText = ""; @@ -56,15 +56,16 @@ Cloneable, Comparable<Company> { protected static Logger log = Logger.getLogger(Company.class.getPackage().getName()); - public Company() { - } - - public void init(String name, CompanyTypeI type) { - this.name = name; - this.type = type; + @Override + public void init(Item parent, String id) { + super.init(parent, id); closedObject.init(this, "closed"); specialProperties.init(this, "specialProperties"); } + + public void initType(CompanyType type) { + this.type = type; + } /** Only to be called from subclasses */ public void configureFromXML(Tag tag) throws ConfigurationException { @@ -140,7 +141,7 @@ Cloneable, Comparable<Company> { /** * @return Type of company (Public/Private) */ - public CompanyTypeI getType() { + public CompanyType getType() { return type; } @@ -148,14 +149,7 @@ Cloneable, Comparable<Company> { * @return String for type of company (Public/Private) */ public String getTypeName() { - return type.getName(); - } - - /** - * @return Name of company - */ - public String getId() { - return name; + return type.getId(); } public String getLongName() { @@ -234,7 +228,7 @@ Cloneable, Comparable<Company> { public boolean equals(Company company) { if (this.companyNumber == company.getCompanyNumber() - && this.name.equals(company.getId()) + && this.getId().equals(company.getId()) && this.type.equals(company.getType())) return true; return false; diff --git a/rails/game/CompanyManager.java b/rails/game/CompanyManager.java index 5a00ee5..257494c 100644 --- a/rails/game/CompanyManager.java +++ b/rails/game/CompanyManager.java @@ -1 +1 @@ -package rails.game; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import rails.common.LocalText; import rails.common.parser.ConfigurableComponentI; import rails.common.parser.ConfigurationException; import rails.common.parser.Tag; import rails.game.state.AbstractItem; public class CompanyManager extends AbstractItem implements CompanyManagerI, ConfigurableComponentI { /** A List with all private companies */ private List<PrivateCompany> lPrivateCompanies = new ArrayList<PrivateCompany>(); /** A List with all public companies */ private List<PublicCompany> lPublicCompanies = new ArrayList<PublicCompany>(); /** A map with all private companies by name */ private Map<String, PrivateCompany> mPrivateCompanies = new HashMap<String, PrivateCompany>(); /** A map with all public (i.e. non-private) companies by name */ private Map<String, PublicCompany> mPublicCompanies = new HashMap<String, PublicCompany>(); /** A map of all type names to maps of companies of that type by name */ // TODO Redundant, current usage can be replaced. private Map<String, Map<String, Company>> mCompaniesByTypeAndName = new HashMap<String, Map<String, Company>>(); /** A list of all company types */ private List<CompanyTypeI> lCompanyTypes = new ArrayList<CompanyTypeI>(); /** A list of all start packets (usually one) */ private List<StartPacket> startPackets = new ArrayList<StartPacket>(); /** A map of all start packets, keyed by name. Default name is "Initial" */ private Map<String, StartPacket> startPacketMap = new HashMap<String, StartPacket>(); /** A map to enable translating aliases to names */ protected Map<String, String> aliases = null; private int numberOfPublicCompanies = 0; protected static Logger log = Logger.getLogger(CompanyManager.class.getPackage().getName()); protec |