From: <ev...@us...> - 2010-07-04 20:44:36
|
Revision: 1331 http://rails.svn.sourceforge.net/rails/?rev=1331&view=rev Author: evos Date: 2010-07-04 20:44:29 +0000 (Sun, 04 Jul 2010) Log Message: ----------- Fixed price token order changes at end of SR Modified Paths: -------------- trunk/18xx/rails/game/GameManager.java trunk/18xx/rails/game/GameManagerI.java trunk/18xx/rails/game/StockRound.java Modified: trunk/18xx/rails/game/GameManager.java =================================================================== --- trunk/18xx/rails/game/GameManager.java 2010-07-04 15:17:14 UTC (rev 1330) +++ trunk/18xx/rails/game/GameManager.java 2010-07-04 20:44:29 UTC (rev 1331) @@ -1,10 +1,22 @@ /* $Header: /Users/blentz/rails_rcs/cvs/18xx/rails/game/GameManager.java,v 1.107 2010/06/17 21:35:54 evos Exp $ */ package rails.game; -import java.io.*; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; import org.apache.log4j.Logger; import org.apache.log4j.NDC; @@ -12,15 +24,28 @@ import rails.algorithms.RevenueManager; import rails.common.GuiDef; import rails.common.GuiHints; -import rails.game.action.*; -import rails.game.correct.*; -import rails.game.move.*; +import rails.game.action.GameAction; +import rails.game.action.NullAction; +import rails.game.action.PossibleAction; +import rails.game.action.PossibleActions; +import rails.game.action.RepayLoans; +import rails.game.correct.CorrectionAction; +import rails.game.correct.CorrectionManagerI; +import rails.game.correct.CorrectionType; +import rails.game.move.AddToList; +import rails.game.move.CashMove; +import rails.game.move.MoveStack; +import rails.game.move.Moveable; import rails.game.special.SpecialPropertyI; import rails.game.special.SpecialTokenLay; import rails.game.state.BooleanState; import rails.game.state.IntegerState; import rails.game.state.State; -import rails.util.*; +import rails.util.BuildInfo; +import rails.util.Config; +import rails.util.LocalText; +import rails.util.Tag; +import rails.util.Util; /** * This class manages the playing rounds by supervising all implementations of @@ -34,11 +59,11 @@ * action package. */ public static final long saveFileVersionID = - saveFileHeaderVersionID * PossibleAction.serialVersionUID; + saveFileHeaderVersionID * PossibleAction.serialVersionUID; protected Class<? extends StockRound> stockRoundClass = StockRound.class; protected Class<? extends OperatingRound> operatingRoundClass = - OperatingRound.class; + OperatingRound.class; // Variable UI Class names protected String gameUIManagerClassName = GuiDef.getDefaultClassName(GuiDef.ClassName.GAME_UI_MANAGER); @@ -75,7 +100,7 @@ new HashMap<String, Portfolio> (); protected IntegerState playerCertificateLimit - = new IntegerState ("PlayerCertificateLimit", 0); + = new IntegerState ("PlayerCertificateLimit", 0); protected int currentNumberOfOperatingRounds = 1; protected boolean skipFirstStockRound = false; protected boolean showCompositeORNumber = true; @@ -85,10 +110,10 @@ protected boolean gameEndsAfterSetOfORs = true; protected EnumMap<GameDef.Parm, Object> gameParameters - = new EnumMap<GameDef.Parm, Object>(GameDef.Parm.class); + = new EnumMap<GameDef.Parm, Object>(GameDef.Parm.class); -// protected EnumSet<CorrectionType> activeCorrections -// = EnumSet.noneOf(CorrectionType.class); + // protected EnumSet<CorrectionType> activeCorrections + // = EnumSet.noneOf(CorrectionType.class); /** * Current round should not be set here but from within the Round classes. @@ -103,9 +128,9 @@ protected IntegerState srNumber = new IntegerState ("SRNumber"); protected IntegerState absoluteORNumber = - new IntegerState("AbsoluteORNUmber"); + new IntegerState("AbsoluteORNUmber"); protected IntegerState relativeORNumber = - new IntegerState("RelativeORNumber"); + new IntegerState("RelativeORNumber"); protected int numOfORs; protected BooleanState gameOver = new BooleanState("GameOver" ,false); @@ -142,7 +167,7 @@ * For now, the key is a fixed string, but that may change in the future. */ protected static Map<String, GameManagerI> gameManagerMap - = new HashMap<String, GameManagerI>(); + = new HashMap<String, GameManagerI>(); /** * The temporary fixed key to the currently single GameManager instance @@ -188,10 +213,10 @@ /** A List of available game options */ protected List<GameOption> availableGameOptions = - new ArrayList<GameOption>(); + new ArrayList<GameOption>(); protected static Logger log = - Logger.getLogger(GameManager.class.getPackage().getName()); + Logger.getLogger(GameManager.class.getPackage().getName()); public GameManager() { gmName = GM_NAME; @@ -209,7 +234,7 @@ Tag gameTag = tag.getChild("Game"); if (gameTag == null) throw new ConfigurationException( - "No Game tag specified in GameManager tag"); + "No Game tag specified in GameManager tag"); gameName = gameTag.getAttributeAsString("name"); if (gameName == null) throw new ConfigurationException("No name specified in Game tag"); @@ -261,19 +286,19 @@ // StockRound class and other properties - Tag srTag = gameParmTag.getChild("StockRound"); + Tag srTag = gameParmTag.getChild("StockRound"); if (srTag != null) { String srClassName = - srTag.getAttributeAsString("class", "rails.game.StockRound"); + srTag.getAttributeAsString("class", "rails.game.StockRound"); try { stockRoundClass = - Class.forName(srClassName).asSubclass(StockRound.class); + Class.forName(srClassName).asSubclass(StockRound.class); } catch (ClassNotFoundException e) { throw new ConfigurationException("Cannot find class " - + srClassName, e); + + srClassName, e); } String stockRoundSequenceRuleString = - srTag.getAttributeAsString("sequence"); + srTag.getAttributeAsString("sequence"); if (Util.hasValue(stockRoundSequenceRuleString)) { if (stockRoundSequenceRuleString.equalsIgnoreCase("SellBuySell")) { setGameParameter(GameDef.Parm.STOCK_ROUND_SEQUENCE, @@ -288,8 +313,8 @@ } skipFirstStockRound = - srTag.getAttributeAsBoolean("skipFirst", - skipFirstStockRound); + srTag.getAttributeAsBoolean("skipFirst", + skipFirstStockRound); for (String ruleTagName : srTag.getChildren().keySet()) { if (ruleTagName.equals("NoSaleInFirstSR")) { @@ -301,21 +326,21 @@ } } - } + } // OperatingRound class Tag orTag = gameParmTag.getChild("OperatingRound"); if (orTag != null) { String orClassName = - orTag.getAttributeAsString("class", - "rails.game.OperatingRound"); + orTag.getAttributeAsString("class", + "rails.game.OperatingRound"); try { operatingRoundClass = - Class.forName(orClassName).asSubclass( - OperatingRound.class); + Class.forName(orClassName).asSubclass( + OperatingRound.class); } catch (ClassNotFoundException e) { throw new ConfigurationException("Cannot find class " - + orClassName, e); + + orClassName, e); } } @@ -354,8 +379,8 @@ Tag bankBreaksTag = endOfGameTag.getChild("BankBreaks"); if (bankBreaksTag != null) { gameEndsWhenBankHasLessOrEqual = - bankBreaksTag.getAttributeAsInteger("limit", - gameEndsWhenBankHasLessOrEqual); + bankBreaksTag.getAttributeAsInteger("limit", + gameEndsWhenBankHasLessOrEqual); String attr = bankBreaksTag.getAttributeAsString("finish"); if (attr.equalsIgnoreCase("SetOfORs")) { gameEndsAfterSetOfORs = true; @@ -372,7 +397,7 @@ Tag gameUIMgrTag = guiClassesTag.getChild("GameUIManager"); if (gameUIMgrTag != null) { gameUIManagerClassName = - gameUIMgrTag.getAttributeAsString("class", gameUIManagerClassName); + gameUIMgrTag.getAttributeAsString("class", gameUIManagerClassName); // Check instantiatability (not sure if this belongs here) canClassBeInstantiated (gameUIManagerClassName); } @@ -381,7 +406,7 @@ Tag orMgrTag = guiClassesTag.getChild("ORUIManager"); if (orMgrTag != null) { orUIManagerClassName = - orMgrTag.getAttributeAsString("class", orUIManagerClassName); + orMgrTag.getAttributeAsString("class", orUIManagerClassName); // Check instantiatability (not sure if this belongs here) canClassBeInstantiated (orUIManagerClassName); } @@ -390,7 +415,7 @@ Tag gameStatusTag = guiClassesTag.getChild("GameStatus"); if (gameStatusTag != null) { gameStatusClassName = - gameStatusTag.getAttributeAsString("class", gameStatusClassName); + gameStatusTag.getAttributeAsString("class", gameStatusClassName); // Check instantiatability (not sure if this belongs here) canClassBeInstantiated (gameStatusClassName); } @@ -399,8 +424,8 @@ Tag statusWindowTag = guiClassesTag.getChild("StatusWindow"); if (statusWindowTag != null) { statusWindowClassName = - statusWindowTag.getAttributeAsString("class", - statusWindowClassName); + statusWindowTag.getAttributeAsString("class", + statusWindowClassName); // Check instantiatability (not sure if this belongs here) canClassBeInstantiated (statusWindowClassName); } @@ -431,7 +456,7 @@ Class.forName(className); } catch (ClassNotFoundException e) { throw new ConfigurationException("Cannot find class " - + className, e); + + className, e); } } @@ -497,7 +522,7 @@ if (company.getMaxNumberOfLoans() != 0) guiParameters.put(GuiDef.Parm.HAS_ANY_COMPANY_LOANS, true); } -loop: for (PrivateCompanyI company : companyManager.getAllPrivateCompanies()) { + loop: for (PrivateCompanyI company : companyManager.getAllPrivateCompanies()) { for (SpecialPropertyI sp : company.getSpecialProperties()) { if (sp instanceof SpecialTokenLay && ((SpecialTokenLay)sp).getToken() instanceof BonusToken) { @@ -513,7 +538,7 @@ guiParameters.put(GuiDef.Parm.NO_MAP_MODE, true); guiParameters.put(GuiDef.Parm.ROUTE_HIGHLIGHT, false); guiParameters.put(GuiDef.Parm.REVENUE_SUGGEST, false); - } else { + } else { if (getGameOption("RouteAwareness").equalsIgnoreCase("Highlight")) { guiParameters.put(GuiDef.Parm.ROUTE_HIGHLIGHT, true); } @@ -561,7 +586,7 @@ startOperatingRound(false); } else if (skipFirstStockRound) { PhaseI currentPhase = - phaseManager.getCurrentPhase(); + phaseManager.getCurrentPhase(); numOfORs = currentPhase.getNumberOfOperatingRounds(); log.info("Phase=" + currentPhase.getName() + " ORs=" + numOfORs); @@ -612,7 +637,7 @@ } catch (Exception e) { log.fatal("Cannot find class " + startRoundClassName, e); - System.exit(1); + System.exit(1); } StartRound startRound = createRound (startRoundClass); startRound.start (); @@ -640,7 +665,7 @@ round = cons.newInstance(this); } catch (Exception e) { log.fatal("Cannot instantiate class " - + roundClass.getName(), e); + + roundClass.getName(), e); System.exit(1); } setRound (round); @@ -648,7 +673,7 @@ } protected <T extends RoundI, U extends RoundI> - T createRound (Class<T> roundClass, U parentRound) { + T createRound (Class<T> roundClass, U parentRound) { if (parentRound == null) { return createRound (roundClass); @@ -660,7 +685,7 @@ round = cons.newInstance(this, parentRound); } catch (Exception e) { log.fatal("Cannot instantiate class " - + roundClass.getName(), e); + + roundClass.getName(), e); System.exit(1); } setRound (round); @@ -710,7 +735,7 @@ interruptedRound = getCurrentRound(); createRound (ShareSellingRound.class, interruptedRound) - .start(player, cashToRaise, unsellableCompany); + .start(player, cashToRaise, unsellableCompany); } /* (non-Javadoc) @@ -799,7 +824,7 @@ if (result && !(action instanceof GameAction) && action.hasActed()) { new AddToList<PossibleAction>(executedActions, action, - "ExecutedActions"); + "ExecutedActions"); } } @@ -834,7 +859,7 @@ // logging of game actions activated for (PossibleAction pa : possibleActions.getList()) { log.debug(((Player) currentPlayer.getObject()).getName() + " may: " - + pa.toString()); + + pa.toString()); } return result; @@ -865,9 +890,9 @@ private boolean processCorrectionActions(PossibleAction a){ - boolean result = false; + boolean result = false; - if (a instanceof CorrectionAction) { + if (a instanceof CorrectionAction) { CorrectionAction ca= (CorrectionAction)a; CorrectionType ct = ca.getCorrectionType(); CorrectionManagerI cm = getCorrectionManager(ct); @@ -899,8 +924,8 @@ log.debug("Action ("+action.getPlayerName()+"): " + action); if (!processCorrectionActions(action) && !getCurrentRound().process(action)) { String msg = "Player "+action.getPlayerName()+"\'s action \"" - +action.toString()+"\"\n in "+getCurrentRound().getRoundName() - +" is considered invalid by the game engine"; + +action.toString()+"\"\n in "+getCurrentRound().getRoundName() + +" is considered invalid by the game engine"; log.error(msg); DisplayBuffer.add(msg); if (moveStack.isOpen()) moveStack.finish(); @@ -918,14 +943,14 @@ throw new Exception("Reload failure", e); } new AddToList<PossibleAction>(executedActions, action, - "ExecutedActions"); + "ExecutedActions"); if (moveStack.isOpen()) moveStack.finish(); - + log.debug("Turn: "+getCurrentPlayer().getName()); } -// DisplayBuffer.clear(); -// previous line removed to allow display of nextPlayerMessages + // DisplayBuffer.clear(); + // previous line removed to allow display of nextPlayerMessages guiHints.clearVisibilityHints(); return true; @@ -938,8 +963,8 @@ try { ObjectOutputStream oos = - new ObjectOutputStream(new FileOutputStream(new File( - filepath))); + new ObjectOutputStream(new FileOutputStream(new File( + filepath))); oos.writeObject(Game.version+" "+BuildInfo.buildDate); oos.writeObject(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); oos.writeObject(saveFileVersionID); @@ -973,8 +998,8 @@ for (MapHex hex:hexRow) if (hex != null) { pw.println(hex.getName() + "," + hex.getCurrentTile().getExternalId() + "," - + hex.getCurrentTileRotation() + "," - + hex.getOrientationName(hex.getCurrentTileRotation()) + + hex.getCurrentTileRotation() + "," + + hex.getOrientationName(hex.getCurrentTileRotation()) ) ; } @@ -1019,8 +1044,8 @@ public void registerBankruptcy() { endedByBankruptcy.set(true); String message = - LocalText.getText("PlayerIsBankrupt", - getCurrentPlayer().getName()); + LocalText.getText("PlayerIsBankrupt", + getCurrentPlayer().getName()); ReportBuffer.add(message); DisplayBuffer.add(message); if (gameEndsWithBankruptcy) { @@ -1044,7 +1069,7 @@ newPresident = null; maxShare = 0; for (int index=getCurrentPlayerIndex()+1; - index<getCurrentPlayerIndex()+numberOfPlayers; index++) { + index<getCurrentPlayerIndex()+numberOfPlayers; index++) { player = getPlayerByIndex(index%numberOfPlayers); share = player.getPortfolio().getShare(company); if (share >= company.getPresidentsShare().getShare() @@ -1068,7 +1093,7 @@ // Finish the share selling round if (getCurrentRound() instanceof ShareSellingRound) { - finishShareSellingRound(); + finishShareSellingRound(); } } } @@ -1142,7 +1167,7 @@ int i = 0; for (Player p : rankedPlayers) { b.add((++i) + ". " + Bank.format(p.getWorth()) + " " - + p.getName()); + + p.getName()); } return b; @@ -1167,8 +1192,8 @@ */ public void setCurrentPlayerIndex(int currentPlayerIndex) { currentPlayerIndex = currentPlayerIndex % numberOfPlayers; -// currentPlayer.set(players.get(currentPlayerIndex)); -// changed to activate nextPlayerMessages + // currentPlayer.set(players.get(currentPlayerIndex)); + // changed to activate nextPlayerMessages setCurrentPlayer(players.get(currentPlayerIndex)); } @@ -1192,7 +1217,7 @@ */ public void setPriorityPlayer() { int priorityPlayerIndex = - (getCurrentPlayer().getIndex() + 1) % numberOfPlayers; + (getCurrentPlayer().getIndex() + 1) % numberOfPlayers; setPriorityPlayer(players.get(priorityPlayerIndex)); } @@ -1203,7 +1228,7 @@ public void setPriorityPlayer(Player player) { priorityPlayer.set(player); log.debug("Priority player set to " + player.getIndex() + " " - + player.getName()); + + player.getName()); } /* (non-Javadoc) @@ -1280,7 +1305,7 @@ public void setNextPlayer() { int currentPlayerIndex = getCurrentPlayerIndex(); do { - currentPlayerIndex = ++currentPlayerIndex % numberOfPlayers; + currentPlayerIndex = ++currentPlayerIndex % numberOfPlayers; } while (players.get(currentPlayerIndex).isBankrupt()); setCurrentPlayerIndex(currentPlayerIndex); } @@ -1546,9 +1571,42 @@ cm=ct.newCorrectionManager(this); correctionManagers.put(ct, cm); log.debug("Added CorrectionManager for " + ct); -} + } return cm; } + /** Return a list of companies in operation order. + * <p>Note that, unlike Round.setOperatingCompanies(), this method does <b>not</b> check + * if the companies are actualy allowed to operate. One purpose is to check for upping the + * share price at the end of an SR un sucn a way, that the token order gets preserved. + * @return + */ + public List<PublicCompanyI> getCompaniesInRunningOrder () { + + Map<Integer, PublicCompanyI> operatingCompanies = + new TreeMap<Integer, PublicCompanyI>(); + StockSpaceI space; + int key; + int minorNo = 0; + for (PublicCompanyI company : companyManager.getAllPublicCompanies()) { + + // Key must put companies in reverse operating order, because sort + // is ascending. + if (company.hasStockPrice() && company.hasStarted()) { + space = company.getCurrentSpace(); + key = + 1000000 * (999 - space.getPrice()) + 10000 + * (99 - space.getColumn()) + 100 + * space.getRow() + + space.getStackPosition(company); + } else { + key = ++minorNo; + } + operatingCompanies.put(new Integer(key), company); + } + + return new ArrayList<PublicCompanyI>(operatingCompanies.values()); + } + } Modified: trunk/18xx/rails/game/GameManagerI.java =================================================================== --- trunk/18xx/rails/game/GameManagerI.java 2010-07-04 15:17:14 UTC (rev 1330) +++ trunk/18xx/rails/game/GameManagerI.java 2010-07-04 20:44:29 UTC (rev 1331) @@ -1,202 +1,204 @@ -package rails.game; - -import java.util.List; -import java.util.Map; - -import rails.algorithms.RevenueManager; -import rails.common.GuiDef; -import rails.common.GuiHints; -import rails.game.action.PossibleAction; -import rails.game.correct.CorrectionManagerI; -import rails.game.correct.CorrectionType; -import rails.game.model.ModelObject; -import rails.game.move.MoveStack; -import rails.game.move.MoveableHolder; -import rails.game.special.SpecialPropertyI; - -public interface GameManagerI extends MoveableHolder, ConfigurableComponentI { - - /** - * @see rails.game.ConfigurableComponentI#configureFromXML(org.w3c.dom.Element) - */ - public abstract void init(String gameName, PlayerManager playerManager, - CompanyManagerI companyManager, PhaseManager phaseManager, - TrainManager trainManager, StockMarketI stockMarket, - MapManager mapManager, TileManager tileManager, - RevenueManager revenueManager, Bank bank); - public abstract void startGame(Map<String, String> gameOptions); - - public abstract CompanyManagerI getCompanyManager(); - - /** - * Should be called by each Round when it finishes. - * - * @param round The object that represents the finishing round. - */ - public abstract void nextRound(RoundI round); - - public String getORId (); - public abstract String getCompositeORNumber(); - public int getRelativeORNumber(); - - public abstract int getSRNumber(); - - public abstract void startShareSellingRound(Player sellingPlayer, - int cashToRaise, PublicCompanyI unsellableCompany); - - public abstract void startTreasuryShareTradingRound(); - - /** - * The central server-side method that takes a client-side initiated action - * and processes it. - * - * @param action A PossibleAction subclass object sent by the client. - * @return TRUE is the action was valid. - */ - public abstract boolean process(PossibleAction action); - - public abstract boolean processOnReload(List<PossibleAction> actions) - throws Exception; - - public abstract void finishShareSellingRound(); - - public abstract void finishTreasuryShareRound(); - - public abstract void registerBankruptcy(); - - public abstract void registerBrokenBank(); - - /** - * To be called by the UI to check if the rails.game is over. - * - * @return - */ - public abstract boolean isGameOver(); - - public void setGameOverReportedUI(boolean b); - - public boolean getGameOverReportedUI(); - - /** - * Create a HTML-formatted rails.game status report. - * - * @return - */ - public abstract List<String> getGameReport(); - - /** - * Should be called whenever a Phase changes. The effect on the number of - * ORs is delayed until a StockRound finishes. - * - */ - public abstract RoundI getCurrentRound(); - - /** - * @return Returns the currentPlayerIndex. - */ - public abstract int getCurrentPlayerIndex(); - - /** - * @param currentPlayerIndex The currentPlayerIndex to set. - */ - public abstract void setCurrentPlayerIndex(int currentPlayerIndex); - - public abstract void setCurrentPlayer(Player player); - - /** - * Set priority deal to the player after the current player. - * - */ - public abstract void setPriorityPlayer(); - - public abstract void setPriorityPlayer(Player player); - - /** - * @return Returns the priorityPlayer. - */ - public abstract Player getPriorityPlayer(); - - /** - * @return Returns the currentPlayer. - */ - public abstract Player getCurrentPlayer(); - - /** - * @return Returns the players. - */ - public abstract List<Player> getPlayers(); - - public abstract int getNumberOfPlayers(); - - public abstract List<String> getPlayerNames(); - - public abstract List<PublicCompanyI> getAllPublicCompanies(); - - public abstract List<PrivateCompanyI> getAllPrivateCompanies(); - - /** - * Return a player by its index in the list, modulo the number of players. - * - * @param index The player index. - * @return A player object. - */ - public abstract Player getPlayerByIndex(int index); - - public abstract void setNextPlayer(); - - public void addPortfolio (Portfolio portfolio); - public Portfolio getPortfolioByName (String name); - - /** - * @return the StartPacket - */ - public abstract StartPacket getStartPacket(); - - /** - * @return Current phase - */ - public abstract PhaseI getCurrentPhase(); - - public abstract PhaseManager getPhaseManager(); - public void initialiseNewPhase(PhaseI phase); - - public abstract TrainManager getTrainManager (); - public PlayerManager getPlayerManager(); - public TileManager getTileManager(); - public StockMarketI getStockMarket(); - public MapManager getMapManager(); - public RevenueManager getRevenueManager(); - public Bank getBank (); - - public String getGameName (); - public String getGameOption (String key); - - public int getPlayerCertificateLimit(Player player); - public void setPlayerCertificateLimit(int newLimit); - public ModelObject getPlayerCertificateLimitModel (); - - public abstract String getHelp(); - - public abstract boolean canAnyCompanyHoldShares(); - - public abstract String getClassName(GuiDef.ClassName key); - - public abstract Object getGuiParameter(GuiDef.Parm key); - public Object getGameParameter (GameDef.Parm key); - public void setGameParameter (GameDef.Parm key, Object value); - - public RoundI getInterruptedRound(); - - public List<SpecialPropertyI> getCommonSpecialProperties (); - public <T extends SpecialPropertyI> List<T> getSpecialProperties( - Class<T> clazz, boolean includeExercised); - - public String getGMKey (); - public MoveStack getMoveStack (); - public DisplayBuffer getDisplayBuffer(); - public void addToNextPlayerMessages(String s, boolean undoable); - public ReportBuffer getReportBuffer(); - public GuiHints getUIHints(); - - public CorrectionManagerI getCorrectionManager(CorrectionType ct); +package rails.game; + +import java.util.List; +import java.util.Map; + +import rails.algorithms.RevenueManager; +import rails.common.GuiDef; +import rails.common.GuiHints; +import rails.game.action.PossibleAction; +import rails.game.correct.CorrectionManagerI; +import rails.game.correct.CorrectionType; +import rails.game.model.ModelObject; +import rails.game.move.MoveStack; +import rails.game.move.MoveableHolder; +import rails.game.special.SpecialPropertyI; + +public interface GameManagerI extends MoveableHolder, ConfigurableComponentI { + + /** + * @see rails.game.ConfigurableComponentI#configureFromXML(org.w3c.dom.Element) + */ + public abstract void init(String gameName, PlayerManager playerManager, + CompanyManagerI companyManager, PhaseManager phaseManager, + TrainManager trainManager, StockMarketI stockMarket, + MapManager mapManager, TileManager tileManager, + RevenueManager revenueManager, Bank bank); + public abstract void startGame(Map<String, String> gameOptions); + + public abstract CompanyManagerI getCompanyManager(); + + /** + * Should be called by each Round when it finishes. + * + * @param round The object that represents the finishing round. + */ + public abstract void nextRound(RoundI round); + + public String getORId (); + public abstract String getCompositeORNumber(); + public int getRelativeORNumber(); + + public abstract int getSRNumber(); + + public abstract void startShareSellingRound(Player sellingPlayer, + int cashToRaise, PublicCompanyI unsellableCompany); + + public abstract void startTreasuryShareTradingRound(); + + /** + * The central server-side method that takes a client-side initiated action + * and processes it. + * + * @param action A PossibleAction subclass object sent by the client. + * @return TRUE is the action was valid. + */ + public abstract boolean process(PossibleAction action); + + public abstract boolean processOnReload(List<PossibleAction> actions) + throws Exception; + + public abstract void finishShareSellingRound(); + + public abstract void finishTreasuryShareRound(); + + public abstract void registerBankruptcy(); + + public abstract void registerBrokenBank(); + + /** + * To be called by the UI to check if the rails.game is over. + * + * @return + */ + public abstract boolean isGameOver(); + + public void setGameOverReportedUI(boolean b); + + public boolean getGameOverReportedUI(); + + /** + * Create a HTML-formatted rails.game status report. + * + * @return + */ + public abstract List<String> getGameReport(); + + /** + * Should be called whenever a Phase changes. The effect on the number of + * ORs is delayed until a StockRound finishes. + * + */ + public abstract RoundI getCurrentRound(); + + /** + * @return Returns the currentPlayerIndex. + */ + public abstract int getCurrentPlayerIndex(); + + /** + * @param currentPlayerIndex The currentPlayerIndex to set. + */ + public abstract void setCurrentPlayerIndex(int currentPlayerIndex); + + public abstract void setCurrentPlayer(Player player); + + /** + * Set priority deal to the player after the current player. + * + */ + public abstract void setPriorityPlayer(); + + public abstract void setPriorityPlayer(Player player); + + /** + * @return Returns the priorityPlayer. + */ + public abstract Player getPriorityPlayer(); + + /** + * @return Returns the currentPlayer. + */ + public abstract Player getCurrentPlayer(); + + /** + * @return Returns the players. + */ + public abstract List<Player> getPlayers(); + + public abstract int getNumberOfPlayers(); + + public abstract List<String> getPlayerNames(); + + public abstract List<PublicCompanyI> getAllPublicCompanies(); + + public abstract List<PrivateCompanyI> getAllPrivateCompanies(); + + /** + * Return a player by its index in the list, modulo the number of players. + * + * @param index The player index. + * @return A player object. + */ + public abstract Player getPlayerByIndex(int index); + + public abstract void setNextPlayer(); + + public void addPortfolio (Portfolio portfolio); + public Portfolio getPortfolioByName (String name); + + /** + * @return the StartPacket + */ + public abstract StartPacket getStartPacket(); + + /** + * @return Current phase + */ + public abstract PhaseI getCurrentPhase(); + + public abstract PhaseManager getPhaseManager(); + public void initialiseNewPhase(PhaseI phase); + + public abstract TrainManager getTrainManager (); + public PlayerManager getPlayerManager(); + public TileManager getTileManager(); + public StockMarketI getStockMarket(); + public MapManager getMapManager(); + public RevenueManager getRevenueManager(); + public Bank getBank (); + + public String getGameName (); + public String getGameOption (String key); + + public int getPlayerCertificateLimit(Player player); + public void setPlayerCertificateLimit(int newLimit); + public ModelObject getPlayerCertificateLimitModel (); + + public abstract String getHelp(); + + public abstract boolean canAnyCompanyHoldShares(); + + public abstract String getClassName(GuiDef.ClassName key); + + public abstract Object getGuiParameter(GuiDef.Parm key); + public Object getGameParameter (GameDef.Parm key); + public void setGameParameter (GameDef.Parm key, Object value); + + public RoundI getInterruptedRound(); + + public List<SpecialPropertyI> getCommonSpecialProperties (); + public <T extends SpecialPropertyI> List<T> getSpecialProperties( + Class<T> clazz, boolean includeExercised); + + public String getGMKey (); + public MoveStack getMoveStack (); + public DisplayBuffer getDisplayBuffer(); + public void addToNextPlayerMessages(String s, boolean undoable); + public ReportBuffer getReportBuffer(); + public GuiHints getUIHints(); + + public CorrectionManagerI getCorrectionManager(CorrectionType ct); + public List<PublicCompanyI> getCompaniesInRunningOrder (); + } \ No newline at end of file Modified: trunk/18xx/rails/game/StockRound.java =================================================================== --- trunk/18xx/rails/game/StockRound.java 2010-07-04 15:17:14 UTC (rev 1330) +++ trunk/18xx/rails/game/StockRound.java 2010-07-04 20:44:29 UTC (rev 1331) @@ -1,12 +1,29 @@ package rails.game; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import rails.common.GuiDef; -import rails.game.action.*; -import rails.game.move.*; -import rails.game.special.*; -import rails.game.state.*; +import rails.game.action.BuyCertificate; +import rails.game.action.NullAction; +import rails.game.action.PossibleAction; +import rails.game.action.RequestTurn; +import rails.game.action.SellShares; +import rails.game.action.StartCompany; +import rails.game.action.UseSpecialProperty; +import rails.game.move.AddToList; +import rails.game.move.CashMove; +import rails.game.move.DoubleMapChange; +import rails.game.special.ExchangeForShare; +import rails.game.special.SpecialProperty; +import rails.game.special.SpecialPropertyI; +import rails.game.state.BooleanState; +import rails.game.state.IntegerState; +import rails.game.state.State; import rails.util.LocalText; /** @@ -23,22 +40,22 @@ protected Player startingPlayer; protected State companyBoughtThisTurnWrapper = - new State("CompanyBoughtThisTurn", PublicCompany.class); + new State("CompanyBoughtThisTurn", PublicCompany.class); protected BooleanState hasSoldThisTurnBeforeBuying = - new BooleanState("HoldSoldBeforeBuyingThisTurn", false); + new BooleanState("HoldSoldBeforeBuyingThisTurn", false); protected BooleanState hasActed = new BooleanState("HasActed", false); // Is protected IntegerState numPasses = new IntegerState("StockRoundPasses"); protected Map<String, StockSpaceI> sellPrices = - new HashMap<String, StockSpaceI>(); + new HashMap<String, StockSpaceI>(); /* Transient data needed for rule enforcing */ /** HashMap per player containing a HashMap per company */ protected HashMap<Player, HashMap<PublicCompanyI, Object>> playersThatSoldThisRound = - new HashMap<Player, HashMap<PublicCompanyI, Object>>(); + new HashMap<Player, HashMap<PublicCompanyI, Object>>(); /* Rule constants */ static protected final int SELL_BUY_SELL = 0; @@ -74,7 +91,7 @@ public void start() { ReportBuffer.add(LocalText.getText("StartStockRound", - getStockRoundNumber())); + getStockRoundNumber())); setCurrentPlayerIndex(gameManager.getPriorityPlayer().getIndex()); startingPlayer = getCurrentPlayer(); // For the Report @@ -157,17 +174,17 @@ /* Get the next available IPO certificates */ // Never buy more than one from the IPO PublicCompanyI companyBoughtThisTurn = - (PublicCompanyI) companyBoughtThisTurnWrapper.getObject(); + (PublicCompanyI) companyBoughtThisTurnWrapper.getObject(); if (companyBoughtThisTurn == null) { from = ipo; Map<String, List<PublicCertificateI>> map = - from.getCertsPerCompanyMap(); + from.getCertsPerCompanyMap(); int shares; for (String compName : map.keySet()) { certs = map.get(compName); if (certs == null || certs.isEmpty()) continue; - + /* Only the top certificate is buyable from the IPO */ int lowestIndex = 99; cert = null; @@ -179,7 +196,7 @@ cert = c; } } - + comp = cert.getCompany(); unitsForPrice = comp.getShareUnitsForSharePrice(); if (isSaleRecorded(currentPlayer, comp)) continue; @@ -223,7 +240,7 @@ /* Get the unique Pool certificates and check which ones can be bought */ from = pool; Map<String, List<PublicCertificateI>> map = - from.getCertsPerCompanyMap(); + from.getCertsPerCompanyMap(); /* Allow for multiple share unit certificates (e.g. 1835) */ PublicCertificateI[] uniqueCerts; int[] numberOfCerts; @@ -241,7 +258,7 @@ price = stockSpace.getPrice() / unitsForPrice; shareUnit = comp.getShareUnit(); maxNumberOfSharesToBuy - = maxAllowedNumberOfSharesToBuy(currentPlayer, comp, shareUnit); + = maxAllowedNumberOfSharesToBuy(currentPlayer, comp, shareUnit); /* Checks if the player can buy any shares of this company */ if (maxNumberOfSharesToBuy < 1) continue; @@ -279,7 +296,7 @@ /* Would the player exceed the total certificate limit? */ if (!stockSpace.isNoCertLimit() - && !mayPlayerBuyCertificate(currentPlayer, comp, number)) + && !mayPlayerBuyCertificate(currentPlayer, comp, number)) continue; } @@ -301,8 +318,8 @@ for (PublicCompanyI company : companyManager.getAllPublicCompanies()) { certs = - company.getPortfolio().getCertificatesPerCompany( - company.getName()); + company.getPortfolio().getCertificatesPerCompany( + company.getName()); if (certs == null || certs.isEmpty()) continue; cert = certs.get(0); if (isSaleRecorded(currentPlayer, company)) continue; @@ -311,7 +328,7 @@ certs.get(0).getShare()) < 1) continue; stockSpace = company.getCurrentSpace(); if (!stockSpace.isNoCertLimit() - && !mayPlayerBuyCertificate(currentPlayer, company, 1)) continue; + && !mayPlayerBuyCertificate(currentPlayer, company, 1)) continue; if (company.getMarketPrice() <= playerCash) { possibleActions.add(new BuyCertificate(cert, company.getPortfolio(), company.getMarketPrice())); @@ -347,16 +364,16 @@ // In some games, can't sell shares if not operated if (company.mustHaveOperatedToTradeShares() - && !company.hasOperated()) continue; + && !company.hasOperated()) continue; share = maxShareToSell = playerPortfolio.getShare(company); if (maxShareToSell == 0) continue; /* 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; /* @@ -365,7 +382,7 @@ */ if (company.getPresident() == currentPlayer) { int presidentShare = - company.getCertificates().get(0).getShare(); + company.getCertificates().get(0).getShare(); if (maxShareToSell > share - presidentShare) { dumpAllowed = false; int playerShare; @@ -416,14 +433,14 @@ number = shareCountPerUnit[i]; if (number == 0) continue; number = - Math.min(number, maxShareToSell - / (i * company.getShareUnit())); + Math.min(number, maxShareToSell + / (i * company.getShareUnit())); /* In some games (1856), a just bought share may not be sold */ // This code ignores the possibility of different share units if ((Boolean)gameManager.getGameParameter(GameDef.Parm.NO_SALE_OF_JUST_BOUGHT_CERT) - && company.equals(companyBoughtThisTurnWrapper.getObject())) { - number--; + && company.equals(companyBoughtThisTurnWrapper.getObject())) { + number--; } if (number <= 0) continue; @@ -436,8 +453,8 @@ protected void setSpecialActions() { List<SpecialProperty> sps = - currentPlayer.getPortfolio().getSpecialProperties( - SpecialProperty.class, false); + currentPlayer.getPortfolio().getSpecialProperties( + SpecialProperty.class, false); for (SpecialPropertyI sp : sps) { if (sp.isUsableDuringSR()) { possibleActions.add(new UseSpecialProperty(sp)); @@ -464,7 +481,7 @@ break; case NullAction.AUTOPASS: result = done(playerName, true); - break; + break; } } else if (action instanceof StartCompany) { @@ -554,7 +571,7 @@ // The company may not have started yet. if (company.hasStarted()) { errMsg = - LocalText.getText("CompanyAlreadyStarted", companyName); + LocalText.getText("CompanyAlreadyStarted", companyName); break; } @@ -581,8 +598,8 @@ // Else the given price must be a valid start price if ((startSpace = stockMarket.getStartSpace(price)) == null) { errMsg = LocalText.getText("InvalidStartPrice", - Bank.format(price), - company.getName() ); + Bank.format(price), + company.getName() ); break; } } @@ -695,9 +712,9 @@ // The player may not have sold the company this round. if (isSaleRecorded(currentPlayer, company)) { errMsg = - LocalText.getText("AlreadySoldThisTurn", - currentPlayer.getName(), - companyName ); + LocalText.getText("AlreadySoldThisTurn", + currentPlayer.getName(), + companyName ); break; } @@ -709,9 +726,9 @@ // The player may not have bought this turn, unless the company // bought before and now is in the brown area. PublicCompanyI companyBoughtThisTurn = - (PublicCompanyI) companyBoughtThisTurnWrapper.getObject(); + (PublicCompanyI) companyBoughtThisTurnWrapper.getObject(); if (companyBoughtThisTurn != null - && (companyBoughtThisTurn != company || !company.getCurrentSpace().isNoBuyLimit())) { + && (companyBoughtThisTurn != company || !company.getCurrentSpace().isNoBuyLimit())) { errMsg = LocalText.getText("AlreadyBought", playerName); break; } @@ -719,9 +736,9 @@ // Check if that many shares are available if (shares > from.getShare(company)) { errMsg = - LocalText.getText("NotAvailable", - companyName, - from.getName() ); + LocalText.getText("NotAvailable", + companyName, + from.getName() ); break; } @@ -742,20 +759,20 @@ // Check if player would not exceed the certificate limit. // (shortcut: assume 1 cert == 1 certificate) if (!currentSpace.isNoCertLimit() - && !mayPlayerBuyCertificate(currentPlayer, company, number)) { + && !mayPlayerBuyCertificate(currentPlayer, company, number)) { errMsg = - currentPlayer.getName() - + LocalText.getText("WouldExceedCertLimit", - String.valueOf(gameManager.getPlayerCertificateLimit(currentPlayer))); + currentPlayer.getName() + + LocalText.getText("WouldExceedCertLimit", + String.valueOf(gameManager.getPlayerCertificateLimit(currentPlayer))); break; } // Check if player would exceed the per-company share limit if (!currentSpace.isNoHoldLimit() - && !checkAgainstHoldLimit(currentPlayer, company, shares)) { - errMsg = LocalText.getText("WouldExceedHoldLimit", - currentPlayer.getName(), - GameDef.Parm.PLAYER_SHARE_LIMIT.defaultValueAsInt()); + && !checkAgainstHoldLimit(currentPlayer, company, shares)) { + errMsg = LocalText.getText("WouldExceedHoldLimit", + currentPlayer.getName(), + GameDef.Parm.PLAYER_SHARE_LIMIT.defaultValueAsInt()); break; } @@ -811,7 +828,7 @@ cert2 = from.findCertificate(company, cert.getShares(), false); if (cert2 == null) { log.error("Cannot find " + companyName + " " + shareUnit - + "% share in " + from.getName()); + + "% share in " + from.getName()); } cert2.moveTo(currentPlayer.getPortfolio()); } @@ -845,13 +862,13 @@ PublicCompanyI company) { } - + /** Allow different price setting in subclasses (i.e. 1835 Nationalisation) */ protected int getBuyPrice (BuyCertificate action, StockSpaceI currentSpace) { return currentSpace.getPrice(); } - /** + /** * Who receives the cash when a certificate is bought. * With incremental capitalization, this can be the company treasure. * This method must be called <i>before</i> transferring the certificate. @@ -864,8 +881,8 @@ PublicCompanyI comp; CashHolder recipient; if ((comp = (cert).getCompany()).hasFloated() - && oldHolder == ipo - && comp.getCapitalisation() == PublicCompanyI.CAPITALISE_INCREMENTAL) { + && oldHolder == ipo + && comp.getCapitalisation() == PublicCompanyI.CAPITALISE_INCREMENTAL) { recipient = comp; } else { recipient = oldHolder.getOwner(); @@ -873,7 +890,7 @@ return recipient; } - /** Make the certificates of one company available for buying + /** Make the certificates of one company available for buying * by putting these in the IPO. * @param company The company to be released. */ @@ -893,8 +910,8 @@ protected boolean isSaleRecorded(Player player, PublicCompanyI company) { return playersThatSoldThisRound.containsKey(currentPlayer) - && playersThatSoldThisRound.get(currentPlayer).containsKey( - company); + && playersThatSoldThisRound.get(currentPlayer).containsKey( + company); } public boolean sellShares(SellShares action) @@ -906,11 +923,11 @@ 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(); @@ -957,7 +974,7 @@ // 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()) { @@ -1062,7 +1079,7 @@ // First swap the certificates Portfolio dumpedPortfolio = dumpedPlayer.getPortfolio(); List<PublicCertificateI> swapped = - portfolio.swapPresidentCertificate(company, dumpedPortfolio); + portfolio.swapPresidentCertificate(company, dumpedPortfolio); for (int i = 0; i < presSharesToSell; i++) { certsToSell.add(swapped.get(i)); } @@ -1106,7 +1123,7 @@ } protected void adjustSharePrice (PublicCompanyI company, int numberSold, boolean soldBefore) { - + if (company.canSharePriceVary()) { stockMarket.sell(company, numberSold); } @@ -1132,7 +1149,7 @@ public boolean executeExchangeForShare (ExchangeForShare sp) { PublicCompanyI publicCompany = - companyManager.getPublicCompany(sp.getPublicCompanyName()); + companyManager.getPublicCompany(sp.getPublicCompanyName()); CompanyI privateCompany = sp.getOriginalCompany(); Portfolio portfolio = privateCompany.getPortfolio(); Player player = null; @@ -1145,8 +1162,8 @@ /* Check if the private is owned by a player */ if (!(portfolio.getOwner() instanceof Player)) { errMsg = - LocalText.getText("PrivateIsNotOwnedByAPlayer", - privateCompany.getName()); + LocalText.getText("PrivateIsNotOwnedByAPlayer", + privateCompany.getName()); break; } @@ -1155,16 +1172,16 @@ /* Check if a share is available */ if (!ipoHasShare && !poolHasShare) { errMsg = - LocalText.getText("NoSharesAvailable", - publicCompany.getName()); + LocalText.getText("NoSharesAvailable", + publicCompany.getName()); break; } /* Check if the player has room for a share of this company */ if (!checkAgainstHoldLimit(player, publicCompany, 1)) { // TODO: Not nice to use '1' here, should be percentage. errMsg = - LocalText.getText("WouldExceedHoldLimit", - String.valueOf(getGameParameterAsInt(GameDef.Parm.PLAYER_SHARE_LIMIT))); + LocalText.getText("WouldExceedHoldLimit", + String.valueOf(getGameParameterAsInt(GameDef.Parm.PLAYER_SHARE_LIMIT))); break; } break; @@ -1172,33 +1189,33 @@ if (errMsg != null) { DisplayBuffer.add(LocalText.getText( "CannotSwapPrivateForCertificate", - player.getName(), - privateCompany.getName(), - sp.getShare(), - publicCompany.getName(), - errMsg )); + player.getName(), + privateCompany.getName(), + sp.getShare(), + publicCompany.getName(), + errMsg )); return false; } moveStack.start(true); Certificate cert = - ipoHasShare ? ipo.findCertificate(publicCompany, - false) : pool.findCertificate(publicCompany, - false); - cert.moveTo(player.getPortfolio()); - ReportBuffer.add(LocalText.getText("SwapsPrivateForCertificate", - player.getName(), - privateCompany.getName(), - sp.getShare(), - publicCompany.getName())); - sp.setExercised(); - privateCompany.setClosed(); + ipoHasShare ? ipo.findCertificate(publicCompany, + false) : pool.findCertificate(publicCompany, + false); + cert.moveTo(player.getPortfolio()); + ReportBuffer.add(LocalText.getText("SwapsPrivateForCertificate", + player.getName(), + privateCompany.getName(), + sp.getShare(), + publicCompany.getName())); + sp.setExercised(); + privateCompany.setClosed(); - // Check if the company has floated - if (!publicCompany.hasFloated()) checkFlotation(publicCompany); + // Check if the company has floated + if (!publicCompany.hasFloated()) checkFlotation(publicCompany); - return true; + return true; } /** @@ -1237,31 +1254,6 @@ if (numPasses.intValue() >= getNumberOfActivePlayers()) { - ReportBuffer.add(LocalText.getText("END_SR", - String.valueOf(getStockRoundNumber()))); - - /* Check if any companies are sold out. */ - for (PublicCompanyI company : companyManager.getAllPublicCompanies()) { - if (company.hasStockPrice() && company.isSoldOut()) { - StockSpaceI oldSpace = company.getCurrentSpace(); - stockMarket.soldOut(company); - StockSpaceI newSpace = company.getCurrentSpace(); - if (newSpace != oldSpace) { - ReportBuffer.add(LocalText.getText("SoldOut", - company.getName(), - Bank.format(oldSpace.getPrice()), - oldSpace.getName(), - Bank.format(newSpace.getPrice()), - newSpace.getName())); - } else { - ReportBuffer.add(LocalText.getText("SoldOutNoRaise", - company.getName(), - Bank.format(newSpace.getPrice()), - newSpace.getName())); - } - } - } - finishRound(); } else { @@ -1272,6 +1264,37 @@ return true; } + @Override + protected void finishRound () { + + ReportBuffer.add(LocalText.getText("END_SR", + String.valueOf(getStockRoundNumber()))); + + /* Check if any companies are sold out. */ + for (PublicCompanyI company : gameManager.getCompaniesInRunningOrder()) { + if (company.hasStockPrice() && company.isSoldOut()) { + StockSpaceI oldSpace = company.getCurrentSpace(); + stockMarket.soldOut(company); + StockSpaceI newSpace = company.getCurrentSpace(); + if (newSpace != oldSpace) { + ReportBuffer.add(LocalText.getText("SoldOut", + company.getName(), + Bank.format(oldSpace.getPrice()), + oldSpace.getName(), + Bank.format(newSpace.getPrice()), + newSpace.getName())); + } else { + ReportBuffer.add(LocalText.getText("SoldOutNoRaise", + company.getName(), + Bank.format(newSpace.getPrice()), + newSpace.getName())); + } + } + } + + super.finishRound(); + } + protected boolean requestTurn (RequestTurn action) { Player requestingPlayer = playerManager.getPlayerByName(action.getRequestingPlayerName()); @@ -1331,6 +1354,7 @@ gameManager.setPriorityPlayer(); } + @Override public void setCurrentPlayer(Player player) { super.setCurrentPlayer(player); currentPlayer = player; @@ -1356,8 +1380,8 @@ if (getStockRoundNumber() == 1 && noSaleInFirstSR()) return false; if (companyBoughtThisTurnWrapper.getObject() != null - && (sequenceRule == SELL_BUY_OR_BUY_SELL - && hasSoldThisTurnBeforeBuying.booleanValue() || sequenceRule == SELL_BUY)) + ... [truncated message content] |