diff options
author | athrxx | 2011-03-22 15:55:17 +0100 |
---|---|---|
committer | athrxx | 2011-03-22 15:55:17 +0100 |
commit | ea79336ac90e12fe53242cfd9153db9d7087ca0f (patch) | |
tree | 50c74ceb394cf23d845c408659459f3b07192b92 | |
parent | 92f922aabe5811fcf595697bc1316aa57b4c9b66 (diff) | |
parent | 273ba73d5fae0dd0d3b3f7c5f15f03d02c0af1b4 (diff) | |
download | scummvm-rg350-ea79336ac90e12fe53242cfd9153db9d7087ca0f.tar.gz scummvm-rg350-ea79336ac90e12fe53242cfd9153db9d7087ca0f.tar.bz2 scummvm-rg350-ea79336ac90e12fe53242cfd9153db9d7087ca0f.zip |
Merge branch 'master' of https://github.com/scummvm/scummvm
89 files changed, 900 insertions, 1060 deletions
@@ -15,7 +15,7 @@ For a more comprehensive changelog of the latest experimental code, see: - Added Danish translation. - Added Norwegian Bokmaal translation. - Added Norwegian Nynorsk translation. - - Added Debug Console to Cine, Draci, Gob, MADE, Sword1, Touche and + - Added Debug Console to Cine, Draci, Gob, MADE, Sword1, Touche and Tucker Engines. - Closed significant memory leaks. RTL should now be more usable. @@ -50,7 +50,7 @@ For a more comprehensive changelog of the latest experimental code, see: - Added several previously missing parts of the game state in saved games, such as game played time, script created windows, the script string heap and information related to the text parser in old EGA games. - - Added support for magnifier cursors. + - Added support for SCI1.1 magnifier cursors. - Added support for the keypad +/- keys. - Added support for the alternative General MIDI tracks in the Windows CD versions of Eco Quest, Jones in the Fast Lane, King's Quest 5 and Space @@ -63,12 +63,22 @@ For a more comprehensive changelog of the latest experimental code, see: - Corrected several problems and issues in the Skate-O-Rama rooms in Space Quest 4. - Corrected several issues in Hoyle Classic Card Games. - - Fixed several graphical glitches. + - Fixed several graphical glitches (like, for example, parts of the screen + that weren't erased correctly under some rare circumstances). - Fixed several script bugs. - - Fixed several pathfinding related issues and lockups. - - Fixed several music related glitches and possible lockups. + - Fixed several pathfinding related issues and lockups (like, for example, + a lockup in the shower scene of Laura bow 1 and pathfinding in some + screens during the chase sequence in Laura Bow 2). + - Fixed several music related glitches and possible lockups (like, for + example, a rare music lockup that occured when loading a saved game + outside the palace in Quest for Glory 3). - Fixed possible problems and lockups in the character import screens of Quest for Glory 2 and 3. + - Fixed a bug that caused a lockup in the SCI1 CD version of Mixed Up Mother + Goose, after Tommy Tucker's song. + - Fixed a script bug in the CD version of King's Quest 5, which caused a + lockup under certain circumstances when going outside the witch's house + in the dark forest. - Function keys now work correctly when the numlock key is on. - Improved support for fanmade game scripts. - Improved support for non-English versions of games. @@ -92,7 +102,10 @@ For a more comprehensive changelog of the latest experimental code, see: Touche: - Corrected memory leaks and minor issues. - SDL: + Tucker: + - Added workarounds for several issues present in the original game. + + SDL ports: - Added support for OpenGL. (GSoC Task) - Closed memory leaks in Mouse Surfaces. @@ -100,6 +113,14 @@ For a more comprehensive changelog of the latest experimental code, see: - Switched to the official NDK toolchain for building. - Fixed GFX output for various devices. - Fixed various crashes. + - Switched to the native screen resolution to improve text readability. + - Added support for pause/resume. + - Added support for games using 16bit graphics. + - Increased the performance significantly. + - Added support for the "Fullscreen mode" option. Unticking this keeps the + game's aspect ratio. + - Added a new graphics mode for linear filtering. + - Overhauled the input system (see README.Android). Nintendo DS port: - Added support for loadable modules. diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index fd8c2ccffe..4ac2747d25 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -103,14 +103,8 @@ void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { break; case OSystem::kFeatureAspectRatioCorrection: - // TODO: If we enable aspect ratio correction, we automatically set - // the video mode to 4/3. That is quity messy, but since we have that - // messy OpenGL mode use there's not much to do about it right now... - // Of course in case we disasble the aspect ratio correction, we - // might want to setup a different mode, but which one? - // Think of a way to get rid of this mess. - if (enable) - _videoMode.mode = OpenGL::GFX_4_3; + _videoMode.aspectRatioCorrection = enable; + _transactionDetails.needRefresh = true; break; default: @@ -124,7 +118,7 @@ bool OpenGLGraphicsManager::getFeatureState(OSystem::Feature f) { return _videoMode.fullscreen; case OSystem::kFeatureAspectRatioCorrection: - return _videoMode.mode == OpenGL::GFX_4_3; + return _videoMode.aspectRatioCorrection; default: return false; @@ -138,7 +132,6 @@ bool OpenGLGraphicsManager::getFeatureState(OSystem::Feature f) { static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { {"gl1", _s("OpenGL Normal"), OpenGL::GFX_NORMAL}, {"gl2", _s("OpenGL Conserve"), OpenGL::GFX_CONSERVE}, - {"gl3", _s("OpenGL 4/3"), OpenGL::GFX_4_3}, {"gl4", _s("OpenGL Original"), OpenGL::GFX_ORIGINAL}, {0, 0, 0} }; @@ -166,11 +159,10 @@ bool OpenGLGraphicsManager::setGraphicsMode(int mode) { switch (mode) { case OpenGL::GFX_NORMAL: case OpenGL::GFX_CONSERVE: - case OpenGL::GFX_4_3: case OpenGL::GFX_ORIGINAL: break; default: - warning("unknown gfx mode %d", mode); + warning("Unknown gfx mode %d", mode); return false; } @@ -1262,10 +1254,14 @@ void OpenGLGraphicsManager::toggleAntialiasing() { } uint OpenGLGraphicsManager::getAspectRatio() { - if (_videoMode.mode == OpenGL::GFX_NORMAL) - return _videoMode.hardwareWidth * 10000 / _videoMode.hardwareHeight; - else if (_videoMode.mode == OpenGL::GFX_4_3) + // In case we enable aspect ratio correction we force a 4/3 ratio. + // TODO: This makes OpenGL Normal behave like OpenGL Conserve, when aspect + // ratio correction is enabled, but it's better than the previous 4/3 mode + // mess at least... + if (_videoMode.aspectRatioCorrection) return 13333; + else if (_videoMode.mode == OpenGL::GFX_NORMAL) + return _videoMode.hardwareWidth * 10000 / _videoMode.hardwareHeight; else return _videoMode.screenWidth * 10000 / _videoMode.screenHeight; } @@ -1274,10 +1270,7 @@ void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) { if (_overlayVisible) return; - if (_videoMode.mode == OpenGL::GFX_NORMAL) { - x /= _videoMode.scaleFactor; - y /= _videoMode.scaleFactor; - } else if (!_overlayVisible) { + if (!_overlayVisible) { x -= _displayX; y -= _displayY; @@ -1388,22 +1381,6 @@ const char *OpenGLGraphicsManager::getCurrentModeName() { return modeName; } -void OpenGLGraphicsManager::switchDisplayMode(int mode) { - assert(_transactionMode == kTransactionActive); - - if (_videoMode.mode == mode) - return; - - if (mode == -1) // If -1, switch to next mode - _videoMode.mode = (_videoMode.mode + 1) % 4; - else if (mode == -2) // If -2, switch to previous mode - _videoMode.mode = (_videoMode.mode + 3) % 4; - else - _videoMode.mode = mode; - - _transactionDetails.needRefresh = true; -} - #ifdef USE_OSD void OpenGLGraphicsManager::updateOSD() { // The font we are going to use: diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h index f674015b4a..374f1c196e 100644 --- a/backends/graphics/opengl/opengl-graphics.h +++ b/backends/graphics/opengl/opengl-graphics.h @@ -39,8 +39,7 @@ namespace OpenGL { enum { GFX_NORMAL = 0, GFX_CONSERVE = 1, - GFX_4_3 = 2, - GFX_ORIGINAL = 3 + GFX_ORIGINAL = 2 }; } @@ -156,6 +155,7 @@ protected: int mode; int scaleFactor; bool antialiasing; + bool aspectRatioCorrection; int screenWidth, screenHeight; int overlayWidth, overlayHeight; @@ -217,15 +217,6 @@ protected: int _displayWidth; int _displayHeight; - /** - * Sets the dispaly mode. - * - * This can only be used in a GFX transaction. - * - * @param mode the dispaly mode, if -1 it will switch to next mode. If -2 to previous mode. - */ - virtual void switchDisplayMode(int mode); - virtual const char *getCurrentModeName(); virtual void calculateDisplaySize(int &width, int &height); diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp index de9dba1ab1..b9022af120 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.cpp +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -295,10 +295,6 @@ bool OpenGLSdlGraphicsManager::setupFullscreenMode() { } bool OpenGLSdlGraphicsManager::loadGFXMode() { - // Force 4/3 if feature enabled - if (getFeatureState(OSystem::kFeatureAspectRatioCorrection)) - _videoMode.mode = OpenGL::GFX_4_3; - // If the screen was resized, do not change its size if (!_screenResized) { const int scaleFactor = getScale(); @@ -509,10 +505,19 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { // Ctrl-Alt-a switch between display modes if (event.kbd.keycode == 'a') { beginGFXTransaction(); - switchDisplayMode(-1); + setFeatureState(OSystem::kFeatureAspectRatioCorrection, !getFeatureState(OSystem::kFeatureAspectRatioCorrection)); endGFXTransaction(); #ifdef USE_OSD - displayModeChangedMsg(); + char buffer[128]; + if (getFeatureState(OSystem::kFeatureAspectRatioCorrection)) + sprintf(buffer, "Enabled aspect ratio correction\n%d x %d -> %d x %d", + _videoMode.screenWidth, _videoMode.screenHeight, + _hwscreen->w, _hwscreen->h); + else + sprintf(buffer, "Disabled aspect ratio correction\n%d x %d -> %d x %d", + _videoMode.screenWidth, _videoMode.screenHeight, + _hwscreen->w, _hwscreen->h); + displayMessageOnOSD(buffer); #endif internUpdateScreen(); return true; @@ -561,12 +566,12 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { } } - const bool isNormalNumber = (SDLK_1 <= sdlKey && sdlKey <= SDLK_4); - const bool isKeypadNumber = (SDLK_KP1 <= sdlKey && sdlKey <= SDLK_KP4); + const bool isNormalNumber = (SDLK_1 <= sdlKey && sdlKey <= SDLK_3); + const bool isKeypadNumber = (SDLK_KP1 <= sdlKey && sdlKey <= SDLK_KP3); // Ctrl-Alt-<number key> will change the GFX mode if (isNormalNumber || isKeypadNumber) { - if (sdlKey - (isNormalNumber ? SDLK_1 : SDLK_KP1) <= 4) { + if (sdlKey - (isNormalNumber ? SDLK_1 : SDLK_KP1) <= 3) { #ifdef USE_OSD int lastMode = _videoMode.mode; #endif @@ -576,10 +581,6 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { beginGFXTransaction(); setGraphicsMode(sdlKey - (isNormalNumber ? SDLK_1 : SDLK_KP1)); setScale(oldScale); - // TODO: We disable the aspect ratio correction here, - // we might switch to mode which ignores it... - // We should really fix this mess up. - setFeatureState(OSystem::kFeatureAspectRatioCorrection, false); endGFXTransaction(); #ifdef USE_OSD if (lastMode != _videoMode.mode) @@ -597,18 +598,6 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { toggleFullScreen(-1); return true; } - - // Ctrl-Shift-a switch backwards between display modes - if (event.kbd.keycode == 'a') { - beginGFXTransaction(); - switchDisplayMode(-2); - endGFXTransaction(); -#ifdef USE_OSD - displayModeChangedMsg(); -#endif - internUpdateScreen(); - return true; - } } break; case Common::EVENT_KEYUP: diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 6bb6de7289..69b3f1e084 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -27,6 +27,7 @@ #include <sys/time.h> #include <sys/resource.h> +#include <sys/system_properties.h> #include <time.h> #include <unistd.h> @@ -131,6 +132,11 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) : _touchpad_scale(66), _dpad_scale(4), _trackball_scale(2) { + LOGI("Running on: [%s] [%s] SDK:%s ABI:%s", + getSystemProperty("ro.build.fingerprint").c_str(), + getSystemProperty("ro.build.display.id").c_str(), + getSystemProperty("ro.build.version.sdk").c_str(), + getSystemProperty("ro.product.cpu.abi").c_str()); } OSystem_Android::~OSystem_Android() { @@ -548,6 +554,20 @@ void OSystem_Android::logMessage(LogMessageType::Type type, } } +Common::String OSystem_Android::getSystemLanguage() const { + return Common::String::format("%s_%s", + getSystemProperty("persist.sys.language").c_str(), + getSystemProperty("persist.sys.country").c_str()); +} + +Common::String OSystem_Android::getSystemProperty(const char *name) const { + char value[PROP_VALUE_MAX]; + + int len = __system_property_get(name, value); + + return Common::String(value, len); +} + #ifdef DYNAMIC_MODULES void AndroidPluginProvider::addCustomDirectories(Common::FSList &dirs) const { ((OSystem_Android *)g_system)->addPluginDirectories(dirs); diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index 839b3f01c1..eb05dbd390 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -144,6 +144,8 @@ private: FilesystemFactory *_fsFactory; timeval _startTime; + Common::String getSystemProperty(const char *name) const; + void initSurface(); void deinitSurface(); void initViewport(); @@ -280,6 +282,7 @@ public: virtual void logMessage(LogMessageType::Type type, const char *message); virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0); + virtual Common::String getSystemLanguage() const; }; #endif diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk index cb39f8acfe..01ebf73a81 100644 --- a/backends/platform/android/android.mk +++ b/backends/platform/android/android.mk @@ -22,6 +22,8 @@ JAVA_FILES_GEN = \ PATH_DIST = $(srcdir)/dists/android PATH_RESOURCES = $(PATH_DIST)/res +PORT_DISTFILES = $(PATH_DIST)/README.Android + RESOURCES = \ $(PATH_RESOURCES)/values/strings.xml \ $(PATH_RESOURCES)/layout/main.xml \ @@ -178,7 +180,7 @@ androidtest: $(APK_MAIN) $(APK_PLUGINS) androiddistdebug: all $(MKDIR) debug $(CP) $(APK_MAIN) $(APK_PLUGINS) debug/ - for i in $(DIST_FILES_DOCS); do \ + for i in $(DIST_FILES_DOCS) $(PORT_DISTFILES); do \ sed 's/$$/\r/' < $$i > debug/`basename $$i`.txt; \ done diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index 5fc10b2161..c969068d70 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -352,14 +352,20 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, } if (arg2 < 1 || arg2 > ARRAYSIZE(jkeymap)) { - LOGE("received invalid keycode: %d (%d)", arg2, arg3); - return; + if (arg3 < 1) { + LOGE("received invalid keycode: %d (%d)", arg2, arg3); + return; + } else { + // lets bet on the ascii code + e.kbd.keycode = Common::KEYCODE_INVALID; + } + } else { + e.kbd.keycode = jkeymap[arg2]; } if (arg5 > 0) e.synthetic = true; - e.kbd.keycode = jkeymap[arg2]; e.kbd.ascii = arg3; if (arg4 & JMETA_SHIFT) @@ -3119,7 +3119,7 @@ if test "$have_gcc" = yes ; then case $_host_os in # newlib-based system include files suppress non-C89 function # declarations under __STRICT_ANSI__ - amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | wii | wince ) + amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | wii | wince ) CXXFLAGS="$CXXFLAGS -W -Wno-unused-parameter" ;; *) diff --git a/dists/android/README.Android b/dists/android/README.Android new file mode 100644 index 0000000000..39a805fcfa --- /dev/null +++ b/dists/android/README.Android @@ -0,0 +1,50 @@ +README for the Android port of ScummVM +-------------------------------------- + +REQUIREMENTS + + TODO + +INSTALL + + TODO + +CONTROLS + + 5-Way navigation control / DPAD + + DPAD up/down/left/right: Mouse movement + DPAD center: Left mouse button + + Trackball + + Movement: Mouse movement + Click: Left mouse button + + Touchscreen + + The touchscreen can be used in two modes + + 1) Direct mode + 2) Touchpad mode + + When in direct mode, the mouse cursor moves to the touched point on screen. + In touchpad mode, the mouse cursor is independent of the touched point, it + is moved relative to its current position - like on a touchpad. + + The port currently misses its own configuration dialog, the mode can + be toggled with the "Mixed AdLib/MIDI mode" on the MIDI tab in ScummVM's + own option dialog. + + Tap + movement: Mouse movement + Tap without movement: Left mouse button click + Tap held for >0.5s without movement: Right mouse button click + Tap held for >1s without movement: Middle mouse button click + Double Tap + movement: Drag and drop + + System keys + + Back button: Escape + Menu button: ScummVM menu + Menu button held for 0.5s: Toggle virtual keyboard + diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp index 1aa6ef5cc4..7457a317c2 100644 --- a/engines/agi/preagi.cpp +++ b/engines/agi/preagi.cpp @@ -42,8 +42,7 @@ namespace Agi { PreAgiEngine::PreAgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBase(syst, gameDesc) { // Setup mixer - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + syncSoundSettings(); _rnd = new Common::RandomSource(); diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index ae95bb0d2b..574031d047 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -1045,18 +1045,15 @@ uint32 AGOSEngine::getTime() const { } void AGOSEngine::syncSoundSettings() { - // Sync the engine with the config manager - int soundVolumeMusic = ConfMan.getInt("music_volume"); - int soundVolumeSFX = ConfMan.getInt("sfx_volume"); - int soundVolumeSpeech = ConfMan.getInt("speech_volume"); + Engine::syncSoundSettings(); bool mute = false; if (ConfMan.hasKey("mute")) mute = ConfMan.getBool("mute"); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, (mute ? 0 : (_musicPaused ? 0 : soundVolumeMusic))); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, (mute ? 0 : soundVolumeSFX)); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, (mute ? 0 : soundVolumeSpeech)); + // Sync the engine with the config manager + int soundVolumeMusic = ConfMan.getInt("music_volume"); + int soundVolumeSFX = ConfMan.getInt("sfx_volume"); if (_midiEnabled) _midi.setVolume((mute ? 0 : soundVolumeMusic), (mute ? 0 : soundVolumeSFX)); diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index d80ab70660..54d113d69c 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -50,20 +50,15 @@ Sound *g_sound = 0; CineEngine *g_cine = 0; CineEngine::CineEngine(OSystem *syst, const CINEGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { + // Setup mixer + syncSoundSettings(); + DebugMan.addDebugChannel(kCineDebugScript, "Script", "Script debug level"); DebugMan.addDebugChannel(kCineDebugPart, "Part", "Part debug level"); DebugMan.addDebugChannel(kCineDebugSound, "Sound", "Sound debug level"); DebugMan.addDebugChannel(kCineDebugCollision, "Collision", "Collision debug level"); _console = new CineConsole(this); - // Setup mixer - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); - // Use music volume for plain sound types (At least the AdLib player uses a plain sound type - // so previously the music and sfx volume controls didn't affect it at all). - // FIXME: Make AdLib player differentiate between playing sound effects and music and remove this. - _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, ConfMan.getInt("music_volume")); - g_cine = this; g_eventRec.registerRandomSource(_rnd, "cine"); @@ -78,6 +73,20 @@ CineEngine::~CineEngine() { delete _console; } +void CineEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + + bool mute = false; + if (ConfMan.hasKey("mute")) + mute = ConfMan.getBool("mute"); + + // Use music volume for plain sound types (At least the AdLib player uses a plain sound type + // so previously the music and sfx volume controls didn't affect it at all). + // FIXME: Make AdLib player differentiate between playing sound effects and music and remove this. + _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, + mute ? 0 : ConfMan.getInt("music_volume")); +} + Common::Error CineEngine::run() { // Initialize backend initGraphics(320, 200, false); diff --git a/engines/cine/cine.h b/engines/cine/cine.h index 5f49a2907f..7de0bdc86f 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -117,6 +117,8 @@ public: CineEngine(OSystem *syst, const CINEGameDescription *gameDesc); virtual ~CineEngine(); + virtual void syncSoundSettings(); + int getGameType() const; uint32 getFeatures() const; Common::Language getLanguage() const; diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp index c1ea711228..2c5659c4d9 100644 --- a/engines/cruise/cruise.cpp +++ b/engines/cruise/cruise.cpp @@ -52,16 +52,13 @@ CruiseEngine::CruiseEngine(OSystem * syst, const CRUISEGameDescription *gameDesc DebugMan.addDebugChannel(kCruiseDebugScript, "scripts", "Scripts debug level"); DebugMan.addDebugChannel(kCruiseDebugSound, "sound", "Sound debug level"); - // Setup mixer - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, - ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, - ConfMan.getInt("music_volume")); - _vm = this; _debugger = new Debugger(); _sound = new PCSound(_mixer, this); + // Setup mixer + syncSoundSettings(); + g_eventRec.registerRandomSource(_rnd, "cruise"); } @@ -235,6 +232,8 @@ const char *CruiseEngine::getSavegameFile(int saveGameIdx) { } void CruiseEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + _sound->syncSounds(); } diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp index 8a4b1d0d2b..2826a34351 100644 --- a/engines/cruise/sound.cpp +++ b/engines/cruise/sound.cpp @@ -283,9 +283,21 @@ void PCSoundDriver::resetChannel(int channel) { } void PCSoundDriver::syncSounds() { + bool mute = false; + if (ConfMan.hasKey("mute")) + mute = ConfMan.getBool("mute"); + + bool music_mute = mute; + bool sfx_mute = mute; + + if (!mute) { + music_mute = ConfMan.getBool("music_mute"); + sfx_mute = ConfMan.getBool("sfx_mute"); + } + // Get the new music and sfx volumes - _musicVolume = ConfMan.getBool("music_mute") ? 0 : MIN(255, ConfMan.getInt("music_volume")); - _sfxVolume = ConfMan.getBool("sfx_mute") ? 0 : MIN(255, ConfMan.getInt("sfx_volume")); + _musicVolume = music_mute ? 0 : MIN(255, ConfMan.getInt("music_volume")); + _sfxVolume = sfx_mute ? 0 : MIN(255, ConfMan.getInt("sfx_volume")); } AdLibSoundDriver::AdLibSoundDriver(Audio::Mixer *mixer) diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp index d0eb511cbd..0bf2d5d34a 100644 --- a/engines/draci/draci.cpp +++ b/engines/draci/draci.cpp @@ -175,6 +175,9 @@ int DraciEngine::init() { _music->open(); //_music->setAdLib(adlib); + // Setup mixer + syncSoundSettings(); + // Load the game's fonts _smallFont = new Font(kFontSmall); _bigFont = new Font(kFontBig); diff --git a/engines/draci/sound.cpp b/engines/draci/sound.cpp index dc8f548d6b..c8646fff67 100644 --- a/engines/draci/sound.cpp +++ b/engines/draci/sound.cpp @@ -408,6 +408,9 @@ void Sound::stopVoice() { } void Sound::setVolume() { + _showSubtitles = ConfMan.getBool("subtitles"); + _talkSpeed = ConfMan.getInt("talkspeed"); + if (_mixer->isReady()) { _muteSound = ConfMan.getBool("sfx_mute"); _muteVoice = ConfMan.getBool("speech_mute"); @@ -417,10 +420,10 @@ void Sound::setVolume() { if (ConfMan.getBool("mute")) { _muteSound = _muteVoice = true; } - _showSubtitles = ConfMan.getBool("subtitles"); - _talkSpeed = ConfMan.getInt("talkspeed"); - const int soundVolume = ConfMan.getInt("sfx_volume"); - const int speechVolume = ConfMan.getInt("speech_volume"); + + const int soundVolume = _muteSound ? 0: ConfMan.getInt("sfx_volume"); + const int speechVolume = _muteVoice ? 0 : ConfMan.getInt("speech_volume"); + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolume); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, speechVolume); } diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index b59ab6f566..19395dcd3f 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -195,8 +195,7 @@ Common::Error DrasculaEngine::run() { loadArchives(); // Setup mixer - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + syncSoundSettings(); currentChapter = 1; // values from 1 to 6 will start each part of game loadedDifferentChapter = 0; diff --git a/engines/engine.cpp b/engines/engine.cpp index 5ce0f99921..0e5e58bc72 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -430,7 +430,6 @@ int Engine::runDialog(GUI::Dialog &dialog) { } void Engine::syncSoundSettings() { - // Sync the engine with the config manager int soundVolumeMusic = ConfMan.getInt("music_volume"); int soundVolumeSFX = ConfMan.getInt("sfx_volume"); @@ -440,6 +439,7 @@ void Engine::syncSoundSettings() { if (ConfMan.hasKey("mute")) mute = ConfMan.getBool("mute"); + _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, (mute ? 0 : Audio::Mixer::kMaxMixerVolume)); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, (mute ? 0 : soundVolumeMusic)); _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, (mute ? 0 : soundVolumeSFX)); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, (mute ? 0 : soundVolumeSpeech)); diff --git a/engines/engine.h b/engines/engine.h index 508e9887ef..168a1dc2a0 100644 --- a/engines/engine.h +++ b/engines/engine.h @@ -163,6 +163,15 @@ public: * Notify the engine that the sound settings in the config manager may have * changed and that it hence should adjust any internal volume etc. values * accordingly. + * The default implementation sets the volume levels of all mixer sound + * types according to the config entries of the active domain. + * When overwriting, call the default implementation first, then adjust the + * volumes further (if required). + * + * @note When setting volume levels, respect the "mute" config entry. + * @note The volume for the plain sound type is reset to the maximum + * volume. If the engine can associate its own value for this + * type, it needs to overwrite this member and set it accordingly. * @todo find a better name for this */ virtual void syncSoundSettings(); diff --git a/engines/gob/detection_tables.h b/engines/gob/detection_tables.h index c779d5d764..b12fb81be1 100644 --- a/engines/gob/detection_tables.h +++ b/engines/gob/detection_tables.h @@ -3723,6 +3723,20 @@ static const GOBGameDescription gameDescriptions[] = { kFeatures640x480 | kFeaturesTrueColor, 0, 0, 0 }, + { // Supplied by Collector9 in bug report #3228040 + { + "urban", + "", + AD_ENTRY1s("intro.stk", "6ce3d878178932053267237ec4843ce1", 1252518), + EN_USA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeUrban, + kFeatures640x480 | kFeaturesTrueColor, + 0, 0, 0 + }, { // Supplied by gamin in the forums { "urban", @@ -4935,7 +4949,7 @@ static const GOBGameDescription fallbackDescs[] = { GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeUrban, - kFeaturesCD | kFeaturesTrueColor, + kFeatures640x480 | kFeaturesTrueColor, 0, 0, 0 }, { //13 diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index b65bbe0d0f..12914163c2 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -575,6 +575,9 @@ bool GobEngine::initGameParts() { return false; } + // Setup mixer + syncSoundSettings(); + _inter->setupOpcodes(); return true; diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 4a4f5e0de5..67c8f3dbc7 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -322,6 +322,8 @@ void GroovieEngine::errorString(const char *buf_input, char *buf_output, int buf } void GroovieEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + bool mute = ConfMan.getBool("mute"); // Set the music volume diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp index aa4d4384c1..333eb59707 100644 --- a/engines/hugo/display.cpp +++ b/engines/hugo/display.cpp @@ -479,7 +479,7 @@ void Screen::shadowStr(int16 sx, const int16 sy, const char *s, const byte color * present in the DOS versions */ void Screen::userHelp() const { - Utils::Box(kBoxAny , "%s", + Utils::notifyBox( "F1 - Press F1 again\n" " for instructions\n" "F2 - Sound on/off\n" diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp index 94e1756a0d..f4eada456d 100644 --- a/engines/hugo/file.cpp +++ b/engines/hugo/file.cpp @@ -550,7 +550,7 @@ void FileManager::printBootText() { buf[i] ^= cypher[i % strlen(cypher)]; buf[i] = '\0'; - Utils::Box(kBoxOk, "%s", buf); + Utils::notifyBox(buf); } free(buf); diff --git a/engines/hugo/file_v1d.cpp b/engines/hugo/file_v1d.cpp index d8b3fa494f..48f274e88a 100644 --- a/engines/hugo/file_v1d.cpp +++ b/engines/hugo/file_v1d.cpp @@ -121,7 +121,7 @@ void FileManager_v1d::instructions() const { f.read(wrkLine, 1); } while (*wrkLine++ != '#'); // '#' is EOP wrkLine[-2] = '\0'; // Remove EOP and previous CR - Utils::Box(kBoxAny, "%s", line); + Utils::notifyBox(line); wrkLine = line; f.read(readBuf, 2); // Remove CRLF after EOP } diff --git a/engines/hugo/file_v2w.cpp b/engines/hugo/file_v2w.cpp index b917d81bd5..245d4d017e 100644 --- a/engines/hugo/file_v2w.cpp +++ b/engines/hugo/file_v2w.cpp @@ -48,7 +48,7 @@ FileManager_v2w::~FileManager_v2w() { * Same comment than in SCI: maybe in the future we can implement this, but for now this message should suffice */ void FileManager_v2w::instructions() const { - Utils::Box(kBoxAny, "Please use an external viewer to open the game's help file: HUGOWIN%d.HLP", _vm->_gameVariant + 1); + Utils::notifyBox(Common::String::format("Please use an external viewer to open the game's help file: HUGOWIN%d.HLP", _vm->_gameVariant + 1)); } } // End of namespace Hugo diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp index 231b2a5d51..6ba9e8eaa8 100644 --- a/engines/hugo/hugo.cpp +++ b/engines/hugo/hugo.cpp @@ -165,7 +165,7 @@ bool HugoEngine::isPacked() const { * Print options for user when dead */ void HugoEngine::gameOverMsg() { - Utils::Box(kBoxOk, "%s", _text->getTextUtil(kGameOver)); + Utils::notifyBox(_text->getTextUtil(kGameOver)); } Common::Error HugoEngine::run() { @@ -176,6 +176,10 @@ Common::Error HugoEngine::run() { _inventory = new InventoryHandler(this); _route = new Route(this); _sound = new SoundHandler(this); + + // Setup mixer + syncSoundSettings(); + _text = new TextHandler(this); _topMenu = new TopMenu(this); @@ -674,8 +678,8 @@ void HugoEngine::endGame() { debugC(1, kDebugEngine, "endGame"); if (_boot.registered != kRegRegistered) - Utils::Box(kBoxAny, "%s", _text->getTextEngine(kEsAdvertise)); - Utils::Box(kBoxAny, "%s\n%s", _episode, getCopyrightString()); + Utils::notifyBox(_text->getTextEngine(kEsAdvertise)); + Utils::notifyBox(Common::String::format("%s\n%s", _episode, getCopyrightString())); _status.viewState = kViewExit; } diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h index a137df786f..ed021f5cd6 100644 --- a/engines/hugo/hugo.h +++ b/engines/hugo/hugo.h @@ -132,11 +132,6 @@ enum HugoRegistered { }; /** - * Ways to dismiss a text/prompt box - */ -enum box_t {kBoxAny, kBoxOk, kBoxPrompt, kBoxYesNo}; - -/** * Inventory icon bar states */ enum istate_t {kInventoryOff, kInventoryUp, kInventoryDown, kInventoryActive}; diff --git a/engines/hugo/intro.cpp b/engines/hugo/intro.cpp index 7551476300..7cd5a0fd17 100644 --- a/engines/hugo/intro.cpp +++ b/engines/hugo/intro.cpp @@ -337,13 +337,13 @@ bool intro_v3d::introPlay() { // Text boxes at various times switch (introTicks) { case 4: - Utils::Box(kBoxOk, "%s", _vm->_text->getTextIntro(kIntro1)); + Utils::notifyBox(_vm->_text->getTextIntro(kIntro1)); break; case 9: - Utils::Box(kBoxOk, "%s", _vm->_text->getTextIntro(kIntro2)); + Utils::notifyBox(_vm->_text->getTextIntro(kIntro2)); break; case 35: - Utils::Box(kBoxOk, "%s", _vm->_text->getTextIntro(kIntro3)); + Utils::notifyBox(_vm->_text->getTextIntro(kIntro3)); break; } } @@ -429,13 +429,13 @@ bool intro_v3w::introPlay() { // Text boxes at various times switch (introTicks) { case 4: - Utils::Box(kBoxOk, "%s", _vm->_text->getTextIntro(kIntro1)); + Utils::notifyBox(_vm->_text->getTextIntro(kIntro1)); break; case 9: - Utils::Box(kBoxOk, "%s", _vm->_text->getTextIntro(kIntro2)); + Utils::notifyBox(_vm->_text->getTextIntro(kIntro2)); break; case 35: - Utils::Box(kBoxOk, "%s", _vm->_text->getTextIntro(kIntro3)); + Utils::notifyBox(_vm->_text->getTextIntro(kIntro3)); break; } } diff --git a/engines/hugo/mouse.cpp b/engines/hugo/mouse.cpp index 73805dcfba..1b2dd588b8 100644 --- a/engines/hugo/mouse.cpp +++ b/engines/hugo/mouse.cpp @@ -187,7 +187,7 @@ void MouseHandler::processRightClick(const int16 objId, const int16 cx, const in if (_vm->_hero->cycling == kCycleInvisible) // If invisible do _vm->_object->useObject(objId); // immediate use else - Utils::Box(kBoxAny, "%s", _vm->_text->getTextMouse(kMsNoWayText)); // Can't get there + Utils::notifyBox(_vm->_text->getTextMouse(kMsNoWayText)); // Can't get there } break; } @@ -241,7 +241,7 @@ void MouseHandler::processLeftClick(const int16 objId, const int16 cx, const int else if (_hotspots[i].direction == Common::KEYCODE_LEFT) x += kHeroMaxWidth; if (!_vm->_route->startRoute(kRouteExit, i, x, y)) - Utils::Box(kBoxAny, "%s", _vm->_text->getTextMouse(kMsNoWayText)); // Can't get there + Utils::notifyBox(_vm->_text->getTextMouse(kMsNoWayText)); // Can't get there } // Get rid of any attached icon @@ -271,7 +271,7 @@ void MouseHandler::processLeftClick(const int16 objId, const int16 cx, const int if (_vm->_hero->cycling == kCycleInvisible) // If invisible do _vm->_object->lookObject(obj); // immediate decription else - Utils::Box(kBoxAny, "%s", _vm->_text->getTextMouse(kMsNoWayText)); // Can't get there + Utils::notifyBox(_vm->_text->getTextMouse(kMsNoWayText)); // Can't get there } break; } diff --git a/engines/hugo/object.cpp b/engines/hugo/object.cpp index f82a6a53c6..0a52a0f62d 100644 --- a/engines/hugo/object.cpp +++ b/engines/hugo/object.cpp @@ -175,7 +175,7 @@ void ObjectHandler::useObject(int16 objId) { // Deselect dragged icon if inventory not active if (_vm->_inventory->getInventoryState() != kInventoryActive) _vm->_screen->resetInventoryObjId(); - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(use->dataIndex)); + Utils::notifyBox(_vm->_text->getTextData(use->dataIndex)); return; } } @@ -353,7 +353,7 @@ void ObjectHandler::showTakeables() { if ((obj->cycling != kCycleInvisible) && (obj->screenIndex == *_vm->_screen_p) && (((TAKE & obj->genericCmd) == TAKE) || obj->objValue)) { - Utils::Box(kBoxAny, "You can also see:\n%s.", _vm->_text->getNoun(obj->nounIndex, LOOK_NAME)); + Utils::notifyBox(Common::String::format("You can also see:\n%s.", _vm->_text->getNoun(obj->nounIndex, LOOK_NAME))); } } } diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp index a0a3ee3350..feee4cbadd 100644 --- a/engines/hugo/parser.cpp +++ b/engines/hugo/parser.cpp @@ -288,7 +288,7 @@ void Parser::keyHandler(Common::Event event) { _vm->_file->restoreGame(-1); break; case Common::KEYCODE_n: - if (Utils::Box(kBoxYesNo, "%s", "Are you sure you want to start a new game?") != 0) + if (Utils::yesNoBox("Are you sure you want to start a new game?")) _vm->_file->restoreGame(0); break; case Common::KEYCODE_s: @@ -485,7 +485,7 @@ void Parser::showDosInventory() const { if (index & 1) buffer += "\n"; buffer += Common::String(_vm->_text->getTextParser(kTBOutro)); - Utils::Box(kBoxAny, "%s", buffer.c_str()); + Utils::notifyBox(buffer.c_str()); } } // End of namespace Hugo diff --git a/engines/hugo/parser_v1d.cpp b/engines/hugo/parser_v1d.cpp index df3a73feb8..de18427d93 100644 --- a/engines/hugo/parser_v1d.cpp +++ b/engines/hugo/parser_v1d.cpp @@ -151,25 +151,25 @@ bool Parser_v1d::isGenericVerb_v1(const char *word, object_t *obj) { // Following is equivalent to switch, but couldn't do one if (word == _vm->_text->getVerb(_vm->_look, 0)) { if ((LOOK & obj->genericCmd) == LOOK) - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(obj->dataIndex)); + Utils::notifyBox(_vm->_text->getTextData(obj->dataIndex)); else - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBUnusual_1d)); + Utils::notifyBox(_vm->_text->getTextParser(kTBUnusual_1d)); } else if (word == _vm->_text->getVerb(_vm->_take, 0)) { if (obj->carriedFl) - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBHave)); + Utils::notifyBox(_vm->_text->getTextParser(kTBHave)); else if ((TAKE & obj->genericCmd) == TAKE) takeObject(obj); else if (!obj->verbOnlyFl) // Make sure not taking object in context! - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNoUse)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNoUse)); else return false; } else if (word == _vm->_text->getVerb(_vm->_drop, 0)) { if (!obj->carriedFl) - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBDontHave)); + Utils::notifyBox(_vm->_text->getTextParser(kTBDontHave)); else if ((DROP & obj->genericCmd) == DROP) dropObject(obj); else - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNeed)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNeed)); } else { // It was not a generic cmd return false; } @@ -206,7 +206,7 @@ bool Parser_v1d::isObjectVerb_v1(const char *word, object_t *obj) { uint16 *reqs = _arrayReqs[cmnd->reqIndex]; // ptr to list of required objects for (i = 0; reqs[i]; i++) { // for each obj if (!_vm->_object->isCarrying(reqs[i])) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(cmnd->textDataNoCarryIndex)); + Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataNoCarryIndex)); return true; } } @@ -214,14 +214,14 @@ bool Parser_v1d::isObjectVerb_v1(const char *word, object_t *obj) { // Required objects are present, now check state is correct if ((obj->state != cmnd->reqState) && (cmnd->reqState != kStateDontCare)){ - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(cmnd->textDataWrongIndex)); + Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataWrongIndex)); return true; } // Everything checked. Change the state and carry out any actions if (cmnd->reqState != kStateDontCare) // Don't change new state if required state didn't care obj->state = cmnd->newState; - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(cmnd->textDataDoneIndex)); + Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataDoneIndex)); _vm->_scheduler->insertActionList(cmnd->actIndex); // Special case if verb is Take or Drop. Assume additional generic actions if ((word == _vm->_text->getVerb(_vm->_take, 0)) || (word == _vm->_text->getVerb(_vm->_drop, 0))) @@ -241,7 +241,7 @@ bool Parser_v1d::isBackgroundWord_v1(const char *noun, const char *verb, objectL for (int i = 0; obj[i].verbIndex; i++) { if ((verb == _vm->_text->getVerb(obj[i].verbIndex, 0)) && (noun == _vm->_text->getNoun(obj[i].nounIndex, 0))) { - Utils::Box(kBoxAny, "%s", _vm->_file->fetchString(obj[i].commentIndex)); + Utils::notifyBox(_vm->_file->fetchString(obj[i].commentIndex)); return true; } } @@ -260,7 +260,7 @@ void Parser_v1d::takeObject(object_t *obj) { _vm->adjustScore(obj->objValue); - Utils::Box(kBoxAny, TAKE_TEXT, _vm->_text->getNoun(obj->nounIndex, TAKE_NAME)); + Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(obj->nounIndex, TAKE_NAME))); } /** @@ -276,7 +276,7 @@ void Parser_v1d::dropObject(object_t *obj) { obj->x = _vm->_hero->x - 1; obj->y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1; _vm->adjustScore(-obj->objValue); - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBOk)); + Utils::notifyBox(_vm->_text->getTextParser(kTBOk)); } /** @@ -294,7 +294,7 @@ bool Parser_v1d::isCatchallVerb_v1(bool testNounFl, const char *noun, const char for (int i = 0; obj[i].verbIndex; i++) { if ((verb == _vm->_text->getVerb(obj[i].verbIndex, 0)) && ((noun == _vm->_text->getNoun(obj[i].nounIndex, 0)) || (obj[i].nounIndex == 0))) { - Utils::Box(kBoxAny, "%s", _vm->_file->fetchString(obj[i].commentIndex)); + Utils::notifyBox(_vm->_file->fetchString(obj[i].commentIndex)); return true; } } @@ -364,7 +364,7 @@ void Parser_v1d::lineHandler() { } if (!strcmp("exit", _vm->_line) || strstr(_vm->_line, "quit")) { - if (Utils::Box(kBoxYesNo, "%s", _vm->_text->getTextParser(kTBExit_1d)) != 0) + if (Utils::yesNoBox(_vm->_text->getTextParser(kTBExit_1d))) _vm->endGame(); return; } @@ -418,11 +418,11 @@ void Parser_v1d::lineHandler() { } noun = findNextNoun(noun); if (*farComment != '\0') // An object matched but not near enough - Utils::Box(kBoxAny, "%s", farComment); + Utils::notifyBox(farComment); else if (!isCatchallVerb_v1(true, noun, verb, _catchallList) && !isCatchallVerb_v1(false, noun, verb, _backgroundObjects[*_vm->_screen_p]) && !isCatchallVerb_v1(false, noun, verb, _catchallList)) - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBEh_1d)); + Utils::notifyBox(_vm->_text->getTextParser(kTBEh_1d)); } void Parser_v1d::showInventory() const { diff --git a/engines/hugo/parser_v1w.cpp b/engines/hugo/parser_v1w.cpp index d3424274f8..305fb995e1 100644 --- a/engines/hugo/parser_v1w.cpp +++ b/engines/hugo/parser_v1w.cpp @@ -119,7 +119,7 @@ void Parser_v1w::lineHandler() { // Special meta commands // EXIT/QUIT if (!strcmp("exit", _vm->_line) || strstr(_vm->_line, "quit")) { - if (Utils::Box(kBoxYesNo, "%s", _vm->_text->getTextParser(kTBExit_1d)) != 0) + if (Utils::yesNoBox(_vm->_text->getTextParser(kTBExit_1d))) _vm->endGame(); return; } @@ -182,7 +182,7 @@ void Parser_v1w::lineHandler() { // If a not-near comment was generated, print it if (*farComment != '\0') { - Utils::Box(kBoxAny, "%s", farComment); + Utils::notifyBox(farComment); return; } @@ -190,16 +190,16 @@ void Parser_v1w::lineHandler() { const char *verb = findVerb(); const char *noun = findNoun(); if (verb == _vm->_text->getVerb(_vm->_look, 0) && _vm->_maze.enabledFl) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBMaze)); + Utils::notifyBox(_vm->_text->getTextParser(kTBMaze)); _vm->_object->showTakeables(); } else if (verb && noun) { // A combination I didn't think of - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNoPoint)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNoPoint)); } else if (noun) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNoun)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNoun)); } else if (verb) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBVerb)); + Utils::notifyBox(_vm->_text->getTextParser(kTBVerb)); } else { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBEh)); + Utils::notifyBox(_vm->_text->getTextParser(kTBEh)); } } diff --git a/engines/hugo/parser_v2d.cpp b/engines/hugo/parser_v2d.cpp index d19b8b1091..d6f2adfedc 100644 --- a/engines/hugo/parser_v2d.cpp +++ b/engines/hugo/parser_v2d.cpp @@ -114,7 +114,7 @@ void Parser_v2d::lineHandler() { } if (!strcmp("exit", _vm->_line) || strstr(_vm->_line, "quit")) { - if (Utils::Box(kBoxYesNo, "%s", _vm->_text->getTextParser(kTBExit_1d)) != 0) + if (Utils::yesNoBox(_vm->_text->getTextParser(kTBExit_1d))) _vm->endGame(); return; } @@ -175,16 +175,16 @@ void Parser_v2d::lineHandler() { && !isCatchallVerb_v1(false, noun, verb, _backgroundObjects[*_vm->_screen_p]) && !isCatchallVerb_v1(false, noun, verb, _catchallList)) { if (*farComment != '\0') { // An object matched but not near enough - Utils::Box(kBoxAny, "%s", farComment); + Utils::notifyBox(farComment); } else if (_vm->_maze.enabledFl && (verb == _vm->_text->getVerb(_vm->_look, 0))) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBMaze)); + Utils::notifyBox(_vm->_text->getTextParser(kTBMaze)); _vm->_object->showTakeables(); } else if (verb && noun) { // A combination I didn't think of - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNoUse_2d)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNoUse_2d)); } else if (verb || noun) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNoun)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNoun)); } else { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBEh_2d)); + Utils::notifyBox(_vm->_text->getTextParser(kTBEh_2d)); } } } diff --git a/engines/hugo/parser_v3d.cpp b/engines/hugo/parser_v3d.cpp index fcd937808b..f08d472240 100644 --- a/engines/hugo/parser_v3d.cpp +++ b/engines/hugo/parser_v3d.cpp @@ -116,7 +116,7 @@ void Parser_v3d::lineHandler() { // Special meta commands // EXIT/QUIT if (!strcmp("exit", _vm->_line) || strstr(_vm->_line, "quit")) { - if (Utils::Box(kBoxYesNo, "%s", _vm->_text->getTextParser(kTBExit_1d)) != 0) + if (Utils::yesNoBox(_vm->_text->getTextParser(kTBExit_1d))) _vm->endGame(); return; } @@ -184,7 +184,7 @@ void Parser_v3d::lineHandler() { // If a not-near comment was generated, print it if (*farComment != '\0') { - Utils::Box(kBoxAny, "%s", farComment); + Utils::notifyBox(farComment); return; } @@ -193,13 +193,13 @@ void Parser_v3d::lineHandler() { const char *noun = findNoun(); if (verb && noun) { // A combination I didn't think of - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNoPoint)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNoPoint)); } else if (noun) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNoun)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNoun)); } else if (verb) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBVerb)); + Utils::notifyBox(_vm->_text->getTextParser(kTBVerb)); } else { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBEh)); + Utils::notifyBox(_vm->_text->getTextParser(kTBEh)); } } @@ -236,7 +236,7 @@ bool Parser_v3d::isObjectVerb_v3(object_t *obj, char *comment) { uint16 *reqs = _arrayReqs[cmnd->reqIndex]; // ptr to list of required objects for (i = 0; reqs[i]; i++) { // for each obj if (!_vm->_object->isCarrying(reqs[i])) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(cmnd->textDataNoCarryIndex)); + Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataNoCarryIndex)); return true; } } @@ -244,14 +244,14 @@ bool Parser_v3d::isObjectVerb_v3(object_t *obj, char *comment) { // Required objects are present, now check state is correct if ((obj->state != cmnd->reqState) && (cmnd->reqState != kStateDontCare)) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(cmnd->textDataWrongIndex)); + Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataWrongIndex)); return true; } // Everything checked. Change the state and carry out any actions if (cmnd->reqState != kStateDontCare) // Don't change new state if required state didn't care obj->state = cmnd->newState; - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(cmnd->textDataDoneIndex)); + Utils::notifyBox(_vm->_text->getTextData(cmnd->textDataDoneIndex)); _vm->_scheduler->insertActionList(cmnd->actIndex); // See if any additional generic actions @@ -273,35 +273,35 @@ bool Parser_v3d::isGenericVerb_v3(object_t *obj, char *comment) { if (isWordPresent(_vm->_text->getVerbArray(_vm->_look)) && isNear_v3(obj, _vm->_text->getVerb(_vm->_look, 0), comment)) { // Test state-dependent look before general look if ((obj->genericCmd & LOOK_S) == LOOK_S) { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(obj->stateDataIndex[obj->state])); + Utils::notifyBox(_vm->_text->getTextData(obj->stateDataIndex[obj->state])); } else { if ((LOOK & obj->genericCmd) == LOOK) { if (obj->dataIndex != 0) - Utils::Box(kBoxAny, "%s", _vm->_text->getTextData(obj->dataIndex)); + Utils::notifyBox(_vm->_text->getTextData(obj->dataIndex)); else return false; } else { - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBUnusual)); + Utils::notifyBox(_vm->_text->getTextParser(kTBUnusual)); } } } else if (isWordPresent(_vm->_text->getVerbArray(_vm->_take)) && isNear_v3(obj, _vm->_text->getVerb(_vm->_take, 0), comment)) { if (obj->carriedFl) - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBHave)); + Utils::notifyBox(_vm->_text->getTextParser(kTBHave)); else if ((TAKE & obj->genericCmd) == TAKE) takeObject(obj); else if (obj->cmdIndex) // No comment if possible commands return false; else if (!obj->verbOnlyFl && (TAKE & obj->genericCmd) == TAKE) // Make sure not taking object in context! - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNoUse)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNoUse)); else return false; } else if (isWordPresent(_vm->_text->getVerbArray(_vm->_drop))) { if (!obj->carriedFl && ((DROP & obj->genericCmd) == DROP)) - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBDontHave)); + Utils::notifyBox(_vm->_text->getTextParser(kTBDontHave)); else if (obj->carriedFl && ((DROP & obj->genericCmd) == DROP)) dropObject(obj); else if (obj->cmdIndex == 0) - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBNeed)); + Utils::notifyBox(_vm->_text->getTextParser(kTBNeed)); else return false; } else { // It was not a generic cmd @@ -383,7 +383,7 @@ void Parser_v3d::takeObject(object_t *obj) { if (obj->seqNumb > 0) // If object has an image, force walk to dropped obj->viewx = -1; // (possibly moved) object next time taken! - Utils::Box(kBoxAny, TAKE_TEXT, _vm->_text->getNoun(obj->nounIndex, TAKE_NAME)); + Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(obj->nounIndex, TAKE_NAME))); } /** @@ -402,7 +402,7 @@ void Parser_v3d::dropObject(object_t *obj) { obj->y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1; obj->y = (obj->y + obj->currImagePtr->y2 < kYPix) ? obj->y : kYPix - obj->currImagePtr->y2 - 10; _vm->adjustScore(-obj->objValue); - Utils::Box(kBoxAny, "%s", _vm->_text->getTextParser(kTBOk)); + Utils::notifyBox(_vm->_text->getTextParser(kTBOk)); } /** @@ -422,7 +422,7 @@ bool Parser_v3d::isCatchallVerb_v3(objectList_t obj) const { (!obj[i].matchFl || !findNoun()) && ((obj[i].roomState == kStateDontCare) || (obj[i].roomState == _vm->_screenStates[*_vm->_screen_p]))) { - Utils::Box(kBoxAny, "%s", _vm->_file->fetchString(obj[i].commentIndex)); + Utils::notifyBox(_vm->_file->fetchString(obj[i].commentIndex)); _vm->_scheduler->processBonus(obj[i].bonusIndex); // If this is LOOK (without a noun), show any takeable objects @@ -450,7 +450,7 @@ bool Parser_v3d::isBackgroundWord_v3(objectList_t obj) const { isWordPresent(_vm->_text->getNounArray(obj[i].nounIndex)) && ((obj[i].roomState == kStateDontCare) || (obj[i].roomState == _vm->_screenStates[*_vm->_screen_p]))) { - Utils::Box(kBoxAny, "%s", _vm->_file->fetchString(obj[i].commentIndex)); + Utils::notifyBox(_vm->_file->fetchString(obj[i].commentIndex)); _vm->_scheduler->processBonus(obj[i].bonusIndex); return true; } diff --git a/engines/hugo/schedule.cpp b/engines/hugo/schedule.cpp index 1556f3a154..45a2b77826 100644 --- a/engines/hugo/schedule.cpp +++ b/engines/hugo/schedule.cpp @@ -1242,7 +1242,7 @@ event_t *Scheduler::doAction(event_t *curEvent) { insertActionList(action->a11.actFailIndex); break; case TEXT: // act12: Text box (CF WARN) - Utils::Box(kBoxAny, "%s", _vm->_file->fetchString(action->a12.stringIndex)); // Fetch string from file + Utils::notifyBox(_vm->_file->fetchString(action->a12.stringIndex)); // Fetch string from file break; case SWAP_IMAGES: // act13: Swap 2 object images _vm->_object->swapImages(action->a13.objIndex1, action->a13.objIndex2); @@ -1367,7 +1367,7 @@ event_t *Scheduler::doAction(event_t *curEvent) { gameStatus.storyModeFl = action->a39.storyModeFl; break; case WARN: // act40: Text box (CF TEXT) - Utils::Box(kBoxOk, "%s", _vm->_file->fetchString(action->a40.stringIndex)); + Utils::notifyBox(_vm->_file->fetchString(action->a40.stringIndex)); break; case COND_BONUS: // act41: Perform action if got bonus if (_points[action->a41.BonusIndex].scoredFl) @@ -1376,10 +1376,10 @@ event_t *Scheduler::doAction(event_t *curEvent) { insertActionList(action->a41.actFailIndex); break; case TEXT_TAKE: // act42: Text box with "take" message - Utils::Box(kBoxAny, TAKE_TEXT, _vm->_text->getNoun(_vm->_object->_objects[action->a42.objIndex].nounIndex, TAKE_NAME)); + Utils::notifyBox(Common::String::format(TAKE_TEXT, _vm->_text->getNoun(_vm->_object->_objects[action->a42.objIndex].nounIndex, TAKE_NAME))); break; case YESNO: // act43: Prompt user for Yes or No - if (Utils::Box(kBoxYesNo, "%s", _vm->_file->fetchString(action->a43.promptIndex)) != 0) + if (Utils::yesNoBox(_vm->_file->fetchString(action->a43.promptIndex))) insertActionList(action->a43.actYesIndex); else insertActionList(action->a43.actNoIndex); @@ -1529,7 +1529,7 @@ void Scheduler_v1d::runScheduler() { } void Scheduler_v1d::promptAction(act *action) { - Utils::Box(kBoxPrompt, "%s", _vm->_file->fetchString(action->a3.promptIndex)); + Utils::promptBox(_vm->_file->fetchString(action->a3.promptIndex)); warning("STUB: doAction(act3)"); // TODO: The answer of the player is not handled currently! Once it'll be read in the messageBox, uncomment this block @@ -1578,7 +1578,7 @@ const char *Scheduler_v2d::getCypher() const { } void Scheduler_v2d::promptAction(act *action) { - Utils::Box(kBoxPrompt, "%s", _vm->_file->fetchString(action->a3.promptIndex)); + Utils::promptBox(_vm->_file->fetchString(action->a3.promptIndex)); warning("STUB: doAction(act3), expecting answer %s", _vm->_file->fetchString(action->a3.responsePtr[0])); // TODO: The answer of the player is not handled currently! Once it'll be read in the messageBox, uncomment this block diff --git a/engines/hugo/util.cpp b/engines/hugo/util.cpp index f36c431867..044b58e986 100644 --- a/engines/hugo/util.cpp +++ b/engines/hugo/util.cpp @@ -41,10 +41,12 @@ namespace Hugo { +namespace Utils { + /** * Returns index (0 to 7) of first 1 in supplied byte, or 8 if not found */ -int Utils::firstBit(byte data) { +int firstBit(byte data) { if (!data) return 8; @@ -60,7 +62,7 @@ int Utils::firstBit(byte data) { /** * Returns index (0 to 7) of last 1 in supplied byte, or 8 if not found */ -int Utils::lastBit(byte data) { +int lastBit(byte data) { if (!data) return 8; @@ -76,7 +78,7 @@ int Utils::lastBit(byte data) { /** * Reverse the bit order in supplied byte */ -void Utils::reverseByte(byte *data) { +void reverseByte(byte *data) { byte maskIn = 0x80; byte maskOut = 0x01; byte result = 0; @@ -89,58 +91,31 @@ void Utils::reverseByte(byte *data) { *data = result; } -const char *Utils::Box(box_t dismiss, const char *s, ...) { - static char buffer[kMaxStrLength + 1]; // Format text into this - - if (!s) - return 0; // NULL strings catered for - - if (s[0] == '\0') - return 0; +void notifyBox(const Common::String &msg) { + if (msg.empty()) + return; - if (strlen(s) > kMaxStrLength - 100) { // Test length - warning("String too long: '%s'", s); - return 0; - } + GUI::MessageDialog dialog(msg, "OK"); + dialog.runModal(); +} - va_list marker; - va_start(marker, s); - vsprintf(buffer, s, marker); // Format string into buffer - va_end(marker); +Common::String promptBox(const Common::String &msg) { + if (msg.empty()) + return Common::String(); - if (buffer[0] == '\0') - return 0; + EntryDialog dialog(msg, "OK", ""); + return dialog.getEditString(); +} - switch(dismiss) { - case kBoxAny: - case kBoxOk: { - GUI::MessageDialog dialog(buffer, "OK"); - dialog.runModal(); - break; - } - case kBoxYesNo: { - GUI::MessageDialog dialog(buffer, "YES", "NO"); - if (dialog.runModal() == GUI::kMessageOK) - return buffer; +bool yesNoBox(const Common::String &msg) { + if (msg.empty()) return 0; - break; - } - case kBoxPrompt: { - EntryDialog dialog(buffer, "OK", ""); - Common::String result = dialog.getEditString(); - - return result.c_str(); - - break; - } - default: - error("Unknown BOX Type %d", dismiss); - } - return 0; + GUI::MessageDialog dialog(msg, "YES", "NO"); + return (dialog.runModal() == GUI::kMessageOK); } -char *Utils::strlwr(char *buffer) { +char *strlwr(char *buffer) { char *result = buffer; while (*buffer != '\0') { @@ -152,4 +127,6 @@ char *Utils::strlwr(char *buffer) { return result; } +} // End of namespace Utils + } // End of namespace Hugo diff --git a/engines/hugo/util.h b/engines/hugo/util.h index acead5a0c4..85fef01a6e 100644 --- a/engines/hugo/util.h +++ b/engines/hugo/util.h @@ -40,16 +40,36 @@ enum seqTextUtil { }; namespace Utils { -static const int kMaxStrLength = 1024; int firstBit(byte data); int lastBit(byte data); void reverseByte(byte *data); -const char *Box(box_t, const char *, ...) GCC_PRINTF(2, 3); +/** + * Show a dialog notifying the user about something, with + * only a simple "OK" button to dismiss it. + */ +void notifyBox(const Common::String &msg); + +/** + * Show a dialog prompting the player to input some text. + */ +Common::String promptBox(const Common::String &msg); + +/** + * Show a dialog prompting the player for a "yes"/"no" choice. + */ +bool yesNoBox(const Common::String &msg); + +/** + * Convert a string to lower case, in place. + * @param buffer string to convert to lower case + * @return the string which was passed in + */ char *strlwr(char *buffer); -} + +} // End of namespace Utils } // End of namespace Hugo diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp index ad6e5f2a24..9074225e94 100644 --- a/engines/lastexpress/lastexpress.cpp +++ b/engines/lastexpress/lastexpress.cpp @@ -56,6 +56,8 @@ LastExpressEngine::LastExpressEngine(OSystem *syst, const ADGameDescription *gd) _font(NULL), _logic(NULL), _menu(NULL), _frameCounter(0), _lastFrameCount(0), _graphicsMan(NULL), _resMan(NULL), _sceneMan(NULL), _soundMan(NULL), _eventMouse(NULL), _eventTick(NULL), _eventMouseBackup(NULL), _eventTickBackup(NULL) { + // Setup mixer + syncSoundSettings(); // Adding the default directories const Common::FSNode gameDataDir(ConfMan.get("path")); diff --git a/engines/lure/lure.cpp b/engines/lure/lure.cpp index ca102e237c..b0968c1956 100644 --- a/engines/lure/lure.cpp +++ b/engines/lure/lure.cpp @@ -95,6 +95,10 @@ Common::Error LureEngine::init() { _gameToLoad = -1; _initialised = true; + + // Setup mixer + syncSoundSettings(); + return Common::kNoError; } @@ -264,6 +268,8 @@ GUI::Debugger *LureEngine::getDebugger() { } void LureEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + Sound.syncSounds(); } diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp index 2bdd53040a..d8d25f6895 100644 --- a/engines/m4/m4.cpp +++ b/engines/m4/m4.cpp @@ -107,6 +107,8 @@ void gameMenuHotkeyHandler(MadsM4Engine *vm, View *view, uint32 key) { MadsM4Engine::MadsM4Engine(OSystem *syst, const M4GameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { + // Setup mixer + syncSoundSettings(); // FIXME _vm = this; diff --git a/engines/made/made.cpp b/engines/made/made.cpp index 11f7734495..1c8d54aada 100644 --- a/engines/made/made.cpp +++ b/engines/made/made.cpp @@ -146,11 +146,15 @@ MadeEngine::~MadeEngine() { } void MadeEngine::syncSoundSettings() { - _music->setVolume(ConfMan.getInt("music_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + Engine::syncSoundSettings(); + + bool mute = false; + if (ConfMan.hasKey("mute")) + mute = ConfMan.getBool("mute"); + + _music->setVolume(mute ? 0 : ConfMan.getInt("music_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, + mute ? 0 : ConfMan.getInt("sfx_volume")); } int16 MadeEngine::getTicks() { diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp index a3db630c6a..015cbffb26 100644 --- a/engines/mohawk/mohawk.cpp +++ b/engines/mohawk/mohawk.cpp @@ -46,8 +46,8 @@ MohawkEngine::MohawkEngine(OSystem *syst, const MohawkGameDescription *gamedesc) if (!_mixer->isReady()) error ("Sound initialization failed"); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + // Setup mixer + syncSoundSettings(); _sound = 0; _video = 0; diff --git a/engines/mohawk/myst_vars.cpp b/engines/mohawk/myst_vars.cpp deleted file mode 100644 index f8ea11a1e2..0000000000 --- a/engines/mohawk/myst_vars.cpp +++ /dev/null @@ -1,578 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "mohawk/myst.h" -#include "mohawk/myst_vars.h" - -namespace Mohawk { - -// The Myst variable system is complex, and the structure is fairly -// unknown. The idea of this class is to abstract the variable references -// from the storage structure until the structure is clear enough that -// the complexity of this abstraction can be removed. - -// The exact organization of local/global, persistent/non-persistent -// age-specific mapping etc. is currently unknown. - -MystVarEntry introVars[] = { - { 0, 7, "Age To Link To" } // 0 to 7 - // 0 = Selenitic - // 1 = Stoneship - // 2 = Myst (Library Ceiling) - // 3 = Mechanical - // 4 = Channelwood - // 5 = Myst (Start of Movie - Over Sea) - // 6 = D'ni - // 7 = Myst (End of Movie - On Dock) -}; - -MystVarEntry seleniticVars[] = { - { 0, 0, "Sound Pickup At Windy Tunnel" }, // 0 to 1 // TODO: Multiple Uses of Var 0? - { 1, 0, "Sound Pickup At Volcanic Crack" }, // 0 to 1 - { 2, 0, "Sound Pickup At Clock" }, // 0 to 1 - { 3, 0, "Sound Pickup At Water Pool" }, // 0 to 1 - { 4, 0, "Sound Pickup At Crystal Rocks" }, // 0 to 1 - { 5, 0, "Sound Receiver Doors" }, // 0 to 1 - { 6, 0, "Windy Tunnel Lights" }, // 0 to 1 - { 7, 0, "Maze Runner Porthole View" }, // 0 to 3 - { 8, 0, "Sound Receiver Screen (Control Variable?)" }, - { 9, 0, "Sound Receiver Water Pool Button Selected" }, - { 10, 0, "Sound Receiver Volcanic Crack Button Selected" }, - { 11, 0, "Sound Receiver Clock Button Selected" }, - { 12, 0, "Sound Receiver Crystal Rocks Button Selected" }, - { 13, 0, "Sound Receiver Windy Tunnel Button Selected" }, - { 14, 0, "Sound Receiver LED Digit #0 (Left)" }, - { 15, 0, "Sound Receiver LED Digit #1" }, - { 16, 0, "Sound Receiver LED Digit #2" }, - { 17, 0, "Sound Receiver LED Digit #3 (Right)" }, - { 18, 0, "Sound Receiver Green Arrow - Right" }, - { 19, 0, "Sound Receiver Green Arrow - Left" }, - { 20, 0, "Sound Lock Slider #1 (Left) (Position?)" }, - { 21, 0, "Sound Lock Slider #2 (Position?)" }, - { 22, 0, "Sound Lock Slider #3 (Position?)" }, - { 23, 0, "Sound Lock Slider #4 (Position?)" }, - { 24, 0, "Sound Lock Slider #5 (Right) (Position?)" }, - { 25, 0, "Maze Runner Compass Heading" }, // 0 to 8 - { 26, 0, "Sound Receiver Sum Button Selected" }, - { 27, 0, "Maze Runner Red Warning Light" }, - { 28, 0, "Sound Lock Button State" }, - { 29, 0, "Maze Runner Door Button State" }, - { 30, 0, "Maze Runner Door State" }, - { 31, 0, "Maze Runner Forward Button Lit" }, // 0 to 2 - { 32, 0, "Maze Runner Left & Right Button Lit" }, // 0 to 2 - { 33, 0, "Maze Runner Backtrack Button Lit" }, // 0 to 2 - { 102, 1, "Red Page in Age" }, // 0 to 1 - { 103, 1, "Blue Page in Age" } // 0 to 1 -}; - -MystVarEntry stoneshipVars[] = { - { 0, 0, "Water Pump Button #3 (Right) / Lighthouse Water Drained" }, // 0 to 2 = Button Up & Unlit, Button Down & Lit, Button Up & Lit - { 1, 0, "Water Pump Button #2 / Tunnels To Brothers Rooms Drained" }, // 0 to 2 = Button Up & Unlit, Button Down & Lit, Button Up & Lit - { 2, 0, "Water Pump Button #1 (Left) / Ship Cabin Water Drained" }, // 0 to 2 = Button Up & Unlit, Button Down & Lit, Button Up & Lit - { 3, 0, "Lighthouse (Water or Chest Floating?)" }, // 0 to 1, Used by Far View - { 4, 0, "Lighthouse Water/Chest State" }, // 0 to 2 = Water, No Water, Water & Chest Floating - { 5, 2, "Lighthouse Trapdoor State" }, // 0 to 2 = Closed & Unlocked, Open, Closed & Locked - { 6, 0, "Lighthouse Chest Valve Position" }, // 0 to 1 - { 7, 0, "Lighthouse Chest Unlocked" }, // 0 to 1 - { 8, 0, "Lighthouse Chest Key Position?" }, // 0 to 2, 2 = Bottom of Lighthouse -// Var 9 Unused - { 10, 1, "Lighthouse Chest Full Of Water" }, // 0 to 1 - { 11, 3, "Lighthouse Key State" }, // 0 to 3 = Closed?, Open & No Key, Open & No Key, Open & Key - { 12, 0, "Lighthouse Trapdoor - Holding Key" }, // 0 to 1 - { 13, 0, "State of Water in Tunnels to Brothers' Rooms" }, // 0 to 2 = Dark & Water, Dark & Drained, Lit & Water - { 14, 0, "Tunnels to Brothers' Rooms Lit" }, // 0 to 1 - { 15, 0, "Side Door in Tunnels To Brother's Rooms Open" }, // 0 to 1 - { 16, 0, "Underwater Light Lit" }, // 0 to 1 - { 17, 0, "Sirrus' Room Drawer with Drugs Open" }, // 0 to 1 - { 18, 0, "Brother Room Door Open" }, // 0 to 1, Used for Door Slam - { 19, 0, "Brother Room Door State" }, // 0 to 2 = Closed, Open & Dark, Open & Lit - { 20, 0, "Ship Cabin Myst Book Present" }, // 0 to 1 - { 21, 0, "Brothers Rooms' Chest Of Drawers Drawer State" }, // 0 to 6 (Card 2197) or 0 to 7 (Card 2004) - { 22, 0, "Sirrus' Chest of Drawers Drawer #1 (Top) Open" }, // 0 to 1 - { 23, 0, "Sirrus' Chest of Drawers Drawer #2 Open" }, // 0 to 1 - { 24, 0, "Sirrus' Chest of Drawers Drawer #3 Open" }, // 0 to 1 -// Var 25 Unused - Replaced by Var 35. - { 26, 0, "Sirrus' Chest of Drawers Left Small Drawer Open" }, // 0 to 1 - { 27, 0, "Sirrus' Chest of Drawers Right Small Drawer Open" }, // 0 to 1 - { 28, 0, "Telescope View Position" }, // Range Unknown.. 0 to 360? - { 29, 0, "Achenar's Room Rose/Skull Hologram Button Lit" }, // 0 to 1 - { 30, 2, "Light State in Tunnel to Compass Rose Room" }, // 0 to 2 = Lit & Underwater Light Lit, Lit, Dark - { 31, 0, "Lighthouse Lamp Room Battery Pack Indicator Light" }, // 0 to 1 - { 32, 0, "Lighthouse Lamp Room Battery Pack Meter Level" }, // Range Unknown.. // Must be 1 to vertical size of image... - { 33, 0, "State of Side Door in Tunnels to Compass Rose Room (Power?)" }, // 0 to 2 = Closed (No Power), Closed (Power), Open - { 34, 1, "Achenar's Room Drawer with Torn Note Closed" }, // 0 to 1 - { 35, 2, "Sirrus' Room Drawer #4 (Bottom) Open and Red Page State" }, // 0 to 2 = Open, Open with Page, Closed - { 36, 0, "Ship Cabin Door State" }, // 0 to 2 = Closed, Open & Dark, Open & Lit - { 102, 1, "Red Page in Age" }, // 0 to 1 - { 103, 1, "Blue Page in Age" }, // 0 to 1 - { 105, 0, "Ship Cabin Door State" } -}; - -MystVarEntry mystVars[] = { - { 0, 1, "Myst Library Bookcase Closed / Library Exit Open" }, // 0 to 1 // TODO: Multiple Uses of Var 0? - { 1, 0, "Myst Library Bookcase Open / Library Exit Blocked" }, // 0 to 1 - { 2, 0, "Marker Switch Near Cabin" }, // 0 to 1 - { 3, 0, "Marker Switch Near Clock Tower" }, // 0 to 1 - { 4, 0, "Marker Switch on Dock" }, // 0 to 1 - { 5, 0, "Marker Switch Near Ship Pool" }, // 0 to 1 - { 6, 0, "Marker Switch Near Cogs" }, // 0 to 1 - { 7, 0, "Marker Switch Near Generator Room" }, // 0 to 1 - { 8, 0, "Marker Switch Near Stellar Observatory" }, // 0 to 1 - { 9, 0, "Marker Switch Near Rocket Ship" }, // 0 to 1 - { 10, 0, "Ship Floating State" }, // 0 to 1 - { 11, 0, "Cabin Door Open State" }, - { 12, 0, "Clock Tower Gear Bridge" }, // 0 to 1 - { 13, 0, "Tower Elevator Sound Control" }, // 0 to 1 - { 14, 0, "Tower Solution (Key) Plaque" }, // 0 to 4 - // 0 = None - // 1 = 59 V - // 2 = 2:40 2-2-1 - // 3 = October 11, 1984 10:04 AM - // January 17, 1207 5:46 AM - // November 23, 9791 6:57 PM - // 4 = 7, 2, 4 - { 15, 0, "Tower Window (Book) View" }, // 0 to 6 - // 0 = Wall - // 1 = Rocketship - // 2 = Cogs Closed - // 3 = Ship Sunk - // 4 = Channelwood Tree - // 5 = Ship Floating - // 6 = Cogs Open - { 16, 0, "Tower Window (Book) View From Ladder Top" }, // 0 to 2 - // 0 = Wall - // 1 = Sky - // 2 = Sky with Channelwood Tree - { 17, 0, "Fireplace Grid Row #1 (Top)" }, // Bitfield 0x00 to 0xFF - { 18, 0, "Fireplace Grid Row #2" }, // Bitfield 0x00 to 0xFF - { 19, 0, "Fireplace Grid Row #3" }, // Bitfield 0x00 to 0xFF - { 20, 0, "Fireplace Grid Row #4" }, // Bitfield 0x00 to 0xFF - { 21, 0, "Fireplace Grid Row #5" }, // Bitfield 0x00 to 0xFF - { 22, 0, "Fireplace Grid Row #6 (Bottom)" }, // Bitfield 0x00 to 0xFF - { 23, 0, "Fireplace Pattern Correct" }, // 0 to 1 - { 24, 1, "Fireplace Blue Page Present" }, // 0 to 1 - { 25, 1, "Fireplace Red Page Present" }, // 0 to 1 - { 26, 0, "Ship Puzzle Box Image (Cross)" }, // 0 to 2 - { 27, 0, "Ship Puzzle Box Image (Leaf)" }, // 0 to 2 - { 28, 0, "Ship Puzzle Box Image (Arrow)" }, // 0 to 2 - { 29, 0, "Ship Puzzle Box Image (Eye)" }, // 0 to 2 - { 30, 0, "Ship Puzzle Box Image (Snake)" }, // 0 to 2 - { 31, 0, "Ship Puzzle Box Image (Spider)" }, // 0 to 2 - { 32, 0, "Ship Puzzle Box Image (Anchor)" }, // 0 to 2 - { 33, 0, "Ship Puzzle Box Image (Ostrich)" }, // 0 to 2 - { 34, 2, "Dock Forechamber Imager State" }, // 0 to 2 = Off, Mountain, Water - { 35, 5, "Dock Forechamber Imager Control Left Digit" }, // 0 to 9 - { 36, 6, "Dock Forechamber Imager Control Right Digit" }, // 0 to 9 - { 37, 0, "Clock Tower Control Wheels Position" }, // 0 to 8 -// Var 38 Unused -// 39 = TODO: ? - { 40, 0, "Cog Close/Open State" }, - { 41, 0, "Dock Marker Switch Vault State" }, // 0 to 2 = Closed, Open & Page Taken, Open & Page Present -// Var 42 Unused - { 43, 0, "Clock Tower Time" }, // 0 to 143 - { 44, 0, "Rocket Ship Power State" }, // 0 to 2 = None, Insufficient, Correct - { 45, 1, "Dock Forechamber Imager Water Effect Enabled" }, // 0 to 1 - { 46, 0, "Number Of Pages in Red Book" }, // 0 to 6 = 0-5, Extra - { 47, 0, "Number Of Pages in Blue Book" }, // 0 to 6 = 0-5, Extra - { 48, 0, "Marker Switch on Dock - Duplicate of Var #4?" }, // 0 to 2 - { 49, 0, "Generator Running" }, // Boolean used for Sound.. -// 50 = TODO: ? - { 51, 2, "Forechamber Imager Movie Control Variable" }, // 0 to 4 = Blank, Mountain, Water, Atrus, Marker Switch - { 52, 0, "Generator Switch #1" }, - { 53, 0, "Generator Switch #2" }, - { 54, 0, "Generator Switch #3" }, - { 55, 0, "Generator Switch #4" }, - { 56, 0, "Generator Switch #5" }, - { 57, 0, "Generator Switch #6" }, - { 58, 0, "Generator Switch #7" }, - { 59, 0, "Generator Switch #8" }, - { 60, 0, "Generator Switch #9" }, - { 61, 0, "Generator Switch #10" }, - { 62, 0, "Generator Power Dial Left LED Digit" }, // 0 to 9 - { 63, 0, "Generator Power Dial Right LED Digit" }, // 0 to 9 - { 64, 0, "Generator Power To Spaceship Dial Left LED Digit" }, // 0 to 9 - { 65, 0, "Generator Power To Spaceship Dial Right LED Digit" }, // 0 to 9 - { 66, 0, "Generator Room Lights On" }, // Boolean - { 67, 9, "Cabin Safe Lock Number #1 - Left" }, - { 68, 9, "Cabin Safe Lock Number #2" }, - { 69, 9, "Cabin Safe Lock Number #3 - Right" }, - { 70, 0, "Cabin Safe Matchbox State" }, // 0 to 2 - { 71, 1, "Stellar Observatory Lights" }, - { 72, 0, "Channelwood Tree Position" }, // 0 to 12, 4 for Alcove - { 73, 9, "Stellar Observatory Telescope Control - Month" }, // 0 to 11, Not in order... - // 0 = OCT, 1 = NOV, 2 = DEC, 3 = JUL, 4 = AUG, 5 = SEP - // 6 = APR, 7 = MAY, 8 = JUN, 9 = JAN, 10 = FEB, 11 = MAR - { 74, 10, "Stellar Observatory Telescope Control - Day Digit #1 (Left)" }, // 0 to 10 = 0 to 9, Blank - { 75, 1, "Stellar Observatory Telescope Control - Day Digit #2 (Right)" }, // 0 to 10 = 0 to 9, Blank - { 76, 10, "Stellar Observatory Telescope Control - Year Digit #1 (Left)" }, // 0 to 10 = 0 to 9, Blank - { 77, 10, "Stellar Observatory Telescope Control - Year Digit #2" }, // 0 to 10 = 0 to 9, Blank - { 78, 10, "Stellar Observatory Telescope Control - Year Digit #3" }, // 0 to 10 = 0 to 9, Blank - { 79, 0, "Stellar Observatory Telescope Control - Year Digit #4 (Right)" }, // 0 to 10 = 0 to 9, Blank - { 80, 1, "Stellar Observatory Telescope Control - Hour Digit #1 (Left)" }, // 0 to 10 = 0 to 9, Blank - { 81, 2, "Stellar Observatory Telescope Control - Hour Digit #2 (Right)" }, // 0 to 10 = 0 to 9, Blank - { 82, 0, "Stellar Observatory Telescope Control - Minute Digit #1 (Left)" }, // 0 to 10 = 0 to 9, Blank - { 83, 0, "Stellar Observatory Telescope Control - Minute Digit #2 (Right)" }, // 0 to 10 = 0 to 9, Blank -// 84 to 87 = TODO: ? - { 88, 0, "Stellar Observatory Telescope Control - AM/PM Indicator" }, // 0 = AM, 1 = PM - { 89, 0, "Stellar Observatory Telescope Control - Slider #1 (Left)" }, // 0 to 2 = Not Present, Dark, Lit - { 90, 0, "Stellar Observatory Telescope Control - Slider #2" }, // 0 to 2 = Not Present, Dark, Lit - { 91, 0, "Stellar Observatory Telescope Control - Slider #3" }, // 0 to 2 = Not Present, Dark, Lit - { 92, 0, "Stellar Observatory Telescope Control - Slider #4 (Right)" }, // 0 to 2 = Not Present, Dark, Lit - { 93, 0, "Breaker nearest Generator Room Blown" }, - { 94, 0, "Breaker nearest Rocket Ship Blown" }, -// 95 = TODO: ? - { 96, 0, "Generator Power Dial Needle Position" }, // 0 to 24 - { 97, 0, "Generator Power To Spaceship Dial Needle Position" }, // 0 to 24 - { 98, 0, "Cabin Boiler Pilot Light Lit" }, - { 99, 0, "Cabin Boiler Gas Valve Position" }, // 0 to 5 - { 100, 0, "Red Book Page State" }, // Bitfield - { 101, 0, "Blue Book Page State" }, // Bitfield - { 102, 1, "Red Page in Age" }, // 0 to 1 - { 103, 1, "Blue Page in Age" }, // 0 to 1 -// 104 = TODO: ? - { 105, 0, "Clock Tower Door / Ship Box Temp Value" }, - { 106, 0, "Red / Blue Book State" }, // 0 to 4, 0-3 = Books Present 4 = Books Burnt - { 300, 0, "Rocket Ship Music Puzzle Slider State" }, // 0 to 2 = Not Present, Dark, Lit - { 301, 0, "Rocket Ship Piano Key Depressed" }, // 0 to 1 - { 302, 0, "Green Book Opened Before Flag" }, // 0 to 1 - { 303, 1, "Myst Library Bookcase Closed / Library Exit Open" }, - { 304, 0, "Myst Library Image Present on Tower Rotation Map" }, // 0 to 1 - { 305, 0, "Cabin Boiler Lit" }, - { 306, 0, "Cabin Boiler Steam Sound Control" }, // 0 to 27 - { 307, 0, "Cabin Boiler Needle Position i.e. Fully Pressurised" }, // 0 to 1 - { 308, 0, "Cabin Safe Handle Position / Matchbox Temp Value" }, - { 309, 0, "Red/Blue/Green Book Open" }, // 0 to 1 - { 310, 0, "Dock Forechamber Imager Control Temp Value?" } -}; - -MystVarEntry mechVars[] = { - { 0, 0, "Achenar's Room Secret Panel State" }, // TODO: Multiple Uses of Var 0? - { 1, 0, "Sirrus's Room Secret Panel State" }, - { 2, 0, "Achenar's Secret Room Crate Lid Open and Blue Page Present" }, // 0 to 4 - // 0 = Lid Closed, Blue Page Present - // 1 = Lid Closed, Blue Page Not Present - // 2 = Lid Open, Blue Page Not Present - // 3 = Lid Open, Blue Page Present - { 3, 0, "Achenar's Secret Room Crate Lid Open" }, // 0 to 1 - { 4, 0, "Myst Book Staircase State" }, - { 5, 0, "Fortress Telescope View" }, - { 6, 0, "Large Cog Visible Through Distant Fortress Doorway" }, // 0 to 1 - { 7, 0, "Fortress Elevator Door Rotated to Open" }, // 0 to 1 -// Var 8 Not Used -// Var 9 Not Used - { 10, 0, "Fortress Staircase State" }, // 0 to 1 - { 11, 0, "Fortress Elevator Rotation Control - Position Indicator" }, // 0 to 9, 4 = Red Open Position - { 12, 0, "Fortress Elevator Rotation Control - Top Cog Position" }, // 0 to 5 - { 13, 0, "Fortress Elevator Vertical Position - View" }, // 0 to 2, Used for View Logic on change from Card 6150 - { 14, 0, "Fortress Elevator Vertical Position - Button" }, // 0 to 2, Used for Button Logic on Card 6120 - { 15, 0, "Code Lock State" }, // 0 to 2 - { 16, 0, "Code Lock Shape #1 (Left)" }, - { 17, 0, "Code Lock Shape #2" }, - { 18, 0, "Code Lock Shape #3" }, - { 19, 0, "Code Lock Shape #4 (Right)" }, - { 20, 0, "Red Dodecahedron Lit" }, - { 21, 0, "Green Dodecahedron Lit" }, - { 22, 0, "Yellow Tetrahedron Lit" }, - { 23, 0, "In Elevator" }, // 0 to 1 - { 102, 1, "Red Page in Age" }, // 0 to 1 - { 103, 1, "Blue Page in Age" } // 0 to 1 -}; - -MystVarEntry channelwoodVars[] = { - { 0, 0, "Multiple Uses..." }, // TODO: Multiple Uses of Var 0? - { 1, 0, "Water Pump Bridge State" }, // 0 to 1 - { 2, 0, "Lower Walkway to Upper Walkway Elevator State" }, // 0 to 1 - { 3, 0, "Water Flowing (R) to Pump for Upper Walkway to Temple Elevator" }, // 0 to 1 - { 4, 0, "Water Flowing (L, R, R, L, Pipe Extended) to Pump for Book Room Elevator" }, // 0 to 1 - { 5, 0, "Lower Walkway to Upper Walkway Spiral Stair Lower Door Open" }, // 0 to 1 - { 6, 0, "Pipe Bridge Extended" }, // 0 to 1 - { 7, 0, "Bridge Pump Running" }, // 0 to 1 - { 8, 0, "Water Tank Valve State" }, // 0 to 1 - { 9, 0, "First Water Valve State" }, // 0 to 1 - { 10, 0, "Second (L) Water Valve State" }, // 0 to 1 - { 11, 0, "Third (L, R) Water Valve State" }, // 0 to 1 - { 12, 0, "Fourth (L, R, R) Water Valve State" }, // 0 to 1 - { 13, 0, "Fourth (L, R, L) Water Valve State" }, // 0 to 1 - { 14, 0, "Third (L, L) Water Valve State" }, // 0 to 1 - { 15, 0, "Water Flowing (L, R, R, R) to Pump for Lower Walkway to Upper Walkway Elevator" }, // 0 to 1 - { 16, 0, "Lower Walkway to Upper Walkway Spiral Stair Upper Door Open" }, // 0 to 1 - { 17, 0, "Achenar's Holoprojector Selection" }, // 0 to 3 - { 18, 0, "Drawer in Sirrus' Room with Wine Bottles and Torn Note Open" }, // 0 to 1 - { 19, 0, "Water Flowing to First Water Valve" }, // 0 to 1 - { 20, 0, "Water Flowing to Second (L) Water Valve" }, // 0 to 1 - { 21, 0, "Water Flowing to Third (L, R) Water Valve" }, // 0 to 1 - { 22, 0, "Water Flowing to Fourth (L, R, R) Water Valve" }, // 0 to 1 - { 23, 0, "Water Flowing to Fourth (L, R, L) Water Valve" }, // 0 to 1 - { 24, 0, "Water Flowing to Third (L, L) Water Valve" }, // 0 to 1 - { 25, 0, "Water Flowing to Pipe Bridge (L, R, R, L)" }, // 0 to 1 - { 26, 0, "Water Flowing to Pipe At Entry Point (L, R, L, R)" }, // 0 to 1 - { 27, 0, "Water Flowing to Join and Pump Bridge (L, R, L, L)" }, // 0 to 1 - { 28, 0, "Water Flowing to Join and Pump Bridge (L, L, R)" }, // 0 to 1 - { 29, 0, "Water Flowing to Pipe In Water (L, L, L)" }, // 0 to 1 - { 30, 0, "Lower Walkway to Upper Walkway Elevator Door Open" }, // 0 to 1 - { 31, 0, "Water Flowing to Join (L, L, R)" }, // 0 to 2 = Stop Sound, Background, Background with Water Flow - { 32, 0, "Water Flowing (L, R, R, L, Pipe) State" }, // 0 to 2 = Stop Sound, Background, Background with Water Flow - { 33, 0, "Lower Walkway to Upper Walkway Spiral Stair Upper Door State" }, // 0 to 2 = Closed, Open, Open but slams behind you. - { 102, 1, "Red Page in Age" }, // 0 to 1 - { 103, 1, "Blue Page in Age" }, // 0 to 1 - { 105, 0, "Upper Walkway to Temple Elevator Door Open / Temple Iron Door Open" } // 0 to 1, used for slam sound -}; - -MystVarEntry dniVars[] = { - { 0, 0, "Atrus Gone" }, // 0 to 1 // TODO: Multiple Uses of Var 0? - { 1, 0, "Myst Book State" }, // 0 to 2 = Book Inactive, Book Unlinkable, Book Linkable - { 2, 0, "Sound Control" }, // 0 to 2 = Win Tune, Lose Tune, Stop Sound - { 106, 0, "Atrus State Control" } // 0 to 4 = Atrus Writing, Atrus Holding Out Hand, Atrus Gone, Atrus #2, Atrus #2 -}; - -MystVarEntry creditsVars[] = { - { 0, 0, "Image Control" }, // 0 to 6 - { 1, 1, "Sound Control" } // 0 to 1 = Win Tune, Lose Tune -}; - -MystVar::MystVar(MohawkEngine_Myst *vm) { - _vm = vm; -} - -MystVar::~MystVar() { -} - -// Only for use by Save/Load, all other code should use getVar() -uint16 MystVar::saveGetVar(uint16 stack, uint16 v) { - uint16 value = 0; - MystVarEntry unknownVar = { v, 0, "Unknown" }; - const char *desc = NULL; - uint16 i; - - switch (stack) { - case kIntroStack: - for (i = 0; i < ARRAYSIZE(introVars); i++) { - if (introVars[i].refNum == v) { - value = introVars[i].storage; - desc = introVars[i].description; - break; - } - } - break; - case kSeleniticStack: - for (i = 0; i < ARRAYSIZE(seleniticVars); i++) { - if (seleniticVars[i].refNum == v) { - value = seleniticVars[i].storage; - desc = seleniticVars[i].description; - break; - } - } - break; - case kStoneshipStack: - for (i = 0; i < ARRAYSIZE(stoneshipVars); i++) { - if (stoneshipVars[i].refNum == v) { - value = stoneshipVars[i].storage; - desc = stoneshipVars[i].description; - break; - } - } - break; - case kDemoPreviewStack: - case kMystStack: - for (i = 0; i < ARRAYSIZE(mystVars); i++) { - if (mystVars[i].refNum == v) { - value = mystVars[i].storage; - desc = mystVars[i].description; - break; - } - } - break; - case kMechanicalStack: - for (i = 0; i < ARRAYSIZE(mechVars); i++) { - if (mechVars[i].refNum == v) { - value = mechVars[i].storage; - desc = mechVars[i].description; - break; - } - } - break; - case kChannelwoodStack: - for (i = 0; i < ARRAYSIZE(channelwoodVars); i++) { - if (channelwoodVars[i].refNum == v) { - value = channelwoodVars[i].storage; - desc = channelwoodVars[i].description; - break; - } - } - break; - case kDniStack: - for (i = 0; i < ARRAYSIZE(dniVars); i++) { - if (dniVars[i].refNum == v) { - value = dniVars[i].storage; - desc = dniVars[i].description; - break; - } - } - break; - case kCreditsStack: - for (i = 0; i < ARRAYSIZE(creditsVars); i++) { - if (creditsVars[i].refNum == v) { - value = creditsVars[i].storage; - desc = creditsVars[i].description; - break; - } - } - break; - default: - break; - } - - if (desc == NULL) { - for (i = 0; i < _unknown.size(); i++) { - if (_unknown[i].refNum == v) { - value = _unknown[i].storage; - desc = _unknown[i].description; - break; - } - } - - if (desc == NULL) { - warning("MystVar::getVar(%d): Unknown variable reference", v); - _unknown.push_back(unknownVar); - desc = _unknown.back().description; - } - } - - debugC(kDebugVariable, "MystVar::getVar(%d = %s): %d", v, desc, value); - return value; -} - -// Only for use by Save/Load, all other code should use setVar() -void MystVar::loadSetVar(uint16 stack, uint16 v, uint16 value) { - const char *desc = NULL; - MystVarEntry unknownVar = { v, value, "Unknown" }; - uint16 i; - - switch (stack) { - case kIntroStack: - for (i = 0; i < ARRAYSIZE(introVars); i++) { - if (introVars[i].refNum == v) { - introVars[i].storage = value; - desc = introVars[i].description; - break; - } - } - break; - case kSeleniticStack: - for (i = 0; i < ARRAYSIZE(seleniticVars); i++) { - if (seleniticVars[i].refNum == v) { - seleniticVars[i].storage = value; - desc = seleniticVars[i].description; - break; - } - } - break; - case kStoneshipStack: - for (i = 0; i < ARRAYSIZE(stoneshipVars); i++) { - if (stoneshipVars[i].refNum == v) { - stoneshipVars[i].storage = value; - desc = stoneshipVars[i].description; - break; - } - } - break; - case kDemoPreviewStack: - case kMystStack: - for (i = 0; i < ARRAYSIZE(mystVars); i++) { - if (mystVars[i].refNum == v) { - mystVars[i].storage = value; - desc = mystVars[i].description; - break; - } - } - break; - case kMechanicalStack: - for (i = 0; i < ARRAYSIZE(mechVars); i++) { - if (mechVars[i].refNum == v) { - mechVars[i].storage = value; - desc = mechVars[i].description; - break; - } - } - break; - case kChannelwoodStack: - for (i = 0; i < ARRAYSIZE(channelwoodVars); i++) { - if (channelwoodVars[i].refNum == v) { - channelwoodVars[i].storage = value; - desc = channelwoodVars[i].description; - break; - } - } - break; - case kDniStack: - for (i = 0; i < ARRAYSIZE(dniVars); i++) { - if (dniVars[i].refNum == v) { - dniVars[i].storage = value; - desc = dniVars[i].description; - break; - } - } - break; - case kCreditsStack: - for (i = 0; i < ARRAYSIZE(creditsVars); i++) { - if (creditsVars[i].refNum == v) { - creditsVars[i].storage = value; - desc = creditsVars[i].description; - break; - } - } - break; - default: - break; - } - - if (desc == NULL) { - for (i = 0; i < _unknown.size(); i++) { - if (_unknown[i].refNum == v) { - _unknown[i].storage = value; - desc = _unknown[i].description; - break; - } - } - - if (desc == NULL) { - warning("MystVar::setVar(%d): Unknown variable reference", v); - _unknown.push_back(unknownVar); - desc = _unknown.back().description; - } - } - - debugC(kDebugVariable, "MystVar::setVar(%d = %s): %d", v, desc, value); -} - -uint16 MystVar::getVar(uint16 v) { - return this->saveGetVar(_vm->getCurStack(), v); -} - -void MystVar::setVar(uint16 v, uint16 value) { - this->loadSetVar(_vm->getCurStack(), v, value); -} - -} // End of namespace Mohawk diff --git a/engines/mohawk/myst_vars.h b/engines/mohawk/myst_vars.h deleted file mode 100644 index 065d8df2cb..0000000000 --- a/engines/mohawk/myst_vars.h +++ /dev/null @@ -1,60 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "mohawk/myst.h" - -#ifndef MYST_VARS_H -#define MYST_VARS_H - -namespace Mohawk { - -struct MystVarEntry { - uint16 refNum; - uint16 storage; // Used for Initial Value setting - const char *description; -}; - -class MystVar { -public: - MystVar(MohawkEngine_Myst *vm); - ~MystVar(); - - // Only for use by Save/Load - // All other code should use getVar() / setVar() - void loadSetVar(uint16 stack, uint16 v, uint16 value); - uint16 saveGetVar(uint16 stack, uint16 v); - - uint16 getVar(uint16 v); - void setVar(uint16 v, uint16 value); - -private: - MohawkEngine_Myst *_vm; - - Common::Array<MystVarEntry> _unknown; -}; - -} // End of namespace Mohawk - -#endif diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index e9742e0bc2..1d47d453a0 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -57,9 +57,10 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio _gameOver = false; _activatedSLST = false; _ignoreNextMouseUp = false; - _extrasFile = NULL; + _extrasFile = 0; _curStack = aspit; - _hotspots = NULL; + _hotspots = 0; + removeTimer(); // NOTE: We can never really support CD swapping. All of the music files // (*_Sounds.mhk) are stored on disc 1. They are copied to the hard drive @@ -185,12 +186,13 @@ Common::Error MohawkEngine_Riven::run() { } void MohawkEngine_Riven::handleEvents() { - Common::Event event; - - // Update background videos and the water effect + // Update background running things + checkTimer(); bool needsUpdate = _gfx->runScheduledWaterEffects(); needsUpdate |= _video->updateMovies(); + Common::Event event; + while (_eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_MOUSEMOVE: @@ -376,6 +378,9 @@ void MohawkEngine_Riven::changeToCard(uint16 dest) { } void MohawkEngine_Riven::refreshCard() { + // Clear any timer still floating around + removeTimer(); + loadHotspots(_curCard); _gfx->_updatesEnabled = true; @@ -393,13 +398,15 @@ void MohawkEngine_Riven::refreshCard() { if (!_activatedSLST) _sound->playSLST(1, _curCard); - if (_showHotspots) { + if (_showHotspots) for (uint16 i = 0; i < _hotspotCount; i++) _gfx->drawRect(_hotspots[i].rect, _hotspots[i].enabled); - } // Now we need to redraw the cursor if necessary and handle mouse over scripts updateCurrentHotspot(); + + // Finally, install any hardcoded timer + installCardTimer(); } void MohawkEngine_Riven::loadCard(uint16 id) { @@ -744,6 +751,88 @@ Common::String MohawkEngine_Riven::getStackName(uint16 stack) const { return rivenStackNames[stack]; } +void MohawkEngine_Riven::installTimer(TimerProc proc, uint32 time) { + removeTimer(); + _timerProc = proc; + _timerTime = time + getTotalPlayTime(); +} + +void MohawkEngine_Riven::checkTimer() { + if (!_timerProc) + return; + + // NOTE: If the specified timer function is called, it is its job to remove the timer! + if (getTotalPlayTime() >= _timerTime) { + TimerProc proc = _timerProc; + proc(this); + } +} + +void MohawkEngine_Riven::removeTimer() { + _timerProc = 0; + _timerTime = 0; +} + +static void catherineIdleTimer(MohawkEngine_Riven *vm) { + uint32 *cathCheck = vm->getVar("pcathcheck"); + uint32 *cathState = vm->getVar("acathstate"); + uint16 movie; + + // Choose a random movie based on where Catherine is + if (*cathCheck == 0) { + static const int movieList[] = { 5, 6, 7, 8 }; + *cathCheck = 1; + movie = movieList[vm->_rnd->getRandomNumber(3)]; + } else if (*cathState == 1) { + static const int movieList[] = { 11, 14 }; + movie = movieList[vm->_rnd->getRandomBit()]; + } else { + static const int movieList[] = { 9, 10, 12, 13 }; + movie = movieList[vm->_rnd->getRandomNumber(3)]; + } + + // Update her state if she moves from left/right or right/left, resp. + if (movie == 5 || movie == 7 || movie == 11 || movie == 14) + *cathState = 2; + else + *cathState = 1; + + // Play the movie, blocking + vm->_video->activateMLST(movie, vm->getCurCard()); + vm->_cursor->hideCursor(); + vm->_video->playMovieBlockingRiven(movie); + vm->_cursor->showCursor(); + vm->_system->updateScreen(); + + // Install the next timer for the next video + uint32 timeUntilNextMovie = vm->_rnd->getRandomNumber(120) * 1000; + + *vm->getVar("pcathtime") = timeUntilNextMovie + vm->getTotalPlayTime(); + + vm->installTimer(&catherineIdleTimer, timeUntilNextMovie); +} + +void MohawkEngine_Riven::installCardTimer() { + switch (getCurCardRMAP()) { + case 0x3a85: // Top of elevator on prison island + // Handle Catherine hardcoded videos + installTimer(&catherineIdleTimer, _rnd->getRandomNumberRng(1, 33) * 1000); + break; + case 0x77d6: // Sunners, top of stairs + // TODO: Background Sunner videos + break; + case 0x79bd: // Sunners, middle of stairs + // TODO: Background Sunner videos + break; + case 0x7beb: // Sunners, bottom of stairs + // TODO: Background Sunner videos + break; + case 0xb6ca: // Sunners, shoreline + // TODO: Background Sunner videos + break; + } +} + bool ZipMode::operator== (const ZipMode &z) const { return z.name == name && z.id == id; } diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index 60a31736d7..6eb02901bb 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -127,6 +127,8 @@ public: Common::Error saveGameState(int slot, const char *desc); bool hasFeature(EngineFeature f) const; + typedef void (*TimerProc)(MohawkEngine_Riven *vm); + private: MohawkArchive *_extrasFile; // We need a separate handle for the extra data RivenConsole *_console; @@ -152,6 +154,10 @@ private: uint32 *_vars; uint32 _varCount; + // Timer + TimerProc _timerProc; + uint32 _timerTime; + // Miscellaneous bool _gameOver; bool _ignoreNextMouseUp; @@ -195,6 +201,12 @@ public: bool _activatedSLST; void runLoadDialog(); void delayAndUpdate(uint32 ms); + + // Timer + void installTimer(TimerProc proc, uint32 time); + void installCardTimer(); + void checkTimer(); + void removeTimer(); }; } // End of namespace Mohawk diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 5424a07a3c..2fc0c4e17b 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -870,12 +870,57 @@ void RivenExternal::xbupdateboiler(uint16 argc, uint16 *argv) { } } +static void ytramTrapTimer(MohawkEngine_Riven *vm) { + // Remove this timer + vm->removeTimer(); + + // Check if we've caught a Ytram + vm->_externalScriptHandler->checkYtramCatch(true); +} + void RivenExternal::xbsettrap(uint16 argc, uint16 *argv) { - // TODO: Set the Ytram trap + // Set the Ytram trap + + // We can catch the Ytram between 10 seconds and 3 minutes from now + uint32 timeUntilCatch = _vm->_rnd->getRandomNumberRng(10, 60 * 3) * 1000; + *_vm->getVar("bytramtime") = timeUntilCatch + _vm->getTotalPlayTime(); + + // And set the timer too + _vm->installTimer(&ytramTrapTimer, timeUntilCatch); +} + +void RivenExternal::checkYtramCatch(bool playSound) { + // Check if we've caught a Ytram + + uint32 *ytramTime = _vm->getVar("bytramtime"); + + // If the trap still has not gone off, reinstall our timer + // This is in case you set the trap, walked away, and returned + if (_vm->getTotalPlayTime() < *ytramTime) { + _vm->installTimer(&ytramTrapTimer, *ytramTime - _vm->getTotalPlayTime()); + return; + } + + // Increment the movie per catch (max = 3) + uint32 *ytramMovie = _vm->getVar("bytram"); + *ytramMovie += 1; + if (*ytramMovie > 3) + *ytramMovie = 3; + + // Reset variables + *_vm->getVar("bytrapped") = 1; + *_vm->getVar("bbait") = 0; + *_vm->getVar("bytrap") = 0; + *ytramTime = 0; + + // Play the capture sound, if requested + if (playSound) + _vm->_sound->playSound(33); } void RivenExternal::xbcheckcatch(uint16 argc, uint16 *argv) { - // TODO: Check if we've caught a Ytram + // Just pass our parameter along... + checkYtramCatch(argv[0] != 0); } void RivenExternal::xbait(uint16 argc, uint16 *argv) { @@ -914,7 +959,28 @@ void RivenExternal::xbait(uint16 argc, uint16 *argv) { } void RivenExternal::xbfreeytram(uint16 argc, uint16 *argv) { - // TODO: Play a random Ytram movie + // Play a random Ytram movie after freeing it + uint16 mlstId; + + switch (*_vm->getVar("bytram")) { + case 1: + mlstId = 11; + break; + case 2: + mlstId = 12; + break; + default: + mlstId = _vm->_rnd->getRandomNumberRng(13, 15); + break; + } + + // Activate the MLST and play the video + _vm->_video->activateMLST(mlstId, _vm->getCurCard()); + _vm->_video->playMovieBlockingRiven(11); + + // Now play the second movie + _vm->_video->activateMLST(mlstId + 5, _vm->getCurCard()); + _vm->_video->playMovieBlockingRiven(12); } void RivenExternal::xbaitplate(uint16 argc, uint16 *argv) { @@ -1380,12 +1446,105 @@ void RivenExternal::xglview_villageoff(uint16 argc, uint16 *argv) { _vm->_gfx->updateScreen(); } +static void catherineViewerIdleTimer(MohawkEngine_Riven *vm) { + uint32 *cathState = vm->getVar("gcathstate"); + uint16 movie; + + // Choose a new movie + if (*cathState == 1) { + static const int movieList[] = { 9, 10, 19, 19, 21, 21 }; + movie = movieList[vm->_rnd->getRandomNumber(5)]; + } else if (*cathState == 2) { + static const int movieList[] = { 18, 20, 22 }; + movie = movieList[vm->_rnd->getRandomNumber(2)]; + } else { + static const int movieList[] = { 11, 11, 12, 17, 17, 17, 17, 23 }; + movie = movieList[vm->_rnd->getRandomNumber(7)]; + } + + // Update Catherine's state + if (movie == 10 || movie == 17 || movie == 18 || movie == 20) + *cathState = 1; + else if (movie == 19 || movie == 21 || movie == 23) + *cathState = 2; + else + *cathState = 3; + + // Begin playing the new movie + vm->_video->activateMLST(movie, vm->getCurCard()); + VideoHandle videoHandle = vm->_video->playMovieRiven(30); + + // Reset the timer + vm->installTimer(&catherineViewerIdleTimer, vm->_video->getDuration(videoHandle) + vm->_rnd->getRandomNumber(60) * 1000); +} + void RivenExternal::xglview_prisonon(uint16 argc, uint16 *argv) { - // TODO: Activate random background Catherine videos + // Activate random background Catherine videos + + // Turn on the left viewer to 'prison mode' + *_vm->getVar("glview") = 1; + + // Get basic starting states + uint16 cathMovie = _vm->_rnd->getRandomNumberRng(8, 23); + uint16 turnOnMovie = 4; + uint32 *cathState = _vm->getVar("gcathstate"); + + // Adjust the turn on movie + if (cathMovie == 14) + turnOnMovie = 6; + else if (cathMovie == 15) + turnOnMovie = 7; + + // Adjust Catherine's state + if (cathMovie == 9 || cathMovie == 11 || cathMovie == 12 || cathMovie == 22) + *cathState = 3; + else if (cathMovie == 19 || cathMovie == 21 || cathMovie == 23 || cathMovie == 14) + *cathState = 2; + else + *cathState = 1; + + // Turn on the viewer + _vm->_cursor->hideCursor(); + _vm->_video->playMovieBlockingRiven(turnOnMovie); + _vm->_cursor->showCursor(); + + uint32 timeUntilNextMovie; + + // Begin playing a movie immediately if Catherine is already in the viewer + if (cathMovie == 8 || (cathMovie >= 13 && cathMovie <= 16)) { + _vm->_video->activateMLST(cathMovie, _vm->getCurCard()); + VideoHandle videoHandle = _vm->_video->playMovieRiven(30); + + timeUntilNextMovie = _vm->_video->getDuration(videoHandle) + _vm->_rnd->getRandomNumber(60) * 1000; + } else { + // Otherwise, just redraw the imager + timeUntilNextMovie = _vm->_rnd->getRandomNumberRng(10, 20) * 1000; + _vm->_gfx->drawPLST(8); + _vm->_gfx->updateScreen(); + } + + // Create the timer for the next video + _vm->installTimer(&catherineViewerIdleTimer, timeUntilNextMovie); } void RivenExternal::xglview_prisonoff(uint16 argc, uint16 *argv) { - // TODO: Deactivate random background Catherine videos + // Deactivate random background Catherine videos + + // Update the viewer state (now off) + *_vm->getVar("glview") = 0; + + // Remove the timer we set in xglview_prisonon() + _vm->removeTimer(); + + // Play the 'turn off' movie after stopping any videos still playing + _vm->_video->stopVideos(); + _vm->_cursor->hideCursor(); + _vm->_video->playMovieBlockingRiven(5); + _vm->_cursor->showCursor(); + + // Redraw the viewer + _vm->_gfx->drawPLST(1); + _vm->_gfx->updateScreen(); } // ------------------------------------------------------------------------------------ diff --git a/engines/mohawk/riven_external.h b/engines/mohawk/riven_external.h index 90fdc664c1..034cd662f6 100644 --- a/engines/mohawk/riven_external.h +++ b/engines/mohawk/riven_external.h @@ -41,6 +41,7 @@ public: uint16 getComboDigit(uint32 correctCombo, uint32 digit); uint32 getDomeSliderState() { return _sliderState; } void setDomeSliderState(uint32 state) { _sliderState = state; } + void checkYtramCatch(bool playSound); private: MohawkEngine_Riven *_vm; diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp index c7b5cd01fd..d70c3c69b1 100644 --- a/engines/mohawk/riven_saveload.cpp +++ b/engines/mohawk/riven_saveload.cpp @@ -167,14 +167,22 @@ bool RivenSaveLoad::loadGame(Common::String filename) { uint32 *var = _vm->getVar(name); - *var = rawVariables[i]; - - if (name.equalsIgnoreCase("CurrentStackID")) + // Handle any special variables here + // WORKAROUND: bytramtime is reset here for one main reason: + // The save does not store any start point for the time, so we don't know the real time. + // Because of this, in many cases, the original would just give a 'free' Ytram upon saving + // since the time would be used in a new (improper) time frame. + // TODO: Check of the other 'time' variables require this too + if (name.equalsIgnoreCase("CurrentStackID")) // Remap to our definitions, store for later stackID = mapOldStackIDToNew(rawVariables[i]); - else if (name.equalsIgnoreCase("CurrentCardID")) + else if (name.equalsIgnoreCase("CurrentCardID")) // Store for later cardID = rawVariables[i]; - else if (name.equalsIgnoreCase("ReturnStackID")) + else if (name.equalsIgnoreCase("ReturnStackID") && *var != 0) // if 0, the game did not use the variable yet *var = mapOldStackIDToNew(rawVariables[i]); + else if (name.equalsIgnoreCase("bytramtime")) // WORKAROUND: See above + *var = 0; + else // Otherwise, just store it + *var = rawVariables[i]; } _vm->changeToStack(stackID); diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 9bf202083a..f481b5ceb2 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -490,6 +490,11 @@ uint32 VideoManager::getElapsedTime(VideoHandle handle) { return _videoStreams[handle]->getElapsedTime(); } +uint32 VideoManager::getDuration(VideoHandle handle) { + assert(handle != NULL_VID_HANDLE); + return _videoStreams[handle]->getDuration(); +} + bool VideoManager::endOfVideo(VideoHandle handle) { assert(handle != NULL_VID_HANDLE); return _videoStreams[handle].endOfVideo(); diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 6b9cfa25d2..e65629a1ec 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -104,6 +104,7 @@ public: int32 getCurFrame(VideoHandle handle); uint32 getFrameCount(VideoHandle handle); uint32 getElapsedTime(VideoHandle handle); + uint32 getDuration(VideoHandle videoHandle); bool endOfVideo(VideoHandle handle); void setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end); void seekToTime(VideoHandle handle, Audio::Timestamp time); diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 1113eb5dca..3055439e47 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -52,6 +52,8 @@ uint32 _globalFlags = 0; Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc), _location(getGameType()), _dialogueMan(0) { + // Setup mixer + syncSoundSettings(); _vm = this; DebugMan.addDebugChannel(kDebugDialogue, "dialogue", "Dialogues debug level"); diff --git a/engines/queen/queen.cpp b/engines/queen/queen.cpp index 74bb52f574..692e38179a 100644 --- a/engines/queen/queen.cpp +++ b/engines/queen/queen.cpp @@ -240,14 +240,20 @@ void QueenEngine::checkOptionSettings() { } void QueenEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + readOptionSettings(); } void QueenEngine::readOptionSettings() { + bool mute = false; + if (ConfMan.hasKey("mute")) + mute = ConfMan.getBool("mute"); + _sound->setVolume(ConfMan.getInt("music_volume")); - _sound->musicToggle(!ConfMan.getBool("music_mute")); - _sound->sfxToggle(!ConfMan.getBool("sfx_mute")); - _sound->speechToggle(!ConfMan.getBool("speech_mute")); + _sound->musicToggle(!(mute || ConfMan.getBool("music_mute"))); + _sound->sfxToggle(!(mute || ConfMan.getBool("sfx_mute"))); + _sound->speechToggle(!(mute || ConfMan.getBool("speech_mute"))); _talkSpeed = (ConfMan.getInt("talkspeed") * (MAX_TEXT_SPEED - MIN_TEXT_SPEED) + 255 / 2) / 255 + MIN_TEXT_SPEED; _subtitles = ConfMan.getBool("subtitles"); checkOptionSettings(); @@ -470,11 +476,14 @@ Common::Error QueenEngine::run() { } _sound = Sound::makeSoundInstance(_mixer, this, _resource->getCompression()); + _walk = new Walk(this); //_talkspeedScale = (MAX_TEXT_SPEED - MIN_TEXT_SPEED) / 255.0; registerDefaultSettings(); - readOptionSettings(); + + // Setup mixer + syncSoundSettings(); _logic->start(); if (ConfMan.hasKey("save_slot") && canLoadOrSave()) { diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp index 6eb7362338..a34af99ec3 100644 --- a/engines/queen/sound.cpp +++ b/engines/queen/sound.cpp @@ -192,10 +192,12 @@ Sound *Sound::makeSoundInstance(Audio::Mixer *mixer, QueenEngine *vm, uint8 comp } void Sound::setVolume(int vol) { - _musicVolume = vol; + if (ConfMan.hasKey("mute") && ConfMan.getBool("mute")) + _musicVolume = 0; + else + _musicVolume = vol; + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _musicVolume); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); } void Sound::saveState(byte *&ptr) { diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index dd3034cdb9..f801001d88 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -239,6 +239,9 @@ void Music::setVolume(int volume, int time) { volume = 255; if (time == 1) { + if (ConfMan.hasKey("mute") && ConfMan.getBool("mute")) + volume = 0; + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); _driver->setVolume(volume); _vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback); diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index 2e34b49dc5..62493f5eac 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -625,6 +625,8 @@ GUI::Debugger *SagaEngine::getDebugger() { } void SagaEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + _subtitlesEnabled = ConfMan.getBool("subtitles"); _readingSpeed = getTalkspeed(); diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp index 07e8487ee4..8ffce4e6cd 100644 --- a/engines/saga/sound.cpp +++ b/engines/saga/sound.cpp @@ -175,8 +175,12 @@ void Sound::stopAll() { } void Sound::setVolume() { - _vm->_soundVolume = ConfMan.getInt("sfx_volume"); - _vm->_speechVolume = ConfMan.getInt("speech_volume"); + bool mute = false; + if (ConfMan.hasKey("mute")) + mute = ConfMan.getBool("mute"); + + _vm->_soundVolume = mute ? 0 : ConfMan.getInt("sfx_volume"); + _vm->_speechVolume = mute ? 0 : ConfMan.getInt("speech_volume"); _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, _vm->_soundVolume); _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, _vm->_speechVolume); } diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index fddae530e0..93d21c32e0 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -40,6 +40,7 @@ #include "sci/sound/music.h" #include "sci/sound/drivers/mididriver.h" #include "sci/sound/drivers/map-mt32-to-gm.h" +#include "sci/graphics/animate.h" #include "sci/graphics/cache.h" #include "sci/graphics/cursor.h" #include "sci/graphics/screen.h" @@ -47,6 +48,7 @@ #include "sci/graphics/paint16.h" #include "sci/graphics/paint32.h" #include "sci/graphics/palette.h" +#include "sci/graphics/ports.h" #include "sci/graphics/view.h" #include "sci/parser/vocabulary.h" @@ -125,6 +127,10 @@ Console::Console(SciEngine *engine) : GUI::Debugger(), DCmd_Register("undither", WRAP_METHOD(Console, cmdUndither)); DCmd_Register("pic_visualize", WRAP_METHOD(Console, cmdPicVisualize)); DCmd_Register("play_video", WRAP_METHOD(Console, cmdPlayVideo)); + DCmd_Register("animate_list", WRAP_METHOD(Console, cmdAnimateList)); + DCmd_Register("al", WRAP_METHOD(Console, cmdAnimateList)); // alias + DCmd_Register("window_list", WRAP_METHOD(Console, cmdWindowList)); + DCmd_Register("wl", WRAP_METHOD(Console, cmdWindowList)); // alias // Segments DCmd_Register("segment_table", WRAP_METHOD(Console, cmdPrintSegmentTable)); DCmd_Register("segtable", WRAP_METHOD(Console, cmdPrintSegmentTable)); // alias @@ -356,6 +362,8 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf(" draw_cel - Draws a cel from a view resource\n"); DebugPrintf(" pic_visualize - Enables visualization of the drawing process of EGA pictures\n"); DebugPrintf(" undither - Enable/disable undithering\n"); + DebugPrintf(" play_video - Plays a SEQ, AVI, VMD, RBT or DUK video\n"); + DebugPrintf(" animate_object_list / al - Shows the current list of objects in kAnimate's draw list\n"); DebugPrintf("\n"); DebugPrintf("Segments:\n"); DebugPrintf(" segment_table / segtable - Lists all segments\n"); @@ -1576,6 +1584,22 @@ bool Console::cmdPlayVideo(int argc, const char **argv) { } } +bool Console::cmdAnimateList(int argc, const char **argv) { + if (_engine->_gfxAnimate) { + DebugPrintf("Animate list:\n"); + _engine->_gfxAnimate->printAnimateList(this); + } + return true; +} + +bool Console::cmdWindowList(int argc, const char **argv) { + if (_engine->_gfxPorts) { + DebugPrintf("Window list:\n"); + _engine->_gfxPorts->printWindowList(this); + } + return true; + +} bool Console::cmdParseGrammar(int argc, const char **argv) { DebugPrintf("Parse grammar, in strict GNF:\n"); @@ -1710,9 +1734,7 @@ bool Console::segmentInfo(int nr) { for (uint i = 0; i < ct->_table.size(); i++) if (ct->isValidEntry(i)) { - reg_t objpos; - objpos.offset = i; - objpos.segment = nr; + reg_t objpos = make_reg(nr, i); DebugPrintf(" [%04x] %s; copy of ", i, _engine->_gamestate->_segMan->getObjectName(objpos)); // Object header const Object *obj = _engine->_gamestate->_segMan->getObject(ct->_table[i].getPos()); diff --git a/engines/sci/console.h b/engines/sci/console.h index d45454376a..93ccc45503 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -95,6 +95,8 @@ private: bool cmdUndither(int argc, const char **argv); bool cmdPicVisualize(int argc, const char **argv); bool cmdPlayVideo(int argc, const char **argv); + bool cmdAnimateList(int argc, const char **argv); + bool cmdWindowList(int argc, const char **argv); // Segments bool cmdPrintSegmentTable(int argc, const char **argv); bool cmdSegmentInfo(int argc, const char **argv); diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 923d35fe16..23d76cc0f6 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -1608,7 +1608,13 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH }, - // Larry 1 VGA Remake - English Amiga (from www.back2roots.org) +#if 0 + // The resource.002 file, contained in disk 3, is broken in this version + // (it contains a large chunk of zeroes and several broken resources, + // e.g. pic 250 and views 250 and 251). + // Thus this detection entry isn't accurate. + + // Larry 1 Remake - English Amiga (from www.back2roots.org) // Executable scanning reports "1.004.024" // SCI interpreter version 1.000.784 {"lsl1sci", "SCI", { @@ -1619,6 +1625,7 @@ static const struct ADGameDescription SciGameDescriptions[] = { {"resource.003", 0, "4a34c3367c2fe7eb380d741374da1989", 572251}, AD_LISTEND}, Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO_NOSPEECH }, +#endif // Larry 1 VGA Remake - English DOS (from spookypeanut) // Executable scanning reports "1.000.577", VERSION file reports "2.1" diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp index d205763051..e395eeab94 100644 --- a/engines/sci/engine/gc.cpp +++ b/engines/sci/engine/gc.cpp @@ -49,28 +49,23 @@ const char *segmentTypeNames[] = { }; #endif -struct WorklistManager { - Common::Array<reg_t> _worklist; - AddrSet _map; // used for 2 contains() calls, inside push() and run_gc() +void WorklistManager::push(reg_t reg) { + if (!reg.segment) // No numbers + return; - void push(reg_t reg) { - if (!reg.segment) // No numbers - return; + debugC(kDebugLevelGC, "[GC] Adding %04x:%04x", PRINT_REG(reg)); - debugC(kDebugLevelGC, "[GC] Adding %04x:%04x", PRINT_REG(reg)); + if (_map.contains(reg)) + return; // already dealt with it - if (_map.contains(reg)) - return; // already dealt with it - - _map.setVal(reg, true); - _worklist.push_back(reg); - } + _map.setVal(reg, true); + _worklist.push_back(reg); +} - void pushArray(const Common::Array<reg_t> &tmp) { - for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it) - push(*it); - } -}; +void WorklistManager::pushArray(const Common::Array<reg_t> &tmp) { + for (Common::Array<reg_t>::const_iterator it = tmp.begin(); it != tmp.end(); ++it) + push(*it); +} static AddrSet *normalizeAddresses(SegManager *segMan, const AddrSet &nonnormal_map) { AddrSet *normal_map = new AddrSet(); @@ -103,18 +98,6 @@ static void processWorkList(SegManager *segMan, WorklistManager &wm, const Commo } } -static void processEngineHunkList(WorklistManager &wm) { - PortList windowList = g_sci->_gfxPorts->_windowList; - - for (PortList::const_iterator it = windowList.begin(); it != windowList.end(); ++it) { - if ((*it)->isWindow()) { - Window *wnd = ((Window *)*it); - wm.push(wnd->hSaved1); - wm.push(wnd->hSaved2); - } - } -} - AddrSet *findAllActiveReferences(EngineState *s) { assert(!s->_executionStack.empty()); @@ -174,8 +157,8 @@ AddrSet *findAllActiveReferences(EngineState *s) { processWorkList(s->_segMan, wm, heap); - if (getSciVersion() <= SCI_VERSION_1_1) - processEngineHunkList(wm); + if (g_sci->_gfxPorts) + g_sci->_gfxPorts->processEngineHunkList(wm); return normalizeAddresses(s->_segMan, wm._map); } diff --git a/engines/sci/engine/gc.h b/engines/sci/engine/gc.h index f4318a1453..48e1c6b482 100644 --- a/engines/sci/engine/gc.h +++ b/engines/sci/engine/gc.h @@ -58,6 +58,15 @@ AddrSet *findAllActiveReferences(EngineState *s); */ void run_gc(EngineState *s); +struct WorklistManager { + Common::Array<reg_t> _worklist; + AddrSet _map; // used for 2 contains() calls, inside push() and run_gc() + + void push(reg_t reg); + void pushArray(const Common::Array<reg_t> &tmp); +}; + + } // End of namespace Sci #endif // SCI_ENGINE_GC_H diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp index e02b27c788..d8f3fa09b0 100644 --- a/engines/sci/graphics/animate.cpp +++ b/engines/sci/graphics/animate.cpp @@ -27,6 +27,7 @@ #include "common/stack.h" #include "graphics/primitives.h" +#include "sci/console.h" #include "sci/sci.h" #include "sci/event.h" #include "sci/engine/kernel.h" @@ -728,4 +729,21 @@ void GfxAnimate::kernelAddToPicView(GuiResourceId viewId, int16 loopNo, int16 ce addToPicSetPicNotValid(); } +void GfxAnimate::printAnimateList(Console *con) { + AnimateList::iterator it; + const AnimateList::iterator end = _list.end(); + + for (it = _list.begin(); it != end; ++it) { + Script *scr = _s->_segMan->getScriptIfLoaded(it->object.segment); + int16 scriptNo = scr ? scr->getScriptNumber() : -1; + + con->DebugPrintf("%04x:%04x (%s), script %d, view %d (%d, %d), pal %d, " + "at %d, %d, scale %d, %d / %d (z: %d, prio: %d, shown: %d, signal: %d)\n", + PRINT_REG(it->object), _s->_segMan->getObjectName(it->object), + scriptNo, it->viewId, it->loopNo, it->celNo, it->paletteNo, + it->x, it->y, it->scaleX, it->scaleY, it->scaleSignal, + it->z, it->priority, it->showBitsFlag, it->signal); + } +} + } // End of namespace Sci diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h index 87072b7a8d..b2aadcbead 100644 --- a/engines/sci/graphics/animate.h +++ b/engines/sci/graphics/animate.h @@ -77,6 +77,7 @@ struct AnimateEntry { typedef Common::List<AnimateEntry> AnimateList; typedef Common::Array<AnimateEntry> AnimateArray; +class Console; class GfxCache; class GfxCursor; class GfxPorts; @@ -105,6 +106,7 @@ public: void reAnimate(Common::Rect rect); void addToPicDrawCels(); void addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control); + void printAnimateList(Console *con); virtual void kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t *argv); virtual void kernelAddToPicList(reg_t listReference, int argc, reg_t *argv); diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h index 4f709fd7c6..69ddf09ea6 100644 --- a/engines/sci/graphics/paint16.h +++ b/engines/sci/graphics/paint16.h @@ -36,7 +36,6 @@ class GfxPorts; class GfxScreen; class GfxPalette; class Font; -class SciGuiPicture; class GfxView; /** diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp index 9ac8d103fc..cc206bd5b9 100644 --- a/engines/sci/graphics/ports.cpp +++ b/engines/sci/graphics/ports.cpp @@ -25,8 +25,10 @@ #include "common/util.h" +#include "sci/console.h" #include "sci/sci.h" #include "sci/engine/features.h" +#include "sci/engine/gc.h" #include "sci/engine/kernel.h" #include "sci/engine/state.h" #include "sci/engine/selector.h" @@ -707,4 +709,26 @@ int16 GfxPorts::kernelPriorityToCoordinate(byte priority) { return _priorityBottom; } +void GfxPorts::processEngineHunkList(WorklistManager &wm) { + for (PortList::const_iterator it = _windowList.begin(); it != _windowList.end(); ++it) { + if ((*it)->isWindow()) { + Window *wnd = ((Window *)*it); + wm.push(wnd->hSaved1); + wm.push(wnd->hSaved2); + } + } +} + +void GfxPorts::printWindowList(Console *con) { + for (PortList::const_iterator it = _windowList.begin(); it != _windowList.end(); ++it) { + if ((*it)->isWindow()) { + Window *wnd = ((Window *)*it); + con->DebugPrintf("%d: '%s' at %d, %d, (%d, %d, %d, %d), drawn: %d, style: %d\n", + wnd->id, wnd->title.c_str(), wnd->left, wnd->top, + wnd->rect.left, wnd->rect.top, wnd->rect.right, wnd->rect.bottom, + wnd->bDrawn, wnd->wndStyle); + } + } +} + } // End of namespace Sci diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h index 9faee2be8d..31ed671daf 100644 --- a/engines/sci/graphics/ports.h +++ b/engines/sci/graphics/ports.h @@ -32,10 +32,10 @@ namespace Sci { -class SciGui; class GfxPaint16; class GfxScreen; class GfxText16; +struct WorklistManager; // window styles enum { @@ -103,6 +103,8 @@ public: void kernelGraphAdjustPriority(int top, int bottom); byte kernelCoordinateToPriority(int16 y); int16 kernelPriorityToCoordinate(byte priority); + void processEngineHunkList(WorklistManager &wm); + void printWindowList(Console *con); Port *_wmgrPort; Window *_picWind; @@ -115,10 +117,10 @@ public: virtual void saveLoadWithSerializer(Common::Serializer &ser); +private: /** The list of open 'windows' (and ports), in visual order. */ PortList _windowList; -private: /** The list of all open 'windows' (and ports), ordered by their id. */ PortArray _windowsById; diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 26ddb00a01..cd50b2402c 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -77,7 +77,6 @@ class GfxText16; class GfxTransitions; #ifdef ENABLE_SCI32 -class SciGui32; class RobotDecoder; class GfxFrameout; #endif diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index c2556d6467..564f3a7e9c 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -1874,11 +1874,11 @@ void ScummEngine::setupMusic(int midi) { } void ScummEngine::syncSoundSettings() { + Engine::syncSoundSettings(); // Sync the engine with the config manager int soundVolumeMusic = ConfMan.getInt("music_volume"); int soundVolumeSfx = ConfMan.getInt("sfx_volume"); - int soundVolumeSpeech = ConfMan.getInt("speech_volume"); bool mute = false; @@ -1886,7 +1886,7 @@ void ScummEngine::syncSoundSettings() { mute = ConfMan.getBool("mute"); if (mute) - soundVolumeMusic = soundVolumeSfx = soundVolumeSpeech = 0; + soundVolumeMusic = soundVolumeSfx = 0; } if (_musicEngine) { @@ -1897,10 +1897,6 @@ void ScummEngine::syncSoundSettings() { _townsPlayer->setSfxVolume(soundVolumeSfx); } - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSfx); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech); - if (ConfMan.getBool("speech_mute")) _voiceMode = 2; else diff --git a/engines/sky/sky.cpp b/engines/sky/sky.cpp index c42bb6301e..f3556c84b3 100644 --- a/engines/sky/sky.cpp +++ b/engines/sky/sky.cpp @@ -100,6 +100,22 @@ SkyEngine::~SkyEngine() { free(_itemList[i]); } +void SkyEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + + bool mute = false; + if (ConfMan.hasKey("mute")) + mute = ConfMan.getBool("mute"); + + if (ConfMan.getBool("sfx_mute")) + SkyEngine::_systemVars.systemFlags |= SF_FX_OFF; + + if (ConfMan.getBool("music_mute")) + SkyEngine::_systemVars.systemFlags |= SF_MUS_OFF; + + _skyMusic->setVolume(mute ? 0: ConfMan.getInt("music_volume") >> 1); +} + GUI::Debugger *SkyEngine::getDebugger() { return _debugger; } @@ -242,16 +258,6 @@ Common::Error SkyEngine::go() { Common::Error SkyEngine::init() { initGraphics(320, 200, false); - if (ConfMan.getBool("sfx_mute")) { - SkyEngine::_systemVars.systemFlags |= SF_FX_OFF; - } - if (ConfMan.getBool("music_mute")) { - SkyEngine::_systemVars.systemFlags |= SF_MUS_OFF; - } - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); - _skyDisk = new Disk(); _skySound = new Sound(_mixer, _skyDisk, Audio::Mixer::kMaxChannelVolume); @@ -346,7 +352,8 @@ Common::Error SkyEngine::init() { } } - _skyMusic->setVolume(ConfMan.getInt("music_volume") >> 1); + // Setup mixer + syncSoundSettings(); _debugger = new Debugger(_skyLogic, _skyMouse, _skyScreen, _skyCompact); return Common::kNoError; diff --git a/engines/sky/sky.h b/engines/sky/sky.h index 29e7c9ab42..d8ced1e569 100644 --- a/engines/sky/sky.h +++ b/engines/sky/sky.h @@ -84,6 +84,8 @@ public: SkyEngine(OSystem *syst); virtual ~SkyEngine(); + virtual void syncSoundSettings(); + static bool isDemo(); static bool isCDVersion(); diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp index 537720401d..8768e62457 100644 --- a/engines/sword1/sword1.cpp +++ b/engines/sword1/sword1.cpp @@ -170,6 +170,8 @@ void SwordEngine::reinitialize() { } void SwordEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + uint musicVol = ConfMan.getInt("music_volume"); uint sfxVol = ConfMan.getInt("sfx_volume"); uint speechVol = ConfMan.getInt("speech_volume"); @@ -228,9 +230,6 @@ void SwordEngine::syncSoundSettings() { _sound->setSpeechVol(speechVolL, speechVolR); _sound->setSfxVol(sfxVolL, sfxVolR); } - - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, mute ? 0 : ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, mute ? 0 : ConfMan.getInt("speech_volume")); } void SwordEngine::flagsToBool(bool *dest, uint8 flags) { diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp index 9c67fcdf25..7ad021b3a5 100644 --- a/engines/sword2/sword2.cpp +++ b/engines/sword2/sword2.cpp @@ -319,11 +319,10 @@ void Sword2Engine::registerDefaultSettings() { } void Sword2Engine::syncSoundSettings() { + Engine::syncSoundSettings(); + bool mute = ConfMan.getBool("mute"); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, mute ? 0 : ConfMan.getInt("music_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, mute ? 0 : ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, mute ? 0 : ConfMan.getInt("sfx_volume")); setSubtitles(ConfMan.getBool("subtitles")); // Our own settings dialog can mute the music, speech and sound effects diff --git a/engines/sword25/gfx/graphicengine_script.cpp b/engines/sword25/gfx/graphicengine_script.cpp index d67d0038c3..d8daaab32c 100644 --- a/engines/sword25/gfx/graphicengine_script.cpp +++ b/engines/sword25/gfx/graphicengine_script.cpp @@ -81,26 +81,6 @@ static ActionCallback *actionCallbackPtr = 0; // FIXME: should be turned into Gr #define ANIMATION_TEMPLATE_CLASS_NAME "Gfx.AnimationTemplate" static const char *GFX_LIBRARY_NAME = "Gfx"; -// Wie luaL_checkudata, nur ohne dass kein Fehler erzeugt wird. -static void *my_checkudata(lua_State *L, int ud, const char *tname) { - int top = lua_gettop(L); - - void *p = lua_touserdata(L, ud); - if (p != NULL) { /* value is a userdata? */ - if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ - // lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ - LuaBindhelper::getMetatable(L, tname); - if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ - lua_settop(L, top); - return p; - } - } - } - - lua_settop(L, top); - return NULL; -} - static void newUintUserData(lua_State *L, uint value) { void *userData = lua_newuserdata(L, sizeof(value)); memcpy(userData, &value, sizeof(value)); @@ -108,8 +88,8 @@ static void newUintUserData(lua_State *L, uint value) { static AnimationTemplate *checkAnimationTemplate(lua_State *L, int idx = 1) { // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.AnimationTemplate - uint animationTemplateHandle; - if ((animationTemplateHandle = *reinterpret_cast<uint *>(my_checkudata(L, idx, ANIMATION_TEMPLATE_CLASS_NAME))) != 0) { + uint animationTemplateHandle = *reinterpret_cast<uint *>(LuaBindhelper::my_checkudata(L, idx, ANIMATION_TEMPLATE_CLASS_NAME)); + if (animationTemplateHandle != 0) { AnimationTemplate *animationTemplatePtr = AnimationTemplateRegistry::instance().resolveHandle(animationTemplateHandle); if (!animationTemplatePtr) luaL_error(L, "The animation template with the handle %d does no longer exist.", animationTemplateHandle); @@ -370,10 +350,10 @@ static const luaL_reg GFX_FUNCTIONS[] = { static RenderObjectPtr<RenderObject> checkRenderObject(lua_State *L, bool errorIfRemoved = true) { // Der erste Parameter muss vom Typ userdata sein und die Metatable einer Klasse haben, die von Gfx.RenderObject "erbt". uint *userDataPtr; - if ((userDataPtr = (uint *) my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0 || - (userDataPtr = (uint *) my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0 || - (userDataPtr = (uint *) my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0 || - (userDataPtr = (uint *) my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0) { + if ((userDataPtr = (uint *)LuaBindhelper::my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0 || + (userDataPtr = (uint *)LuaBindhelper::my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0 || + (userDataPtr = (uint *)LuaBindhelper::my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0 || + (userDataPtr = (uint *)LuaBindhelper::my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0) { RenderObjectPtr<RenderObject> roPtr(*userDataPtr); if (roPtr.isValid()) return roPtr; @@ -600,11 +580,11 @@ static const luaL_reg RENDEROBJECT_METHODS[] = { static RenderObjectPtr<Panel> checkPanel(lua_State *L) { // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Panel uint *userDataPtr; - if ((userDataPtr = (uint *)my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0) { + if ((userDataPtr = (uint *)LuaBindhelper::my_checkudata(L, 1, PANEL_CLASS_NAME)) != 0) { RenderObjectPtr<RenderObject> roPtr(*userDataPtr); - if (roPtr.isValid()) { + if (roPtr.isValid()) return roPtr->toPanel(); - } else + else luaL_error(L, "The panel with the handle %d does no longer exist.", *userDataPtr); } else { luaL_argcheck(L, 0, 1, "'" PANEL_CLASS_NAME "' expected"); @@ -645,11 +625,11 @@ static const luaL_reg PANEL_METHODS[] = { static RenderObjectPtr<Bitmap> checkBitmap(lua_State *L) { // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Bitmap uint *userDataPtr; - if ((userDataPtr = (uint *)my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0) { + if ((userDataPtr = (uint *)LuaBindhelper::my_checkudata(L, 1, BITMAP_CLASS_NAME)) != 0) { RenderObjectPtr<RenderObject> roPtr(*userDataPtr); - if (roPtr.isValid()) { + if (roPtr.isValid()) return roPtr->toBitmap(); - } else + else luaL_error(L, "The bitmap with the handle %d does no longer exist.", *userDataPtr); } else { luaL_argcheck(L, 0, 1, "'" BITMAP_CLASS_NAME "' expected"); @@ -790,13 +770,12 @@ static const luaL_reg BITMAP_METHODS[] = { static RenderObjectPtr<Animation> checkAnimation(lua_State *L) { // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Animation uint *userDataPtr; - if ((userDataPtr = (uint *)my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0) { + if ((userDataPtr = (uint *)LuaBindhelper::my_checkudata(L, 1, ANIMATION_CLASS_NAME)) != 0) { RenderObjectPtr<RenderObject> roPtr(*userDataPtr); if (roPtr.isValid()) return roPtr->toAnimation(); - else { + else luaL_error(L, "The animation with the handle %d does no longer exist.", *userDataPtr); - } } else { luaL_argcheck(L, 0, 1, "'" ANIMATION_CLASS_NAME "' expected"); } @@ -1064,7 +1043,7 @@ static const luaL_reg ANIMATION_METHODS[] = { static RenderObjectPtr<Text> checkText(lua_State *L) { // Der erste Parameter muss vom Typ userdata sein und die Metatable der Klasse Gfx.Text uint *userDataPtr; - if ((userDataPtr = (uint *)my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0) { + if ((userDataPtr = (uint *)LuaBindhelper::my_checkudata(L, 1, TEXT_CLASS_NAME)) != 0) { RenderObjectPtr<RenderObject> roPtr(*userDataPtr); if (roPtr.isValid()) return roPtr->toText(); diff --git a/engines/sword25/math/geometry_script.cpp b/engines/sword25/math/geometry_script.cpp index 6562a0f0a5..4b5e0550fe 100644 --- a/engines/sword25/math/geometry_script.cpp +++ b/engines/sword25/math/geometry_script.cpp @@ -51,27 +51,6 @@ namespace Sword25 { #define REGION_CLASS_NAME "Geo.Region" #define WALKREGION_CLASS_NAME "Geo.WalkRegion" -// How luaL_checkudata, only without that no error is generated. -static void *my_checkudata(lua_State *L, int ud, const char *tname) { - int top = lua_gettop(L); - - void *p = lua_touserdata(L, ud); - if (p != NULL) { /* value is a userdata? */ - if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ - // lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ - LuaBindhelper::getMetatable(L, tname); - /* does it have the correct mt? */ - if (lua_rawequal(L, -1, -2)) { - lua_settop(L, top); - return p; - } - } - } - - lua_settop(L, top); - return NULL; -} - static void newUintUserData(lua_State *L, uint value) { void *userData = lua_newuserdata(L, sizeof(value)); memcpy(userData, &value, sizeof(value)); @@ -276,9 +255,9 @@ static const luaL_reg GEO_FUNCTIONS[] = { static Region *checkRegion(lua_State *L) { // The first parameter must be of type 'userdata', and the Metatable class Geo.Region or Geo.WalkRegion - uint *regionHandlePtr; - if ((regionHandlePtr = reinterpret_cast<uint *>(my_checkudata(L, 1, REGION_CLASS_NAME))) != 0 || - (regionHandlePtr = reinterpret_cast<uint *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) { + uint *regionHandlePtr = reinterpret_cast<uint *>(LuaBindhelper::my_checkudata(L, 1, REGION_CLASS_NAME)); + if (regionHandlePtr != 0 || + (regionHandlePtr = reinterpret_cast<uint *>(LuaBindhelper::my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) { return RegionRegistry::instance().resolveHandle(*regionHandlePtr); } else { luaL_argcheck(L, 0, 1, "'" REGION_CLASS_NAME "' expected"); @@ -398,7 +377,7 @@ static const luaL_reg REGION_METHODS[] = { static WalkRegion *checkWalkRegion(lua_State *L) { // The first parameter must be of type 'userdate', and the Metatable class Geo.WalkRegion uint regionHandle; - if ((regionHandle = *reinterpret_cast<uint *>(my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) { + if ((regionHandle = *reinterpret_cast<uint *>(LuaBindhelper::my_checkudata(L, 1, WALKREGION_CLASS_NAME))) != 0) { return reinterpret_cast<WalkRegion *>(RegionRegistry::instance().resolveHandle(regionHandle)); } else { luaL_argcheck(L, 0, 1, "'" WALKREGION_CLASS_NAME "' expected"); diff --git a/engines/sword25/script/luabindhelper.cpp b/engines/sword25/script/luabindhelper.cpp index 5ff9708b95..03a1802a04 100644 --- a/engines/sword25/script/luabindhelper.cpp +++ b/engines/sword25/script/luabindhelper.cpp @@ -303,6 +303,27 @@ bool LuaBindhelper::getMetatable(lua_State *L, const Common::String &tableName) return true; } +// Like luaL_checkudata, only without that no error is generated. +void *LuaBindhelper::my_checkudata(lua_State *L, int ud, const char *tname) { + int top = lua_gettop(L); + + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + // lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */ + LuaBindhelper::getMetatable(L, tname); + if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */ + lua_settop(L, top); + return p; + } + } + } + + lua_settop(L, top); + return NULL; +} + + bool LuaBindhelper::createTable(lua_State *L, const Common::String &tableName) { const char *partBegin = tableName.c_str(); diff --git a/engines/sword25/script/luabindhelper.h b/engines/sword25/script/luabindhelper.h index dc45104d53..94f52743f3 100644 --- a/engines/sword25/script/luabindhelper.h +++ b/engines/sword25/script/luabindhelper.h @@ -110,6 +110,8 @@ public: static bool getMetatable(lua_State *L, const Common::String &tableName); + static void *my_checkudata(lua_State *L, int ud, const char *tname); + private: static bool createTable(lua_State *L, const Common::String &tableName); }; diff --git a/engines/sword25/sword25.cpp b/engines/sword25/sword25.cpp index 55b9aa340d..aac21f4b55 100644 --- a/engines/sword25/sword25.cpp +++ b/engines/sword25/sword25.cpp @@ -56,6 +56,8 @@ const char *const DEFAULT_SCRIPT_FILE = "/system/boot.lua"; Sword25Engine::Sword25Engine(OSystem *syst, const ADGameDescription *gameDesc): Engine(syst), _gameDescription(gameDesc) { + // Setup mixer + syncSoundSettings(); DebugMan.addDebugChannel(kDebugScript, "Script", "Script debug level"); DebugMan.addDebugChannel(kDebugScript, "Scripts", "Script debug level"); diff --git a/engines/sword25/util/lua/lmathlib.cpp b/engines/sword25/util/lua/lmathlib.cpp index bb9c6ed442..7e64d75789 100644 --- a/engines/sword25/util/lua/lmathlib.cpp +++ b/engines/sword25/util/lua/lmathlib.cpp @@ -6,6 +6,11 @@ #include <stdlib.h> +// MSVC does not define M_PI, M_SQRT2 and other math defines by default. +// _USE_MATH_DEFINES must be defined in order to have these defined, thus +// we enable it here. For more information, check: +// http://msdn.microsoft.com/en-us/library/4hwaceh6(v=VS.100).aspx +#define _USE_MATH_DEFINES #include <math.h> #define lmathlib_c diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp index 97d533f29f..6b47a7fc4d 100644 --- a/engines/touche/touche.cpp +++ b/engines/touche/touche.cpp @@ -44,7 +44,6 @@ namespace Touche { ToucheEngine::ToucheEngine(OSystem *system, Common::Language language) : Engine(system), _midiPlayer(0), _language(language) { - _saveLoadCurrentPage = 0; _saveLoadCurrentSlot = 0; _hideInventoryTexts = false; @@ -103,9 +102,8 @@ Common::Error ToucheEngine::run() { _midiPlayer = new MidiPlayer; - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + // Setup mixer + syncSoundSettings(); res_openDataFile(); res_allocateTables(); @@ -245,10 +243,9 @@ Common::Point ToucheEngine::getMousePos() const { } void ToucheEngine::syncSoundSettings() { + Engine::syncSoundSettings(); + readConfigurationSettings(); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); } void ToucheEngine::mainLoop() { diff --git a/engines/tucker/detection.cpp b/engines/tucker/detection.cpp index f0437d2f87..7404abc2e7 100644 --- a/engines/tucker/detection.cpp +++ b/engines/tucker/detection.cpp @@ -122,8 +122,8 @@ static const ADParams detectionParams = { 0, // Flags 0, - // Additional GUI options (for every game} - Common::GUIO_NOLAUNCHLOAD, + // Additional GUI options (for every game) + Common::GUIO_NONE, // Maximum directory depth 1, // List of directory globs @@ -156,6 +156,7 @@ public: virtual bool hasFeature(MetaEngineFeature f) const { switch (f) { case kSupportsListSaves: + case kSupportsLoadingDuringStartup: case kSupportsDeleteSave: return true; default: diff --git a/engines/tucker/tucker.cpp b/engines/tucker/tucker.cpp index 6e44eadc47..e41cbfbeef 100644 --- a/engines/tucker/tucker.cpp +++ b/engines/tucker/tucker.cpp @@ -68,12 +68,6 @@ Common::Error TuckerEngine::run() { return Common::kNoError; } -void TuckerEngine::syncSoundSettings() { - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); -} - int TuckerEngine::getRandomNumber() { return _rnd.getRandomNumber(0x7FFF); } @@ -130,10 +124,7 @@ void TuckerEngine::restart() { _timerCounter2 = 0; _partNum = _currentPartNum = 0; _locationNum = 0; - _nextLocationNum = ConfMan.getInt("boot_param"); - if (_nextLocationNum == 0) { - _nextLocationNum = (_gameFlags & kGameFlagDemo) == 0 ? kStartupLocationGame : kStartupLocationDemo; - } + _nextLocationNum = (_gameFlags & kGameFlagDemo) == 0 ? kStartupLocationGame : kStartupLocationDemo; _gamePaused = false; _gameDebug = false; _displayGameHints = false; @@ -359,6 +350,15 @@ void TuckerEngine::mainLoop() { _spriteAnimationFrameIndex = _spriteAnimationsTable[14].firstFrameIndex; + if (ConfMan.hasKey("save_slot")) { + const int slot = ConfMan.getInt("save_slot"); + if (slot >= 0 && slot <= kLastSaveSlot) { + loadGameState(slot); + } + } else if (ConfMan.hasKey("boot_param")) { + _nextLocationNum = ConfMan.getInt("boot_param"); + } + do { ++_syncCounter; if (_flagsTable[137] != _flagsTable[138]) { diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h index fd931998e4..532892fd48 100644 --- a/engines/tucker/tucker.h +++ b/engines/tucker/tucker.h @@ -280,7 +280,6 @@ public: virtual Common::Error run(); virtual bool hasFeature(EngineFeature f) const; - virtual void syncSoundSettings(); GUI::Debugger *getDebugger() { return _console; } protected: diff --git a/video/qt_decoder.h b/video/qt_decoder.h index e876097dfd..f11689e021 100644 --- a/video/qt_decoder.h +++ b/video/qt_decoder.h @@ -122,6 +122,7 @@ public: // SeekableVideoDecoder API void seekToFrame(uint32 frame); void seekToTime(Audio::Timestamp time); + uint32 getDuration() const { return _duration * 1000 / _timeScale; } private: // This is the file handle from which data is read from. It can be the actual file handle or a decompressed stream. diff --git a/video/video_decoder.h b/video/video_decoder.h index 97cd133bc0..348b5dc0a3 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -266,6 +266,11 @@ public: * Implementation of RewindableVideoDecoder::rewind(). */ virtual void rewind() { seekToTime(0); } + + /** + * Get the total duration of the video (in ms). + */ + virtual uint32 getDuration() const = 0; }; } // End of namespace Video |