From: Frederick W. <fre...@us...> - 2012-01-28 18:22:52
|
LocalisedText.properties | 37 ++- data/Properties.xml | 34 ++ rails/common/parser/Config.java | 2 rails/common/parser/ConfigItem.java | 9 rails/game/Game.java | 7 rails/game/GameManager.java | 5 rails/game/GameManagerI.java | 2 rails/game/OperatingRound.java | 3 rails/game/Phase.java | 3 rails/game/PublicCompany.java | 4 rails/game/PublicCompanyI.java | 2 rails/game/StockRound.java | 3 rails/game/specific/_1880/OperatingRound_1880.java | 3 rails/sound/BackgroundMusicManager.java | 174 -------------- rails/sound/SoundConfig.java | 82 ++++++ rails/sound/SoundContext.java | 137 +++++++++++ rails/sound/SoundEventInterpreter.java | 180 +++++++++++++++ rails/sound/SoundManager.java | 61 +++++ rails/sound/SoundPlayer.java | 250 +++++++++++++++++++++ rails/ui/swing/ConfigWindow.java | 17 + rails/ui/swing/GameSetupWindow.java | 4 rails/ui/swing/GameUIManager.java | 8 rails/ui/swing/ORUIManager.java | 7 rails/ui/swing/ReportWindowDynamic.java | 9 24 files changed, 832 insertions(+), 211 deletions(-) New commits: commit c9ae6202c1b83402661f2bf47c95d01d695e53f4 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 28 14:15:45 2012 +0100 Added stock market opening bell Background music only changes after bell ringing is completed (as in SimTex's 1830). diff --git a/rails/sound/SoundConfig.java b/rails/sound/SoundConfig.java index f6dfd8b..c9ea6c5 100644 --- a/rails/sound/SoundConfig.java +++ b/rails/sound/SoundConfig.java @@ -22,7 +22,6 @@ public class SoundConfig { public static final String KEY_SFX_Enabled = "sound.sfx"; public static final String KEY_SFX_STR_BidStartItem = "sound.sfx.str.bidStartItem"; public static final String KEY_SFX_STR_BuyStartItem = "sound.sfx.str.buyStartItem"; - //TODO Opening Bell public static final String KEY_SFX_SR_OpeningBell = "sound.sfx.sr.openingBell"; public static final String KEY_SFX_SR_NewPresident = "sound.sfx.sr.newPresident"; public static final String KEY_SFX_SR_BuyShare_President = "sound.sfx.sr.buyShare.president"; diff --git a/rails/sound/SoundContext.java b/rails/sound/SoundContext.java index 13b4c5a..4d4be08 100644 --- a/rails/sound/SoundContext.java +++ b/rails/sound/SoundContext.java @@ -69,9 +69,14 @@ public class SoundContext { + averageRevenue * (1 - slidingAverageAdjustmentFactor); } - private void playBackgroundMusic() { + /** + * @return true if new background music is played + */ + private boolean playBackgroundMusic() { + boolean isNewMusicPlayed = false; + //do nothing if music is not enabled - if (!SoundConfig.isBGMEnabled()) return; + if (!SoundConfig.isBGMEnabled()) return false; String currentRoundConfigKey = null; if (currentRound instanceof StartRound) { @@ -91,9 +96,19 @@ public class SoundContext { currentRoundConfigKey, currentPhaseName); if (!newBackgroundMusicFileName.equals(currentBackgroundMusicFileName)) { currentBackgroundMusicFileName = newBackgroundMusicFileName; - player.playBGM(newBackgroundMusicFileName); + isNewMusicPlayed = true; + + //additionally play stock market opening bell if appropriate + if (SoundConfig.isSFXEnabled() && currentRound instanceof StockRound) { + player.playSFXWithFollowupBGM( + SoundConfig.get(SoundConfig.KEY_SFX_SR_OpeningBell), + newBackgroundMusicFileName); + } else { + player.playBGM(newBackgroundMusicFileName); + } } } + return isNewMusicPlayed; } public void notifyOfPhase(PhaseI newPhase) { if (!newPhase.equals(currentPhase)) { @@ -105,7 +120,14 @@ public class SoundContext { public void notifyOfRound(RoundI newRound) { if (!newRound.equals(currentRound)) { currentRound = newRound; - playBackgroundMusic(); + boolean isNewMusicPlayed = playBackgroundMusic(); + + //play stock market opening bell for stock rounds without new background music + //(e.g., if music is disabled but sfx is enabled) + if (!isNewMusicPlayed && SoundConfig.isSFXEnabled() + && currentRound instanceof StockRound) { + player.playSFXByConfigKey(SoundConfig.KEY_SFX_SR_OpeningBell); + } } } public void notifyOfGameSetup() { diff --git a/rails/sound/SoundPlayer.java b/rails/sound/SoundPlayer.java index b5614f9..2e53c03 100644 --- a/rails/sound/SoundPlayer.java +++ b/rails/sound/SoundPlayer.java @@ -149,6 +149,17 @@ public class SoundPlayer { if (player!=null) player.close(); } } + private class PlayerThreadWithFollowupBGM extends PlayerThread { + private String bgmFileName; + public PlayerThreadWithFollowupBGM(String fileName, String bgmFileName) { + super(fileName); + this.bgmFileName = bgmFileName; + } + public void play() { + super.play(); + playBGM(bgmFileName); + } + } private PlayerThread lastSFXThread = null; @@ -203,6 +214,19 @@ public class SoundPlayer { public void playSFXByConfigKey(String configKey, double playSoundProportion) { playSFX(SoundConfig.get(configKey), playSoundProportion); } + + public void playSFXWithFollowupBGM(String sfxFileName,String bgmFileName) { + playSFX(new PlayerThreadWithFollowupBGM (sfxFileName,bgmFileName)); + } + + /** + * Plays the specified SFX and, after completing SFX play, the specified BGM + * is launched. + */ + public void playSFXWithFollowupBGMByConfigKey(String sfxConfigKey, String bgmConfigKey) { + playSFXWithFollowupBGM( + SoundConfig.get(sfxConfigKey),SoundConfig.get(bgmConfigKey)); + } public void playBGM(String backgroundMusicFileName) { LoopPlayerThread newPlayerThread = new LoopPlayerThread(backgroundMusicFileName); commit e67cb1a9452a655e75ba3450f79fbb3bef710157 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 28 13:06:53 2012 +0100 Considered load, timewarp, music/sfx config for enabling sounds Now, sound framework correctly handles these situations: - timewarp (sfx disabled) - game loading (sfx/music disabled) - changing enabled/disabled config within the game In order to achieve this, some parts of rails had to be adjusted: - new config item option that init is executed even from the game setup - dynamic reported window now correctly first sets the time warp mode and only then goes to the clicked the step. diff --git a/data/Properties.xml b/data/Properties.xml index 5dd4f7b..ac703c0 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -63,7 +63,8 @@ </Section> <Section name="Music"> <Property name="sound.backgroundMusic" type="LIST" values="disabled,enabled" - initClass="rails.sound.SoundManager" initMethod="init"/> + initClass="rails.sound.SoundManager" initMethod="init" + alwaysCallInit="true"/> <Property name="sound.backgroundMusic.gameSetup" type="FILE" /> <Property name="sound.backgroundMusic.startRound" type="FILE" /> <Property name="sound.backgroundMusic.stockRound" type="STRING" /> diff --git a/rails/common/parser/Config.java b/rails/common/parser/Config.java index c7f64ed..107e888 100644 --- a/rails/common/parser/Config.java +++ b/rails/common/parser/Config.java @@ -145,7 +145,7 @@ public final class Config { continue; } userProperties.setProperty(item.name, item.getNewValue()); - if (applyInitMethods) item.callInitMethod(); + item.callInitMethod(applyInitMethods); log.debug("Changed property name = " + item.name + " to value = " + item.getNewValue()); item.setNewValue(null); } diff --git a/rails/common/parser/ConfigItem.java b/rails/common/parser/ConfigItem.java index dc9feb7..ab2bab6 100644 --- a/rails/common/parser/ConfigItem.java +++ b/rails/common/parser/ConfigItem.java @@ -33,6 +33,7 @@ public final class ConfigItem { // method call attributes private final String initClass; private final String initMethod; + private final boolean alwaysCallInit; private final boolean initParameter; @@ -75,6 +76,7 @@ public final class ConfigItem { // optional: init method attributes initClass = tag.getAttributeAsString("initClass"); initMethod = tag.getAttributeAsString("initMethod"); + alwaysCallInit = tag.getAttributeAsBoolean("alwaysCallInit",false); initParameter = tag.getAttributeAsBoolean("initParameter", false); // initialize newValue @@ -107,7 +109,12 @@ public final class ConfigItem { return Config.get(this.name); } - void callInitMethod() { + /** + * @param applyInitMethod Specifies whether init should be called. Can be overruled + * by an additional tag alwaysCallInit + */ + void callInitMethod(boolean applyInitMethod) { + if (!applyInitMethod && !alwaysCallInit) return; if (initClass == null || initMethod == null) return; // call without parameter diff --git a/rails/sound/SoundConfig.java b/rails/sound/SoundConfig.java index b1bd84b..f6dfd8b 100644 --- a/rails/sound/SoundConfig.java +++ b/rails/sound/SoundConfig.java @@ -39,6 +39,9 @@ public class SoundConfig { public static final String KEY_SFX_OR_BuyTrain = "sound.sfx.or.buyTrain"; public static final String KEY_SFX_OR_BuyPrivate = "sound.sfx.or.buyPrivate"; + //if set to true, sfx is reported not to be enabled irrespective of the configuration + private static boolean isSFXDisabled = false; + public static String get(String configKey) { return get(configKey,null); } @@ -69,10 +72,12 @@ public class SoundConfig { return isEnabled(KEY_BGM_Enabled); } public static boolean isSFXEnabled() { - return isEnabled(KEY_SFX_Enabled); + return isEnabled(KEY_SFX_Enabled) && !isSFXDisabled; } private static boolean isEnabled(String key) { - //TODO add consideration for load replays (temporary disabled) return "enabled".equals(get(key)); } + public static void setSFXDisabled(boolean timeWarpMode) { + isSFXDisabled = timeWarpMode; + } } diff --git a/rails/sound/SoundContext.java b/rails/sound/SoundContext.java index 01ae6fd..13b4c5a 100644 --- a/rails/sound/SoundContext.java +++ b/rails/sound/SoundContext.java @@ -33,8 +33,23 @@ public class SoundContext { } public void notifyOfMusicEnablement(boolean musicEnabled) { - // TODO notifyOfMusicEnablement - + if (!musicEnabled && player.isBGMPlaying()) { + player.stopBGM(); + } + if (musicEnabled && !player.isBGMPlaying()) { + String musicFileNamePriorToDisable = currentBackgroundMusicFileName; + + //try to start BGM based on rounds / phases + currentBackgroundMusicFileName = null; + playBackgroundMusic(); + + //if no BGM could be started, replay the music that was active before disabling + //BGM music + if (currentBackgroundMusicFileName == null) { + currentBackgroundMusicFileName = musicFileNamePriorToDisable; + player.playBGM(musicFileNamePriorToDisable); + } + } } public void notifyOfSetRevenue(int actualRevenue) { @@ -93,5 +108,8 @@ public class SoundContext { playBackgroundMusic(); } } - + public void notifyOfGameSetup() { + currentBackgroundMusicFileName = SoundConfig.get(SoundConfig.KEY_BGM_GameSetup); + if (SoundConfig.isBGMEnabled()) player.playBGM(currentBackgroundMusicFileName); + } } diff --git a/rails/sound/SoundEventInterpreter.java b/rails/sound/SoundEventInterpreter.java index 09ed9a6..f494655 100644 --- a/rails/sound/SoundEventInterpreter.java +++ b/rails/sound/SoundEventInterpreter.java @@ -9,6 +9,10 @@ import rails.game.state.*; /** * Converts processed actions and model updates to triggers for playing sounds. + * + * Model observers get their own inner classes since their constructors are parameterized + * (needed to initialize member variables among others - especially important if game is + * loaded). * * @author Frederick Weld * @@ -20,6 +24,7 @@ public class SoundEventInterpreter { private Player formerPresident = null; public PresidentModelObserver(PublicCompanyI pc) { this.pc = pc; + if (pc != null) formerPresident = pc.getPresident(); } public void update(Observable o, Object arg) { if (formerPresident != pc.getPresident()) { @@ -31,6 +36,23 @@ public class SoundEventInterpreter { } } + private class CompanyFloatsModelObserver implements Observer { + private PublicCompanyI pc; + Boolean hasFloated = false; + public CompanyFloatsModelObserver(PublicCompanyI pc) { + this.pc = pc; + if (pc != null) hasFloated = pc.hasFloated(); + } + public void update(Observable o, Object arg) { + if (hasFloated != pc.hasFloated()) { + hasFloated = pc.hasFloated(); + if (SoundConfig.isSFXEnabled()) { + player.playSFXByConfigKey (SoundConfig.KEY_SFX_SR_CompanyFloats); + } + } + } + } + private SoundContext context; private SoundPlayer player; @@ -147,26 +169,12 @@ public class SoundEventInterpreter { for (PublicCompanyI c : gameManager.getCompanyManager().getAllPublicCompanies() ) { //presidency changes c.getPresidentModel().addObserver(new PresidentModelObserver(c)); - //company floats - c.getFloatedModel().addObserver(new Observer() { - Boolean hasFloated = false; - public void update(Observable o, Object arg) { - if (arg instanceof Boolean && arg != null) { - if (!((Boolean)arg).booleanValue() == hasFloated) { - hasFloated = ((Boolean)arg).booleanValue(); - if (SoundConfig.isSFXEnabled()) { - player.playSFXByConfigKey ( - SoundConfig.KEY_SFX_SR_CompanyFloats); - } - } - } - } - }); + c.getFloatedModel().addObserver(new CompanyFloatsModelObserver(c)); } } } - public void notifyOfGameSetup() { - if (SoundConfig.isBGMEnabled()) player.playBGMByConfigKey(SoundConfig.KEY_BGM_GameSetup); + public void notifyOfTimeWarp(boolean timeWarpMode) { + SoundConfig.setSFXDisabled(timeWarpMode); } } diff --git a/rails/sound/SoundManager.java b/rails/sound/SoundManager.java index 22d14f9..0e04c4f 100644 --- a/rails/sound/SoundManager.java +++ b/rails/sound/SoundManager.java @@ -2,7 +2,6 @@ package rails.sound; import rails.game.GameManagerI; import rails.game.action.PossibleAction; -import rails.game.action.SetDividend; /** * This is a singleton class as there should never be two @@ -54,6 +53,9 @@ public class SoundManager { * Called when game setup window initially opens */ public static void notifyOfGameSetup() { - getInstance().eventInterpreter.notifyOfGameSetup(); + getInstance().context.notifyOfGameSetup(); + } + public static void notifyOfTimeWarp(boolean timeWarpMode) { + getInstance().eventInterpreter.notifyOfTimeWarp(timeWarpMode); } } diff --git a/rails/sound/SoundPlayer.java b/rails/sound/SoundPlayer.java index ad73f1e..b5614f9 100644 --- a/rails/sound/SoundPlayer.java +++ b/rails/sound/SoundPlayer.java @@ -214,4 +214,13 @@ public class SoundPlayer { public void playBGMByConfigKey(String configKey) { playBGM(SoundConfig.get(configKey)); } + + public void stopBGM() { + LoopPlayerThread oldPlayerThread = adjustLastBGMThread(null); + if (oldPlayerThread != null) oldPlayerThread.interrupt(); + } + + public boolean isBGMPlaying() { + return (lastBGMThread != null); + } } diff --git a/rails/ui/swing/ReportWindowDynamic.java b/rails/ui/swing/ReportWindowDynamic.java index e2935da..a5c6128 100644 --- a/rails/ui/swing/ReportWindowDynamic.java +++ b/rails/ui/swing/ReportWindowDynamic.java @@ -20,6 +20,7 @@ import rails.game.ReportBuffer; import rails.game.action.GameAction; import rails.game.action.PossibleActions; import rails.game.move.MoveStack; +import rails.sound.SoundManager; import rails.ui.swing.elements.ActionButton; /** @@ -208,11 +209,12 @@ public class ReportWindowDynamic extends AbstractReportWindow implements Action public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + activateTimeWarp(); URL url = e.getURL(); -// String protocol = e.getURL().getProtocol(); +// String protocol = e.getURL().getProtocol(); int index = url.getPort(); gotoIndex(index + 1); - activateTimeWarp(); + toFront(); } } @@ -242,8 +244,8 @@ public class ReportWindowDynamic extends AbstractReportWindow implements Action gameUIManager.setEnabledAllWindows(false, this); timeWarpMode = true; closeable = false; + SoundManager.notifyOfTimeWarp(timeWarpMode); } - toFront(); } private void deactivateTimeWarp() { @@ -252,6 +254,7 @@ public class ReportWindowDynamic extends AbstractReportWindow implements Action playFromHereButton.setVisible(false); returnButton.setVisible(false); timeWarpMode = false; + SoundManager.notifyOfTimeWarp(timeWarpMode); closeable = true; } } commit 775ef65fbe5f73e84e2ecc420d7969a0597f59d3 Author: Frederick Weld <fre...@gm...> Date: Sat Jan 28 11:59:31 2012 +0100 Enhanced sound framework for rails 2.0 compliance The old BackgroundMusicManager is deleted together with all calls to him that had been placed inside the game engine. The new sound framework is notified as an observer to the relevant game models. Hence, it complies to the publish/subscriber paradigm that will be enforced in rails 2.0. As a sidenote, GameManagerI and PublicCompanyI had to be extended with a getter-method for required game models (getCurrentRoundModel and getFloatedModel respectively). diff --git a/LocalisedText.properties b/LocalisedText.properties index 0886408..df07a3b 100644 --- a/LocalisedText.properties +++ b/LocalisedText.properties @@ -213,6 +213,8 @@ Config.label.sound.backgroundMusic.startRound=Start Round Config.label.sound.backgroundMusic.stockRound=Stock Round (several files) Config.label.sound.backgroundMusic.operatingRound=Operating Round (several files) Config.label.sound.sfx=Sound Effects +Config.label.sound.sfx.str.bidStartItem=Bid on Start Item +Config.label.sound.sfx.str.buyStartItem=Buy Start Item Config.label.sound.sfx.or.buyPrivate=Buy Private (as a company) Config.label.sound.sfx.or.buyTrain=Buy Train (several files) Config.label.sound.sfx.or.decision.payout=Payout Revenue diff --git a/data/Properties.xml b/data/Properties.xml index fd9d582..5dd4f7b 100644 --- a/data/Properties.xml +++ b/data/Properties.xml @@ -72,6 +72,8 @@ </Section> <Section name="SFX"> <Property name="sound.sfx" type="LIST" values="disabled,enabled" /> + <Property name="sound.sfx.str.bidStartItem" type="FILE" /> + <Property name="sound.sfx.str.buyStartItem" type="FILE" /> <Property name="sound.sfx.sr.openingBell" type="FILE" /> <Property name="sound.sfx.sr.newPresident" type="FILE" /> <Property name="sound.sfx.sr.buyShare.president" type="FILE" /> diff --git a/rails/game/Game.java b/rails/game/Game.java index 3f7dfa8..a882493 100644 --- a/rails/game/Game.java +++ b/rails/game/Game.java @@ -11,7 +11,6 @@ import rails.common.DisplayBuffer; import rails.common.LocalText; import rails.common.parser.*; import rails.game.action.PossibleAction; -import rails.sound.BackgroundMusicManager; import rails.util.GameFileIO; public class Game { @@ -147,16 +146,12 @@ public class Game { return false; } - BackgroundMusicManager.init(); - return true; } public static Game load(String filepath) { - BackgroundMusicManager.mute(); - // use GameLoader object to load game GameFileIO gameLoader = new GameFileIO(); gameLoader.loadGameData(filepath); @@ -174,8 +169,6 @@ public class Game { DisplayBuffer.add(LocalText.getText("LoadFailed", e.getMessage())); } - BackgroundMusicManager.unMute(); - return gameLoader.getGame(); } diff --git a/rails/game/GameManager.java b/rails/game/GameManager.java index 886aa80..791dd01 100644 --- a/rails/game/GameManager.java +++ b/rails/game/GameManager.java @@ -13,6 +13,7 @@ import rails.common.*; import rails.common.parser.*; import rails.game.action.*; import rails.game.correct.*; +import rails.game.model.ModelObject; import rails.game.move.*; import rails.game.special.SpecialPropertyI; import rails.game.special.SpecialTokenLay; @@ -1423,6 +1424,10 @@ public class GameManager implements ConfigurableComponentI, GameManagerI { return (RoundI) currentRound.get(); } + public ModelObject getCurrentRoundModel() { + return currentRound; + } + /* (non-Javadoc) * @see rails.game.GameManagerI#getCurrentPlayerIndex() */ diff --git a/rails/game/GameManagerI.java b/rails/game/GameManagerI.java index a321507..c7bc6d7 100644 --- a/rails/game/GameManagerI.java +++ b/rails/game/GameManagerI.java @@ -98,6 +98,8 @@ public interface GameManagerI extends MoveableHolder, ConfigurableComponentI { */ public abstract RoundI getCurrentRound(); + public abstract ModelObject getCurrentRoundModel(); + /** * @return Returns the currentPlayerIndex. */ diff --git a/rails/game/OperatingRound.java b/rails/game/OperatingRound.java index c7099a7..d799ad9 100644 --- a/rails/game/OperatingRound.java +++ b/rails/game/OperatingRound.java @@ -11,7 +11,6 @@ import rails.game.correct.OperatingCost; import rails.game.move.*; import rails.game.special.*; import rails.game.state.*; -import rails.sound.BackgroundMusicManager; import rails.util.SequenceUtil; /** @@ -107,8 +106,6 @@ public class OperatingRound extends Round implements Observer { ReportBuffer.add(LocalText.getText("START_OR", thisOrNumber)); - BackgroundMusicManager.notifyOfOperatingRoundStart(); - for (Player player : gameManager.getPlayers()) { player.setWorthAtORStart(); } diff --git a/rails/game/Phase.java b/rails/game/Phase.java index 2e3f7b3..add140e 100644 --- a/rails/game/Phase.java +++ b/rails/game/Phase.java @@ -8,7 +8,6 @@ import org.apache.log4j.Logger; import rails.common.LocalText; import rails.common.parser.ConfigurationException; import rails.common.parser.Tag; -import rails.sound.BackgroundMusicManager; import rails.util.Util; public class Phase implements PhaseI { @@ -314,8 +313,6 @@ public class Phase implements PhaseI { } } - BackgroundMusicManager.setPhase(name); - if (actions != null && !actions.isEmpty()) { for (String actionName : actions.keySet()) { gameManager.processPhaseAction (actionName, actions.get(actionName)); diff --git a/rails/game/PublicCompany.java b/rails/game/PublicCompany.java index 3ad1c2c..3a8377c 100644 --- a/rails/game/PublicCompany.java +++ b/rails/game/PublicCompany.java @@ -1024,6 +1024,10 @@ public class PublicCompany extends Company implements PublicCompanyI { public boolean hasFloated() { return hasFloated.booleanValue(); } + + public ModelObject getFloatedModel() { + return hasFloated; + } /** * Has the company already operated? diff --git a/rails/game/PublicCompanyI.java b/rails/game/PublicCompanyI.java index ab08a06..ecd928f 100644 --- a/rails/game/PublicCompanyI.java +++ b/rails/game/PublicCompanyI.java @@ -96,6 +96,8 @@ public interface PublicCompanyI extends CompanyI, CashHolder, TokenHolder { */ public boolean hasFloated(); + + public ModelObject getFloatedModel(); /** * Has the company already operated? diff --git a/rails/game/StockRound.java b/rails/game/StockRound.java index 0d3fcf8..4f0b40b 100644 --- a/rails/game/StockRound.java +++ b/rails/game/StockRound.java @@ -8,7 +8,6 @@ import rails.game.action.*; import rails.game.move.*; import rails.game.special.*; import rails.game.state.*; -import rails.sound.BackgroundMusicManager; /** * Implements a basic Stock Round. <p> A new instance must be created for each @@ -91,8 +90,6 @@ public class StockRound extends Round { ReportBuffer.add(LocalText.getText("StartStockRound", getStockRoundNumber())); - BackgroundMusicManager.notifyOfStockRoundStart(); - setCurrentPlayerIndex(gameManager.getPriorityPlayer().getIndex()); startingPlayer = getCurrentPlayer(); // For the Report ReportBuffer.add(LocalText.getText("HasPriority", diff --git a/rails/game/specific/_1880/OperatingRound_1880.java b/rails/game/specific/_1880/OperatingRound_1880.java index 7d9a9ee..d3b094d 100644 --- a/rails/game/specific/_1880/OperatingRound_1880.java +++ b/rails/game/specific/_1880/OperatingRound_1880.java @@ -48,7 +48,6 @@ import rails.game.special.SpecialTrainBuy; import rails.game.specific._1880.PublicCompany_1880; import rails.game.specific._1880.GameManager_1880; import rails.game.state.EnumState; -import rails.sound.BackgroundMusicManager; /** * @author Martin @@ -169,8 +168,6 @@ public class OperatingRound_1880 extends OperatingRound { ReportBuffer.add(LocalText.getText("START_OR", thisOrNumber)); - BackgroundMusicManager.notifyOfOperatingRoundStart(); - for (Player player : gameManager.getPlayers()) { player.setWorthAtORStart(); } diff --git a/rails/sound/BackgroundMusicManager.java b/rails/sound/BackgroundMusicManager.java deleted file mode 100644 index ca34604..0000000 --- a/rails/sound/BackgroundMusicManager.java +++ /dev/null @@ -1,176 +0,0 @@ -/** - * - */ -package rails.sound; - -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.util.*; - -import javazoom.jl.player.Player; -import org.apache.log4j.Logger; - -import rails.common.parser.Config; - -/** - * This is a static class as there should never be two - * background musics playing at the same time. - * - * This class is notified of: - * - phase changes (eg., 2-train -> 3-train) - * - round changes (eg., SR -> OR) - * - * Based on this information, the appropriate background music (mp3) is played - * in the background. - */ -public class BackgroundMusicManager { - //TODO Kill old music manager - - private static class Context { - public int round; - public String phaseName; - public Context(int round, String phaseName) { - this.round = round; - this.phaseName = phaseName; - } - public boolean equals(Object o) { - if (!(o instanceof Context)) return false; - Context c = (Context)o; - return ((round == c.round) && (phaseName.equals(c.phaseName))); - } - public int hashCode() { - return round+phaseName.hashCode(); - } - public Context clone() { - return new Context(round,phaseName); - } - } - private static final int ROUND_UNDEFINED = -1; - private static final int ROUND_STOCK = 0; - private static final int ROUND_OPERATING = 1; - private static final String PHASENAME_DEFAULT = ""; - private static Map<Context,String> contextToMusicFileMapping; - private static boolean isDisabled = true; - private static boolean isMute = false; - private static boolean isPlaying = false; - private static String currentMusicFileName; - private static Thread playingThread; - private static Context context = new Context(ROUND_UNDEFINED,PHASENAME_DEFAULT); - private static Logger log = Logger.getLogger(BackgroundMusicManager.class.getPackage().getName()); - - private static void setContextToMusicFileMapping (String config,Context defaultContext) { - if (config == null || config.equals("")) return; - String[] assignments = config.split(","); - for ( int i = 0 ; i < assignments.length ; i++ ) { - String[] assignment = assignments[i].split("="); - Context c = defaultContext.clone(); - if (assignment.length == 1) { - //default assignment (meaning, phase-independent) - contextToMusicFileMapping.put(c, assignment[0]); - } - else if (assignment.length == 2) { - //phase-dependent assignment - c.phaseName = assignment[0]; - contextToMusicFileMapping.put(c, assignment[1]); - } - } - } - public static void init() { - String enablement = Config.get("sound.backgroundMusic"); - if (enablement != null && enablement.equals("enabled")) { - isDisabled = false; - contextToMusicFileMapping = new HashMap<Context,String>(); - setContextToMusicFileMapping( - Config.get("sound.backgroundMusic.stockRound"), - new Context(ROUND_STOCK,PHASENAME_DEFAULT) - ); - setContextToMusicFileMapping( - Config.get("sound.backgroundMusic.operatingRound"), - new Context(ROUND_OPERATING,PHASENAME_DEFAULT) - ); - playNewMusic(); - } else { - stopMusic(); - isDisabled = true; - } - - } - public static void setPhase(String name) { - if (!context.phaseName.equals(name)) { - context.phaseName = name; - playNewMusic(); - } - } - public static void notifyOfStockRoundStart() { - if (context.round != ROUND_STOCK) { - context.round = ROUND_STOCK; - playNewMusic(); - } - } - public static void notifyOfOperatingRoundStart() { - if (context.round != ROUND_OPERATING) { - context.round = ROUND_OPERATING; - playNewMusic(); - } - } - public static void mute() { - isMute = true; - stopMusic(); - } - public static void unMute() { - isMute = false; - playNewMusic(); - } - - private static void playNewMusic() { - if (!isMute && !isDisabled) { - if (isPlaying) stopMusic(); - if (contextToMusicFileMapping != null) { - String newMusicFileName = (String)contextToMusicFileMapping.get(context); - if (newMusicFileName == null) { - //try phase-defaulting if nothing was found - newMusicFileName = (String)contextToMusicFileMapping.get(new Context(context.round,PHASENAME_DEFAULT)); - } - //only restart/change the music if a new music file is to be played - if (newMusicFileName != null && !newMusicFileName.equals(currentMusicFileName)) { - currentMusicFileName = newMusicFileName; - // run music playing in new thread to play in background - playingThread = new Thread() { - Player player; - boolean isKilled = false; - public void run() { - try { - while (!isKilled) { - FileInputStream fis = new FileInputStream(currentMusicFileName); - BufferedInputStream bis = new BufferedInputStream(fis); - player = new Player(bis); - log.info("Now playing: "+currentMusicFileName); - player.play(); - player.close(); - } - } - catch (Exception e) { - //if anything goes wrong, don't play anything - log.error(e); - } - } - public void interrupt() { - super.interrupt(); - isKilled = true; - if (player!=null) player.close(); - } - }; - playingThread.start(); - isPlaying = true; - } - } - } - } - private static void stopMusic() { - if (isPlaying) { - playingThread.interrupt(); - isPlaying = false; - currentMusicFileName = null; - } - } -} diff --git a/rails/sound/SoundConfig.java b/rails/sound/SoundConfig.java index ef3bad3..b1bd84b 100644 --- a/rails/sound/SoundConfig.java +++ b/rails/sound/SoundConfig.java @@ -14,34 +14,24 @@ import rails.common.parser.Config; */ public class SoundConfig { public static final String KEY_BGM_Enabled = "sound.backgroundMusic"; - //TODO GameSetup public static final String KEY_BGM_GameSetup = "sound.backgroundMusic.gameSetup"; - //TODO StartRound public static final String KEY_BGM_StartRound = "sound.backgroundMusic.startRound"; - //TODO StockRound public static final String KEY_BGM_StockRound = "sound.backgroundMusic.stockRound"; - //TODO OperatingRound public static final String KEY_BGM_OperatingRound = "sound.backgroundMusic.operatingRound"; - //TODO EndOfGame Round public static final String KEY_BGM_EndOfGameRound = "sound.backgroundMusic.endOfGameRound"; public static final String KEY_SFX_Enabled = "sound.sfx"; + public static final String KEY_SFX_STR_BidStartItem = "sound.sfx.str.bidStartItem"; + public static final String KEY_SFX_STR_BuyStartItem = "sound.sfx.str.buyStartItem"; //TODO Opening Bell public static final String KEY_SFX_SR_OpeningBell = "sound.sfx.sr.openingBell"; - //TODO New president public static final String KEY_SFX_SR_NewPresident = "sound.sfx.sr.newPresident"; - //TODO Buy Share Pres public static final String KEY_SFX_SR_BuyShare_President = "sound.sfx.sr.buyShare.president"; - //TODO Buy Share non Pres public static final String KEY_SFX_SR_BuyShare_NonPresident = "sound.sfx.sr.buyShare.nonPresident"; - //TODO Sell Share Pres public static final String KEY_SFX_SR_SellShare_President = "sound.sfx.sr.sellShare.president"; - //TODO Sell Share non Pres public static final String KEY_SFX_SR_SellShare_NonPresident = "sound.sfx.sr.sellShare.nonPresident"; - //TODO Company Floats public static final String KEY_SFX_SR_CompanyFloats = "sound.sfx.sr.companyFloats"; public static final String KEY_SFX_OR_LayTile = "sound.sfx.or.layTile"; public static final String KEY_SFX_OR_LayToken = "sound.sfx.or.layToken"; - //TODO Set Revenue public static final String KEY_SFX_OR_SetRevenue = "sound.sfx.or.setRevenue"; public static final String KEY_SFX_OR_Decision_Payout = "sound.sfx.or.decision.payout"; public static final String KEY_SFX_OR_Decision_Split = "sound.sfx.or.decision.split"; @@ -75,13 +65,14 @@ public class SoundConfig { if (resultValue == null) resultValue = ""; return resultValue; } - public static boolean isMusicEnabled() { + public static boolean isBGMEnabled() { return isEnabled(KEY_BGM_Enabled); } public static boolean isSFXEnabled() { return isEnabled(KEY_SFX_Enabled); } private static boolean isEnabled(String key) { + //TODO add consideration for load replays (temporary disabled) return "enabled".equals(get(key)); } } diff --git a/rails/sound/SoundContext.java b/rails/sound/SoundContext.java index 9292371..01ae6fd 100644 --- a/rails/sound/SoundContext.java +++ b/rails/sound/SoundContext.java @@ -3,6 +3,8 @@ */ package rails.sound; +import rails.game.*; + /** * Takes care of the current context from a music/sfx perspective. * Reacts on context changes by triggering changes to the played music/sfx. @@ -11,10 +13,85 @@ package rails.sound; * */ public class SoundContext { - + private double averageRevenue = 50; + //to which degree (from 0=none to 1=full) is new revenue considered for determining + //the new average revenue value + private final static double slidingAverageAdjustmentFactor = 0.2; + //how much percent of the set revenue sfx is played if the revenue is average + private final static double averageSetRevenuePlaySoundProportion = 0.4; + //how much percent of the set revenue sfx is played if the revenue is epsilon; + private final static double minimumSetRevenuePlaySoundProportion = 0.167; + + private RoundI currentRound = null; + private PhaseI currentPhase = null; + private String currentBackgroundMusicFileName = null; + + private SoundPlayer player; + + public SoundContext(SoundPlayer player) { + this.player = player; + } + public void notifyOfMusicEnablement(boolean musicEnabled) { // TODO notifyOfMusicEnablement } + public void notifyOfSetRevenue(int actualRevenue) { + //ignore zero revenue + if (actualRevenue <= 0) return; + + double playSoundProportion = minimumSetRevenuePlaySoundProportion + + ( 1 - minimumSetRevenuePlaySoundProportion ) + * ( averageSetRevenuePlaySoundProportion - minimumSetRevenuePlaySoundProportion ) + * actualRevenue / averageRevenue; + if (playSoundProportion > 1) playSoundProportion = 1; + + player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_SetRevenue, + playSoundProportion); + + averageRevenue = actualRevenue * slidingAverageAdjustmentFactor + + averageRevenue * (1 - slidingAverageAdjustmentFactor); + } + + private void playBackgroundMusic() { + //do nothing if music is not enabled + if (!SoundConfig.isBGMEnabled()) return; + + String currentRoundConfigKey = null; + if (currentRound instanceof StartRound) { + currentRoundConfigKey = SoundConfig.KEY_BGM_StartRound; + } else if (currentRound instanceof StockRound) { + currentRoundConfigKey = SoundConfig.KEY_BGM_StockRound; + } else if (currentRound instanceof OperatingRound) { + currentRoundConfigKey = SoundConfig.KEY_BGM_OperatingRound; + } else if (currentRound instanceof EndOfGameRound) { + currentRoundConfigKey = SoundConfig.KEY_BGM_EndOfGameRound; + } + //only play anything if round is recognized and new music is to be played + if (currentRoundConfigKey != null) { + String currentPhaseName = ""; + if (currentPhase != null) currentPhaseName = currentPhase.getName(); + String newBackgroundMusicFileName = SoundConfig.get( + currentRoundConfigKey, currentPhaseName); + if (!newBackgroundMusicFileName.equals(currentBackgroundMusicFileName)) { + currentBackgroundMusicFileName = newBackgroundMusicFileName; + player.playBGM(newBackgroundMusicFileName); + } + } + } + public void notifyOfPhase(PhaseI newPhase) { + if (!newPhase.equals(currentPhase)) { + currentPhase = newPhase; + playBackgroundMusic(); + } + } + + public void notifyOfRound(RoundI newRound) { + if (!newRound.equals(currentRound)) { + currentRound = newRound; + playBackgroundMusic(); + } + } + } diff --git a/rails/sound/SoundEventInterpreter.java b/rails/sound/SoundEventInterpreter.java index db40e1b..09ed9a6 100644 --- a/rails/sound/SoundEventInterpreter.java +++ b/rails/sound/SoundEventInterpreter.java @@ -1,7 +1,11 @@ package rails.sound; -import rails.game.GameManagerI; +import java.util.Observable; +import java.util.Observer; + +import rails.game.*; import rails.game.action.*; +import rails.game.state.*; /** * Converts processed actions and model updates to triggers for playing sounds. @@ -10,8 +14,27 @@ import rails.game.action.*; * */ public class SoundEventInterpreter { + + private class PresidentModelObserver implements Observer { + private PublicCompanyI pc; + private Player formerPresident = null; + public PresidentModelObserver(PublicCompanyI pc) { + this.pc = pc; + } + public void update(Observable o, Object arg) { + if (formerPresident != pc.getPresident()) { + formerPresident = pc.getPresident(); + if (SoundConfig.isSFXEnabled()) { + player.playSFXByConfigKey (SoundConfig.KEY_SFX_SR_NewPresident); + } + } + } + } + private SoundContext context; private SoundPlayer player; + + public SoundEventInterpreter (SoundContext context,SoundPlayer player) { this.context = context; this.player = player; @@ -19,7 +42,7 @@ public class SoundEventInterpreter { public void notifyOfActionProcessing(GameManagerI gm,PossibleAction action) { /** - * Interpretation of events for which only sfx is relevant + * Interpretation of events for which are only sfx is relevant */ if (SoundConfig.isSFXEnabled()) { @@ -33,6 +56,7 @@ public class SoundEventInterpreter { player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_LayToken); } else if (action instanceof SetDividend) { + //set revenue not treated here SetDividend sd = (SetDividend)action; if (sd.getRevenueAllocation() == SetDividend.PAYOUT) { player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_Decision_Payout); @@ -49,7 +73,100 @@ public class SoundEventInterpreter { } else if (action instanceof BuyPrivate) { player.playSFXByConfigKey (SoundConfig.KEY_SFX_OR_BuyPrivate); + } + + //SR actions + + else if (action instanceof BuyCertificate) { + BuyCertificate bc = (BuyCertificate)action; + String presidentName = ""; + if (bc.getCompany().getPresident() != null) { + presidentName = bc.getCompany().getPresident().getName(); + } + if (presidentName.equals(bc.getPlayerName())) { + player.playSFXByConfigKey (SoundConfig.KEY_SFX_SR_BuyShare_President); + } else { + player.playSFXByConfigKey (SoundConfig.KEY_SFX_SR_BuyShare_NonPresident); + } + + } else if (action instanceof SellShares) { + SellShares ss = (SellShares)action; + String presidentName = ""; + if (ss.getCompany().getPresident() != null) { + presidentName = ss.getCompany().getPresident().getName(); + } + if (presidentName.equals(ss.getPlayerName())) { + player.playSFXByConfigKey (SoundConfig.KEY_SFX_SR_SellShare_President); + } else { + player.playSFXByConfigKey (SoundConfig.KEY_SFX_SR_SellShare_NonPresident); + } + + } + + //Start Round actions + + else if (action instanceof rails.game.action.BidStartItem) { + player.playSFXByConfigKey (SoundConfig.KEY_SFX_STR_BidStartItem); + + } else if (action instanceof rails.game.action.BuyStartItem) { + player.playSFXByConfigKey (SoundConfig.KEY_SFX_STR_BuyStartItem); + + } + + } + } + public void notifyOfGameInit(GameManagerI gameManager) { + //subscribe to round changes + if (gameManager.getCurrentRoundModel() != null) { + gameManager.getCurrentRoundModel().addObserver( + new Observer() { + public void update(Observable o, Object arg) { + if (o instanceof State) { + State s = (State)o; + context.notifyOfRound((RoundI)s.get()); + } + } + }); + } + + //subscribe to phase changes + if (gameManager.getPhaseManager() != null) { + gameManager.getPhaseManager().getCurrentPhaseModel().addObserver( + new Observer() { + public void update(Observable o, Object arg) { + if (o instanceof State) { + State s = (State)o; + context.notifyOfPhase((PhaseI)s.get()); + } + } + }); + } + + //subscribe to company events + if (gameManager.getCompanyManager() != null) { + for (PublicCompanyI c : gameManager.getCompanyManager().getAllPublicCompanies() ) { + //presidency changes + c.getPresidentModel().addObserver(new PresidentModelObserver(c)); + + //company floats + c.getFloatedModel().addObserver(new Observer() { + Boolean hasFloated = false; + public void update(Observable o, Object arg) { + if (arg instanceof Boolean && arg != null) { + if (!((Boolean)arg).booleanValue() == hasFloated) { + hasFloated = ((Boolean)arg).booleanValue(); + if (SoundConfig.isSFXEnabled()) { + player.playSFXByConfigKey ( + SoundConfig.KEY_SFX_SR_CompanyFloats); + } + } + } + } + }); } } } + public void notifyOfGameSetup() { + if (SoundConfig.isBGMEnabled()) player.playBGMByConfigKey(SoundConfig.KEY_BGM_GameSetup); + } } diff --git a/rails/sound/SoundManager.java b/rails/sound/SoundManager.java index bc4f7cc..22d14f9 100644 --- a/rails/sound/SoundManager.java +++ b/rails/sound/SoundManager.java @@ -2,6 +2,7 @@ package rails.sound; import rails.game.GameManagerI; import rails.game.action.PossibleAction; +import rails.game.action.SetDividend; /** * This is a singleton class as there should never be two @@ -25,7 +26,7 @@ public class SoundManager { private SoundManager() { player = new SoundPlayer(); - context = new SoundContext(); + context = new SoundContext(player); eventInterpreter = new SoundEventInterpreter(context,player); } public static SoundManager getInstance() { @@ -33,9 +34,26 @@ public class SoundManager { return manager; } public static void init() { - getInstance().context.notifyOfMusicEnablement(SoundConfig.isMusicEnabled()); + getInstance().context.notifyOfMusicEnablement(SoundConfig.isBGMEnabled()); } public static void notifyOfActionProcessing(GameManagerI gm,PossibleAction action) { getInstance().eventInterpreter.notifyOfActionProcessing(gm,action); } + public static void notifyOfSetRevenue(int actualRevenue) { + if (SoundConfig.isSFXEnabled()) { + getInstance().context.notifyOfSetRevenue(actualRevenue); + } + } + /** + * Called when game engine has been instantiated for a specific game + */ + public static void notifyOfGameInit(GameManagerI gameManager) { + getInstance().eventInterpreter.notifyOfGameInit(gameManager); + } + /** + * Called when game setup window initially opens + */ + public static void notifyOfGameSetup() { + getInstance().eventInterpreter.notifyOfGameSetup(); + } } diff --git a/rails/sound/SoundPlayer.java b/rails/sound/SoundPlayer.java index d695a90..ad73f1e 100644 --- a/rails/sound/SoundPlayer.java +++ b/rails/sound/SoundPlayer.java @@ -6,7 +6,9 @@ package rails.sound; import java.io.BufferedInputStream; import java.io.FileInputStream; +import javazoom.jl.decoder.JavaLayerException; import javazoom.jl.player.Player; +import javazoom.jl.player.advanced.AdvancedPlayer; /** * Handles play requests for music and sfx. @@ -43,6 +45,16 @@ public class SoundPlayer { //wait until prior thread has finished playing if (priorThread != null) priorThread.waitForPlayingDone(); priorThread = null; //release handle + + play(); + + //wake the subsequent thread if there is one waiting + synchronized (this) { + notify(); + playingDone = true; + } + } + public void play() { try { FileInputStream fis = new FileInputStream(fileName); BufferedInputStream bis = new BufferedInputStream(fis); @@ -53,16 +65,95 @@ public class SoundPlayer { catch (Exception e) { //if anything goes wrong, don't play anything } - //wake the subsequent thread if there is one waiting - synchronized (this) { - notify(); - playingDone = true; + } + } + private class PortionPlayerThread extends PlayerThread { + private double startPos; + private double endPos; + /** + * @param startPos Relative offset [0..1] - first mp3 frame played + * @param endPos Relative offset [0..1] - last mp3 frame played + */ + public PortionPlayerThread(String fileName, double startPos, double endPos) { + super(fileName); + this.startPos = startPos; + this.endPos = endPos; + } + @Override + public void play() { + try { + FileInputStream fis = new FileInputStream(fileName); + BufferedInputStream bis = new BufferedInputStream(fis); + PortionPlayer player = new PortionPlayer(bis); + player.play(startPos, endPos); + player.close(); + } + catch (Exception e) { + //if anything goes wrong, don't play anything + } + } + } + private class PortionPlayer extends AdvancedPlayer { + BufferedInputStream bis; + public PortionPlayer(BufferedInputStream bis) throws JavaLayerException { + super(bis); + this.bis = bis; + } + /** + * @param startPos Relative offset [0..1] - first mp3 frame played + * @param endPos Relative offset [0..1] - last mp3 frame played + */ + public void play(double startPos, double endPos) { + try { + //first get number of frames + bis.mark(Integer.MAX_VALUE); + int frameNum = 0; + while (skipFrame()) { + frameNum++; + } + int startFrame = (int)Math.floor(startPos * frameNum); + int endFrame = (int)Math.ceil(endPos * frameNum); + if (startFrame < endFrame) { + bis.reset(); + play(startFrame, endFrame); + } + } catch (Exception e) { + //if anything goes wrong, don't play anything } } } + private class LoopPlayerThread extends PlayerThread { + boolean isStopped = false; + Player player = null; + public LoopPlayerThread(String fileName) { + super(fileName); + } + public void play() { + try { + while (!isStopped) { + FileInputStream fis = new FileInputStream(fileName); + BufferedInputStream bis = new BufferedInputStream(fis); + player = new Player(bis); + player.play(); + player.close(); + } + } + catch (Exception e) { + //if anything goes wrong, don't play anything + } + } + @Override + public void interrupt() { + super.interrupt(); + isStopped = true; + if (player!=null) player.close(); + } + } private PlayerThread lastSFXThread = null; + private LoopPlayerThread lastBGMThread = null; + /** * atomic switching of the pointer to the last thread which played an sfx. * @param newThread Player thread for the new sfx @@ -74,16 +165,53 @@ public class SoundPlayer { return pt; } - public void playSFX(String fileName) { - PlayerThread newPlayerThread = new PlayerThread (fileName); + /** + * atomic switching of the pointer to the last thread which played music. + * @param newThread Player thread for the new music + * @return Player thread which was the last to play music + */ + synchronized private LoopPlayerThread adjustLastBGMThread(LoopPlayerThread newThread) { + LoopPlayerThread pt = lastBGMThread; + lastBGMThread = newThread; + return pt; + } + + private void playSFX(PlayerThread newPlayerThread) { PlayerThread oldPlayerThread = adjustLastSFXThread(newPlayerThread); newPlayerThread.setPriorThread(oldPlayerThread); newPlayerThread.start(); } + + public void playSFX(String fileName) { + playSFX(new PlayerThread (fileName)); + } public void playSFXByConfigKey(String configKey) { playSFX(SoundConfig.get(configKey)); } public void playSFXByConfigKey(String configKey,String parameter) { playSFX(SoundConfig.get(configKey,parameter)); } + + public void playSFX(String fileName, double playSoundProportion) { + playSFX(new PortionPlayerThread (fileName, 1 - playSoundProportion, 1)); + } + + /** + * The latter part of the sfx is played. + * @param playSoundProportion The length of this part relatively to the overall sound duration. + */ + public void playSFXByConfigKey(String configKey, double playSoundProportion) { + playSFX(SoundConfig.get(configKey), playSoundProportion); + } + + public void playBGM(String backgroundMusicFileName) { + LoopPlayerThread newPlayerThread = new LoopPlayerThread(backgroundMusicFileName); + LoopPlayerThread oldPlayerThread = adjustLastBGMThread(newPlayerThread); + if (oldPlayerThread != null) oldPlayerThread.interrupt(); + newPlayerThread.start(); + } + + public void playBGMByConfigKey(String configKey) { + playBGM(SoundConfig.get(configKey)); + } } diff --git a/rails/ui/swing/GameSetupWindow.java b/rails/ui/swing/GameSetupWindow.java index d9652ec..e91880d 100644 --- a/rails/ui/swing/GameSetupWindow.java +++ b/rails/ui/swing/GameSetupWindow.java @@ -20,6 +20,7 @@ import rails.common.parser.Config; import rails.common.parser.GameOption; import rails.common.parser.GameInfo; import rails.game.*; +import rails.sound.SoundManager; import rails.util.*; /** @@ -147,6 +148,9 @@ public class GameSetupWindow extends JDialog implements ActionListener { // This needs to happen after we have a valid gameName. fillPlayersPane(); + + // Notify the sound manager about having started the setup menu + SoundManager.notifyOfGameSetup(); } private void populateGridBag() { diff --git a/rails/ui/swing/GameUIManager.java b/rails/ui/swing/GameUIManager.java index 5154bf1..81b700f 100644 --- a/rails/ui/swing/GameUIManager.java +++ b/rails/ui/swing/GameUIManager.java @@ -221,6 +221,9 @@ public class GameUIManager implements DialogOwner { // define configWindow configWindow = new ConfigWindow(true); configWindow.init(); + + // notify sound manager of game initialization + SoundManager.notifyOfGameInit(gameManager); } public void startLoadedGame() { diff --git a/rails/ui/swing/ORUIManager.java b/rails/ui/swing/ORUIManager.java index db96ac7..f10d2a4 100644 --- a/rails/ui/swing/ORUIManager.java +++ b/rails/ui/swing/ORUIManager.java @@ -17,6 +17,7 @@ import rails.game.action.*; import rails.game.correct.*; import rails.game.correct.MapCorrectionManager.ActionStep; import rails.game.special.*; +import rails.sound.SoundManager; import rails.ui.swing.elements.*; import rails.ui.swing.hexmap.GUIHex; import rails.ui.swing.hexmap.HexMap; @@ -493,6 +494,12 @@ public class ORUIManager implements DialogOwner { orPanel.stopRevenueUpdate(); log.debug("Set revenue amount is " + amount); action.setActualRevenue(amount); + + // notify sound manager of set revenue amount as soon as + // set revenue is pressed (not waiting for the completion + // of the set dividend action) + SoundManager.notifyOfSetRevenue(amount); + if (amount == 0 || action.getRevenueAllocation() != SetDividend.UNKNOWN) { log.debug("Allocation is known: " + action.getRevenueAllocation()); commit cd230ed207c83462c4eeeac9006abfeefca03669 Author: Frederick Weld <fre...@gm...> Date: Fri Jan 27 20:27:01 2012 +0100 Created new framework for playing music and sound effects Playing sounds (both bgm / sfx) is disabled by default. Background music (BGM) is configurable on a per-round-type and per-phase basis. (currently 5 round types supported) There are 15 sound effects (SFX) types, of which - one is parameterizable (train type for buy train) - one is played for a varying amount of time (set revenue depending on the revenue - similar to RRT1) The framework classes are found in rails.sound. As a facade to the rest of rails, the Sound Manager is notified of - processed events (by GameUIManager) - this covers close to 90% of the triggers of playing sounds - model updates (by the respective models) The input received by the framework is evaluated by the event interpreter who - triggers sound playing directly (straightforward cases) - triggers sound context adjustment (complex case - eg. phase bgm) - which triggers in turn playing sounds diff --git a/Loca... [truncated message content] |