diff options
author | Paul Gilbert | 2016-07-26 19:48:14 -0400 |
---|---|---|
committer | Paul Gilbert | 2016-07-26 19:48:14 -0400 |
commit | 504cf6ecb688a3f1c65a857bffd527d8b0e6ba63 (patch) | |
tree | 0c0d96d4061c11850c851f0fc981c75a58c20515 /engines/mohawk | |
parent | d8c28d15ae553d047b7e571f98727fa79ee143f3 (diff) | |
parent | e19922d181e775791f9105b8be7ff410770ede51 (diff) | |
download | scummvm-rg350-504cf6ecb688a3f1c65a857bffd527d8b0e6ba63.tar.gz scummvm-rg350-504cf6ecb688a3f1c65a857bffd527d8b0e6ba63.tar.bz2 scummvm-rg350-504cf6ecb688a3f1c65a857bffd527d8b0e6ba63.zip |
Merge branch 'master' into xeen
Diffstat (limited to 'engines/mohawk')
61 files changed, 2431 insertions, 1416 deletions
diff --git a/engines/mohawk/POTFILES b/engines/mohawk/POTFILES index 54d9dcaa3a..036059da6a 100644 --- a/engines/mohawk/POTFILES +++ b/engines/mohawk/POTFILES @@ -1,3 +1,4 @@ +engines/mohawk/detection.cpp engines/mohawk/dialogs.cpp engines/mohawk/myst.cpp engines/mohawk/riven.cpp diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp index 6435daf46f..d8c6d6aacd 100644 --- a/engines/mohawk/bitmap.cpp +++ b/engines/mohawk/bitmap.cpp @@ -53,6 +53,16 @@ MohawkBitmap::MohawkBitmap() { _drawTable = drawTable; _drawTableSize = ARRAYSIZE(drawTable); + + _header.width = 0; + _header.height = 0; + _header.bytesPerRow = 0; + _header.format = 0; + _header.colorTable.colorCount = 0; + _header.colorTable.palette = nullptr; + _header.colorTable.rgbBits = 0; + _header.colorTable.tableSize = 0; + _data = nullptr; } MohawkBitmap::~MohawkBitmap() { diff --git a/engines/mohawk/configure.engine b/engines/mohawk/configure.engine index 47402c4560..ccb9499ef0 100644 --- a/engines/mohawk/configure.engine +++ b/engines/mohawk/configure.engine @@ -1,6 +1,6 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books" +add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books" "highres" add_engine cstime "Where in Time is Carmen Sandiego?" no add_engine riven "Riven: The Sequel to Myst" no "" "" "16bit" -add_engine myst "Myst" no +add_engine myst "Myst" yes diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index 9b5bae78be..fd79e53b07 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -63,6 +63,8 @@ MystConsole::MystConsole(MohawkEngine_Myst *vm) : GUI::Debugger(), _vm(vm) { registerCmd("disableInitOpcodes", WRAP_METHOD(MystConsole, Cmd_DisableInitOpcodes)); registerCmd("cache", WRAP_METHOD(MystConsole, Cmd_Cache)); registerCmd("resources", WRAP_METHOD(MystConsole, Cmd_Resources)); + registerCmd("quickTest", WRAP_METHOD(MystConsole, Cmd_QuickTest)); + registerVar("show_resource_rects", &_vm->_showResourceRects); } MystConsole::~MystConsole() { @@ -119,7 +121,7 @@ static const uint16 default_start_card[12] = { 10000, 2000, 5038, - 2, // TODO: Should be 1? + 1, 1, 6122, 4134, @@ -329,6 +331,44 @@ bool MystConsole::Cmd_Resources(int argc, const char **argv) { return true; } +bool MystConsole::Cmd_QuickTest(int argc, const char **argv) { + // Go through all the ages, all the views and click random stuff + for (uint i = 0; i < ARRAYSIZE(mystStackNames); i++) { + if (i == 2 || i == 5 || i == 9 || i == 10) continue; + debug("Loading stack %s", mystStackNames[i]); + _vm->changeToStack(i, default_start_card[i], 0, 0); + + Common::Array<uint16> ids = _vm->getResourceIDList(ID_VIEW); + for (uint j = 0; j < ids.size(); j++) { + if (ids[j] == 4632) continue; + + debug("Loading card %d", ids[j]); + _vm->changeToCard(ids[j], kTransitionCopy); + + _vm->_video->updateMovies(); + _vm->_scriptParser->runPersistentScripts(); + _vm->_system->updateScreen(); + + int16 resIndex = _vm->_rnd->getRandomNumber(_vm->_resources.size()) - 1; + if (resIndex >= 0 && _vm->_resources[resIndex]->isEnabled()) { + _vm->_resources[resIndex]->handleMouseDown(); + _vm->_resources[resIndex]->handleMouseUp(); + } + + _vm->_video->updateMovies(); + _vm->_scriptParser->runPersistentScripts(); + _vm->_system->updateScreen(); + + if (_vm->getCurStack() != i) { + // Clicking may have linked us to another age + _vm->changeToStack(i, default_start_card[i], 0, 0); + } + } + } + + return true; +} + #endif // ENABLE_MYST #ifdef ENABLE_RIVEN diff --git a/engines/mohawk/console.h b/engines/mohawk/console.h index af01c0d1e0..dc40049a89 100644 --- a/engines/mohawk/console.h +++ b/engines/mohawk/console.h @@ -55,6 +55,7 @@ private: bool Cmd_DisableInitOpcodes(int argc, const char **argv); bool Cmd_Cache(int argc, const char **argv); bool Cmd_Resources(int argc, const char **argv); + bool Cmd_QuickTest(int argc, const char **argv); }; #endif diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h index f95222d3a1..bfb7daf945 100644 --- a/engines/mohawk/cstime.h +++ b/engines/mohawk/cstime.h @@ -111,7 +111,7 @@ enum { }; struct CSTimeEvent { - CSTimeEvent() { } + CSTimeEvent() : type(0), param1(0), param2(0) { } CSTimeEvent(uint16 t, uint16 p1, uint16 p2) : type(t), param1(p1), param2(p2) { } uint16 type; diff --git a/engines/mohawk/cstime_game.cpp b/engines/mohawk/cstime_game.cpp index 8eced701c3..c939d8bc24 100644 --- a/engines/mohawk/cstime_game.cpp +++ b/engines/mohawk/cstime_game.cpp @@ -94,6 +94,11 @@ CSTimeChar::CSTimeChar(MohawkEngine_CSTime *vm, CSTimeScene *scene, uint id) : _ _lastTime2 = 0; _lastTime3 = 0; + _unknown1 = _unknown2 = _unknown3 = 0; + _enabled = false; + _nextCue = 0; + _waveStatus = 0; + _playingWaveId = 0; } diff --git a/engines/mohawk/cstime_ui.cpp b/engines/mohawk/cstime_ui.cpp index f3fe27a966..59be95adf6 100644 --- a/engines/mohawk/cstime_ui.cpp +++ b/engines/mohawk/cstime_ui.cpp @@ -79,6 +79,8 @@ CSTimeInterface::CSTimeInterface(MohawkEngine_CSTime *vm) : _vm(vm) { _rolloverTextFeature = NULL; _bubbleTextFeature = NULL; + _draggedItem = 0; + _mouseWasInScene = false; _state = kCSTimeInterfaceStateNormal; @@ -1034,6 +1036,8 @@ CSTimeInventoryDisplay::CSTimeInventoryDisplay(MohawkEngine_CSTime *vm, Common:: _cuffsState = false; _cuffsShape = 10; + _draggedItem = 0; + _invRect = baseRect; for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) { diff --git a/engines/mohawk/cstime_view.cpp b/engines/mohawk/cstime_view.cpp index 7879175bb0..8727560094 100644 --- a/engines/mohawk/cstime_view.cpp +++ b/engines/mohawk/cstime_view.cpp @@ -243,7 +243,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) { if ((feature->_flags & kFeatureNewDisable) || (feature->_flags & kFeatureNewDisableOnReset)) { feature->_data.enabled = 0; } - feature->_dirty = 1; + feature->_dirty = true; if (feature->_flags & kFeatureInternalRegion) { // TODO: create region [+140] (if not already done) } @@ -257,7 +257,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) { // TODO: or clip with bounds } } - feature->_dirty = 1; + feature->_dirty = true; if (feature->_flags & kFeatureNewInternalTiming) { feature->_nextTime += feature->_delayTime; } else { @@ -277,7 +277,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) { } feature->_data.currOffset = 26; - feature->_done = 0; + feature->_done = false; } if (feature->_flags & kFeatureNewDisable) feature->_data.enabled = 0; @@ -307,7 +307,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) { } case 0: // TODO: set ptr +176 to 1 - feature->_done = 1; + feature->_done = true; if (feature->_doneProc) { (this->*(feature->_doneProc))(feature); // TODO: with -1 } diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp index 4b66829e6a..72eebca917 100644 --- a/engines/mohawk/cursors.cpp +++ b/engines/mohawk/cursors.cpp @@ -34,8 +34,8 @@ #include "graphics/wincursor.h" #ifdef ENABLE_MYST -#include "mohawk/bitmap.h" #include "mohawk/myst.h" +#include "mohawk/myst_graphics.h" #endif namespace Mohawk { @@ -86,11 +86,9 @@ void DefaultCursorManager::setCursor(uint16 id) { #ifdef ENABLE_MYST MystCursorManager::MystCursorManager(MohawkEngine_Myst *vm) : _vm(vm) { - _bmpDecoder = new MystBitmap(); } MystCursorManager::~MystCursorManager() { - delete _bmpDecoder; } void MystCursorManager::showCursor() { @@ -111,17 +109,18 @@ void MystCursorManager::setCursor(uint16 id) { return; } - // Both Myst and Myst ME use the "MystBitmap" format for cursor images. - MohawkSurface *mhkSurface = _bmpDecoder->decodeImage(_vm->getResource(ID_WDIB, id)); - Graphics::Surface *surface = mhkSurface->getSurface(); Common::SeekableReadStream *clrcStream = _vm->getResource(ID_CLRC, id); uint16 hotspotX = clrcStream->readUint16LE(); uint16 hotspotY = clrcStream->readUint16LE(); delete clrcStream; + // Both Myst and Myst ME use the "MystBitmap" format for cursor images. + MohawkSurface *mhkSurface = _vm->_gfx->findImage(id); + Graphics::Surface *surface = mhkSurface->getSurface(); + // Myst ME stores some cursors as 24bpp images instead of 8bpp if (surface->format.bytesPerPixel == 1) { - CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, 0); + CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, 255); // We're using the screen palette for the original game, but we need // to use this for any 8bpp cursor in ME. @@ -133,7 +132,6 @@ void MystCursorManager::setCursor(uint16 id) { } _vm->_needsUpdate = true; - delete mhkSurface; } void MystCursorManager::setDefaultCursor() { diff --git a/engines/mohawk/cursors.h b/engines/mohawk/cursors.h index c41b5c273e..742ae30107 100644 --- a/engines/mohawk/cursors.h +++ b/engines/mohawk/cursors.h @@ -102,7 +102,6 @@ enum { }; class MohawkEngine_Myst; -class MystBitmap; // The cursor manager for Myst // Uses WDIB + CLRC resources @@ -119,7 +118,6 @@ public: private: MohawkEngine_Myst *_vm; - MystBitmap *_bmpDecoder; }; #endif // ENABLE_MYST diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp index 926c296257..246d3ec3c1 100644 --- a/engines/mohawk/detection.cpp +++ b/engines/mohawk/detection.cpp @@ -26,6 +26,7 @@ #include "common/savefile.h" #include "common/system.h" #include "common/textconsole.h" +#include "common/translation.h" #include "mohawk/livingbooks.h" @@ -35,10 +36,12 @@ #ifdef ENABLE_MYST #include "mohawk/myst.h" +#include "mohawk/myst_state.h" #endif #ifdef ENABLE_RIVEN #include "mohawk/riven.h" +#include "mohawk/riven_saveload.h" #endif namespace Mohawk { @@ -52,7 +55,7 @@ struct MohawkGameDescription { }; const char* MohawkEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 MohawkEngine::getFeatures() const { @@ -159,10 +162,24 @@ static const char *directoryGlobs[] = { 0 }; +static const ADExtraGuiOptionsMap optionsList[] = { + { + GAMEOPTION_PLAY_MYST_FLYBY, + { + _s("Play the Myst fly by movie"), + _s("The Myst fly by movie was not played by the original engine."), + "playmystflyby", + false + } + }, + + AD_EXTRA_GUI_OPTIONS_TERMINATOR +}; + class MohawkMetaEngine : public AdvancedMetaEngine { public: - MohawkMetaEngine() : AdvancedMetaEngine(Mohawk::gameDescriptions, sizeof(Mohawk::MohawkGameDescription), mohawkGames) { - _singleid = "mohawk"; + MohawkMetaEngine() : AdvancedMetaEngine(Mohawk::gameDescriptions, sizeof(Mohawk::MohawkGameDescription), mohawkGames, optionsList) { + _singleId = "mohawk"; _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } @@ -182,45 +199,107 @@ public: virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; virtual SaveStateList listSaves(const char *target) const; + SaveStateList listSavesForPrefix(const char *prefix, const char *extension) const; virtual int getMaximumSaveSlot() const { return 999; } virtual void removeSaveState(const char *target, int slot) const; + virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; }; bool MohawkMetaEngine::hasFeature(MetaEngineFeature f) const { return (f == kSupportsListSaves) || (f == kSupportsLoadingDuringStartup) - || (f == kSupportsDeleteSave); + || (f == kSupportsDeleteSave) + || (f == kSavesSupportMetaInfo) + || (f == kSavesSupportThumbnail) + || (f == kSavesSupportCreationDate) + || (f == kSavesSupportPlayTime); +} + +SaveStateList MohawkMetaEngine::listSavesForPrefix(const char *prefix, const char *extension) const { + Common::String pattern = Common::String::format("%s-###.%s", prefix, extension); + Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern); + size_t prefixLen = strlen(prefix); + + SaveStateList saveList; + for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { + // Extract the slot number from the filename + char slot[4]; + slot[0] = (*filename)[prefixLen + 1]; + slot[1] = (*filename)[prefixLen + 2]; + slot[2] = (*filename)[prefixLen + 3]; + slot[3] = '\0'; + + int slotNum = atoi(slot); + + saveList.push_back(SaveStateDescriptor(slotNum, "")); + } + + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); + + return saveList; } SaveStateList MohawkMetaEngine::listSaves(const char *target) const { - Common::StringArray filenames; SaveStateList saveList; // Loading games is only supported in Myst/Riven currently. +#ifdef ENABLE_MYST if (strstr(target, "myst")) { - filenames = g_system->getSavefileManager()->listSavefiles("*.mys"); - - for (uint32 i = 0; i < filenames.size(); i++) - saveList.push_back(SaveStateDescriptor(i, filenames[i])); - } else if (strstr(target, "riven")) { - filenames = g_system->getSavefileManager()->listSavefiles("*.rvn"); + saveList = listSavesForPrefix("myst", "mys"); - for (uint32 i = 0; i < filenames.size(); i++) - saveList.push_back(SaveStateDescriptor(i, filenames[i])); + for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) { + // Read the description from the save + int slot = save->getSaveSlot(); + Common::String description = Mohawk::MystGameState::querySaveDescription(slot); + save->setDescription(description); + } } +#endif +#ifdef ENABLE_RIVEN + if (strstr(target, "riven")) { + saveList = listSavesForPrefix("riven", "rvn"); + + for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) { + // Read the description from the save + int slot = save->getSaveSlot(); + Common::String description = Mohawk::RivenSaveLoad::querySaveDescription(slot); + save->setDescription(description); + } + } +#endif return saveList; } void MohawkMetaEngine::removeSaveState(const char *target, int slot) const { + // Removing saved games is only supported in Myst/Riven currently. +#ifdef ENABLE_MYST if (strstr(target, "myst")) { - Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.mys"); - g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str()); - } else if (strstr(target, "riven")) { - Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.rvn"); - g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str()); + Mohawk::MystGameState::deleteSave(slot); + } +#endif +#ifdef ENABLE_RIVEN + if (strstr(target, "riven")) { + Mohawk::RivenSaveLoad::deleteSave(slot); + } +#endif +} + +SaveStateDescriptor MohawkMetaEngine::querySaveMetaInfos(const char *target, int slot) const { +#ifdef ENABLE_MYST + if (strstr(target, "myst")) { + return Mohawk::MystGameState::querySaveMetaInfos(slot); + } +#endif +#ifdef ENABLE_RIVEN + if (strstr(target, "riven")) { + return Mohawk::RivenSaveLoad::querySaveMetaInfos(slot); + } else +#endif + { + return SaveStateDescriptor(); } } diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h index 6bb836b5b8..d9aba26ca3 100644 --- a/engines/mohawk/detection_tables.h +++ b/engines/mohawk/detection_tables.h @@ -22,6 +22,13 @@ namespace Mohawk { +#define GAMEOPTION_PLAY_MYST_FLYBY GUIO_GAMEOPTIONS1 + +#define GUI_OPTIONS_MYST GUIO3(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI) +#define GUI_OPTIONS_MYST_ME GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GAMEOPTION_PLAY_MYST_FLYBY) +#define GUI_OPTIONS_MYST_DEMO GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GUIO_NOLAUNCHLOAD) +#define GUI_OPTIONS_MYST_MAKING_OF GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GUIO_NOLAUNCHLOAD) + static const MohawkGameDescription gameDescriptions[] = { // Myst // English Windows 3.11 @@ -33,8 +40,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "ae3258c9c90128d274aa6a790b3ad181"), Common::EN_ANY, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -51,8 +58,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("DEMO.DAT", "c39303dd53fb5c4e7f3c23231c606cd0"), Common::EN_ANY, Common::kPlatformWindows, - ADGF_DEMO | ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_DEMO | ADGF_TESTING, + GUI_OPTIONS_MYST_DEMO }, GType_MYST, GF_DEMO, @@ -69,8 +76,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "4beb3366ed3f3b9bfb6e81a14a43bdcc"), Common::DE_DEU, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -87,8 +94,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "e0937cca1ab125e48e30dc3cd5046ddf"), Common::DE_DEU, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -105,8 +112,26 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "f7e7d7ca69934f1351b5acd4fe4d44c2"), Common::ES_ESP, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST + }, + GType_MYST, + 0, + 0, + }, + + // Myst + // Italian Windows ? + // From goodoldgeorg in bug #6895 + { + { + "myst", + "", + AD_ENTRY1("MYST.DAT", "a5795ce1751fc42525e4f9a1859181d5"), + Common::IT_ITA, + Common::kPlatformWindows, + ADGF_TESTING, + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -123,8 +148,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "032c88e3b7e8db4ca475e7b7db9a66bb"), Common::JA_JPN, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -141,8 +166,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "d631d42567a941c67c78f2e491f4ea58"), Common::FR_FRA, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -159,8 +184,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MAKING.DAT", "f6387e8f0f7b8a3e42c95294315d6a0e"), Common::EN_ANY, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST_MAKING_OF }, GType_MAKINGOF, 0, @@ -177,8 +202,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MAKING.DAT", "03ff62607e64419ab2b6ebf7b7bcdf63"), Common::JA_JPN, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST_MAKING_OF }, GType_MAKINGOF, 0, @@ -195,8 +220,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "c4cae9f143b5947262e6cb2397e1617e"), Common::EN_ANY, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -213,8 +238,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "f88e0ace66dbca78eebdaaa1d3314ceb"), Common::DE_DEU, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -231,8 +256,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "aea81633b2d2ae498f09072fb87263b6"), Common::FR_FRA, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -249,8 +274,8 @@ static const MohawkGameDescription gameDescriptions[] = { AD_ENTRY1("MYST.DAT", "4a05771b60f4a69869838d01e85c9e80"), Common::PL_POL, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -312,6 +337,24 @@ static const MohawkGameDescription gameDescriptions[] = { }, // Riven: The Sequel to Myst + // Version 1.0 (5CD), 1.02 (DVD, From "Myst: La Trilogie") + // From gamin + { + { + "riven", + "", + AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"), + Common::FR_FRA, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO1(GUIO_NOASPECT) + }, + GType_RIVEN, + 0, + 0, + }, + + // Riven: The Sequel to Myst // Version 1.0 (5CD) - Italian // From dodomorandi on bug #6629 { @@ -330,6 +373,40 @@ static const MohawkGameDescription gameDescriptions[] = { }, // Riven: The Sequel to Myst + // Version 1.0.0 (5CD) - Russian, Fargus + { + { + "riven", + "", + AD_ENTRY1s("a_Data.MHK", "2a840ed74fe5dc3a388bced674d379d5", 12024358), + Common::RU_RUS, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO1(GUIO_NOASPECT) + }, + GType_RIVEN, + 0, + 0, + }, + + // Riven: The Sequel to Myst + // Version 1.1 (5CD) - Russian, Fargus + { + { + "riven", + "", + AD_ENTRY1("a_Data.MHK", "59bd2e3ccbae2f1faa1b23a18dc316eb"), + Common::RU_RUS, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO1(GUIO_NOASPECT) + }, + GType_RIVEN, + 0, + 0, + }, + + // Riven: The Sequel to Myst // Version 1.? (DVD, From "Myst 10th Anniversary Edition") // From Clone2727 { @@ -366,14 +443,14 @@ static const MohawkGameDescription gameDescriptions[] = { }, // Riven: The Sequel to Myst - // Version ? (DVD, From "Myst: La Trilogie") - // From gamin + // Version 1.02 (DVD, From "Myst: Antologia") + // From pykman { { "riven", "", - AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"), - Common::FR_FRA, + AD_ENTRY1("a_Data.MHK", "733a710cf5f848b441ec72d988ab8a3d"), + Common::PL_POL, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) @@ -384,14 +461,13 @@ static const MohawkGameDescription gameDescriptions[] = { }, // Riven: The Sequel to Myst - // Version 1.02 (DVD, From "Myst: Antologia") - // From pykman + // Version 1.1 (DVD), Russan, Fargus { { "riven", - "", - AD_ENTRY1("a_Data.MHK", "733a710cf5f848b441ec72d988ab8a3d"), - Common::PL_POL, + "DVD", + AD_ENTRY1("a_Data.MHK", "b5f40e6e6b843bf3abea291faa0911f4"), + Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO1(GUIO_NOASPECT) @@ -1819,6 +1895,23 @@ static const MohawkGameDescription gameDescriptions[] = { "Living Books Player" }, + // From Matthew Winder in bug#6557 + // v1.0E, English, Windows + { + { + "arthurbday", + "", + AD_ENTRY1s("AB16B.LB", "c169be346de7b0bbfcd18761fc0a3e49", 3093), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV2, + 0, + 0, + }, + // From Torsten in bug#3422652 { { @@ -2041,6 +2134,22 @@ static const MohawkGameDescription gameDescriptions[] = { 0 }, + // From Matthew Winder in bug#6557 + { + { + "lilmonster", + "", + AD_ENTRY1s("lmasf.lb", "fcb665df1713d0411a41515efb20bebc", 4136), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOASPECT) + }, + GType_LIVINGBOOKSV2, + 0, + 0 + }, + // From afholman in bug#3309308 { { @@ -2645,8 +2754,8 @@ static const MohawkGameDescription fallbackDescs[] = { AD_ENTRY1(0, 0), Common::UNK_LANG, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -2660,8 +2769,8 @@ static const MohawkGameDescription fallbackDescs[] = { AD_ENTRY1(0, 0), Common::UNK_LANG, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST_MAKING_OF }, GType_MAKINGOF, 0, @@ -2675,8 +2784,8 @@ static const MohawkGameDescription fallbackDescs[] = { AD_ENTRY1(0, 0), Common::UNK_LANG, Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + ADGF_TESTING, + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp index ffc455286f..8c11e3a5e9 100644 --- a/engines/mohawk/dialogs.cpp +++ b/engines/mohawk/dialogs.cpp @@ -24,7 +24,7 @@ #include "mohawk/dialogs.h" #include "gui/gui-manager.h" -#include "gui/ThemeEngine.h" +#include "gui/saveload.h" #include "gui/widget.h" #include "common/system.h" #include "common/translation.h" @@ -82,39 +82,122 @@ enum { kWaterCmd = 'WATR', kDropCmd = 'DROP', kMapCmd = 'SMAP', - kMenuCmd = 'MENU' + kMenuCmd = 'MENU', + kSaveCmd = 'SAVE', + kLoadCmd = 'LOAD', + kQuitCmd = 'QUIT' }; +#if defined(ENABLE_MYST) || defined(ENABLE_RIVEN) + +MohawkOptionsDialog::MohawkOptionsDialog(MohawkEngine *vm) : + GUI::Dialog(0, 0, 360, 200), + _vm(vm) { + _loadButton = new GUI::ButtonWidget(this, 245, 25, 100, 25, _("~L~oad"), 0, kLoadCmd); + _saveButton = new GUI::ButtonWidget(this, 245, 60, 100, 25, _("~S~ave"), 0, kSaveCmd); + new GUI::ButtonWidget(this, 245, 95, 100, 25, _("~Q~uit"), 0, kQuitCmd); + + new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd); + new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd); + + _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); + _saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); +} + +MohawkOptionsDialog::~MohawkOptionsDialog() { + delete _loadDialog; + delete _saveDialog; +} + +void MohawkOptionsDialog::open() { + GUI::Dialog::open(); + + _loadButton->setEnabled(_vm->canLoadGameStateCurrently()); + _saveButton->setEnabled(_vm->canSaveGameStateCurrently()); +} + + +void MohawkOptionsDialog::save() { + int slot = _saveDialog->runModalWithCurrentTarget(); + + if (slot >= 0) { + Common::String result(_saveDialog->getResultString()); + if (result.empty()) { + // If the user was lazy and entered no save name, come up with a default name. + result = _saveDialog->createDefaultSaveDescription(slot); + } + + _vm->saveGameState(slot, result); + close(); + } +} + +void MohawkOptionsDialog::load() { + int slot = _loadDialog->runModalWithCurrentTarget(); + + if (slot >= 0) { + _vm->loadGameState(slot); + close(); + } +} + +void MohawkOptionsDialog::reflowLayout() { + const int screenW = g_system->getOverlayWidth(); + const int screenH = g_system->getOverlayHeight(); + + // Center the dialog + _x = (screenW - getWidth()) / 2; + _y = (screenH - getHeight()) / 2; + + GUI::Dialog::reflowLayout(); +} + + +void MohawkOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { + switch (cmd) { + case kLoadCmd: + load(); + break; + case kSaveCmd: + save(); + break; + case GUI::kCloseCmd: + close(); + break; + default: + GUI::Dialog::handleCommand(sender, cmd, data); + } +} + +#endif + #ifdef ENABLE_MYST -MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) { +MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : MohawkOptionsDialog(vm), _vm(vm) { // I18N: Option for fast scene switching - _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); - _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~T~ransitions Enabled"), 0, kTransCmd); + _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); + _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), 0, kTransCmd); // I18N: Drop book page _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd); // Myst ME only has maps if (_vm->getFeatures() & GF_ME) - _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("~S~how Map"), 0, kMapCmd); + _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), 0, kMapCmd); else _showMapButton = 0; // Myst demo only has a menu if (_vm->getFeatures() & GF_DEMO) - _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("~M~ain Menu"), 0, kMenuCmd); + _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd); else _returnToMenuButton = 0; - - new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd); - new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd); } MystOptionsDialog::~MystOptionsDialog() { } void MystOptionsDialog::open() { - Dialog::open(); + MohawkOptionsDialog::open(); _dropPageButton->setEnabled(_vm->_gameState->_globals.heldPage != 0); @@ -144,18 +227,30 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui case kMapCmd: _vm->_needsShowMap = true; close(); - break; + break; case kMenuCmd: _vm->_needsShowDemoMenu = true; close(); - break; + break; + case kQuitCmd: { + if (_vm->getGameType() != GType_MAKINGOF) { + _vm->_needsShowCredits = true; + } else { + Common::Event eventQ; + eventQ.type = Common::EVENT_QUIT; + g_system->getEventManager()->pushEvent(eventQ); + } + close(); + } + break; case GUI::kOKCmd: _vm->_gameState->_globals.zipMode = _zipModeCheckbox->getState(); _vm->_gameState->_globals.transitions = _transitionsCheckbox->getState(); - GUI::OptionsDialog::handleCommand(sender, cmd, data); + setResult(1); + close(); break; default: - GUI::OptionsDialog::handleCommand(sender, cmd, data); + MohawkOptionsDialog::handleCommand(sender, cmd, data); } } @@ -163,19 +258,18 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui #ifdef ENABLE_RIVEN -RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) { - _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); - _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd); - - new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd); - new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd); +RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) : + MohawkOptionsDialog(vm), + _vm(vm) { + _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); + _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd); } RivenOptionsDialog::~RivenOptionsDialog() { } void RivenOptionsDialog::open() { - Dialog::open(); + MohawkOptionsDialog::open(); _zipModeCheckbox->setState(_vm->_vars["azip"] != 0); _waterEffectCheckbox->setState(_vm->_vars["waterenabled"] != 0); @@ -183,17 +277,21 @@ void RivenOptionsDialog::open() { void RivenOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { switch (cmd) { - case kZipCmd: + case GUI::kOKCmd: _vm->_vars["azip"] = _zipModeCheckbox->getState() ? 1 : 0; - break; - case kWaterCmd: _vm->_vars["waterenabled"] = _waterEffectCheckbox->getState() ? 1 : 0; + setResult(1); + close(); break; - case GUI::kCloseCmd: + case kQuitCmd: { + Common::Event eventQ; + eventQ.type = Common::EVENT_QUIT; + g_system->getEventManager()->pushEvent(eventQ); close(); break; + } default: - GUI::OptionsDialog::handleCommand(sender, cmd, data); + MohawkOptionsDialog::handleCommand(sender, cmd, data); } } diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h index 7470cd3acd..3cfb628f9d 100644 --- a/engines/mohawk/dialogs.h +++ b/engines/mohawk/dialogs.h @@ -28,9 +28,14 @@ #include "common/events.h" #include "common/str.h" #include "gui/dialog.h" -#include "gui/options.h" -#include "gui/widget.h" -#include "gui/widgets/list.h" + +namespace GUI { +class SaveLoadChooser; +class ButtonWidget; +class CheckboxWidget; +class CommandSender; +class StaticTextWidget; +} namespace Mohawk { @@ -66,21 +71,50 @@ public: virtual void handleKeyDown(Common::KeyState state); }; +#if defined(ENABLE_MYST) || defined(ENABLE_RIVEN) + +class MohawkOptionsDialog : public GUI::Dialog { +public: + MohawkOptionsDialog(MohawkEngine *_vm); + virtual ~MohawkOptionsDialog(); + + virtual void open() override; + virtual void reflowLayout() override; + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override; + +private: + MohawkEngine *_vm; + + GUI::ButtonWidget *_loadButton; + GUI::ButtonWidget *_saveButton; + + GUI::SaveLoadChooser *_loadDialog; + GUI::SaveLoadChooser *_saveDialog; + + void save(); + void load(); +}; + +#endif + #ifdef ENABLE_MYST class MohawkEngine_Myst; -class MystOptionsDialog : public GUI::OptionsDialog { +class MystOptionsDialog : public MohawkOptionsDialog { public: MystOptionsDialog(MohawkEngine_Myst *vm); - ~MystOptionsDialog(); - void open(); + virtual ~MystOptionsDialog(); + + virtual void open() override; + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); - virtual void handleCommand(GUI::CommandSender*, uint32, uint32); private: MohawkEngine_Myst *_vm; + GUI::CheckboxWidget *_zipModeCheckbox; GUI::CheckboxWidget *_transitionsCheckbox; + GUI::ButtonWidget *_dropPageButton; GUI::ButtonWidget *_showMapButton; GUI::ButtonWidget *_returnToMenuButton; @@ -92,15 +126,17 @@ private: class MohawkEngine_Riven; -class RivenOptionsDialog : public GUI::OptionsDialog { +class RivenOptionsDialog : public MohawkOptionsDialog { public: RivenOptionsDialog(MohawkEngine_Riven *vm); - ~RivenOptionsDialog(); - void open(); + virtual ~RivenOptionsDialog(); + + virtual void open() override; + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override; - virtual void handleCommand(GUI::CommandSender*, uint32, uint32); private: MohawkEngine_Riven *_vm; + GUI::CheckboxWidget *_zipModeCheckbox; GUI::CheckboxWidget *_waterEffectCheckbox; }; diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h index 5f9b523e9a..f9fdeea15f 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -74,6 +74,10 @@ public: // Free all surfaces in the cache void clearCache(); + // findImage will search the cache to find the image. + // If not found, it will call decodeImage to get a new one. + MohawkSurface *findImage(uint16 id); + void preloadImage(uint16 image); virtual void setPalette(uint16 id); void copyAnimImageToScreen(uint16 image, int left = 0, int top = 0); @@ -85,10 +89,6 @@ public: protected: void copyAnimImageSectionToScreen(MohawkSurface *image, Common::Rect src, Common::Rect dest); - // findImage will search the cache to find the image. - // If not found, it will call decodeImage to get a new one. - MohawkSurface *findImage(uint16 id); - // decodeImage will always return a new image. virtual MohawkSurface *decodeImage(uint16 id) = 0; virtual Common::Array<MohawkSurface *> decodeImages(uint16 id); diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h index 6fa733e38e..ac91dca971 100644 --- a/engines/mohawk/mohawk.h +++ b/engines/mohawk/mohawk.h @@ -20,8 +20,8 @@ * */ -#ifndef MOHAWK_H -#define MOHAWK_H +#ifndef MOHAWK_MOHAWK_H +#define MOHAWK_MOHAWK_H #include "common/scummsys.h" #include "common/array.h" diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index b6a6c27329..633b67f7e9 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -66,38 +66,22 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription DebugMan.addDebugChannel(kDebugHelp, "Help", "Track Help File (HELP) Parsing"); DebugMan.addDebugChannel(kDebugCache, "Cache", "Track Resource Cache Accesses"); - // Engine tweaks - // Disabling this makes engine behavior as per - // original, including bugs, missing bits etc. :) - _tweaksEnabled = true; - _currentCursor = 0; _mainCursor = kDefaultMystCursor; _showResourceRects = false; _curCard = 0; _needsUpdate = false; + _canSafelySaveLoad = false; _curResource = -1; - _hoverResource = 0; - _dragResource = 0; - - _gfx = NULL; - _console = NULL; - _scriptParser = NULL; - _gameState = NULL; - _loadDialog = NULL; - _optionsDialog = NULL; - - _cursorHintCount = 0; - _cursorHints = NULL; - - _prevStack = NULL; - - _view.conditionalImageCount = 0; - _view.conditionalImages = NULL; - _view.soundList = NULL; - _view.soundListVolume = NULL; - _view.scriptResCount = 0; - _view.scriptResources = NULL; + _hoverResource = nullptr; + + _gfx = nullptr; + _console = nullptr; + _scriptParser = nullptr; + _gameState = nullptr; + _optionsDialog = nullptr; + + _prevStack = nullptr; } MohawkEngine_Myst::~MohawkEngine_Myst() { @@ -107,20 +91,12 @@ MohawkEngine_Myst::~MohawkEngine_Myst() { delete _console; delete _scriptParser; delete _gameState; - delete _loadDialog; delete _optionsDialog; delete _prevStack; delete _rnd; - delete[] _cursorHints; - - delete[] _view.conditionalImages; - delete[] _view.scriptResources; - for (uint32 i = 0; i < _resources.size(); i++) delete _resources[i]; - - _resources.clear(); } // Uses cached data objects in preference to disk access @@ -138,7 +114,11 @@ Common::SeekableReadStream *MohawkEngine_Myst::getResource(uint32 tag, uint16 id } error("Could not find a \'%s\' resource with ID %04x", tag2str(tag), id); - return NULL; + return nullptr; +} + +Common::Array<uint16> MohawkEngine_Myst::getResourceIDList(uint32 type) const { + return _mhk[0]->getResourceIDList(type); } void MohawkEngine_Myst::cachePreload(uint32 tag, uint16 id) { @@ -242,7 +222,6 @@ Common::Error MohawkEngine_Myst::run() { _gfx = new MystGraphics(this); _console = new MystConsole(this); _gameState = new MystGameState(this, _saveFileMan); - _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); _optionsDialog = new MystOptionsDialog(this); _cursor = new MystCursorManager(this); _rnd = new Common::RandomSource("myst"); @@ -251,12 +230,10 @@ Common::Error MohawkEngine_Myst::run() { _cursor->showCursor(); // Load game from launcher/command line if requested - if (ConfMan.hasKey("save_slot") && canLoadGameStateCurrently()) { - uint32 gameToLoad = ConfMan.getInt("save_slot"); - Common::StringArray savedGamesList = _gameState->generateSaveGameList(); - if (gameToLoad > savedGamesList.size()) - error ("Could not find saved game"); - _gameState->load(savedGamesList[gameToLoad]); + if (ConfMan.hasKey("save_slot") && hasGameSaveSupport()) { + int saveSlot = ConfMan.getInt("save_slot"); + if (!_gameState->load(saveSlot)) + error("Failed to load save game from slot %i", saveSlot); } else { // Start us on the first stack. if (getGameType() == GType_MAKINGOF) @@ -284,7 +261,7 @@ Common::Error MohawkEngine_Myst::run() { _needsUpdate = _video->updateMovies(); _scriptParser->runPersistentScripts(); - while (_eventMan->pollEvent(event)) { + while (pollEvent(event)) { switch (event.type) { case Common::EVENT_MOUSEMOVE: { _needsUpdate = true; @@ -324,17 +301,15 @@ Common::Error MohawkEngine_Myst::run() { case Common::KEYCODE_SPACE: pauseGame(); break; - case Common::KEYCODE_F4: - _showResourceRects = !_showResourceRects; - if (_showResourceRects) - drawResourceRects(); - break; case Common::KEYCODE_F5: _needsPageDrop = false; _needsShowMap = false; _needsShowDemoMenu = false; + _needsShowCredits = false; + _canSafelySaveLoad = true; runDialog(*_optionsDialog); + _canSafelySaveLoad = false; if (_needsPageDrop) { dropPage(); @@ -350,6 +325,12 @@ Common::Error MohawkEngine_Myst::run() { changeToStack(kDemoStack, 2002, 0, 0); _needsShowDemoMenu = false; } + + if (_needsShowCredits) { + _cursor->hideCursor(); + changeToStack(kCreditsStack, 10000, 0, 0); + _needsShowCredits = false; + } break; default: break; @@ -372,6 +353,15 @@ Common::Error MohawkEngine_Myst::run() { return Common::kNoError; } +bool MohawkEngine_Myst::pollEvent(Common::Event &event) { + // Saving / Loading is allowed from the GMM only when the main event loop is running + _canSafelySaveLoad = true; + bool eventReturned = _eventMan->pollEvent(event); + _canSafelySaveLoad = false; + + return eventReturned; +} + bool MohawkEngine_Myst::skippableWait(uint32 duration) { uint32 end = _system->getMillis() + duration; bool skipped = false; @@ -413,6 +403,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS // Fill screen with black and empty cursor _cursor->setCursor(0); + _currentCursor = 0; if (getFeatures() & GF_ME) _system->fillScreen(_system->getScreenFormat().RGBToColor(0, 0, 0)); @@ -502,7 +493,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS if (getFeatures() & GF_ME) { // Play Flyby Entry Movie on Masterpiece Edition. - const char *flyby = 0; + const char *flyby = nullptr; switch (_curStack) { case kSeleniticStack: @@ -512,8 +503,9 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS flyby = "stoneship flyby"; break; // Myst Flyby Movie not used in Original Masterpiece Edition Engine + // We play it when first arriving on Myst, and if the user has chosen so. case kMystStack: - if (_tweaksEnabled) + if (ConfMan.getBool("playmystflyby") && card == 4134) flyby = "myst flyby"; break; case kMechanicalStack: @@ -539,12 +531,12 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS uint16 MohawkEngine_Myst::getCardBackgroundId() { uint16 imageToDraw = 0; - if (_view.conditionalImageCount == 0) + if (_view.conditionalImages.size() == 0) imageToDraw = _view.mainImage; else { - for (uint16 i = 0; i < _view.conditionalImageCount; i++) { + for (uint16 i = 0; i < _view.conditionalImages.size(); i++) { uint16 varValue = _scriptParser->getVar(_view.conditionalImages[i].var); - if (varValue < _view.conditionalImages[i].numStates) + if (varValue < _view.conditionalImages[i].values.size()) imageToDraw = _view.conditionalImages[i].values[varValue]; } } @@ -586,36 +578,7 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) { drawCardBackground(); // Handle sound - int16 soundAction = 0; - uint16 soundActionVolume = 0; - - if (_view.sound == kMystSoundActionConditional) { - uint16 soundVarValue = _scriptParser->getVar(_view.soundVar); - if (soundVarValue >= _view.soundCount) - warning("Conditional sound variable outside range"); - else { - soundAction = _view.soundList[soundVarValue]; - soundActionVolume = _view.soundListVolume[soundVarValue]; - } - } else { - soundAction = _view.sound; - soundActionVolume = _view.soundVolume; - } - - if (soundAction == kMystSoundActionContinue) - debug(2, "Continuing with current sound"); - else if (soundAction == kMystSoundActionChangeVolume) { - debug(2, "Continuing with current sound, changing volume"); - _sound->changeBackgroundVolumeMyst(soundActionVolume); - } else if (soundAction == kMystSoundActionStop) { - debug(2, "Stopping sound"); - _sound->stopBackgroundMyst(); - } else if (soundAction > 0) { - debug(2, "Playing new sound %d", soundAction); - _sound->replaceBackgroundMyst(soundAction, soundActionVolume); - } else { - error("Unknown sound action %d", soundAction); - } + applySoundBlock(_view.soundBlock); if (_view.flags & kMystZipDestination) _gameState->addZipDest(_curStack, card); @@ -637,15 +600,17 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) { // Make sure the screen is updated if (transition != kNoTransition) { - if (!_gameState->_globals.transitions) - transition = kTransitionCopy; - - _gfx->runTransition(transition, Common::Rect(544, 333), 10, 0); + if (_gameState->_globals.transitions) { + _gfx->runTransition(transition, Common::Rect(544, 333), 10, 0); + } else { + _gfx->copyBackBufferToScreen(Common::Rect(544, 333)); + _system->updateScreen(); + _needsUpdate = false; + } } // Make sure we have the right cursor showing - _dragResource = 0; - _hoverResource = 0; + _hoverResource = nullptr; _curResource = -1; checkCurrentResource(); @@ -671,13 +636,13 @@ void MohawkEngine_Myst::checkCurrentResource() { // Tell previous resource the mouse is no longer hovering it if (_hoverResource && !_hoverResource->contains(mouse)) { _hoverResource->handleMouseLeave(); - _hoverResource = 0; + _hoverResource = nullptr; } for (uint16 i = 0; i < _resources.size(); i++) if (_resources[i]->contains(mouse)) { - if (_hoverResource != _resources[i] && _resources[i]->type == kMystHoverArea) { - _hoverResource = static_cast<MystResourceType13 *>(_resources[i]); + if (_hoverResource != _resources[i] && _resources[i]->type == kMystAreaHover) { + _hoverResource = static_cast<MystAreaHover *>(_resources[i]); _hoverResource->handleMouseEnter(); } @@ -694,17 +659,17 @@ void MohawkEngine_Myst::checkCurrentResource() { checkCursorHints(); } -MystResource *MohawkEngine_Myst::updateCurrentResource() { +MystArea *MohawkEngine_Myst::updateCurrentResource() { checkCurrentResource(); if (_curResource >= 0) return _resources[_curResource]; else - return 0; + return nullptr; } void MohawkEngine_Myst::loadCard() { - debugC(kDebugView, "Loading Card View:"); + debugC(kDebugView, "Loading Card View: %d", _curCard); Common::SeekableReadStream *viewStream = getResource(ID_VIEW, _curCard); @@ -713,21 +678,23 @@ void MohawkEngine_Myst::loadCard() { debugC(kDebugView, "Flags: 0x%04X", _view.flags); // The Image Block (Reminiscent of Riven PLST resources) - _view.conditionalImageCount = viewStream->readUint16LE(); - debugC(kDebugView, "Conditional Image Count: %d", _view.conditionalImageCount); - if (_view.conditionalImageCount != 0) { - _view.conditionalImages = new MystCondition[_view.conditionalImageCount]; - for (uint16 i = 0; i < _view.conditionalImageCount; i++) { + uint16 conditionalImageCount = viewStream->readUint16LE(); + debugC(kDebugView, "Conditional Image Count: %d", conditionalImageCount); + if (conditionalImageCount != 0) { + for (uint16 i = 0; i < conditionalImageCount; i++) { + MystCondition conditionalImage; + debugC(kDebugView, "\tImage %d:", i); - _view.conditionalImages[i].var = viewStream->readUint16LE(); - debugC(kDebugView, "\t\tVar: %d", _view.conditionalImages[i].var); - _view.conditionalImages[i].numStates = viewStream->readUint16LE(); - debugC(kDebugView, "\t\tNumber of States: %d", _view.conditionalImages[i].numStates); - _view.conditionalImages[i].values = new uint16[_view.conditionalImages[i].numStates]; - for (uint16 j = 0; j < _view.conditionalImages[i].numStates; j++) { - _view.conditionalImages[i].values[j] = viewStream->readUint16LE(); - debugC(kDebugView, "\t\tState %d -> Value %d", j, _view.conditionalImages[i].values[j]); + conditionalImage.var = viewStream->readUint16LE(); + debugC(kDebugView, "\t\tVar: %d", conditionalImage.var); + uint16 numStates = viewStream->readUint16LE(); + debugC(kDebugView, "\t\tNumber of States: %d", numStates); + for (uint16 j = 0; j < numStates; j++) { + conditionalImage.values.push_back(viewStream->readUint16LE()); + debugC(kDebugView, "\t\tState %d -> Value %d", j, conditionalImage.values[j]); } + + _view.conditionalImages.push_back(conditionalImage); } _view.mainImage = 0; } else { @@ -736,87 +703,58 @@ void MohawkEngine_Myst::loadCard() { } // The Sound Block (Reminiscent of Riven SLST resources) - _view.sound = viewStream->readSint16LE(); - debugCN(kDebugView, "Sound Control: %d = ", _view.sound); - if (_view.sound > 0) { - debugC(kDebugView, "Play new Sound, change volume"); - debugC(kDebugView, "\tSound: %d", _view.sound); - _view.soundVolume = viewStream->readUint16LE(); - debugC(kDebugView, "\tVolume: %d", _view.soundVolume); - } else if (_view.sound == kMystSoundActionContinue) - debugC(kDebugView, "Continue current sound"); - else if (_view.sound == kMystSoundActionChangeVolume) { - debugC(kDebugView, "Continue current sound, change volume"); - _view.soundVolume = viewStream->readUint16LE(); - debugC(kDebugView, "\tVolume: %d", _view.soundVolume); - } else if (_view.sound == kMystSoundActionStop) { - debugC(kDebugView, "Stop sound"); - } else if (_view.sound == kMystSoundActionConditional) { - debugC(kDebugView, "Conditional sound list"); - _view.soundVar = viewStream->readUint16LE(); - debugC(kDebugView, "\tVar: %d", _view.soundVar); - _view.soundCount = viewStream->readUint16LE(); - debugC(kDebugView, "\tCount: %d", _view.soundCount); - _view.soundList = new int16[_view.soundCount]; - _view.soundListVolume = new uint16[_view.soundCount]; - - for (uint16 i = 0; i < _view.soundCount; i++) { - _view.soundList[i] = viewStream->readSint16LE(); - debugC(kDebugView, "\t\tCondition %d: Action %d", i, _view.soundList[i]); - if (_view.soundList[i] == kMystSoundActionChangeVolume || _view.soundList[i] >= 0) { - _view.soundListVolume[i] = viewStream->readUint16LE(); - debugC(kDebugView, "\t\tCondition %d: Volume %d", i, _view.soundListVolume[i]); - } - } - } else { - debugC(kDebugView, "Unknown"); - warning("Unknown sound control value in card"); - } + _view.soundBlock = readSoundBlock(viewStream); // Resources that scripts can call upon - _view.scriptResCount = viewStream->readUint16LE(); - debugC(kDebugView, "Script Resource Count: %d", _view.scriptResCount); - if (_view.scriptResCount != 0) { - _view.scriptResources = new MystView::ScriptResource[_view.scriptResCount]; - for (uint16 i = 0; i < _view.scriptResCount; i++) { - debugC(kDebugView, "\tResource %d:", i); - _view.scriptResources[i].type = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t Type: %d", _view.scriptResources[i].type); - - switch (_view.scriptResources[i].type) { - case 1: - debugC(kDebugView, "\t\t\t\t= Image"); - break; - case 2: - debugC(kDebugView, "\t\t\t\t= Sound"); - break; - case 3: - debugC(kDebugView, "\t\t\t\t= Resource List"); - break; - default: - debugC(kDebugView, "\t\t\t\t= Unknown"); - break; - } + uint16 scriptResCount = viewStream->readUint16LE(); + debugC(kDebugView, "Script Resource Count: %d", scriptResCount); + for (uint16 i = 0; i < scriptResCount; i++) { + MystView::ScriptResource scriptResource; + + debugC(kDebugView, "\tResource %d:", i); + scriptResource.type = (MystView::ScriptResourceType) viewStream->readUint16LE(); + debugC(kDebugView, "\t\t Type: %d", scriptResource.type); + + switch (scriptResource.type) { + case MystView::kResourceImage: + debugC(kDebugView, "\t\t\t\t= Image"); + break; + case MystView::kResourceSound: + debugC(kDebugView, "\t\t\t\t= Sound"); + break; + case MystView::kResourceSwitch: + debugC(kDebugView, "\t\t\t\t= Resource Switch"); + break; + case MystView::kResourceImageNoCache: + debugC(kDebugView, "\t\t\t\t= Image - Caching disabled"); + break; + case MystView::kResourceSoundNoCache: + debugC(kDebugView, "\t\t\t\t= Sound - Caching disabled"); + break; + default: + debugC(kDebugView, "\t\t\t\t= Unknown"); + warning("Unknown script resource type '%d' in card '%d'", scriptResource.type, _curCard); + break; + } - if (_view.scriptResources[i].type == 3) { - _view.scriptResources[i].var = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t Var: %d", _view.scriptResources[i].var); - _view.scriptResources[i].count = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t Resource List Count: %d", _view.scriptResources[i].count); - _view.scriptResources[i].u0 = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t u0: %d", _view.scriptResources[i].u0); - _view.scriptResources[i].resource_list = new int16[_view.scriptResources[i].count]; - - for (uint16 j = 0; j < _view.scriptResources[i].count; j++) { - _view.scriptResources[i].resource_list[j] = viewStream->readSint16LE(); - debugC(kDebugView, "\t\t Resource List %d: %d", j, _view.scriptResources[i].resource_list[j]); - } - } else { - _view.scriptResources[i].resource_list = NULL; - _view.scriptResources[i].id = viewStream->readUint16LE(); - debugC(kDebugView, "\t\t Id: %d", _view.scriptResources[i].id); + if (scriptResource.type == MystView::kResourceSwitch) { + scriptResource.switchVar = viewStream->readUint16LE(); + debugC(kDebugView, "\t\t Var: %d", scriptResource.switchVar); + uint16 count = viewStream->readUint16LE(); + debugC(kDebugView, "\t\t Resource List Count: %d", count); + scriptResource.switchResourceType = (MystView::ScriptResourceType) viewStream->readUint16LE(); + debugC(kDebugView, "\t\t u0: %d", scriptResource.switchResourceType); + + for (uint16 j = 0; j < count; j++) { + scriptResource.switchResourceIds.push_back(viewStream->readSint16LE()); + debugC(kDebugView, "\t\t Resource List %d: %d", j, scriptResource.switchResourceIds[j]); } + } else { + scriptResource.id = viewStream->readUint16LE(); + debugC(kDebugView, "\t\t Id: %d", scriptResource.id); } + + _view.scriptResources.push_back(scriptResource); } // Identifiers for other resources. 0 if non existent. There is always an RLST. @@ -831,7 +769,6 @@ void MohawkEngine_Myst::loadCard() { delete viewStream; // Precache Card Resources - // TODO: Deal with Mac ME External Picture File uint32 cacheImageType; if (getFeatures() & GF_ME) cacheImageType = ID_PICT; @@ -839,63 +776,58 @@ void MohawkEngine_Myst::loadCard() { cacheImageType = ID_WDIB; // Precache Image Block data - if (_view.conditionalImageCount != 0) { - for (uint16 i = 0; i < _view.conditionalImageCount; i++) - for (uint16 j = 0; j < _view.conditionalImages[i].numStates; j++) - cachePreload(cacheImageType, _view.conditionalImages[i].values[j]); - } else + if (_view.conditionalImages.size() != 0) { + for (uint16 i = 0; i < _view.conditionalImages.size(); i++) { + uint16 value = _scriptParser->getVar(_view.conditionalImages[i].var); + cachePreload(cacheImageType, _view.conditionalImages[i].values[value]); + } + } else { cachePreload(cacheImageType, _view.mainImage); + } // Precache Sound Block data - if (_view.sound > 0) - cachePreload(ID_MSND, _view.sound); - else if (_view.sound == kMystSoundActionConditional) { - for (uint16 i = 0; i < _view.soundCount; i++) { - if (_view.soundList[i] > 0) - cachePreload(ID_MSND, _view.soundList[i]); + if (_view.soundBlock.sound > 0) + cachePreload(ID_MSND, _view.soundBlock.sound); + else if (_view.soundBlock.sound == kMystSoundActionConditional) { + uint16 value = _scriptParser->getVar(_view.soundBlock.soundVar); + if (_view.soundBlock.soundList[value].action > 0) { + cachePreload(ID_MSND, _view.soundBlock.soundList[value].action); } } // Precache Script Resources - if (_view.scriptResCount != 0) { - for (uint16 i = 0; i < _view.scriptResCount; i++) { - switch (_view.scriptResources[i].type) { - case 1: - cachePreload(cacheImageType, _view.scriptResources[i].id); - break; - case 2: - cachePreload(ID_MSND, _view.scriptResources[i].id); - break; - case 3: - warning("TODO: Precaching of Script Resource List not supported"); - break; - default: - warning("Unknown Resource in Script Resource List Precaching"); - break; - } + for (uint16 i = 0; i < _view.scriptResources.size(); i++) { + MystView::ScriptResourceType type; + int16 id; + if (_view.scriptResources[i].type == MystView::kResourceSwitch) { + type = _view.scriptResources[i].switchResourceType; + uint16 value = _scriptParser->getVar(_view.scriptResources[i].switchVar); + id = _view.scriptResources[i].switchResourceIds[value]; + } else { + type = _view.scriptResources[i].type; + id = _view.scriptResources[i].id; + } + + if (id < 0) continue; + + switch (type) { + case MystView::kResourceImage: + cachePreload(cacheImageType, id); + break; + case MystView::kResourceSound: + cachePreload(ID_MSND, id); + break; + default: + // The other resource types should not be cached + break; } } } void MohawkEngine_Myst::unloadCard() { - for (uint16 i = 0; i < _view.conditionalImageCount; i++) - delete[] _view.conditionalImages[i].values; - - delete[] _view.conditionalImages; - _view.conditionalImageCount = 0; - _view.conditionalImages = NULL; - - delete[] _view.soundList; - _view.soundList = NULL; - delete[] _view.soundListVolume; - _view.soundListVolume = NULL; - - for (uint16 i = 0; i < _view.scriptResCount; i++) - delete[] _view.scriptResources[i].resource_list; - - delete[] _view.scriptResources; - _view.scriptResources = NULL; - _view.scriptResCount = 0; + _view.conditionalImages.clear(); + _view.soundBlock.soundList.clear(); + _view.scriptResources.clear(); } void MohawkEngine_Myst::runInitScript() { @@ -968,14 +900,12 @@ void MohawkEngine_Myst::loadHelp(uint16 id) { debugC(kDebugHelp, "\thelpText: \"%s\"", helpText.c_str()); delete[] u0; + + delete helpStream; } void MohawkEngine_Myst::loadCursorHints() { - for (uint16 i = 0; i < _cursorHintCount; i++) - delete[] _cursorHints[i].variableHint.values; - _cursorHintCount = 0; - delete[] _cursorHints; - _cursorHints = NULL; + _cursorHints.clear(); if (!_view.hint) { debugC(kDebugHint, "No HINT Present"); @@ -985,33 +915,33 @@ void MohawkEngine_Myst::loadCursorHints() { debugC(kDebugHint, "Loading Cursor Hints:"); Common::SeekableReadStream *hintStream = getResource(ID_HINT, _curCard); - _cursorHintCount = hintStream->readUint16LE(); - debugC(kDebugHint, "Cursor Hint Count: %d", _cursorHintCount); - _cursorHints = new MystCursorHint[_cursorHintCount]; + uint16 cursorHintCount = hintStream->readUint16LE(); + debugC(kDebugHint, "Cursor Hint Count: %d", cursorHintCount); + + for (uint16 i = 0; i < cursorHintCount; i++) { + MystCursorHint hint; - for (uint16 i = 0; i < _cursorHintCount; i++) { debugC(kDebugHint, "Cursor Hint %d:", i); - _cursorHints[i].id = hintStream->readUint16LE(); - debugC(kDebugHint, "\tId: %d", _cursorHints[i].id); - _cursorHints[i].cursor = hintStream->readSint16LE(); - debugC(kDebugHint, "\tCursor: %d", _cursorHints[i].cursor); + hint.id = hintStream->readUint16LE(); + debugC(kDebugHint, "\tId: %d", hint.id); + hint.cursor = hintStream->readSint16LE(); + debugC(kDebugHint, "\tCursor: %d", hint.cursor); - if (_cursorHints[i].cursor == -1) { + if (hint.cursor == -1) { debugC(kDebugHint, "\tConditional Cursor Hints:"); - _cursorHints[i].variableHint.var = hintStream->readUint16LE(); - debugC(kDebugHint, "\tVar: %d", _cursorHints[i].variableHint.var); - _cursorHints[i].variableHint.numStates = hintStream->readUint16LE(); - debugC(kDebugHint, "\tNumber of States: %d", _cursorHints[i].variableHint.numStates); - _cursorHints[i].variableHint.values = new uint16[_cursorHints[i].variableHint.numStates]; - for (uint16 j = 0; j < _cursorHints[i].variableHint.numStates; j++) { - _cursorHints[i].variableHint.values[j] = hintStream->readUint16LE(); - debugC(kDebugHint, "\t\t State %d: Cursor %d", j, _cursorHints[i].variableHint.values[j]); + hint.variableHint.var = hintStream->readUint16LE(); + debugC(kDebugHint, "\tVar: %d", hint.variableHint.var); + uint16 numStates = hintStream->readUint16LE(); + debugC(kDebugHint, "\tNumber of States: %d", numStates); + for (uint16 j = 0; j < numStates; j++) { + hint.variableHint.values.push_back(hintStream->readUint16LE()); + debugC(kDebugHint, "\t\t State %d: Cursor %d", j, hint.variableHint.values[j]); } } else { - _cursorHints[i].variableHint.var = 0; - _cursorHints[i].variableHint.numStates = 0; - _cursorHints[i].variableHint.values = NULL; + hint.variableHint.var = 0; } + + _cursorHints.push_back(hint); } delete hintStream; @@ -1033,12 +963,12 @@ void MohawkEngine_Myst::checkCursorHints() { } // Check all the cursor hints to see if we're in a hotspot that contains a hint. - for (uint16 i = 0; i < _cursorHintCount; i++) + for (uint16 i = 0; i < _cursorHints.size(); i++) if (_cursorHints[i].id == _curResource && _resources[_cursorHints[i].id]->isEnabled()) { if (_cursorHints[i].cursor == -1) { uint16 var_value = _scriptParser->getVar(_cursorHints[i].variableHint.var); - if (var_value >= _cursorHints[i].variableHint.numStates) + if (var_value >= _cursorHints[i].variableHint.values.size()) warning("Variable %d Out of Range in variable HINT Resource %d", _cursorHints[i].variableHint.var, i); else { _currentCursor = _cursorHints[i].variableHint.values[var_value]; @@ -1076,50 +1006,50 @@ void MohawkEngine_Myst::drawResourceImages() { _resources[i]->drawDataToScreen(); } -void MohawkEngine_Myst::redrawResource(MystResourceType8 *resource, bool update) { - resource->drawConditionalDataToScreen(_scriptParser->getVar(resource->getType8Var()), update); +void MohawkEngine_Myst::redrawResource(MystAreaImageSwitch *resource, bool update) { + resource->drawConditionalDataToScreen(_scriptParser->getVar(resource->getImageSwitchVar()), update); } void MohawkEngine_Myst::redrawArea(uint16 var, bool update) { for (uint16 i = 0; i < _resources.size(); i++) - if (_resources[i]->type == kMystConditionalImage && _resources[i]->getType8Var() == var) - redrawResource(static_cast<MystResourceType8 *>(_resources[i]), update); + if (_resources[i]->type == kMystAreaImageSwitch && _resources[i]->getImageSwitchVar() == var) + redrawResource(static_cast<MystAreaImageSwitch *>(_resources[i]), update); } -MystResource *MohawkEngine_Myst::loadResource(Common::SeekableReadStream *rlstStream, MystResource *parent) { - MystResource *resource = 0; +MystArea *MohawkEngine_Myst::loadResource(Common::SeekableReadStream *rlstStream, MystArea *parent) { + MystArea *resource = nullptr; ResourceType type = static_cast<ResourceType>(rlstStream->readUint16LE()); debugC(kDebugResource, "\tType: %d", type); - debugC(kDebugResource, "\tSub_Record: %d", (parent == NULL) ? 0 : 1); + debugC(kDebugResource, "\tSub_Record: %d", (parent == nullptr) ? 0 : 1); switch (type) { - case kMystAction: - resource = new MystResourceType5(this, rlstStream, parent); + case kMystAreaAction: + resource = new MystAreaAction(this, rlstStream, parent); break; - case kMystVideo: - resource = new MystResourceType6(this, rlstStream, parent); + case kMystAreaVideo: + resource = new MystAreaVideo(this, rlstStream, parent); break; - case kMystSwitch: - resource = new MystResourceType7(this, rlstStream, parent); + case kMystAreaActionSwitch: + resource = new MystAreaActionSwitch(this, rlstStream, parent); break; - case kMystConditionalImage: - resource = new MystResourceType8(this, rlstStream, parent); + case kMystAreaImageSwitch: + resource = new MystAreaImageSwitch(this, rlstStream, parent); break; - case kMystSlider: - resource = new MystResourceType10(this, rlstStream, parent); + case kMystAreaSlider: + resource = new MystAreaSlider(this, rlstStream, parent); break; - case kMystDragArea: - resource = new MystResourceType11(this, rlstStream, parent); + case kMystAreaDrag: + resource = new MystAreaDrag(this, rlstStream, parent); break; case kMystVideoInfo: - resource = new MystResourceType12(this, rlstStream, parent); + resource = new MystVideoInfo(this, rlstStream, parent); break; - case kMystHoverArea: - resource = new MystResourceType13(this, rlstStream, parent); + case kMystAreaHover: + resource = new MystAreaHover(this, rlstStream, parent); break; default: - resource = new MystResource(this, rlstStream, parent); + resource = new MystArea(this, rlstStream, parent); break; } @@ -1145,34 +1075,37 @@ void MohawkEngine_Myst::loadResources() { for (uint16 i = 0; i < resourceCount; i++) { debugC(kDebugResource, "Resource #%d:", i); - _resources.push_back(loadResource(rlstStream, NULL)); + _resources.push_back(loadResource(rlstStream, nullptr)); } delete rlstStream; } Common::Error MohawkEngine_Myst::loadGameState(int slot) { - if (_gameState->load(_gameState->generateSaveGameList()[slot])) + if (_gameState->load(slot)) return Common::kNoError; return Common::kUnknownError; } Common::Error MohawkEngine_Myst::saveGameState(int slot, const Common::String &desc) { - Common::StringArray saveList = _gameState->generateSaveGameList(); - - if ((uint)slot < saveList.size()) - _gameState->deleteSave(saveList[slot]); + return _gameState->save(slot, desc) ? Common::kNoError : Common::kUnknownError; +} - return _gameState->save(Common::String(desc)) ? Common::kNoError : Common::kUnknownError; +bool MohawkEngine_Myst::hasGameSaveSupport() const { + return !(getFeatures() & GF_DEMO) && getGameType() != GType_MAKINGOF; } bool MohawkEngine_Myst::canLoadGameStateCurrently() { // No loading in the demo/makingof - return !(getFeatures() & GF_DEMO) && getGameType() != GType_MAKINGOF; + return _canSafelySaveLoad && hasGameSaveSupport(); } bool MohawkEngine_Myst::canSaveGameStateCurrently() { + if (!_canSafelySaveLoad) { + return false; + } + // There's a limited number of stacks the game can save in switch (_curStack) { case kChannelwoodStack: @@ -1225,4 +1158,82 @@ void MohawkEngine_Myst::dropPage() { checkCursorHints(); } +MystSoundBlock MohawkEngine_Myst::readSoundBlock(Common::ReadStream *stream) const { + MystSoundBlock soundBlock; + soundBlock.sound = stream->readSint16LE(); + debugCN(kDebugView, "Sound Control: %d = ", soundBlock.sound); + + if (soundBlock.sound > 0) { + debugC(kDebugView, "Play new Sound, change volume"); + debugC(kDebugView, "\tSound: %d", soundBlock.sound); + soundBlock.soundVolume = stream->readUint16LE(); + debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume); + } else if (soundBlock.sound == kMystSoundActionContinue) + debugC(kDebugView, "Continue current sound"); + else if (soundBlock.sound == kMystSoundActionChangeVolume) { + debugC(kDebugView, "Continue current sound, change volume"); + soundBlock.soundVolume = stream->readUint16LE(); + debugC(kDebugView, "\tVolume: %d", soundBlock.soundVolume); + } else if (soundBlock.sound == kMystSoundActionStop) { + debugC(kDebugView, "Stop sound"); + } else if (soundBlock.sound == kMystSoundActionConditional) { + debugC(kDebugView, "Conditional sound list"); + soundBlock.soundVar = stream->readUint16LE(); + debugC(kDebugView, "\tVar: %d", soundBlock.soundVar); + uint16 soundCount = stream->readUint16LE(); + debugC(kDebugView, "\tCount: %d", soundCount); + + for (uint16 i = 0; i < soundCount; i++) { + MystSoundBlock::SoundItem sound; + + sound.action = stream->readSint16LE(); + debugC(kDebugView, "\t\tCondition %d: Action %d", i, sound.action); + if (sound.action == kMystSoundActionChangeVolume || sound.action >= 0) { + sound.volume = stream->readUint16LE(); + debugC(kDebugView, "\t\tCondition %d: Volume %d", i, sound.volume); + } + + soundBlock.soundList.push_back(sound); + } + } else { + debugC(kDebugView, "Unknown"); + warning("Unknown sound control value '%d' in card '%d'", soundBlock.sound, _curCard); + } + + return soundBlock; +} + +void MohawkEngine_Myst::applySoundBlock(const MystSoundBlock &block) { + int16 soundAction = 0; + uint16 soundActionVolume = 0; + + if (block.sound == kMystSoundActionConditional) { + uint16 soundVarValue = _scriptParser->getVar(block.soundVar); + if (soundVarValue >= block.soundList.size()) + warning("Conditional sound variable outside range"); + else { + soundAction = block.soundList[soundVarValue].action; + soundActionVolume = block.soundList[soundVarValue].volume; + } + } else { + soundAction = block.sound; + soundActionVolume = block.soundVolume; + } + + if (soundAction == kMystSoundActionContinue) + debug(2, "Continuing with current sound"); + else if (soundAction == kMystSoundActionChangeVolume) { + debug(2, "Continuing with current sound, changing volume"); + _sound->changeBackgroundVolumeMyst(soundActionVolume); + } else if (soundAction == kMystSoundActionStop) { + debug(2, "Stopping sound"); + _sound->stopBackgroundMyst(); + } else if (soundAction > 0) { + debug(2, "Playing new sound %d", soundAction); + _sound->replaceBackgroundMyst(soundAction, soundActionVolume); + } else { + error("Unknown sound action %d", soundAction); + } +} + } // End of namespace Mohawk diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h index 4d86642652..0b249e5499 100644 --- a/engines/mohawk/myst.h +++ b/engines/mohawk/myst.h @@ -28,10 +28,9 @@ #include "mohawk/resource_cache.h" #include "mohawk/myst_scripts.h" +#include "common/events.h" #include "common/random.h" -#include "gui/saveload.h" - namespace Mohawk { class MohawkEngine_Myst; @@ -41,9 +40,9 @@ class MystScriptParser; class MystConsole; class MystGameState; class MystOptionsDialog; -class MystResource; -class MystResourceType8; -class MystResourceType13; +class MystArea; +class MystAreaImageSwitch; +class MystAreaHover; // Engine Debug Flags enum { @@ -96,8 +95,19 @@ const uint16 kMasterpieceOnly = 0xFFFF; struct MystCondition { uint16 var; - uint16 numStates; - uint16 *values; + Common::Array<uint16> values; +}; + +struct MystSoundBlock { + struct SoundItem { + int16 action; + uint16 volume; + }; + + int16 sound; + uint16 soundVolume; + uint16 soundVar; + Common::Array<SoundItem> soundList; }; // View Sound Action Type @@ -118,29 +128,29 @@ struct MystView { uint16 flags; // Image Data - uint16 conditionalImageCount; - MystCondition *conditionalImages; + Common::Array<MystCondition> conditionalImages; uint16 mainImage; // Sound Data - int16 sound; - uint16 soundVolume; - uint16 soundVar; - uint16 soundCount; - int16 *soundList; - uint16 *soundListVolume; + MystSoundBlock soundBlock; // Script Resources - uint16 scriptResCount; + enum ScriptResourceType { + kResourceImage = 1, + kResourceSound = 2, + kResourceSwitch = 3, + kResourceImageNoCache = 4, + kResourceSoundNoCache = 5 + }; + struct ScriptResource { - uint16 type; - uint16 id; // Not used by type 3 - // TODO: Type 3 has more. Maybe use a union? - uint16 var; // Used by type 3 only - uint16 count; // Used by type 3 only - uint16 u0; // Used by type 3 only - int16 *resource_list; // Used by type 3 only - } *scriptResources; + ScriptResourceType type; + uint16 id; + uint16 switchVar; + ScriptResourceType switchResourceType; + Common::Array<int16> switchResourceIds; + }; + Common::Array<ScriptResource> scriptResources; // Resource ID's uint16 rlst; @@ -158,18 +168,17 @@ struct MystCursorHint { class MohawkEngine_Myst : public MohawkEngine { protected: - Common::Error run(); + Common::Error run() override; public: MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription *gamedesc); virtual ~MohawkEngine_Myst(); - Common::SeekableReadStream *getResource(uint32 tag, uint16 id); + Common::SeekableReadStream *getResource(uint32 tag, uint16 id) override; + Common::Array<uint16> getResourceIDList(uint32 type) const; Common::String wrapMovieFilename(const Common::String &movieName, uint16 stack); - void reloadSaveList(); - void changeToStack(uint16 stack, uint16 card, uint16 linkSrcSound, uint16 linkDstSound); void changeToCard(uint16 card, TransitionType transition); uint16 getCurCard() { return _curCard; } @@ -177,46 +186,50 @@ public: void setMainCursor(uint16 cursor); uint16 getMainCursor() { return _mainCursor; } void checkCursorHints(); - MystResource *updateCurrentResource(); + MystArea *updateCurrentResource(); bool skippableWait(uint32 duration); - bool _tweaksEnabled; + MystSoundBlock readSoundBlock(Common::ReadStream *stream) const; + void applySoundBlock(const MystSoundBlock &block); + bool _needsUpdate; bool _needsPageDrop; bool _needsShowMap; bool _needsShowDemoMenu; + bool _needsShowCredits; + + bool _showResourceRects; - MystView _view; MystGraphics *_gfx; MystGameState *_gameState; MystScriptParser *_scriptParser; - Common::Array<MystResource *> _resources; - MystResource *_dragResource; + Common::Array<MystArea *> _resources; Common::RandomSource *_rnd; - bool _showResourceRects; - MystResource *loadResource(Common::SeekableReadStream *rlstStream, MystResource *parent); + MystArea *loadResource(Common::SeekableReadStream *rlstStream, MystArea *parent); void setResourceEnabled(uint16 resourceId, bool enable); void redrawArea(uint16 var, bool update = true); - void redrawResource(MystResourceType8 *resource, bool update = true); + void redrawResource(MystAreaImageSwitch *resource, bool update = true); void drawResourceImages(); void drawCardBackground(); uint16 getCardBackgroundId(); + template<class T> + T *getViewResource(uint index); + void setCacheState(bool state) { _cache.enabled = state; } bool getCacheState() { return _cache.enabled; } - GUI::Debugger *getDebugger() { return _console; } + GUI::Debugger *getDebugger() override { return _console; } - bool canLoadGameStateCurrently(); - bool canSaveGameStateCurrently(); - Common::Error loadGameState(int slot); - Common::Error saveGameState(int slot, const Common::String &desc); - bool hasFeature(EngineFeature f) const; + bool canLoadGameStateCurrently() override; + bool canSaveGameStateCurrently() override; + Common::Error loadGameState(int slot) override; + Common::Error saveGameState(int slot, const Common::String &desc) override; + bool hasFeature(EngineFeature f) const override; private: MystConsole *_console; - GUI::SaveLoadChooser *_loadDialog; MystOptionsDialog *_optionsDialog; MystScriptParser *_prevStack; ResourceCache _cache; @@ -224,9 +237,18 @@ private: uint16 _curStack; uint16 _curCard; + MystView _view; bool _runExitScript; + /** + * Saving / Loading is only allowed from the main event loop + */ + bool _canSafelySaveLoad; + bool hasGameSaveSupport() const; + + bool pollEvent(Common::Event &event); + void dropPage(); void loadCard(); @@ -240,15 +262,25 @@ private: void drawResourceRects(); void checkCurrentResource(); int16 _curResource; - MystResourceType13 *_hoverResource; + MystAreaHover *_hoverResource; - uint16 _cursorHintCount; - MystCursorHint *_cursorHints; + Common::Array<MystCursorHint> _cursorHints; void loadCursorHints(); uint16 _currentCursor; uint16 _mainCursor; // Also defines the current page being held (white, blue, red, or none) }; +template<class T> +T *MohawkEngine_Myst::getViewResource(uint index) { + T *resource = dynamic_cast<T *>(_resources[index]); + + if (!resource) { + error("View resource '%d' has unexpected type", index); + } + + return resource; +} + } // End of namespace Mohawk #endif diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp index 7a9596d8e0..4b9cf546fa 100644 --- a/engines/mohawk/myst_areas.cpp +++ b/engines/mohawk/myst_areas.cpp @@ -32,11 +32,11 @@ namespace Mohawk { -MystResource::MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) { +MystArea::MystArea(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) { _vm = vm; _parent = parent; - if (parent == NULL) { + if (parent == nullptr) { _flags = rlstStream->readUint16LE(); _rect.left = rlstStream->readSint16LE(); _rect.top = rlstStream->readSint16LE(); @@ -66,10 +66,10 @@ MystResource::MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rl debugC(kDebugResource, "\tdest: %d", _dest); } -MystResource::~MystResource() { +MystArea::~MystArea() { } -void MystResource::handleMouseUp() { +void MystArea::handleMouseUp() { if (_dest == 0) { warning("Movement type resource with null destination at position (%d, %d), (%d, %d)", _rect.left, _rect.top, _rect.right, _rect.bottom); return; @@ -78,13 +78,13 @@ void MystResource::handleMouseUp() { uint16 opcode; switch (type) { - case kMystForwardArea: + case kMystAreaForward: opcode = 6; break; - case kMystLeftArea: + case kMystAreaLeft: opcode = 8; break; - case kMystRightArea: + case kMystAreaRight: opcode = 7; break; default: @@ -96,27 +96,27 @@ void MystResource::handleMouseUp() { _vm->_scriptParser->runOpcode(opcode, 0); } -bool MystResource::canBecomeActive() { +bool MystArea::canBecomeActive() { return !unreachableZipDest() && (isEnabled() || (_flags & kMystUnknownFlag)); } -bool MystResource::unreachableZipDest() { +bool MystArea::unreachableZipDest() { return (_flags & kMystZipModeEnableFlag) && !_vm->_gameState->isReachableZipDest(_vm->getCurStack() , _dest); } -bool MystResource::isEnabled() { +bool MystArea::isEnabled() { return _flags & kMystHotspotEnableFlag; } -void MystResource::setEnabled(bool enabled) { +void MystArea::setEnabled(bool enabled) { if (enabled) _flags |= kMystHotspotEnableFlag; else _flags &= ~kMystHotspotEnableFlag; } -const Common::String MystResource::describe() { +const Common::String MystArea::describe() { Common::String desc = Common::String::format("type: %2d rect: (%3d %3d %3d %3d)", type, _rect.left, _rect.top, _rect.width(), _rect.height()); @@ -126,7 +126,7 @@ const Common::String MystResource::describe() { return desc; } -void MystResource::drawBoundingRect() { +void MystArea::drawBoundingRect() { if (_rect.isValidRect()) { if (!canBecomeActive()) _vm->_gfx->drawRect(_rect, kRectUnreachable); @@ -137,18 +137,19 @@ void MystResource::drawBoundingRect() { } } -MystResourceType5::MystResourceType5(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) { +MystAreaAction::MystAreaAction(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystArea(vm, rlstStream, parent) { debugC(kDebugResource, "\tResource Type 5 Script:"); _script = vm->_scriptParser->readScript(rlstStream, kMystScriptNormal); } -void MystResourceType5::handleMouseUp() { +void MystAreaAction::handleMouseUp() { _vm->_scriptParser->runScript(_script, this); } -const Common::String MystResourceType5::describe() { - Common::String desc = MystResource::describe(); +const Common::String MystAreaAction::describe() { + Common::String desc = MystArea::describe(); if (_script->size() != 0) { desc += " ops:"; @@ -161,7 +162,7 @@ const Common::String MystResourceType5::describe() { } // In Myst/Making of Myst, the paths are hardcoded ala Windows style without extension. Convert them. -Common::String MystResourceType6::convertMystVideoName(Common::String name) { +Common::String MystAreaVideo::convertMystVideoName(Common::String name) { Common::String temp; for (uint32 i = 1; i < name.size(); i++) { @@ -174,7 +175,8 @@ Common::String MystResourceType6::convertMystVideoName(Common::String name) { return temp + ".mov"; } -MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType5(vm, rlstStream, parent) { +MystAreaVideo::MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaAction(vm, rlstStream, parent) { char c = 0; do { @@ -197,16 +199,7 @@ MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableRead _direction = rlstStream->readSint16LE(); _playBlocking = rlstStream->readUint16LE(); _loop = rlstStream->readUint16LE(); - _u3 = rlstStream->readUint16LE(); - - // TODO: Out of bound values should clip the movie - if (_left < 0) - _left = 0; - if (_top < 0) - _top = 0; - - if (_u3 != 0) - warning("Type 6 _u3 != 0"); + _playRate = rlstStream->readUint16LE(); debugC(kDebugResource, "\tvideoFile: \"%s\"", _videoFile.c_str()); debugC(kDebugResource, "\tleft: %d", _left); @@ -215,15 +208,15 @@ MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableRead debugC(kDebugResource, "\tdirection: %d", _direction); debugC(kDebugResource, "\tplayBlocking: %d", _playBlocking); debugC(kDebugResource, "\tplayOnCardChange: %d", _playOnCardChange); - debugC(kDebugResource, "\tu3: %d", _u3); + debugC(kDebugResource, "\tplayRate: %d", _playRate); } -VideoHandle MystResourceType6::playMovie() { +VideoHandle MystAreaVideo::playMovie() { // Check if the video is already running VideoHandle handle = _vm->_video->findVideoHandle(_videoFile); // If the video is not running, play it - if (!handle || handle->endOfVideo()) { + if (!handle) { handle = _vm->_video->playMovie(_videoFile); if (!handle) error("Failed to open '%s'", _videoFile.c_str()); @@ -231,13 +224,23 @@ VideoHandle MystResourceType6::playMovie() { handle->moveTo(_left, _top); handle->setLooping(_loop != 0); + Common::Rational rate; + if (_playRate != 0) { + rate = Common::Rational(_playRate, 100); + } else { + rate = 1; + } + if (_direction == -1) { + rate = -rate; handle->seek(handle->getDuration()); - handle->setRate(-1); } + + handle->setRate(rate); } else { // Resume the video handle->pause(false); + handle->start(); } if (_playBlocking) { @@ -248,186 +251,156 @@ VideoHandle MystResourceType6::playMovie() { return handle; } -void MystResourceType6::handleCardChange() { +VideoHandle MystAreaVideo::getMovieHandle() { + // If the video is already in the manager, just return the handle + VideoHandle handle = _vm->_video->findVideoHandle(_videoFile); + if (!handle) { + // If the video has not been loaded yet, do it but don't start playing it + handle = _vm->_video->playMovie(_videoFile); + if (!handle) + error("Failed to open '%s'", _videoFile.c_str()); + handle->stop(); + } + + return handle; +} + +void MystAreaVideo::handleCardChange() { if (_playOnCardChange) playMovie(); } -bool MystResourceType6::isPlaying() { +bool MystAreaVideo::isPlaying() { VideoHandle handle = _vm->_video->findVideoHandle(_videoFile); return handle && !handle->endOfVideo(); } -void MystResourceType6::pauseMovie(bool pause) { +void MystAreaVideo::pauseMovie(bool pause) { VideoHandle handle = _vm->_video->findVideoHandle(_videoFile); if (handle && !handle->endOfVideo()) handle->pause(pause); } -MystResourceType7::MystResourceType7(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) { - _var7 = rlstStream->readUint16LE(); - _numSubResources = rlstStream->readUint16LE(); - debugC(kDebugResource, "\tvar7: %d", _var7); - debugC(kDebugResource, "\tnumSubResources: %d", _numSubResources); +MystAreaActionSwitch::MystAreaActionSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystArea(vm, rlstStream, parent) { + _actionSwitchVar = rlstStream->readUint16LE(); + uint16 numSubResources = rlstStream->readUint16LE(); + debugC(kDebugResource, "\tactionSwitchVar: %d", _actionSwitchVar); + debugC(kDebugResource, "\tnumSubResources: %d", numSubResources); - for (uint16 i = 0; i < _numSubResources; i++) + for (uint16 i = 0; i < numSubResources; i++) _subResources.push_back(vm->loadResource(rlstStream, this)); } -MystResourceType7::~MystResourceType7() { +MystAreaActionSwitch::~MystAreaActionSwitch() { for (uint32 i = 0; i < _subResources.size(); i++) delete _subResources[i]; _subResources.clear(); } -// TODO: All these functions to switch subresource are very similar. -// Find way to share code (function pointer pass?) -void MystResourceType7::drawDataToScreen() { - if (_var7 == 0xFFFF) { - if (_numSubResources == 1) - _subResources[0]->drawDataToScreen(); - else if (_numSubResources != 0) - warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources); +void MystAreaActionSwitch::doSwitch(AreaHandler handler) { + if (_actionSwitchVar == 0xFFFF) { + if (_subResources.size() == 1) + (_subResources[0]->*handler)(); + else if (_subResources.size() != 0) + warning("Action switch resource with _numSubResources of %d, but no control variable", _subResources.size()); } else { - uint16 varValue = _vm->_scriptParser->getVar(_var7); + uint16 varValue = _vm->_scriptParser->getVar(_actionSwitchVar); - if (_numSubResources == 1 && varValue != 0) - _subResources[0]->drawDataToScreen(); - else if (_numSubResources != 0) { - if (varValue < _numSubResources) - _subResources[varValue]->drawDataToScreen(); + if (_subResources.size() == 1 && varValue != 0) + (_subResources[0]->*handler)(); + else if (_subResources.size() != 0) { + if (varValue < _subResources.size()) + (_subResources[varValue]->*handler)(); else - warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources); + warning("Action switch resource Var %d: %d exceeds number of sub resources %d", _actionSwitchVar, varValue, _subResources.size()); } } } -void MystResourceType7::handleCardChange() { - if (_var7 == 0xFFFF) { - if (_numSubResources == 1) - _subResources[0]->handleCardChange(); - else if (_numSubResources != 0) - warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources); - } else { - uint16 varValue = _vm->_scriptParser->getVar(_var7); - - if (_numSubResources == 1 && varValue != 0) - _subResources[0]->handleCardChange(); - else if (_numSubResources != 0) { - if (varValue < _numSubResources) - _subResources[varValue]->handleCardChange(); - else - warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources); - } - } +void MystAreaActionSwitch::drawDataToScreen() { + doSwitch(&MystArea::drawDataToScreen); } -void MystResourceType7::handleMouseUp() { - if (_var7 == 0xFFFF) { - if (_numSubResources == 1) - _subResources[0]->handleMouseUp(); - else if (_numSubResources != 0) - warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources); - } else { - uint16 varValue = _vm->_scriptParser->getVar(_var7); - - if (_numSubResources == 1 && varValue != 0) - _subResources[0]->handleMouseUp(); - else if (_numSubResources != 0) { - if (varValue < _numSubResources) - _subResources[varValue]->handleMouseUp(); - else - warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources); - } - } +void MystAreaActionSwitch::handleCardChange() { + doSwitch(&MystArea::handleCardChange); } -void MystResourceType7::handleMouseDown() { - if (_var7 == 0xFFFF) { - if (_numSubResources == 1) - _subResources[0]->handleMouseDown(); - else if (_numSubResources != 0) - warning("Type 7 Resource with _numSubResources of %d, but no control variable", _numSubResources); - } else { - uint16 varValue = _vm->_scriptParser->getVar(_var7); - - if (_numSubResources == 1 && varValue != 0) - _subResources[0]->handleMouseDown(); - else if (_numSubResources != 0) { - if (varValue < _numSubResources) - _subResources[varValue]->handleMouseDown(); - else - warning("Type 7 Resource Var %d: %d exceeds number of sub resources %d", _var7, varValue, _numSubResources); - } - } +void MystAreaActionSwitch::handleMouseUp() { + doSwitch(&MystArea::handleMouseUp); } -MystResourceType8::MystResourceType8(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType7(vm, rlstStream, parent) { - _var8 = rlstStream->readUint16LE(); - _numSubImages = rlstStream->readUint16LE(); - debugC(kDebugResource, "\tvar8: %d", _var8); - debugC(kDebugResource, "\tnumSubImages: %d", _numSubImages); +void MystAreaActionSwitch::handleMouseDown() { + doSwitch(&MystArea::handleMouseDown); +} - _subImages = new MystResourceType8::SubImage[_numSubImages]; +MystAreaImageSwitch::MystAreaImageSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaActionSwitch(vm, rlstStream, parent) { + _imageSwitchVar = rlstStream->readUint16LE(); + uint16 numSubImages = rlstStream->readUint16LE(); + debugC(kDebugResource, "\tvar8: %d", _imageSwitchVar); + debugC(kDebugResource, "\tnumSubImages: %d", numSubImages); - for (uint16 i = 0; i < _numSubImages; i++) { + for (uint16 i = 0; i < numSubImages; i++) { debugC(kDebugResource, "\tSubimage %d:", i); - _subImages[i].wdib = rlstStream->readUint16LE(); - _subImages[i].rect.left = rlstStream->readSint16LE(); + SubImage subImage; + subImage.wdib = rlstStream->readUint16LE(); + subImage.rect.left = rlstStream->readSint16LE(); - if (_subImages[i].rect.left != -1) { - _subImages[i].rect.top = rlstStream->readSint16LE(); - _subImages[i].rect.right = rlstStream->readSint16LE(); - _subImages[i].rect.bottom = rlstStream->readSint16LE(); + if (subImage.rect.left != -1) { + subImage.rect.top = rlstStream->readSint16LE(); + subImage.rect.right = rlstStream->readSint16LE(); + subImage.rect.bottom = rlstStream->readSint16LE(); } else { // Use the hotspot rect as the source rect since the subimage is fullscreen // Convert to bitmap coordinates (upside down) - _subImages[i].rect.left = _rect.left; - _subImages[i].rect.top = 333 - _rect.bottom; - _subImages[i].rect.right = _rect.right; - _subImages[i].rect.bottom = 333 - _rect.top; + subImage.rect.left = _rect.left; + subImage.rect.top = 333 - _rect.bottom; + subImage.rect.right = _rect.right; + subImage.rect.bottom = 333 - _rect.top; } - debugC(kDebugResource, "\twdib: %d", _subImages[i].wdib); - debugC(kDebugResource, "\tleft: %d", _subImages[i].rect.left); - debugC(kDebugResource, "\ttop: %d", _subImages[i].rect.top); - debugC(kDebugResource, "\tright: %d", _subImages[i].rect.right); - debugC(kDebugResource, "\tbottom: %d", _subImages[i].rect.bottom); + debugC(kDebugResource, "\twdib: %d", subImage.wdib); + debugC(kDebugResource, "\tleft: %d", subImage.rect.left); + debugC(kDebugResource, "\ttop: %d", subImage.rect.top); + debugC(kDebugResource, "\tright: %d", subImage.rect.right); + debugC(kDebugResource, "\tbottom: %d", subImage.rect.bottom); + + _subImages.push_back(subImage); } } -MystResourceType8::~MystResourceType8() { - delete[] _subImages; +MystAreaImageSwitch::~MystAreaImageSwitch() { } -void MystResourceType8::drawDataToScreen() { - // Need to call overidden Type 7 function to ensure +void MystAreaImageSwitch::drawDataToScreen() { + // Need to call overridden function to ensure // switch section is processed correctly. - MystResourceType7::drawDataToScreen(); + MystAreaActionSwitch::drawDataToScreen(); bool drawSubImage = false; int16 subImageId = 0; - if (_var8 == 0xFFFF) { - if (_numSubImages == 1) { + if (_imageSwitchVar == 0xFFFF) { + if (_subImages.size() == 1) { subImageId = 0; drawSubImage = true; - } else if (_numSubImages != 0) - warning("Type 8 Resource with _numSubImages of %d, but no control variable", _numSubImages); + } else if (_subImages.size() != 0) + warning("Image Switch resource with _numSubImages of %d, but no control variable", _subImages.size()); } else { - uint16 varValue = _vm->_scriptParser->getVar(_var8); + uint16 varValue = _vm->_scriptParser->getVar(_imageSwitchVar); - if (_numSubImages == 1 && varValue != 0) { + if (_subImages.size() == 1 && varValue != 0) { subImageId = 0; drawSubImage = true; - } else if (_numSubImages != 0) { - if (varValue < _numSubImages) { + } else if (_subImages.size() != 0) { + if (varValue < _subImages.size()) { subImageId = varValue; drawSubImage = true; } else - warning("Type 8 Image Var %d: %d exceeds number of subImages %d", _var8, varValue, _numSubImages); + warning("Image Switch Var %d: %d exceeds number of subImages %d", _imageSwitchVar, varValue, _subImages.size()); } } @@ -442,20 +415,21 @@ void MystResourceType8::drawDataToScreen() { } } -void MystResourceType8::drawConditionalDataToScreen(uint16 state, bool update) { +//TODO: Merge with the method above? +void MystAreaImageSwitch::drawConditionalDataToScreen(uint16 state, bool update) { bool drawSubImage = false; int16 subImageId = 0; - if (_numSubImages == 1 && state != 0) { + if (_subImages.size() == 1 && state != 0) { subImageId = 0; drawSubImage = true; - } else if (_numSubImages != 0) { - if (state < _numSubImages) { + } else if (_subImages.size() != 0) { + if (state < _subImages.size()) { subImageId = state; drawSubImage = true; } else - warning("Type 8 Image Var %d: %d exceeds number of subImages %d", _var8, state, _numSubImages); + warning("Image Switch Var %d: %d exceeds number of subImages %d", _imageSwitchVar, state, _subImages.size()); } @@ -476,18 +450,26 @@ void MystResourceType8::drawConditionalDataToScreen(uint16 state, bool update) { } } -uint16 MystResourceType8::getType8Var() { - return _var8; +uint16 MystAreaImageSwitch::getImageSwitchVar() { + return _imageSwitchVar; +} + +MystAreaImageSwitch::SubImage MystAreaImageSwitch::getSubImage(uint index) const { + return _subImages[index]; } -const Common::String MystResourceType8::describe() { +void MystAreaImageSwitch::setSubImageRect(uint index, const Common::Rect &rect) { + _subImages[index].rect = rect; +} + +const Common::String MystAreaImageSwitch::describe() { Common::String desc = Common::String::format("%s var: %2d", - MystResourceType7::describe().c_str(), _var8); + MystAreaActionSwitch::describe().c_str(), _imageSwitchVar); - if (_numSubImages > 0) { + if (_subImages.size() > 0) { desc += " subImgs:"; - for (uint i = 0; i < _numSubImages; i++) + for (uint i = 0; i < _subImages.size(); i++) desc += Common::String::format(" %d", (int16)_subImages[i].wdib); } @@ -496,7 +478,8 @@ const Common::String MystResourceType8::describe() { // No MystResourceType9! -MystResourceType10::MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType11(vm, rlstStream, parent) { +MystAreaSlider::MystAreaSlider(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaDrag(vm, rlstStream, parent) { _dragSound = rlstStream->readUint16LE(); debugC(kDebugResource, "\tdrag sound : %d", _dragSound); @@ -505,23 +488,23 @@ MystResourceType10::MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableRe _sliderHeight = _rect.bottom - _rect.top; } -MystResourceType10::~MystResourceType10() { +MystAreaSlider::~MystAreaSlider() { } -void MystResourceType10::setStep(uint16 step) { +void MystAreaSlider::setStep(uint16 step) { _rect.top = _minV + _stepV * step - _sliderHeight / 2; _rect.bottom = _rect.top + _sliderHeight; _subImages[0].rect.top = 333 - _rect.bottom - 1; _subImages[0].rect.bottom = 333 - _rect.top - 1; } -void MystResourceType10::setPosition(uint16 pos) { +void MystAreaSlider::setPosition(uint16 pos) { Common::Point mouse; mouse.y = pos; updatePosition(mouse); } -Common::Rect MystResourceType10::boundingBox() { +Common::Rect MystAreaSlider::boundingBox() { Common::Rect bb; bb.top = _rect.top; @@ -544,7 +527,7 @@ Common::Rect MystResourceType10::boundingBox() { return bb; } -void MystResourceType10::restoreBackground() { +void MystAreaSlider::restoreBackground() { // Restore background Common::Rect src = boundingBox(); Common::Rect dest = boundingBox(); @@ -553,14 +536,11 @@ void MystResourceType10::restoreBackground() { _vm->_gfx->copyImageSectionToScreen(_vm->getCardBackgroundId(), src, dest); } -void MystResourceType10::handleMouseDown() { - // Tell the engine we are dragging a resource - _vm->_dragResource = this; - +void MystAreaSlider::handleMouseDown() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); updatePosition(mouse); - MystResourceType11::handleMouseDown(); + MystAreaDrag::handleMouseDown(); // Restore background restoreBackground(); @@ -569,7 +549,7 @@ void MystResourceType10::handleMouseDown() { drawConditionalDataToScreen(2); } -void MystResourceType10::handleMouseUp() { +void MystAreaSlider::handleMouseUp() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); updatePosition(mouse); @@ -593,19 +573,16 @@ void MystResourceType10::handleMouseUp() { value = _pos.x; } - _vm->_scriptParser->setVarValue(_var8, value); - - MystResourceType11::handleMouseUp(); + _vm->_scriptParser->setVarValue(_imageSwitchVar, value); - // No longer in drag mode - _vm->_dragResource = 0; + MystAreaDrag::handleMouseUp(); } -void MystResourceType10::handleMouseDrag() { +void MystAreaSlider::handleMouseDrag() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); updatePosition(mouse); - MystResourceType11::handleMouseDrag(); + MystAreaDrag::handleMouseDrag(); // Restore background restoreBackground(); @@ -614,7 +591,7 @@ void MystResourceType10::handleMouseDrag() { drawConditionalDataToScreen(2); } -void MystResourceType10::updatePosition(const Common::Point &mouse) { +void MystAreaSlider::updatePosition(const Common::Point &mouse) { bool positionChanged = false; Common::Point mouseClipped; @@ -667,7 +644,8 @@ void MystResourceType10::updatePosition(const Common::Point &mouse) { _vm->_sound->replaceSoundMyst(_dragSound); } -MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType8(vm, rlstStream, parent) { +MystAreaDrag::MystAreaDrag(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaImageSwitch(vm, rlstStream, parent) { _flagHV = rlstStream->readUint16LE(); _minH = rlstStream->readUint16LE(); _maxH = rlstStream->readUint16LE(); @@ -694,16 +672,15 @@ MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableRe debugCN(kDebugResource, "Type 11 _mouseDragOpcode: %d\n", _mouseDragOpcode); debugCN(kDebugResource, "Type 11 _mouseUpOpcode: %d\n", _mouseUpOpcode); - for (byte i = 0; i < 3; i++) { + for (byte i = 0; i < ARRAYSIZE(_lists); i++) { debugC(kDebugResource, "\tList %d:", i); - _lists[i].listCount = rlstStream->readUint16LE(); - debugC(kDebugResource, "\t%d values", _lists[i].listCount); + uint16 listCount = rlstStream->readUint16LE(); + debugC(kDebugResource, "\t%d values", listCount); - _lists[i].list = new uint16[_lists[i].listCount]; - for (uint16 j = 0; j < _lists[i].listCount; j++) { - _lists[i].list[j] = rlstStream->readUint16LE(); - debugC(kDebugResource, "\tValue %d: %d", j, _lists[i].list[j]); + for (uint16 j = 0; j < listCount; j++) { + _lists[i].push_back(rlstStream->readUint16LE()); + debugC(kDebugResource, "\tValue %d: %d", j, _lists[i][j]); } } @@ -717,44 +694,42 @@ MystResourceType11::MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableRe _stepV = (_maxV - _minV) / (_stepsV - 1); } -MystResourceType11::~MystResourceType11() { - for (byte i = 0; i < 3; i++) - delete[] _lists[i].list; +MystAreaDrag::~MystAreaDrag() { } -void MystResourceType11::handleMouseDown() { +void MystAreaDrag::handleMouseDown() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); setPositionClipping(mouse, _pos); _vm->_scriptParser->setInvokingResource(this); - _vm->_scriptParser->runOpcode(_mouseDownOpcode, _var8); + _vm->_scriptParser->runOpcode(_mouseDownOpcode, _imageSwitchVar); } -void MystResourceType11::handleMouseUp() { +void MystAreaDrag::handleMouseUp() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); setPositionClipping(mouse, _pos); _vm->_scriptParser->setInvokingResource(this); - _vm->_scriptParser->runOpcode(_mouseUpOpcode, _var8); + _vm->_scriptParser->runOpcode(_mouseUpOpcode, _imageSwitchVar); } -void MystResourceType11::handleMouseDrag() { +void MystAreaDrag::handleMouseDrag() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); setPositionClipping(mouse, _pos); _vm->_scriptParser->setInvokingResource(this); - _vm->_scriptParser->runOpcode(_mouseDragOpcode, _var8); + _vm->_scriptParser->runOpcode(_mouseDragOpcode, _imageSwitchVar); } -const Common::String MystResourceType11::describe() { +const Common::String MystAreaDrag::describe() { return Common::String::format("%s down: %s drag: %s up: %s", - MystResourceType8::describe().c_str(), + MystAreaImageSwitch::describe().c_str(), _vm->_scriptParser->getOpcodeDesc(_mouseDownOpcode).c_str(), _vm->_scriptParser->getOpcodeDesc(_mouseDragOpcode).c_str(), _vm->_scriptParser->getOpcodeDesc(_mouseUpOpcode).c_str()); } -void MystResourceType11::setPositionClipping(const Common::Point &mouse, Common::Point &dest) { +void MystAreaDrag::setPositionClipping(const Common::Point &mouse, Common::Point &dest) { if (_flagHV & 2) dest.y = CLIP<uint16>(mouse.y, _minV, _maxV); @@ -762,19 +737,20 @@ void MystResourceType11::setPositionClipping(const Common::Point &mouse, Common: dest.x = CLIP<uint16>(mouse.x, _minH, _maxH); } -uint16 MystResourceType11::getList1(uint16 index) { - return (index < _lists[0].listCount) ? _lists[0].list[index] : 0; +uint16 MystAreaDrag::getList1(uint16 index) { + return (index < _lists[0].size()) ? _lists[0][index] : 0; } -uint16 MystResourceType11::getList2(uint16 index) { - return (index < _lists[1].listCount) ? _lists[1].list[index] : 0; +uint16 MystAreaDrag::getList2(uint16 index) { + return (index < _lists[1].size()) ? _lists[1][index] : 0; } -uint16 MystResourceType11::getList3(uint16 index) { - return (index < _lists[2].listCount) ? _lists[2].list[index] : 0; +uint16 MystAreaDrag::getList3(uint16 index) { + return (index < _lists[2].size()) ? _lists[2][index] : 0; } -MystResourceType12::MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResourceType11(vm, rlstStream, parent) { +MystVideoInfo::MystVideoInfo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystAreaDrag(vm, rlstStream, parent) { _numFrames = rlstStream->readUint16LE(); _firstFrame = rlstStream->readUint16LE(); uint16 frameWidth = rlstStream->readUint16LE(); @@ -795,16 +771,16 @@ MystResourceType12::MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableRe debugC(kDebugResource, "\t_frameRect.bottom: %d", _frameRect.bottom); } -MystResourceType12::~MystResourceType12() { +MystVideoInfo::~MystVideoInfo() { } -void MystResourceType12::drawFrame(uint16 frame) { +void MystVideoInfo::drawFrame(uint16 frame) { _currentFrame = _firstFrame + frame; _vm->_gfx->copyImageToScreen(_currentFrame, _frameRect); _vm->_system->updateScreen(); } -bool MystResourceType12::pullLeverV() { +bool MystVideoInfo::pullLeverV() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); // Make the handle follow the mouse @@ -820,7 +796,7 @@ bool MystResourceType12::pullLeverV() { return step == maxStep; } -void MystResourceType12::releaseLeverV() { +void MystVideoInfo::releaseLeverV() { const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); // Get current lever frame @@ -836,7 +812,8 @@ void MystResourceType12::releaseLeverV() { } } -MystResourceType13::MystResourceType13(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent) : MystResource(vm, rlstStream, parent) { +MystAreaHover::MystAreaHover(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent) : + MystArea(vm, rlstStream, parent) { _enterOpcode = rlstStream->readUint16LE(); _leaveOpcode = rlstStream->readUint16LE(); @@ -844,27 +821,27 @@ MystResourceType13::MystResourceType13(MohawkEngine_Myst *vm, Common::SeekableRe debugC(kDebugResource, "\t_leaveOpcode: %d", _leaveOpcode); } -void MystResourceType13::handleMouseEnter() { +void MystAreaHover::handleMouseEnter() { // Pass along the enter opcode to the script parser // The variable to use is stored in the dest field _vm->_scriptParser->runOpcode(_enterOpcode, _dest); } -void MystResourceType13::handleMouseLeave() { +void MystAreaHover::handleMouseLeave() { // Pass along the leave opcode (with no parameters) to the script parser // The variable to use is stored in the dest field _vm->_scriptParser->runOpcode(_leaveOpcode, _dest); } -void MystResourceType13::handleMouseUp() { +void MystAreaHover::handleMouseUp() { // Type 13 Resources do nothing on Mouse Clicks. // This is required to override the inherited default - // i.e. MystResource::handleMouseUp + // i.e. MystArea::handleMouseUp } -const Common::String MystResourceType13::describe() { +const Common::String MystAreaHover::describe() { return Common::String::format("%s enter: %s leave: %s", - MystResource::describe().c_str(), + MystArea::describe().c_str(), _vm->_scriptParser->getOpcodeDesc(_enterOpcode).c_str(), _vm->_scriptParser->getOpcodeDesc(_leaveOpcode).c_str()); } diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h index 97ec882497..b19a2df9e2 100644 --- a/engines/mohawk/myst_areas.h +++ b/engines/mohawk/myst_areas.h @@ -32,19 +32,19 @@ namespace Mohawk { // Myst Resource Types enum ResourceType { - kMystForwardArea = 0, - kMystLeftArea = 1, - kMystRightArea = 2, - kMystDownArea = 3, - kMystUpArea = 4, - kMystAction = 5, - kMystVideo = 6, - kMystSwitch = 7, - kMystConditionalImage = 8, - kMystSlider = 10, - kMystDragArea = 11, + kMystAreaForward = 0, + kMystAreaLeft = 1, + kMystAreaRight = 2, + kMystAreaDown = 3, + kMystAreaUp = 4, + kMystAreaAction = 5, + kMystAreaVideo = 6, + kMystAreaActionSwitch = 7, + kMystAreaImageSwitch = 8, + kMystAreaSlider = 10, + kMystAreaDrag = 11, kMystVideoInfo = 12, - kMystHoverArea = 13 + kMystAreaHover = 13 }; // Myst Resource Flags @@ -56,16 +56,14 @@ enum { kMystZipModeEnableFlag = (1 << 3) }; -class MystResource { +class MystArea { public: - MystResource(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResource(); + MystArea(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystArea(); + virtual const Common::String describe(); void drawBoundingRect(); - MystResource *_parent; - ResourceType type; - bool contains(Common::Point point) { return _rect.contains(point); } virtual void drawDataToScreen() {} virtual void handleCardChange() {} @@ -75,7 +73,7 @@ public: void setEnabled(bool enabled); bool isDrawSubimages() { return _flags & kMystSubimageEnableFlag; } uint16 getDest() { return _dest; } - virtual uint16 getType8Var() { return 0xFFFF; } + virtual uint16 getImageSwitchVar() { return 0xFFFF; } bool unreachableZipDest(); bool canBecomeActive(); @@ -84,6 +82,8 @@ public: virtual void handleMouseDown() {} virtual void handleMouseDrag() {} + MystArea *_parent; + ResourceType type; protected: MohawkEngine_Myst *_vm; @@ -92,21 +92,25 @@ protected: uint16 _dest; }; -class MystResourceType5 : public MystResource { +class MystAreaAction : public MystArea { public: - MystResourceType5(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - void handleMouseUp(); - const Common::String describe(); + MystAreaAction(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + + void handleMouseUp() override; + const Common::String describe() override; protected: MystScript _script; }; -class MystResourceType6 : public MystResourceType5 { +class MystAreaVideo : public MystAreaAction { public: - MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); + MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + VideoHandle playMovie(); - void handleCardChange(); + VideoHandle getMovieHandle(); + + void handleCardChange() override; bool isPlaying(); void setDirection(int16 direction) { _direction = direction; } void setBlocking(bool blocking) { _playBlocking = blocking; } @@ -114,6 +118,7 @@ public: protected: static Common::String convertMystVideoName(Common::String name); + Common::String _videoFile; int16 _left; int16 _top; @@ -121,58 +126,63 @@ protected: int16 _direction; // 1 => forward, -1 => backwards uint16 _playBlocking; uint16 _playOnCardChange; - uint16 _u3; + uint16 _playRate; // percents }; -class MystResourceType7 : public MystResource { +class MystAreaActionSwitch : public MystArea { public: - MystResourceType7(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType7(); + MystAreaActionSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystAreaActionSwitch(); - virtual void drawDataToScreen(); - virtual void handleCardChange(); + virtual void drawDataToScreen() override; + virtual void handleCardChange() override; - virtual void handleMouseUp(); - virtual void handleMouseDown(); + virtual void handleMouseUp() override; + virtual void handleMouseDown() override; - MystResource *getSubResource(uint16 index) { return _subResources[index]; } + MystArea *getSubResource(uint16 index) { return _subResources[index]; } protected: - uint16 _var7; - uint16 _numSubResources; - Common::Array<MystResource *> _subResources; + typedef void (MystArea::*AreaHandler)(); + + void doSwitch(AreaHandler handler); + + uint16 _actionSwitchVar; + Common::Array<MystArea *> _subResources; }; -class MystResourceType8 : public MystResourceType7 { +class MystAreaImageSwitch : public MystAreaActionSwitch { public: - MystResourceType8(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType8(); - virtual const Common::String describe(); - - virtual void drawDataToScreen(); - void drawConditionalDataToScreen(uint16 state, bool update = true); - uint16 getType8Var(); + MystAreaImageSwitch(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystAreaImageSwitch(); struct SubImage { uint16 wdib; Common::Rect rect; - } *_subImages; + }; + + virtual const Common::String describe() override; + virtual void drawDataToScreen() override; + void drawConditionalDataToScreen(uint16 state, bool update = true); + uint16 getImageSwitchVar() override; + + SubImage getSubImage(uint index) const; + void setSubImageRect(uint index, const Common::Rect &rect); protected: - uint16 _var8; - uint16 _numSubImages; + uint16 _imageSwitchVar; + Common::Array<SubImage> _subImages; }; -// No MystResourceType9! - -class MystResourceType11 : public MystResourceType8 { +class MystAreaDrag : public MystAreaImageSwitch { public: - MystResourceType11(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType11(); - const Common::String describe(); + MystAreaDrag(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystAreaDrag(); - void handleMouseDown(); - void handleMouseUp(); - void handleMouseDrag(); + const Common::String describe() override; + + virtual void handleMouseDown() override; + virtual void handleMouseUp() override; + virtual void handleMouseDrag() override; uint16 getList1(uint16 index); uint16 getList2(uint16 index); @@ -183,6 +193,8 @@ public: Common::Point _pos; protected: + typedef Common::Array<uint16> ValueList; + void setPositionClipping(const Common::Point &mouse, Common::Point &dest); uint16 _flagHV; @@ -197,21 +209,17 @@ protected: uint16 _mouseDownOpcode; uint16 _mouseDragOpcode; uint16 _mouseUpOpcode; - struct { - uint16 listCount; - uint16 *list; - } _lists[3]; - + ValueList _lists[3]; }; -class MystResourceType10 : public MystResourceType11 { +class MystAreaSlider : public MystAreaDrag { public: - MystResourceType10(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType10(); + MystAreaSlider(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystAreaSlider(); - void handleMouseDown(); - void handleMouseUp(); - void handleMouseDrag(); + void handleMouseDown() override; + void handleMouseUp() override; + void handleMouseDrag() override; void setStep(uint16 step); void setPosition(uint16 pos); void restoreBackground(); @@ -225,10 +233,11 @@ protected: uint16 _sliderHeight; }; -class MystResourceType12 : public MystResourceType11 { +class MystVideoInfo : public MystAreaDrag { public: - MystResourceType12(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - virtual ~MystResourceType12(); + MystVideoInfo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + virtual ~MystVideoInfo(); + void drawFrame(uint16 frame); bool pullLeverV(); void releaseLeverV(); @@ -243,12 +252,13 @@ private: uint16 _currentFrame; }; -class MystResourceType13 : public MystResource { +class MystAreaHover : public MystArea { public: - MystResourceType13(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystResource *parent); - const Common::String describe(); + MystAreaHover(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent); + + const Common::String describe() override; - void handleMouseUp(); + void handleMouseUp() override; void handleMouseEnter(); void handleMouseLeave(); diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp index 49f97cca63..427fba4d22 100644 --- a/engines/mohawk/myst_graphics.cpp +++ b/engines/mohawk/myst_graphics.cpp @@ -40,15 +40,14 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) { if (_vm->getFeatures() & GF_ME) { // High color - initGraphics(_viewport.width(), _viewport.height(), true, NULL); + initGraphics(_viewport.width(), _viewport.height(), true, nullptr); if (_vm->_system->getScreenFormat().bytesPerPixel == 1) error("Myst ME requires greater than 256 colors to run"); } else { // Paletted initGraphics(_viewport.width(), _viewport.height(), true); - setBasePalette(); - setPaletteToScreen(); + clearScreenPalette(); } _pixelFormat = _vm->_system->getScreenFormat(); @@ -73,7 +72,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { // if it's a PICT or WDIB resource. If it's Myst ME it's most likely a PICT, and if it's // original it's definitely a WDIB. However, Myst ME throws us another curve ball in // that PICT resources can contain WDIB's instead of PICT's. - Common::SeekableReadStream *dataStream = NULL; + Common::SeekableReadStream *dataStream = nullptr; if (_vm->getFeatures() & GF_ME && _vm->hasResource(ID_PICT, id)) { // The PICT resource exists. However, it could still contain a MystBitmap @@ -86,7 +85,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { bool isPict = false; - if (_vm->getFeatures() & GF_ME) { + if ((_vm->getFeatures() & GF_ME) && dataStream->size() > 512 + 10 + 4) { // Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap // would be compressed, there's no way to detect for the BM without a hack. // So, we search for the PICT version opcode for detection. @@ -95,7 +94,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { dataStream->seek(0); } - MohawkSurface *mhkSurface = 0; + MohawkSurface *mhkSurface = nullptr; if (isPict) { Image::PICTDecoder pict; @@ -103,12 +102,17 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { if (!pict.loadStream(*dataStream)) error("Could not decode Myst ME PICT"); + delete dataStream; + mhkSurface = new MohawkSurface(pict.getSurface()->convertTo(_pixelFormat)); } else { mhkSurface = _bmpDecoder->decodeImage(dataStream); - if (_vm->getFeatures() & GF_ME) + if (_vm->getFeatures() & GF_ME) { mhkSurface->convertToTrueColor(); + } else { + remapSurfaceToSystemPalette(mhkSurface); + } } assert(mhkSurface); @@ -202,7 +206,7 @@ void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src, if (!(_vm->getFeatures() & GF_ME)) { // Make sure the palette is set assert(mhkSurface->getPalette()); - memcpy(_palette + 10 * 3, mhkSurface->getPalette() + 10 * 3, (256 - 10 * 2) * 3); + memcpy(_palette, mhkSurface->getPalette(), 256 * 3); setPaletteToScreen(); } } @@ -225,9 +229,8 @@ void MystGraphics::copyBackBufferToScreen(Common::Rect r) { void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16 steps, uint16 delay) { - // Do not artificially delay during transitions - int oldEnableDrawingTimeSimulation = _enableDrawingTimeSimulation; - _enableDrawingTimeSimulation = 0; + // Transitions are barely visible without adding delays between the draw calls + enableDrawingTimeSimulation(true); switch (type) { case kTransitionLeftToRight: { @@ -288,7 +291,10 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16 debugC(kDebugView, "Dissolve"); for (int16 step = 0; step < 8; step++) { - simulatePreviousDrawDelay(rect); + // Only one eighth of the rect pixels are updated by a draw step, + // delay by one eighth of the regular time + simulatePreviousDrawDelay(Common::Rect(rect.width() / 8, rect.height())); + transitionDissolve(rect, step); } } @@ -367,7 +373,7 @@ void MystGraphics::runTransition(TransitionType type, Common::Rect rect, uint16 error("Unknown transition %d", type); } - _enableDrawingTimeSimulation = oldEnableDrawingTimeSimulation; + enableDrawingTimeSimulation(false); } void MystGraphics::transitionDissolve(Common::Rect rect, uint step) { @@ -639,8 +645,10 @@ void MystGraphics::simulatePreviousDrawDelay(const Common::Rect &dest) { // Do not draw anything new too quickly after the previous draw call // so that images stay at least a little while on screen // This is enabled only for scripted draw calls - if (time < _nextAllowedDrawTime) + if (time < _nextAllowedDrawTime) { + debugC(kDebugView, "Delaying draw call by %d ms", _nextAllowedDrawTime - time); _vm->_system->delayMillis(_nextAllowedDrawTime - time); + } } // Next draw call allowed at DELAY + AERA * COEFF milliseconds from now @@ -697,10 +705,10 @@ void MystGraphics::clearScreenPalette() { _vm->_system->getPaletteManager()->setPalette(palette, 0, 256); } -void MystGraphics::setBasePalette() { +void MystGraphics::remapSurfaceToSystemPalette(MohawkSurface *mhkSurface) { // Entries [0, 9] of the palette static const byte lowPalette[] = { - 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x00, @@ -723,15 +731,68 @@ void MystGraphics::setBasePalette() { 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, - 0x00, 0x00, 0x00 + 0xFF, 0xFF, 0xFF }; - // Note that 0 and 255 are different from normal Windows. - // Myst seems to hack that to white, resp. black (probably for Mac compat). + byte *originalPalette = mhkSurface->getPalette(); + + // The target palette is made of the Windows reserved palette, and colors 10 to 245 + // of the bitmap palette. Entries 0 to 9 and 246 to 255 of the bitmap palette are + // discarded. + byte targetPalette[256 * 3]; + memcpy(targetPalette, lowPalette, sizeof(lowPalette)); + memcpy(targetPalette + sizeof(lowPalette), originalPalette + sizeof(lowPalette), sizeof(_palette) - sizeof(lowPalette) - sizeof(highPalette)); + memcpy(targetPalette + sizeof(_palette) - sizeof(highPalette), highPalette, sizeof(highPalette)); + + // Remap the discarded entries from the bitmap palette using the target palette. + byte lowColorMap[ARRAYSIZE(lowPalette) / 3]; + byte highColorMap[ARRAYSIZE(highPalette) / 3]; + + for (uint i = 0; i < ARRAYSIZE(lowColorMap); i++) { + uint colorIndex = 3 * i; + byte red = originalPalette[colorIndex + 0]; + byte green = originalPalette[colorIndex + 1]; + byte blue = originalPalette[colorIndex + 2]; + + lowColorMap[i] = getColorIndex(targetPalette, red, green, blue); + } + + for (uint i = 0; i < ARRAYSIZE(highColorMap); i++) { + uint colorIndex = 3 * (i + 246); + byte red = originalPalette[colorIndex + 0]; + byte green = originalPalette[colorIndex + 1]; + byte blue = originalPalette[colorIndex + 2]; + + highColorMap[i] = getColorIndex(targetPalette, red, green, blue); + } + + // Replace the original palette with the target palette + memcpy(originalPalette, targetPalette, sizeof(targetPalette)); + + // Remap the pixel data to the target palette + Graphics::Surface *surface = mhkSurface->getSurface(); + byte *pixels = (byte *) surface->getPixels(); + + for (int i = 0; i < surface->w * surface->h; i++) { + if (pixels[i] < ARRAYSIZE(lowColorMap)) { + pixels[i] = lowColorMap[pixels[i]]; + } else if (pixels[i] >= 246) { + pixels[i] = highColorMap[pixels[i] - 246]; + } + } +} + +byte MystGraphics::getColorIndex(const byte *palette, byte red, byte green, byte blue) { + for (uint i = 0; i < 256; i++) { + if (palette[(3 * i) + 0] == red && palette[(3 * i) + 1] == green && palette[(3 * i) + 2] == blue) { + return i; + } + } - memcpy(_palette, lowPalette, sizeof(lowPalette)); - memset(_palette + sizeof(lowPalette), 0, sizeof(_palette) - sizeof(lowPalette) - sizeof(highPalette)); - memcpy(_palette + sizeof(_palette) - sizeof(highPalette), highPalette, sizeof(highPalette)); + // GDI actually chooses the nearest color if no exact match is found, + // but this should not happen in Myst + debug(1, "Color (%d, %d, %d) not in target palette", red, green, blue); + return 0; } void MystGraphics::setPaletteToScreen() { diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h index 6281c94cc8..cd09a53a3a 100644 --- a/engines/mohawk/myst_graphics.h +++ b/engines/mohawk/myst_graphics.h @@ -56,13 +56,12 @@ public: void fadeFromBlack(); void clearScreenPalette(); - void setBasePalette(); void setPaletteToScreen(); const byte *getPalette() const { return _palette; } protected: - MohawkSurface *decodeImage(uint16 id); - MohawkEngine *getVM() { return (MohawkEngine *)_vm; } + MohawkSurface *decodeImage(uint16 id) override; + MohawkEngine *getVM() override { return (MohawkEngine *)_vm; } private: MohawkEngine_Myst *_vm; @@ -86,6 +85,9 @@ private: void transitionSlideToBottom(Common::Rect rect, uint16 steps, uint16 delay); void transitionPartialToRight(Common::Rect rect, uint32 width, uint32 steps); void transitionPartialToLeft(Common::Rect rect, uint32 width, uint32 steps); + + void remapSurfaceToSystemPalette(MohawkSurface *mhkSurface); + byte getColorIndex(const byte *palette, byte red, byte green, byte blue); }; } // End of namespace Mohawk diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp index 15d74a2253..596180ddb2 100644 --- a/engines/mohawk/myst_scripts.cpp +++ b/engines/mohawk/myst_scripts.cpp @@ -29,8 +29,8 @@ #include "mohawk/video.h" #include "common/system.h" +#include "common/memstream.h" #include "common/textconsole.h" -#include "gui/message.h" namespace Mohawk { @@ -38,7 +38,7 @@ MystScriptEntry::MystScriptEntry() { type = kMystScriptNone; var = 0; argc = 0; - argv = 0; + argv = nullptr; resourceId = 0; u1 = 0; } @@ -81,7 +81,7 @@ MystScriptParser::MystScriptParser(MohawkEngine_Myst *vm) : _vm(vm), _globals(vm->_gameState->_globals) { setupCommonOpcodes(); - _invokingResource = NULL; + _invokingResource = nullptr; _savedCardId = 0; _savedCursorId = 0; _tempVar = 0; @@ -154,7 +154,7 @@ void MystScriptParser::setupCommonOpcodes() { #undef OPCODE -void MystScriptParser::runScript(MystScript script, MystResource *invokingResource) { +void MystScriptParser::runScript(MystScript script, MystArea *invokingResource) { debugC(kDebugScript, "Script Size: %d", script->size()); // Scripted drawing takes more time to simulate older hardware @@ -260,15 +260,6 @@ bool MystScriptParser::setVarValue(uint16 var, uint16 value) { return false; } -// NOTE: Check to be used on Opcodes where var is thought -// not to be used. This emits a warning if var is nonzero. -// It is possible that the opcode does use var 0 in this case, -// but this will catch the majority of missed cases. -void MystScriptParser::varUnusedCheck(uint16 op, uint16 var) { - if (var != 0) - warning("Opcode %d: Unused Var %d", op, var); -} - void MystScriptParser::animatedUpdate(uint16 argc, uint16 *argv, uint16 delay) { uint16 argsRead = 0; @@ -331,7 +322,7 @@ void MystScriptParser::o_changeCardSwitch4(uint16 op, uint16 var, uint16 argc, u if (value) _vm->changeToCard(argv[value -1 ], kTransitionDissolve); - else if (_invokingResource != NULL) + else if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionDissolve); else warning("Missing invokingResource in altDest call"); @@ -344,7 +335,7 @@ void MystScriptParser::o_changeCardSwitchLtR(uint16 op, uint16 var, uint16 argc, if (value) _vm->changeToCard(argv[value -1 ], kTransitionLeftToRight); - else if (_invokingResource != NULL) + else if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionLeftToRight); else warning("Missing invokingResource in altDest call"); @@ -357,7 +348,7 @@ void MystScriptParser::o_changeCardSwitchRtL(uint16 op, uint16 var, uint16 argc, if (value) _vm->changeToCard(argv[value -1 ], kTransitionRightToLeft); - else if (_invokingResource != NULL) + else if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionRightToLeft); else warning("Missing invokingResource in altDest call"); @@ -398,7 +389,7 @@ void MystScriptParser::o_redrawCard(uint16 op, uint16 var, uint16 argc, uint16 * void MystScriptParser::o_goToDest(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionCopy); else warning("Opcode %d: Missing invokingResource", op); @@ -407,7 +398,7 @@ void MystScriptParser::o_goToDest(uint16 op, uint16 var, uint16 argc, uint16 *ar void MystScriptParser::o_goToDestForward(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionDissolve); else warning("Opcode %d: Missing invokingResource", op); @@ -416,7 +407,7 @@ void MystScriptParser::o_goToDestForward(uint16 op, uint16 var, uint16 argc, uin void MystScriptParser::o_goToDestLeft(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionPartToRight); else warning("Opcode %d: Missing invokingResource", op); @@ -425,7 +416,7 @@ void MystScriptParser::o_goToDestLeft(uint16 op, uint16 var, uint16 argc, uint16 void MystScriptParser::o_goToDestRight(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionPartToLeft); else warning("Opcode %d: Missing invokingResource", op); @@ -434,7 +425,7 @@ void MystScriptParser::o_goToDestRight(uint16 op, uint16 var, uint16 argc, uint1 void MystScriptParser::o_goToDestUp(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Change To Dest of Invoking Resource", op); - if (_invokingResource != NULL) + if (_invokingResource != nullptr) _vm->changeToCard(_invokingResource->getDest(), kTransitionTopToBottom); else warning("Opcode %d: Missing invokingResource", op); @@ -442,7 +433,10 @@ void MystScriptParser::o_goToDestUp(uint16 op, uint16 var, uint16 argc, uint16 * void MystScriptParser::o_triggerMovie(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Trigger Type 6 Resource Movie..", op); - // TODO: If movie has sound, pause background music + // The original has code to pause the background music before playing the movie, + // if the movie has a sound track, as well as code to resume it afterwards. But since + // the movie has not yet been loaded at this point, it is impossible to know + // if the movie actually has a sound track. The code is never executed. int16 direction = 1; if (argc == 1) @@ -451,11 +445,9 @@ void MystScriptParser::o_triggerMovie(uint16 op, uint16 var, uint16 argc, uint16 debugC(kDebugScript, "\tDirection: %d", direction); // Trigger resource 6 movie overriding play direction - MystResourceType6 *resource = static_cast<MystResourceType6 *>(_invokingResource); + MystAreaVideo *resource = getInvokingResource<MystAreaVideo>(); resource->setDirection(direction); resource->playMovie(); - - // TODO: If movie has sound, resume background music } void MystScriptParser::o_toggleVarNoRedraw(uint16 op, uint16 var, uint16 argc, uint16 *argv) { @@ -468,7 +460,7 @@ void MystScriptParser::o_drawAreaState(uint16 op, uint16 var, uint16 argc, uint1 debugC(kDebugScript, "Opcode %d: drawAreaState, state: %d", op, argv[0]); debugC(kDebugScript, "\tVar: %d", var); - MystResourceType8 *parent = static_cast<MystResourceType8 *>(_invokingResource->_parent); + MystAreaImageSwitch *parent = static_cast<MystAreaImageSwitch *>(getInvokingResource<MystArea>()->_parent); parent->drawConditionalDataToScreen(argv[0]); } @@ -517,6 +509,11 @@ void MystScriptParser::o_changeCardPop(uint16 op, uint16 var, uint16 argc, uint1 debugC(kDebugScript, "Opcode %d: Return To Stored Card Id", op); debugC(kDebugScript, "\tCardId: %d", _savedCardId); + if (_savedCardId == 0) { + warning("No pushed card to go back to"); + return; + } + TransitionType transition = static_cast<TransitionType>(argv[0]); _vm->changeToCard(_savedCardId, transition); @@ -531,7 +528,7 @@ void MystScriptParser::o_enableAreas(uint16 op, uint16 var, uint16 argc, uint16 for (uint16 i = 0; i < count; i++) { debugC(kDebugScript, "Enable hotspot index %d", argv[i + 1]); - MystResource *resource = 0; + MystArea *resource = nullptr; if (argv[i + 1] == 0xFFFF) resource = _invokingResource; else @@ -556,7 +553,7 @@ void MystScriptParser::o_disableAreas(uint16 op, uint16 var, uint16 argc, uint16 for (uint16 i = 0; i < count; i++) { debugC(kDebugScript, "Disable hotspot index %d", argv[i + 1]); - MystResource *resource = 0; + MystArea *resource = nullptr; if (argv[i + 1] == 0xFFFF) resource = _invokingResource; else @@ -587,7 +584,7 @@ void MystScriptParser::o_toggleAreasActivation(uint16 op, uint16 var, uint16 arg for (uint16 i = 0; i < count; i++) { debugC(kDebugScript, "Enable/Disable hotspot index %d", argv[i + 1]); - MystResource *resource = 0; + MystArea *resource = nullptr; if (argv[i + 1] == 0xFFFF) resource = _invokingResource; else @@ -682,82 +679,20 @@ void MystScriptParser::o_copyImageToBackBuffer(uint16 op, uint16 var, uint16 arg _vm->_gfx->copyImageSectionToBackBuffer(imageId, srcRect, dstRect); } -// TODO: Implement common engine function for read and processing of sound blocks -// for use by this opcode and VIEW sound block. -// TODO: Though the playSound and PlaySoundBlocking opcodes play sounds immediately, -// this opcode changes the main background sound playing.. -// Current behavior here and with VIEW sound block is not right as demonstrated -// by Channelwood Card 3280 (Tank Valve) and water flow sound behavior in pipe -// on cards leading from shed... void MystScriptParser::o_changeBackgroundSound(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - int16 *soundList = NULL; - uint16 *soundListVolume = NULL; - // Used on Stoneship Card 2080 // Used on Channelwood Card 3225 with argc = 8 i.e. Conditional Sound List - if (argc == 1 || argc == 2 || argc == 8) { - debugC(kDebugScript, "Opcode %d: Process Sound Block", op); - uint16 decodeIdx = 0; - - int16 soundAction = argv[decodeIdx++]; - uint16 soundVolume = 65535; - if (soundAction == kMystSoundActionChangeVolume || soundAction > 0) { - soundVolume = argv[decodeIdx++]; - } else if (soundAction == kMystSoundActionConditional) { - debugC(kDebugScript, "Conditional sound list"); - uint16 condVar = argv[decodeIdx++]; - uint16 condVarValue = getVar(condVar); - uint16 condCount = argv[decodeIdx++]; - - debugC(kDebugScript, "\tcondVar: %d = %d", condVar, condVarValue); - debugC(kDebugScript, "\tcondCount: %d", condCount); - - soundList = new int16[condCount]; - soundListVolume = new uint16[condCount]; - - if (condVarValue >= condCount) - warning("Opcode %d: Conditional sound variable outside range", op); - else { - for (uint16 i = 0; i < condCount; i++) { - soundList[i] = argv[decodeIdx++]; - debugC(kDebugScript, "\t\tCondition %d: Action %d", i, soundList[i]); - if (soundAction == kMystSoundActionChangeVolume || soundAction > 0) { - soundListVolume[i] = argv[decodeIdx++]; - } else - soundListVolume[i] = 65535; - debugC(kDebugScript, "\t\tCondition %d: Volume %d", i, soundListVolume[i]); - } - - soundAction = soundList[condVarValue]; - soundVolume = soundListVolume[condVarValue]; - } - } + debugC(kDebugScript, "Opcode %d: Process Sound Block", op); - if (soundAction == kMystSoundActionContinue) - debugC(kDebugScript, "Continue current sound"); - else if (soundAction == kMystSoundActionChangeVolume) { - debugC(kDebugScript, "Continue current sound, change volume"); - debugC(kDebugScript, "\tVolume: %d", soundVolume); - _vm->_sound->changeBackgroundVolumeMyst(soundVolume); - } else if (soundAction == kMystSoundActionStop) { - debugC(kDebugScript, "Stop sound"); - _vm->_sound->stopBackgroundMyst(); - } else if (soundAction > 0) { - debugC(kDebugScript, "Play new Sound, change volume"); - debugC(kDebugScript, "\tSound: %d", soundAction); - debugC(kDebugScript, "\tVolume: %d", soundVolume); - _vm->_sound->replaceBackgroundMyst(soundAction, soundVolume); - } else { - debugC(kDebugScript, "Unknown"); - warning("Unknown sound control value in opcode %d", op); - } - } else - warning("Unknown arg count in opcode %d", op); + Common::MemoryWriteStreamDynamic writeStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES); + for (uint i = 0; i < argc; i++) { + writeStream.writeUint16LE(argv[i]); + } + + Common::MemoryReadStream readStream = Common::MemoryReadStream(writeStream.getData(), writeStream.size()); - delete[] soundList; - soundList = NULL; - delete[] soundListVolume; - soundListVolume = NULL; + MystSoundBlock soundBlock = _vm->readSoundBlock(&readStream); + _vm->applySoundBlock(soundBlock); } void MystScriptParser::o_soundPlaySwitch(uint16 op, uint16 var, uint16 argc, uint16 *argv) { diff --git a/engines/mohawk/myst_scripts.h b/engines/mohawk/myst_scripts.h index 7d8165c762..69052b10f5 100644 --- a/engines/mohawk/myst_scripts.h +++ b/engines/mohawk/myst_scripts.h @@ -34,7 +34,7 @@ namespace Mohawk { #define DECLARE_OPCODE(x) void x(uint16 op, uint16 var, uint16 argc, uint16 *argv) class MohawkEngine_Myst; -class MystResource; +class MystArea; enum MystScriptType { kMystScriptNone, @@ -63,11 +63,11 @@ public: MystScriptParser(MohawkEngine_Myst *vm); virtual ~MystScriptParser(); - void runScript(MystScript script, MystResource *invokingResource = NULL); - void runOpcode(uint16 op, uint16 var = 0, uint16 argc = 0, uint16 *argv = NULL); + void runScript(MystScript script, MystArea *invokingResource = nullptr); + void runOpcode(uint16 op, uint16 var = 0, uint16 argc = 0, uint16 *argv = nullptr); const Common::String getOpcodeDesc(uint16 op); MystScript readScript(Common::SeekableReadStream *stream, MystScriptType type); - void setInvokingResource(MystResource *resource) { _invokingResource = resource; } + void setInvokingResource(MystArea *resource) { _invokingResource = resource; } virtual void disablePersistentScripts() = 0; virtual void runPersistentScripts() = 0; @@ -151,8 +151,6 @@ protected: Common::Array<MystOpcode *> _opcodes; - MystResource *_invokingResource; - uint16 _savedCardId; uint16 _savedMapCardId; uint16 _savedCursorId; @@ -163,9 +161,25 @@ protected: static const uint16 _startCard[]; void setupCommonOpcodes(); - void varUnusedCheck(uint16 op, uint16 var); + + template<class T> + T *getInvokingResource() const; + +private: + MystArea *_invokingResource; }; +template<class T> +T *MystScriptParser::getInvokingResource() const { + T *resource = dynamic_cast<T *>(_invokingResource); + + if (!resource) { + error("Invoking resource has unexpected type"); + } + + return resource; +} + } // End of namespace Mohawk #undef DECLARE_OPCODE diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp index dfa15a9b6c..21c3042359 100644 --- a/engines/mohawk/myst_stacks/channelwood.cpp +++ b/engines/mohawk/myst_stacks/channelwood.cpp @@ -170,7 +170,10 @@ uint16 Channelwood::getVar(uint16 var) { return 0; case 32: // Sound - Water Flowing in Pipe to Book Room Elevator - return ((_state.waterValveStates & 0xf8) == 0xb0 && _state.pipeState) ? 1 : 0; + if ((_state.waterValveStates & 0xf8) == 0xb0) + return _state.pipeState ? 2 : 1; + + return 0; case 33: // Channelwood Lower Walkway to Upper Walkway Spiral Stair Upper Door State if (_state.stairsUpperDoorState) { if (_tempVar == 1) @@ -360,7 +363,7 @@ void Channelwood::o_drawImageChangeCardAndVolume(uint16 op, uint16 var, uint16 a void Channelwood::o_waterTankValveOpen(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Do Water Tank Valve Open Animation", op); - Common::Rect rect = _invokingResource->getRect(); + Common::Rect rect = getInvokingResource<MystArea>()->getRect(); for (uint i = 0; i < 2; i++) for (uint16 imageId = 3601; imageId >= 3595; imageId--) { @@ -374,7 +377,7 @@ void Channelwood::o_waterTankValveOpen(uint16 op, uint16 var, uint16 argc, uint1 void Channelwood::o_leverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generic lever start move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); _vm->_cursor->setCursor(700); _leverPulled = false; @@ -383,7 +386,7 @@ void Channelwood::o_leverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *a void Channelwood::o_leverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generic lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); if (lever->pullLeverV()) { if (!_leverPulled) { @@ -398,7 +401,7 @@ void Channelwood::o_leverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) void Channelwood::o_leverMoveFail(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generic lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); if (lever->pullLeverV()) { if (!_leverPulled) { @@ -416,7 +419,7 @@ void Channelwood::o_leverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *arg debugC(kDebugScript, "Opcode %d: Generic lever end move", op); // Get current lever frame - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Release lever lever->releaseLeverV(); @@ -436,7 +439,7 @@ void Channelwood::o_leverEndMoveResumeBackground(uint16 op, uint16 var, uint16 a void Channelwood::o_leverEndMoveWithSound(uint16 op, uint16 var, uint16 argc, uint16 *argv) { o_leverEndMove(op, var, argc, argv); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); uint16 soundId = lever->getList3(0); if (soundId) _vm->_sound->replaceSoundMyst(soundId); @@ -458,7 +461,7 @@ void Channelwood::o_leverElev3EndMove(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_pumpLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Pump lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); if (lever->pullLeverV()) { uint16 soundId = lever->getList2(0); @@ -472,7 +475,7 @@ void Channelwood::o_pumpLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *ar void Channelwood::o_pumpLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { o_leverEndMove(op, var, argc, argv); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); uint16 soundId = lever->getList3(0); if (soundId) _vm->_sound->replaceBackgroundMyst(soundId, 36864); @@ -481,7 +484,7 @@ void Channelwood::o_pumpLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_stairsDoorToggle(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Play stairs door video", op); - MystResourceType6 *movie = static_cast<MystResourceType6 *>(_invokingResource); + MystAreaVideo *movie = getInvokingResource<MystAreaVideo>(); if (_state.stairsUpperDoorState) { // Close door, play the open movie backwards @@ -497,7 +500,7 @@ void Channelwood::o_stairsDoorToggle(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_valveHandleMove1(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); if (handle->getRect().contains(mouse)) { @@ -513,7 +516,7 @@ void Channelwood::o_valveHandleMove1(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_valveHandleMoveStart1(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move start", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); uint16 soundId = handle->getList1(0); if (soundId) _vm->_sound->replaceSoundMyst(soundId); @@ -525,7 +528,7 @@ void Channelwood::o_valveHandleMoveStart1(uint16 op, uint16 var, uint16 argc, ui void Channelwood::o_valveHandleMoveStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move stop", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); // Update state with valve position if (_tempVar <= 5) @@ -548,7 +551,7 @@ void Channelwood::o_valveHandleMoveStop(uint16 op, uint16 var, uint16 argc, uint void Channelwood::o_valveHandleMove2(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); if (handle->getRect().contains(mouse)) { @@ -564,7 +567,7 @@ void Channelwood::o_valveHandleMove2(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_valveHandleMoveStart2(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move start", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); uint16 soundId = handle->getList1(0); if (soundId) _vm->_sound->replaceSoundMyst(soundId); @@ -576,7 +579,7 @@ void Channelwood::o_valveHandleMoveStart2(uint16 op, uint16 var, uint16 argc, ui void Channelwood::o_valveHandleMove3(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); if (handle->getRect().contains(mouse)) { @@ -592,7 +595,7 @@ void Channelwood::o_valveHandleMove3(uint16 op, uint16 var, uint16 argc, uint16 void Channelwood::o_valveHandleMoveStart3(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Valve handle move start", op); - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); uint16 soundId = handle->getList1(0); if (soundId) _vm->_sound->replaceSoundMyst(soundId); @@ -618,24 +621,32 @@ void Channelwood::o_hologramMonitor(uint16 op, uint16 var, uint16 argc, uint16 * switch (button) { case 0: handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monalgh", kChannelwoodStack)); + if (!handle) + error("Failed to open monalgh movie"); + handle->moveTo(227, 70); break; case 1: handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monamth", kChannelwoodStack)); + if (!handle) + error("Failed to open monamth movie"); + handle->moveTo(227, 70); break; case 2: handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monasirs", kChannelwoodStack)); + if (!handle) + error("Failed to open monasirs movie"); + handle->moveTo(227, 70); break; case 3: handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monsmsg", kChannelwoodStack)); + if (!handle) + error("Failed to open monsmsg movie"); + handle->moveTo(226, 68); break; default: warning("Opcode %d Control Variable Out of Range", op); break; } - - // Move the video to the right location - if (handle) - handle->moveTo(227, 70); } } @@ -677,13 +688,13 @@ void Channelwood::o_hologramTemple(uint16 op, uint16 var, uint16 argc, uint16 *a void Channelwood::o_executeMouseUp(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Execute mouse up", op); - MystResourceType5 *resource = static_cast<MystResourceType5 *>(_vm->_resources[argv[0]]); + MystArea *resource = _vm->getViewResource<MystArea>(argv[0]); resource->handleMouseUp(); } void Channelwood::o_waterTankValveClose(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Do Water Tank Valve Close Animation", op); - Common::Rect rect = _invokingResource->getRect(); + Common::Rect rect = getInvokingResource<MystArea>()->getRect(); for (uint i = 0; i < 2; i++) for (uint16 imageId = 3595; imageId <= 3601; imageId++) { @@ -744,13 +755,14 @@ void Channelwood::o_soundReplace(uint16 op, uint16 var, uint16 argc, uint16 *arg uint16 soundId = argv[0]; - // TODO: If is foreground playing - _vm->_sound->replaceSoundMyst(soundId); + if (!_vm->_sound->isPlaying()) { + _vm->_sound->replaceSoundMyst(soundId); + } } void Channelwood::o_lever_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generic lever init", op); - _leverAction = static_cast<MystResourceType5 *>(_invokingResource); + _leverAction = getInvokingResource<MystArea>(); } void Channelwood::o_pipeValve_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { diff --git a/engines/mohawk/myst_stacks/channelwood.h b/engines/mohawk/myst_stacks/channelwood.h index bd5d7ffe94..ac875e52d8 100644 --- a/engines/mohawk/myst_stacks/channelwood.h +++ b/engines/mohawk/myst_stacks/channelwood.h @@ -40,16 +40,16 @@ public: Channelwood(MohawkEngine_Myst *vm); ~Channelwood(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9932; } + virtual uint16 getMap() override { return 9932; } DECLARE_OPCODE(o_bridgeToggle); DECLARE_OPCODE(o_pipeExtend); @@ -94,7 +94,7 @@ private: uint16 _doorOpened; // 68 bool _leverPulled; - MystResourceType5 *_leverAction; // 72 + MystArea *_leverAction; // 72 bool pipeChangeValve(bool open, uint16 mask); }; diff --git a/engines/mohawk/myst_stacks/credits.cpp b/engines/mohawk/myst_stacks/credits.cpp index b9ff8b26aa..c382263f7c 100644 --- a/engines/mohawk/myst_stacks/credits.cpp +++ b/engines/mohawk/myst_stacks/credits.cpp @@ -28,7 +28,6 @@ #include "mohawk/myst_stacks/credits.h" #include "common/system.h" -#include "gui/message.h" namespace Mohawk { namespace MystStacks { @@ -37,6 +36,7 @@ namespace MystStacks { Credits::Credits(MohawkEngine_Myst *vm) : MystScriptParser(vm) { setupOpcodes(); + _curImage = 0; } Credits::~Credits() { @@ -66,8 +66,10 @@ void Credits::runPersistentScripts() { _curImage++; // After the 6th image has shown, it's time to quit - if (_curImage == 7) + if (_curImage == 7) { _vm->quitGame(); + return; + } // Draw next image _vm->drawCardBackground(); diff --git a/engines/mohawk/myst_stacks/credits.h b/engines/mohawk/myst_stacks/credits.h index 3c0f969203..c2c20372bd 100644 --- a/engines/mohawk/myst_stacks/credits.h +++ b/engines/mohawk/myst_stacks/credits.h @@ -40,12 +40,12 @@ public: Credits(MohawkEngine_Myst *vm); ~Credits(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); + uint16 getVar(uint16 var) override; DECLARE_OPCODE(o_runCredits); diff --git a/engines/mohawk/myst_stacks/demo.h b/engines/mohawk/myst_stacks/demo.h index f19b9a6c2c..64a392502f 100644 --- a/engines/mohawk/myst_stacks/demo.h +++ b/engines/mohawk/myst_stacks/demo.h @@ -40,8 +40,8 @@ public: Demo(MohawkEngine_Myst *vm); ~Demo(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); diff --git a/engines/mohawk/myst_stacks/dni.h b/engines/mohawk/myst_stacks/dni.h index 3dc4645bd3..1a5f0911f9 100644 --- a/engines/mohawk/myst_stacks/dni.h +++ b/engines/mohawk/myst_stacks/dni.h @@ -40,12 +40,12 @@ public: Dni(MohawkEngine_Myst *vm); ~Dni(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); + uint16 getVar(uint16 var) override; void atrus_run(); void loopVideo_run(); diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp index dc66984398..f448108199 100644 --- a/engines/mohawk/myst_stacks/intro.cpp +++ b/engines/mohawk/myst_stacks/intro.cpp @@ -28,8 +28,6 @@ #include "mohawk/video.h" #include "mohawk/myst_stacks/intro.h" -#include "gui/message.h" - namespace Mohawk { namespace MystStacks { @@ -170,7 +168,7 @@ void Intro::mystLinkBook_run() { void Intro::o_mystLinkBook_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Myst link book init", op); - _linkBookMovie = static_cast<MystResourceType6 *>(_invokingResource); + _linkBookMovie = getInvokingResource<MystAreaVideo>(); _startTime = 1; _linkBookRunning = true; } diff --git a/engines/mohawk/myst_stacks/intro.h b/engines/mohawk/myst_stacks/intro.h index a6c4a594d2..0095706795 100644 --- a/engines/mohawk/myst_stacks/intro.h +++ b/engines/mohawk/myst_stacks/intro.h @@ -29,7 +29,7 @@ namespace Mohawk { -class MystResourceType6; +class MystAreaVideo; struct MystScriptEntry; namespace MystStacks { @@ -41,12 +41,12 @@ public: Intro(MohawkEngine_Myst *vm); ~Intro(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); + uint16 getVar(uint16 var) override; DECLARE_OPCODE(o_useLinkBook); @@ -60,7 +60,7 @@ private: uint16 _introStep; bool _linkBookRunning; - MystResourceType6 *_linkBookMovie; + MystAreaVideo *_linkBookMovie; }; } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/makingof.cpp b/engines/mohawk/myst_stacks/makingof.cpp index 1059fd0c5e..a0a1f359ba 100644 --- a/engines/mohawk/myst_stacks/makingof.cpp +++ b/engines/mohawk/myst_stacks/makingof.cpp @@ -27,8 +27,6 @@ #include "mohawk/video.h" #include "mohawk/myst_stacks/makingof.h" -#include "gui/message.h" - namespace Mohawk { namespace MystStacks { diff --git a/engines/mohawk/myst_stacks/makingof.h b/engines/mohawk/myst_stacks/makingof.h index 79ef913bcf..41f91bc3fa 100644 --- a/engines/mohawk/myst_stacks/makingof.h +++ b/engines/mohawk/myst_stacks/makingof.h @@ -40,8 +40,8 @@ public: MakingOf(MohawkEngine_Myst *vm); ~MakingOf(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp index ffcaa226c6..3324c9a22d 100644 --- a/engines/mohawk/myst_stacks/mechanical.cpp +++ b/engines/mohawk/myst_stacks/mechanical.cpp @@ -40,6 +40,9 @@ Mechanical::Mechanical(MohawkEngine_Myst *vm) : setupOpcodes(); _elevatorGoingMiddle = false; + _elevatorPosition = 0; + + _crystalLit = 0; _mystStaircaseState = false; _fortressPosition = 0; @@ -277,7 +280,7 @@ void Mechanical::o_throneEnablePassage(uint16 op, uint16 var, uint16 argc, uint1 void Mechanical::o_birdCrankStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Mechanical bird crank start", op); - MystResourceType11 *crank = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *crank = getInvokingResource<MystAreaDrag>(); uint16 crankSoundId = crank->getList2(0); _vm->_sound->replaceSoundMyst(crankSoundId, Audio::Mixer::kMaxChannelVolume, true); @@ -285,16 +288,16 @@ void Mechanical::o_birdCrankStart(uint16 op, uint16 var, uint16 argc, uint16 *ar _birdSingEndTime = 0; _birdCrankStartTime = _vm->_system->getMillis(); - MystResourceType6 *crankMovie = static_cast<MystResourceType6 *>(crank->getSubResource(0)); + MystAreaVideo *crankMovie = static_cast<MystAreaVideo *>(crank->getSubResource(0)); crankMovie->playMovie(); } void Mechanical::o_birdCrankStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Mechanical bird crank stop", op); - MystResourceType11 *crank = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *crank = getInvokingResource<MystAreaDrag>(); - MystResourceType6 *crankMovie = static_cast<MystResourceType6 *>(crank->getSubResource(0)); + MystAreaVideo *crankMovie = static_cast<MystAreaVideo *>(crank->getSubResource(0)); crankMovie->pauseMovie(true); uint16 crankSoundId = crank->getList2(1); @@ -334,7 +337,7 @@ void Mechanical::o_fortressStaircaseMovie(uint16 op, uint16 var, uint16 argc, ui void Mechanical::o_elevatorRotationStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Elevator rotation lever start", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); _elevatorRotationLeverMoving = true; @@ -349,7 +352,7 @@ void Mechanical::o_elevatorRotationMove(uint16 op, uint16 var, uint16 argc, uint debugC(kDebugScript, "Opcode %d: Elevator rotation lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -367,7 +370,7 @@ void Mechanical::o_elevatorRotationStop(uint16 op, uint16 var, uint16 argc, uint debugC(kDebugScript, "Opcode %d: Elevator rotation lever stop", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Get current lever frame int16 maxStep = lever->getNumFrames() - 1; @@ -416,7 +419,7 @@ void Mechanical::o_fortressRotationSpeedStart(uint16 op, uint16 var, uint16 argc _vm->_cursor->setCursor(700); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); } @@ -424,7 +427,7 @@ void Mechanical::o_fortressRotationSpeedMove(uint16 op, uint16 var, uint16 argc, debugC(kDebugScript, "Opcode %d Fortress rotation speed lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -441,7 +444,7 @@ void Mechanical::o_fortressRotationSpeedMove(uint16 op, uint16 var, uint16 argc, void Mechanical::o_fortressRotationSpeedStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d Fortress rotation speed lever stop", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Release lever for (int i = _fortressRotationSpeed; i >= 0; i--) { @@ -459,7 +462,7 @@ void Mechanical::o_fortressRotationBrakeStart(uint16 op, uint16 var, uint16 argc _vm->_cursor->setCursor(700); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(_fortressRotationBrake); } @@ -467,7 +470,7 @@ void Mechanical::o_fortressRotationBrakeMove(uint16 op, uint16 var, uint16 argc, debugC(kDebugScript, "Opcode %d Fortress rotation brake lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -484,7 +487,7 @@ void Mechanical::o_fortressRotationBrakeMove(uint16 op, uint16 var, uint16 argc, void Mechanical::o_fortressRotationBrakeStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d Fortress rotation brake lever stop", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(_fortressRotationBrake); _vm->checkCursorHints(); @@ -495,7 +498,7 @@ void Mechanical::o_fortressSimulationSpeedStart(uint16 op, uint16 var, uint16 ar _vm->_cursor->setCursor(700); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); } @@ -503,7 +506,7 @@ void Mechanical::o_fortressSimulationSpeedMove(uint16 op, uint16 var, uint16 arg debugC(kDebugScript, "Opcode %d Fortress rotation simulator speed lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -520,7 +523,7 @@ void Mechanical::o_fortressSimulationSpeedMove(uint16 op, uint16 var, uint16 arg void Mechanical::o_fortressSimulationSpeedStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d Fortress rotation simulator speed lever stop", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Release lever for (int i = _fortressSimulationSpeed; i >= 0; i--) { @@ -538,7 +541,7 @@ void Mechanical::o_fortressSimulationBrakeStart(uint16 op, uint16 var, uint16 ar _vm->_cursor->setCursor(700); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(_fortressSimulationBrake); } @@ -546,7 +549,7 @@ void Mechanical::o_fortressSimulationBrakeMove(uint16 op, uint16 var, uint16 arg debugC(kDebugScript, "Opcode %d Fortress rotation simulator brake lever move", op); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // Make the handle follow the mouse int16 maxStep = lever->getNumFrames() - 1; @@ -563,7 +566,7 @@ void Mechanical::o_fortressSimulationBrakeMove(uint16 op, uint16 var, uint16 arg void Mechanical::o_fortressSimulationBrakeStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d Fortress rotation simulator brake lever stop", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(_fortressSimulationBrake); _vm->checkCursorHints(); @@ -664,7 +667,7 @@ void Mechanical::o_elevatorTopMovie(uint16 op, uint16 var, uint16 argc, uint16 * void Mechanical::o_fortressRotationSetPosition(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Set fortress position", op); - VideoHandle gears = _fortressRotationGears->playMovie(); + VideoHandle gears = _fortressRotationGears->getMovieHandle(); uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames(); // Myst ME short movie workaround, explained in o_fortressRotation_init @@ -737,7 +740,7 @@ void Mechanical::o_throne_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) // Used on Card 6238 (Sirrus' Throne) and Card 6027 (Achenar's Throne) debugC(kDebugScript, "Opcode %d: Brother throne init", op); - _invokingResource->setEnabled(getVar(var)); + getInvokingResource<MystArea>()->setEnabled(getVar(var)); } void Mechanical::o_fortressStaircase_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { @@ -763,13 +766,13 @@ void Mechanical::o_bird_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { _birdSinging = false; _birdSingEndTime = 0; - _bird = static_cast<MystResourceType6 *>(_invokingResource); + _bird = getInvokingResource<MystAreaVideo>(); } void Mechanical::o_snakeBox_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Snake box init", op); - _snakeBox = static_cast<MystResourceType6 *>(_invokingResource); + _snakeBox = getInvokingResource<MystAreaVideo>(); } void Mechanical::elevatorRotation_run() { @@ -798,7 +801,7 @@ void Mechanical::o_elevatorRotation_init(uint16 op, uint16 var, uint16 argc, uin } void Mechanical::fortressRotation_run() { - VideoHandle gears = _fortressRotationGears->playMovie(); + VideoHandle gears = _fortressRotationGears->getMovieHandle(); double oldRate = gears->getRate().toDouble(); uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames(); @@ -872,7 +875,7 @@ void Mechanical::fortressRotation_run() { void Mechanical::o_fortressRotation_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Fortress rotation init", op); - _fortressRotationGears = static_cast<MystResourceType6 *>(_invokingResource); + _fortressRotationGears = getInvokingResource<MystAreaVideo>(); VideoHandle gears = _fortressRotationGears->playMovie(); gears->setLooping(true); @@ -938,13 +941,22 @@ void Mechanical::fortressSimulation_run() { holo->setLooping(true); holo->setRate(0); + // HACK: Support negative rates with edit lists + _fortressSimulationHoloRate = 0; + // END HACK + _vm->_cursor->showCursor(); _fortressSimulationInit = false; } else { - VideoHandle holo = _fortressSimulationHolo->playMovie(); + VideoHandle holo = _fortressSimulationHolo->getMovieHandle(); double oldRate = holo->getRate().toDouble(); + + // HACK: Support negative rates with edit lists + oldRate = _fortressSimulationHoloRate; + // END HACK + uint32 moviePosition = Audio::Timestamp(holo->getTime(), 600).totalNumberOfFrames(); int32 positionInQuarter = 900 - (moviePosition + 900) % 1800; @@ -978,7 +990,26 @@ void Mechanical::fortressSimulation_run() { newRate = CLIP<double>(newRate, -2.5, 2.5); - holo->setRate(Common::Rational((int)(newRate * 1000.0), 1000)); + // HACK: Support negative rates with edit lists + + // Our current QuickTime implementation does not support negative + // playback rates for movies using edit lists. + // The fortress rotation simulator movie this code handles is the + // only movie in the game requiring that feature. + + // This hack approximates the next frame to display when the rate + // is negative, and seeks to it. It's not intended to be precise. + + _fortressSimulationHoloRate = newRate; + + if (_fortressSimulationHoloRate < 0) { + double newMoviePosition = moviePosition + _fortressSimulationHoloRate * 10; + holo->setRate(0); + holo->seek(Audio::Timestamp(0, (uint)newMoviePosition, 600)); + } else { + holo->setRate(Common::Rational((int)(newRate * 1000.0), 1000)); + } + // END HACK _gearsWereRunning = true; } else if (_gearsWereRunning) { @@ -986,6 +1017,11 @@ void Mechanical::fortressSimulation_run() { uint16 simulationPosition = (moviePosition + 900) / 1800 % 4; holo->setRate(0); + + // HACK: Support negative rates with edit lists + _fortressSimulationHoloRate = 0; + // END HACK + holo->seek(Audio::Timestamp(0, 1800 * simulationPosition, 600)); _vm->_sound->playSoundBlocking( _fortressRotationSounds[simulationPosition]); @@ -997,7 +1033,7 @@ void Mechanical::fortressSimulation_run() { void Mechanical::o_fortressSimulation_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Fortress rotation simulator init", op); - _fortressSimulationHolo = static_cast<MystResourceType6 *>(_invokingResource); + _fortressSimulationHolo = getInvokingResource<MystAreaVideo>(); _fortressSimulationStartSound1 = argv[0]; _fortressSimulationStartSound2 = argv[1]; @@ -1019,7 +1055,7 @@ void Mechanical::o_fortressSimulation_init(uint16 op, uint16 var, uint16 argc, u void Mechanical::o_fortressSimulationStartup_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Fortress rotation simulator startup init", op); - _fortressSimulationStartup = static_cast<MystResourceType6 *>(_invokingResource); + _fortressSimulationStartup = getInvokingResource<MystAreaVideo>(); } } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/mechanical.h b/engines/mohawk/myst_stacks/mechanical.h index 6360b2be2d..aae02df433 100644 --- a/engines/mohawk/myst_stacks/mechanical.h +++ b/engines/mohawk/myst_stacks/mechanical.h @@ -40,16 +40,16 @@ public: Mechanical(MohawkEngine_Myst *vm); ~Mechanical(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9931; } + virtual uint16 getMap() override { return 9931; } void birdSing_run(); void elevatorRotation_run(); @@ -109,7 +109,7 @@ private: uint16 _fortressRotationBrake; // 80 uint16 _fortressPosition; // 82 uint16 _fortressRotationSounds[4]; // 86 to 92 - MystResourceType6 *_fortressRotationGears; // 172 + MystAreaVideo *_fortressRotationGears; // 172 bool _fortressRotationShortMovieWorkaround; uint32 _fortressRotationShortMovieCount; @@ -121,8 +121,12 @@ private: uint16 _fortressSimulationBrake; // 98 uint16 _fortressSimulationStartSound1; // 102 uint16 _fortressSimulationStartSound2; // 100 - MystResourceType6 *_fortressSimulationHolo; // 160 - MystResourceType6 *_fortressSimulationStartup; // 164 + MystAreaVideo *_fortressSimulationHolo; // 160 + MystAreaVideo *_fortressSimulationStartup; // 164 + + // HACK: Support negative rates with edit lists + double _fortressSimulationHoloRate; + // END HACK uint16 _elevatorGoingDown; // 112 @@ -143,10 +147,10 @@ private: bool _birdSinging; // 144 uint32 _birdCrankStartTime; // 136 uint32 _birdSingEndTime; // 140 - MystResourceType6 *_bird; // 152 + MystAreaVideo *_bird; // 152 - MystResourceType6 *_snakeBox; // 156 + MystAreaVideo *_snakeBox; // 156 }; } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp index 98f0aa5349..bd50c4feb3 100644 --- a/engines/mohawk/myst_stacks/myst.cpp +++ b/engines/mohawk/myst_stacks/myst.cpp @@ -33,8 +33,6 @@ #include "common/system.h" #include "common/textconsole.h" -#include "gui/message.h" - namespace Mohawk { namespace MystStacks { @@ -50,14 +48,16 @@ Myst::Myst(MohawkEngine_Myst *vm) : _libraryBookcaseChanged = false; _dockVaultState = 0; _cabinDoorOpened = 0; + _cabinHandleDown = 0; _cabinMatchState = 2; + _cabinGaugeMovieEnabled = false; _matchBurning = false; - _tree = 0; - _treeAlcove = 0; + _tree = nullptr; + _treeAlcove = nullptr; _treeStopped = false; _treeMinPosition = 0; _imagerValidationStep = 0; - _observatoryCurrentSlider = 0; + _observatoryCurrentSlider = nullptr; _butterfliesMoviePlayed = false; _state.treeLastMoveTime = _vm->_system->getMillis(); } @@ -626,7 +626,7 @@ uint16 Myst::getVar(uint16 var) { case 307: // Cabin Boiler Fully Pressurized return _state.cabinPilotLightLit == 1 && _state.cabinValvePosition > 12; case 308: // Cabin handle position - return 0; // Not implemented in the original + return _cabinHandleDown; default: return MystScriptParser::getVar(var); } @@ -764,6 +764,9 @@ bool Myst::setVarValue(uint16 var, uint16 value) { case 304: // Myst Library Image Present on Tower Rotation Map _towerRotationMapInitialized = value; break; + case 308: // Cabin handle position + _cabinHandleDown = value; + break; case 309: // Tree stopped _treeStopped = value; break; @@ -860,14 +863,14 @@ void Myst::o_fireplaceToggleButton(uint16 op, uint16 var, uint16 argc, uint16 *a if (line & bitmask) { // Unset button for (uint i = 4795; i >= 4779; i--) { - _vm->_gfx->copyImageToScreen(i, _invokingResource->getRect()); + _vm->_gfx->copyImageToScreen(i, getInvokingResource<MystArea>()->getRect()); _vm->_system->updateScreen(); } _fireplaceLines[var - 17] &= ~bitmask; } else { // Set button for (uint i = 4779; i <= 4795; i++) { - _vm->_gfx->copyImageToScreen(i, _invokingResource->getRect()); + _vm->_gfx->copyImageToScreen(i, getInvokingResource<MystArea>()->getRect()); _vm->_system->updateScreen(); } _fireplaceLines[var - 17] |= bitmask; @@ -1251,7 +1254,7 @@ void Myst::o_imagerPlayButton(uint16 op, uint16 var, uint16 argc, uint16 *argv) void Myst::o_imagerEraseButton(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Imager erase button", op); - _imagerRedButton = static_cast<MystResourceType8 *>(_invokingResource->_parent); + _imagerRedButton = static_cast<MystAreaImageSwitch *>(getInvokingResource<MystArea>()->_parent); for (uint i = 0; i < 4; i++) _imagerSound[i] = argv[i]; _imagerValidationCard = argv[4]; @@ -1351,7 +1354,7 @@ void Myst::o_towerElevatorAnimation(uint16 op, uint16 var, uint16 argc, uint16 * void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generator button pressed", op); - MystResource *button = _invokingResource->_parent; + MystArea *button = getInvokingResource<MystArea>()->_parent; generatorRedrawRocket(); @@ -1376,7 +1379,7 @@ void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 * if (_generatorVoltage) _vm->_sound->replaceSoundMyst(6297); else { - _vm->_sound->replaceSoundMyst(7297); // TODO: Replace with play sound and replace background 4297 + _vm->_sound->replaceSoundMyst(7297); _vm->_sound->replaceBackgroundMyst(4297); } @@ -1385,7 +1388,7 @@ void Myst::o_generatorButtonPressed(uint16 op, uint16 var, uint16 argc, uint16 * } // Redraw button - _vm->redrawArea(button->getType8Var()); + _vm->redrawArea(button->getImageSwitchVar()); // Blow breaker if (_state.generatorVoltage > 59) @@ -1398,8 +1401,8 @@ void Myst::generatorRedrawRocket() { _vm->redrawArea(97); } -void Myst::generatorButtonValue(MystResource *button, uint16 &mask, uint16 &value) { - switch (button->getType8Var()) { +void Myst::generatorButtonValue(MystArea *button, uint16 &mask, uint16 &value) { + switch (button->getImageSwitchVar()) { case 52: // Generator Switch #1 mask = 1; value = 10; @@ -1466,7 +1469,7 @@ void Myst::o_cabinSafeHandleStartMove(uint16 op, uint16 var, uint16 argc, uint16 debugC(kDebugScript, "Opcode %d: Cabin safe handle start move", op); // Used on Card 4100 - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); handle->drawFrame(0); _vm->_cursor->setCursor(700); _tempVar = 0; @@ -1476,7 +1479,7 @@ void Myst::o_cabinSafeHandleMove(uint16 op, uint16 var, uint16 argc, uint16 *arg debugC(kDebugScript, "Opcode %d: Cabin safe handle move", op); // Used on Card 4100 - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); if (handle->pullLeverV()) { // Sound not played yet @@ -1506,7 +1509,7 @@ void Myst::o_cabinSafeHandleEndMove(uint16 op, uint16 var, uint16 argc, uint16 * debugC(kDebugScript, "Opcode %d: Cabin safe handle end move", op); // Used on Card 4100 - MystResourceType12 *handle = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *handle = getInvokingResource<MystVideoInfo>(); handle->drawFrame(0); _vm->checkCursorHints(); } @@ -1804,7 +1807,7 @@ void Myst::o_observatoryTimeSliderMove(uint16 op, uint16 var, uint16 argc, uint1 void Myst::o_circuitBreakerStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Circuit breaker start move", op); - MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *breaker = getInvokingResource<MystVideoInfo>(); breaker->drawFrame(0); _vm->_cursor->setCursor(700); _tempVar = 0; @@ -1813,7 +1816,7 @@ void Myst::o_circuitBreakerStartMove(uint16 op, uint16 var, uint16 argc, uint16 void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Circuit breaker move", op); - MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *breaker = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); int16 maxStep = breaker->getStepsV() - 1; @@ -1828,7 +1831,7 @@ void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv // Breaker switched if (step == maxStep) { // Choose breaker - if (breaker->getType8Var() == 93) { + if (breaker->getImageSwitchVar() == 93) { // Voltage is still too high or not broken if (_state.generatorVoltage > 59 || _state.generatorBreakers != 1) { uint16 soundId = breaker->getList2(1); @@ -1864,8 +1867,8 @@ void Myst::o_circuitBreakerMove(uint16 op, uint16 var, uint16 argc, uint16 *argv void Myst::o_circuitBreakerEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Circuit breaker end move", op); - MystResourceType12 *breaker = static_cast<MystResourceType12 *>(_invokingResource); - _vm->redrawArea(breaker->getType8Var()); + MystVideoInfo *breaker = getInvokingResource<MystVideoInfo>(); + _vm->redrawArea(breaker->getImageSwitchVar()); _vm->checkCursorHints(); } @@ -2138,7 +2141,7 @@ void Myst::tree_run() { // Check if alcove is accessible treeSetAlcoveAccessible(); - if (_cabinGaugeMovie) { + if (_cabinGaugeMovieEnabled) { Common::Rational rate = boilerComputeGaugeRate(pressure, delay); boilerResetGauge(rate); } @@ -2187,22 +2190,22 @@ void Myst::o_rocketSoundSliderEndMove(uint16 op, uint16 var, uint16 argc, uint16 if (_state.generatorVoltage == 59 && !_state.generatorBreakers && _rocketSliderSound) _vm->_sound->stopSound(); - if (_invokingResource == _rocketSlider1) + if (getInvokingResource<MystArea>() == _rocketSlider1) _state.rocketSliderPosition[0] = _rocketSlider1->_pos.y; - else if (_invokingResource == _rocketSlider2) + else if (getInvokingResource<MystArea>() == _rocketSlider2) _state.rocketSliderPosition[1] = _rocketSlider2->_pos.y; - else if (_invokingResource == _rocketSlider3) + else if (getInvokingResource<MystArea>() == _rocketSlider3) _state.rocketSliderPosition[2] = _rocketSlider3->_pos.y; - else if (_invokingResource == _rocketSlider4) + else if (getInvokingResource<MystArea>() == _rocketSlider4) _state.rocketSliderPosition[3] = _rocketSlider4->_pos.y; - else if (_invokingResource == _rocketSlider5) + else if (getInvokingResource<MystArea>() == _rocketSlider5) _state.rocketSliderPosition[4] = _rocketSlider5->_pos.y; _vm->_sound->resumeBackgroundMyst(); } void Myst::rocketSliderMove() { - MystResourceType10 *slider = static_cast<MystResourceType10 *>(_invokingResource); + MystAreaSlider *slider = getInvokingResource<MystAreaSlider>(); if (_state.generatorVoltage == 59 && !_state.generatorBreakers) { uint16 soundId = rocketSliderGetSound(slider->_pos.y); @@ -2262,7 +2265,7 @@ void Myst::rocketCheckSolution() { if (solved) { // Reset lever position - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); // Book appearing @@ -2299,17 +2302,17 @@ void Myst::rocketCheckSolution() { void Myst::o_rocketPianoStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket piano start move", op); - MystResourceType11 *key = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *key = getInvokingResource<MystAreaDrag>(); // What the hell?? - Common::Rect src = key->_subImages[1].rect; - Common::Rect rect = key->_subImages[0].rect; + Common::Rect src = key->getSubImage(1).rect; + Common::Rect rect = key->getSubImage(0).rect; Common::Rect dest = rect; dest.top = 332 - rect.bottom; dest.bottom = 332 - rect.top; // Draw pressed piano key - _vm->_gfx->copyImageSectionToScreen(key->_subImages[1].wdib, src, dest); + _vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest); _vm->_system->updateScreen(); // Play note @@ -2326,29 +2329,29 @@ void Myst::o_rocketPianoMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { Common::Rect piano = Common::Rect(85, 123, 460, 270); // Unpress previous key - MystResourceType11 *key = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *key = getInvokingResource<MystAreaDrag>(); - Common::Rect src = key->_subImages[0].rect; + Common::Rect src = key->getSubImage(0).rect; Common::Rect dest = src; dest.top = 332 - src.bottom; dest.bottom = 332 - src.top; // Draw unpressed piano key - _vm->_gfx->copyImageSectionToScreen(key->_subImages[0].wdib, src, dest); + _vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest); if (piano.contains(mouse)) { - MystResource *resource = _vm->updateCurrentResource(); - if (resource && resource->type == kMystDragArea) { + MystArea *resource = _vm->updateCurrentResource(); + if (resource && resource->type == kMystAreaDrag) { // Press new key - key = static_cast<MystResourceType11 *>(resource); - src = key->_subImages[1].rect; - Common::Rect rect = key->_subImages[0].rect; + key = static_cast<MystAreaDrag *>(resource); + src = key->getSubImage(1).rect; + Common::Rect rect = key->getSubImage(0).rect; dest = rect; dest.top = 332 - rect.bottom; dest.bottom = 332 - rect.top; // Draw pressed piano key - _vm->_gfx->copyImageSectionToScreen(key->_subImages[1].wdib, src, dest); + _vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest); // Play note if (_state.generatorVoltage == 59 && !_state.generatorBreakers) { @@ -2368,15 +2371,15 @@ void Myst::o_rocketPianoMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_rocketPianoStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket piano end move", op); - MystResourceType8 *key = static_cast<MystResourceType8 *>(_invokingResource); + MystAreaImageSwitch *key = getInvokingResource<MystAreaImageSwitch>(); - Common::Rect &src = key->_subImages[0].rect; + Common::Rect src = key->getSubImage(0).rect; Common::Rect dest = src; dest.top = 332 - src.bottom; dest.bottom = 332 - src.top; // Draw unpressed piano key - _vm->_gfx->copyImageSectionToScreen(key->_subImages[0].wdib, src, dest); + _vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest); _vm->_system->updateScreen(); _vm->_sound->stopSound(); @@ -2386,7 +2389,7 @@ void Myst::o_rocketPianoStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_rocketLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket lever start move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); _vm->_cursor->setCursor(700); _rocketLeverPosition = 0; @@ -2406,7 +2409,7 @@ void Myst::o_rocketOpenBook(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_rocketLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); // Make the lever follow the mouse @@ -2435,7 +2438,7 @@ void Myst::o_rocketLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_rocketLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket lever end move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); _vm->checkCursorHints(); _rocketLeverPosition = 0; @@ -2712,7 +2715,7 @@ void Myst::clockWheel_run() { } void Myst::clockWheelStartTurn(uint16 wheel) { - MystResourceType11 *resource = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *resource = getInvokingResource<MystAreaDrag>(); uint16 soundId = resource->getList1(0); if (soundId) @@ -2835,10 +2838,10 @@ void Myst::o_observatoryChangeSettingStop(uint16 op, uint16 var, uint16 argc, ui _observatoryIncrement = 0; // Restore button and slider - _vm->_gfx->copyBackBufferToScreen(_invokingResource->getRect()); + _vm->_gfx->copyBackBufferToScreen(getInvokingResource<MystArea>()->getRect()); if (_observatoryCurrentSlider) { _vm->redrawResource(_observatoryCurrentSlider); - _observatoryCurrentSlider = 0; + _observatoryCurrentSlider = nullptr; } _vm->_sound->resumeBackgroundMyst(); } @@ -2874,7 +2877,7 @@ void Myst::o_imagerEraseStop(uint16 op, uint16 var, uint16 argc, uint16 *argv) { void Myst::o_clockLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Clock lever start move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); _vm->_cursor->setCursor(700); _clockMiddleGearMovedAlone = false; @@ -2885,7 +2888,7 @@ void Myst::o_clockLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Clock left lever move", op); if (!_clockLeverPulled) { - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // If lever pulled if (lever->pullLeverV()) { @@ -2977,7 +2980,7 @@ void Myst::o_clockLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) _vm->_sound->replaceSoundMyst(8113); // Release lever - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->releaseLeverV(); // Check if puzzle is solved @@ -3021,7 +3024,7 @@ void Myst::clockGearsCheckSolution() { void Myst::o_clockResetLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Clock reset lever start move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->drawFrame(0); _vm->_cursor->setCursor(700); } @@ -3029,7 +3032,7 @@ void Myst::o_clockResetLeverStartMove(uint16 op, uint16 var, uint16 argc, uint16 void Myst::o_clockResetLeverMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Clock reset lever move", op); - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); // If pulled if (lever->pullLeverV() && _clockWeightPosition != 0) @@ -3084,6 +3087,8 @@ void Myst::clockReset() { } void Myst::clockResetWeight() { + _vm->_sound->replaceSoundMyst(9113); + _clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack)); if (!_clockWeightVideo) error("Failed to open cl1wlfch movie"); @@ -3125,7 +3130,7 @@ void Myst::o_clockResetLeverEndMove(uint16 op, uint16 var, uint16 argc, uint16 * debugC(kDebugScript, "Opcode %d: Clock reset lever end move", op); // Get current lever frame - MystResourceType12 *lever = static_cast<MystResourceType12 *>(_invokingResource); + MystVideoInfo *lever = getInvokingResource<MystVideoInfo>(); lever->releaseLeverV(); @@ -3189,8 +3194,8 @@ void Myst::towerRotationMap_run() { void Myst::o_towerRotationMap_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { _towerRotationMapRunning = true; - _towerRotationMapTower = static_cast<MystResourceType11 *>(_invokingResource); - _towerRotationMapLabel = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]); + _towerRotationMapTower = getInvokingResource<MystAreaImageSwitch>(); + _towerRotationMapLabel = _vm->getViewResource<MystAreaImageSwitch>(argv[0]); _tempVar = 0; _startTime = 0; _towerRotationMapClicked = false; @@ -3202,7 +3207,7 @@ void Myst::towerRotationDrawBuildings() { // Draw other resources for (uint i = 1; i <= 10; i++) { - MystResourceType8 *resource = static_cast<MystResourceType8 *>(_vm->_resources[i]); + MystAreaImageSwitch *resource = _vm->getViewResource<MystAreaImageSwitch>(i); _vm->redrawResource(resource, false); } } @@ -3313,7 +3318,7 @@ void Myst::o_forechamberDoor_init(uint16 op, uint16 var, uint16 argc, uint16 *ar void Myst::o_shipAccess_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { // Enable acces to the ship if (_state.shipFloating) { - _invokingResource->setEnabled(true); + getInvokingResource<MystArea>()->setEnabled(true); } } @@ -3322,7 +3327,7 @@ void Myst::o_butterflies_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) // Used for Card 4256 (Butterfly Movie Activation) if (!_butterfliesMoviePlayed) { - MystResourceType6 *butterflies = static_cast<MystResourceType6 *>(_invokingResource); + MystAreaVideo *butterflies = getInvokingResource<MystAreaVideo>(); butterflies->playMovie(); _butterfliesMoviePlayed = true; @@ -3333,8 +3338,8 @@ void Myst::o_imager_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Imager init", op); debugC(kDebugScript, "Var: %d", var); - MystResourceType7 *select = static_cast<MystResourceType7 *>(_invokingResource); - _imagerMovie = static_cast<MystResourceType6 *>(select->getSubResource(getVar(var))); + MystAreaActionSwitch *select = getInvokingResource<MystAreaActionSwitch>(); + _imagerMovie = static_cast<MystAreaVideo *>(select->getSubResource(getVar(var))); _imagerRunning = true; } @@ -3377,8 +3382,8 @@ void Myst::libraryBookcaseTransform_run(void) { void Myst::o_libraryBookcaseTransform_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { if (_libraryBookcaseChanged) { - MystResourceType7 *resource = static_cast<MystResourceType7 *>(_invokingResource); - _libraryBookcaseMovie = static_cast<MystResourceType6 *>(resource->getSubResource(getVar(0))); + MystAreaActionSwitch *resource = getInvokingResource<MystAreaActionSwitch>(); + _libraryBookcaseMovie = static_cast<MystAreaVideo *>(resource->getSubResource(getVar(0))); _libraryBookcaseSoundId = argv[0]; _libraryBookcaseMoving = true; } @@ -3471,17 +3476,17 @@ void Myst::o_observatory_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) _tempVar = 0; _observatoryNotInitialized = true; - _observatoryVisualizer = static_cast<MystResourceType8 *>(_invokingResource); - _observatoryGoButton = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]); + _observatoryVisualizer = getInvokingResource<MystAreaImageSwitch>(); + _observatoryGoButton = _vm->getViewResource<MystAreaImageSwitch>(argv[0]); if (observatoryIsDDMMYYYY2400()) { - _observatoryDaySlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]); - _observatoryMonthSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]); + _observatoryDaySlider = _vm->getViewResource<MystAreaSlider>(argv[1]); + _observatoryMonthSlider = _vm->getViewResource<MystAreaSlider>(argv[2]); } else { - _observatoryMonthSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]); - _observatoryDaySlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]); + _observatoryMonthSlider = _vm->getViewResource<MystAreaSlider>(argv[1]); + _observatoryDaySlider = _vm->getViewResource<MystAreaSlider>(argv[2]); } - _observatoryYearSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[3]]); - _observatoryTimeSlider = static_cast<MystResourceType10 *>(_vm->_resources[argv[4]]); + _observatoryYearSlider = _vm->getViewResource<MystAreaSlider>(argv[3]); + _observatoryTimeSlider = _vm->getViewResource<MystAreaSlider>(argv[4]); // Set date selection sliders position _observatoryDaySlider->setPosition(_state.observatoryDaySlider); @@ -3503,18 +3508,14 @@ bool Myst::observatoryIsDDMMYYYY2400() { } void Myst::observatoryUpdateVisualizer(uint16 x, uint16 y) { - Common::Rect &visu0 = _observatoryVisualizer->_subImages[0].rect; - Common::Rect &visu1 = _observatoryVisualizer->_subImages[1].rect; - - visu0.left = x; - visu0.right = visu0.left + 105; - visu0.bottom = 512 - y; - visu0.top = visu0.bottom - 106; + Common::Rect visu; + visu.left = x; + visu.right = visu.left + 105; + visu.bottom = 512 - y; + visu.top = visu.bottom - 106; - visu1.left = visu0.left; - visu1.top = visu0.top; - visu1.right = visu0.right; - visu1.bottom = visu0.bottom; + _observatoryVisualizer->setSubImageRect(0, visu); + _observatoryVisualizer->setSubImageRect(1, visu); } void Myst::observatorySetTargetToSetting() { @@ -3618,13 +3619,13 @@ void Myst::gullsFly2_run() { void Myst::o_treeCard_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Enter tree card", op); - _tree = static_cast<MystResourceType8 *>(_invokingResource); + _tree = getInvokingResource<MystAreaImageSwitch>(); } void Myst::o_treeEntry_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Enter tree card with entry", op); - _treeAlcove = static_cast<MystResourceType5 *>(_invokingResource); + _treeAlcove = getInvokingResource<MystArea>(); _treeMinAccessiblePosition = argv[0]; _treeMaxAccessiblePosition = argv[1]; @@ -3683,16 +3684,16 @@ void Myst::boilerFireUpdate(bool init) { void Myst::boilerGaugeInit() { if (_vm->getCurCard() == 4098) { _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabingau", kMystStack)); - if (!_cabinFireMovie) + if (!_cabinGaugeMovie) error("Failed to open cabingau movie"); - _cabinFireMovie->moveTo(243, 96); + _cabinGaugeMovie->moveTo(243, 96); } else { _cabinGaugeMovie = _vm->_video->playMovie(_vm->wrapMovieFilename("cabcgfar", kMystStack)); - if (!_cabinFireMovie) + if (!_cabinGaugeMovie) error("Failed to open cabcgfar movie"); - _cabinFireMovie->moveTo(254, 136); + _cabinGaugeMovie->moveTo(254, 136); } Audio::Timestamp frame; @@ -3703,16 +3704,18 @@ void Myst::boilerGaugeInit() { frame = Audio::Timestamp(0, 0, 600); _vm->_video->drawVideoFrame(_cabinGaugeMovie, frame); + + _cabinGaugeMovieEnabled = true; } void Myst::o_rocketSliders_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Rocket sliders init", op); - _rocketSlider1 = static_cast<MystResourceType10 *>(_vm->_resources[argv[0]]); - _rocketSlider2 = static_cast<MystResourceType10 *>(_vm->_resources[argv[1]]); - _rocketSlider3 = static_cast<MystResourceType10 *>(_vm->_resources[argv[2]]); - _rocketSlider4 = static_cast<MystResourceType10 *>(_vm->_resources[argv[3]]); - _rocketSlider5 = static_cast<MystResourceType10 *>(_vm->_resources[argv[4]]); + _rocketSlider1 = _vm->getViewResource<MystAreaSlider>(argv[0]); + _rocketSlider2 = _vm->getViewResource<MystAreaSlider>(argv[1]); + _rocketSlider3 = _vm->getViewResource<MystAreaSlider>(argv[2]); + _rocketSlider4 = _vm->getViewResource<MystAreaSlider>(argv[3]); + _rocketSlider5 = _vm->getViewResource<MystAreaSlider>(argv[4]); // Initialize sliders position for (uint i = 0; i < 5; i++) @@ -3828,13 +3831,13 @@ void Myst::o_bookAddSpecialPage_exit(uint16 op, uint16 var, uint16 argc, uint16 void Myst::o_treeCard_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Exit tree card", op); - _tree = 0; + _tree = nullptr; } void Myst::o_treeEntry_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Exit tree card with entry", op); - _treeAlcove = 0; + _treeAlcove = nullptr; } void Myst::o_boiler_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { @@ -3842,6 +3845,8 @@ void Myst::o_boiler_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { _cabinGaugeMovie = VideoHandle(); _cabinFireMovie = VideoHandle(); + + _cabinGaugeMovieEnabled = false; } void Myst::o_generatorControlRoom_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) { diff --git a/engines/mohawk/myst_stacks/myst.h b/engines/mohawk/myst_stacks/myst.h index a83609f640..6e2f7cc1c8 100644 --- a/engines/mohawk/myst_stacks/myst.h +++ b/engines/mohawk/myst_stacks/myst.h @@ -40,21 +40,20 @@ public: Myst(MohawkEngine_Myst *vm); ~Myst(); - virtual void disablePersistentScripts(); - virtual void runPersistentScripts(); + virtual void disablePersistentScripts() override; + virtual void runPersistentScripts() override; protected: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9934; } + virtual uint16 getMap() override { return 9934; } void towerRotationMap_run(); virtual void libraryBookcaseTransform_run(); void generatorControlRoom_run(); - void opcode_212_run(); void libraryCombinationBook_run(); void clockWheel_run(); void matchBurn_run(); @@ -192,11 +191,11 @@ protected: bool _generatorControlRoomRunning; uint16 _generatorVoltage; // 58 - MystResourceType10 *_rocketSlider1; // 248 - MystResourceType10 *_rocketSlider2; // 252 - MystResourceType10 *_rocketSlider3; // 256 - MystResourceType10 *_rocketSlider4; // 260 - MystResourceType10 *_rocketSlider5; // 264 + MystAreaSlider *_rocketSlider1; // 248 + MystAreaSlider *_rocketSlider2; // 252 + MystAreaSlider *_rocketSlider3; // 256 + MystAreaSlider *_rocketSlider4; // 260 + MystAreaSlider *_rocketSlider5; // 264 uint16 _rocketSliderSound; // 294 uint16 _rocketLeverPosition; // 296 VideoHandle _rocketLinkBook; @@ -214,7 +213,7 @@ protected: uint32 _gullsNextTime; // 216 bool _libraryBookcaseMoving; - MystResourceType6 *_libraryBookcaseMovie; // 104 + MystAreaVideo *_libraryBookcaseMovie; // 104 uint16 _libraryBookcaseSoundId; // 284 bool _libraryBookcaseChanged; // 288 uint16 _libraryBookSound1; // 298 @@ -223,13 +222,13 @@ protected: uint16 _courtyardBoxSound; // 302 bool _imagerValidationRunning; - MystResourceType8 *_imagerRedButton; // 304 + MystAreaImageSwitch *_imagerRedButton; // 304 uint16 _imagerSound[4]; // 308 to 314 uint16 _imagerValidationCard; // 316 uint16 _imagerValidationStep; // 318 bool _imagerRunning; - MystResourceType6 *_imagerMovie; // 64 + MystAreaVideo *_imagerMovie; // 64 uint16 _fireplaceLines[6]; // 74 to 84 @@ -248,8 +247,8 @@ protected: bool _towerRotationBlinkLabel; uint16 _towerRotationBlinkLabelCount; uint16 _towerRotationMapInitialized; // 292 - MystResourceType11 *_towerRotationMapTower; // 108 - MystResourceType8 *_towerRotationMapLabel; // 112 + MystAreaImageSwitch *_towerRotationMapTower; // 108 + MystAreaImageSwitch *_towerRotationMapLabel; // 112 uint16 _towerRotationSpeed; // 124 bool _towerRotationMapClicked; // 132 bool _towerRotationOverSpot; // 136 @@ -257,10 +256,13 @@ protected: bool _matchBurning; uint16 _matchGoOutCnt; uint16 _cabinDoorOpened; // 56 + uint16 _cabinHandleDown; // 344 uint16 _cabinMatchState; // 60 uint32 _matchGoOutTime; // 144 VideoHandle _cabinFireMovie; // 240 + + bool _cabinGaugeMovieEnabled; VideoHandle _cabinGaugeMovie; // 244 bool _boilerPressureIncreasing; @@ -269,8 +271,8 @@ protected: bool _basementPressureDecreasing; bool _treeStopped; // 236 - MystResourceType8 *_tree; // 220 - MystResourceType5 *_treeAlcove; // 224 + MystAreaImageSwitch *_tree; // 220 + MystArea *_treeAlcove; // 224 uint16 _treeMinPosition; // 228 uint16 _treeMinAccessiblePosition; // 230 uint16 _treeMaxAccessiblePosition; // 232 @@ -280,21 +282,21 @@ protected: bool _observatoryDayChanging; bool _observatoryYearChanging; bool _observatoryTimeChanging; - MystResourceType8 *_observatoryVisualizer; // 184 - MystResourceType8 *_observatoryGoButton; // 188 - MystResourceType10 *_observatoryDaySlider; // 192 - MystResourceType10 *_observatoryMonthSlider; // 196 - MystResourceType10 *_observatoryYearSlider; // 200 - MystResourceType10 *_observatoryTimeSlider; // 204 + MystAreaImageSwitch *_observatoryVisualizer; // 184 + MystAreaImageSwitch *_observatoryGoButton; // 188 + MystAreaSlider *_observatoryDaySlider; // 192 + MystAreaSlider *_observatoryMonthSlider; // 196 + MystAreaSlider *_observatoryYearSlider; // 200 + MystAreaSlider *_observatoryTimeSlider; // 204 uint32 _observatoryLastTime; // 208 bool _observatoryNotInitialized; // 212 int16 _observatoryIncrement; // 346 - MystResourceType10 *_observatoryCurrentSlider; // 348 + MystAreaSlider *_observatoryCurrentSlider; // 348 bool _greenBookRunning; void generatorRedrawRocket(); - void generatorButtonValue(MystResource *button, uint16 &offset, uint16 &value); + void generatorButtonValue(MystArea *button, uint16 &offset, uint16 &value); void rocketSliderMove(); uint16 rocketSliderGetSound(uint16 pos); diff --git a/engines/mohawk/myst_stacks/preview.cpp b/engines/mohawk/myst_stacks/preview.cpp index 4cae4aaca7..42458758f5 100644 --- a/engines/mohawk/myst_stacks/preview.cpp +++ b/engines/mohawk/myst_stacks/preview.cpp @@ -239,13 +239,13 @@ void Preview::o_library_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Library init", op); // Used for Card 3002 (Myst Island Overview) - _library = static_cast<MystResourceType8 *>(_invokingResource); + _library = getInvokingResource<MystAreaImageSwitch>(); } void Preview::o_libraryBookcaseTransformDemo_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { if (_libraryBookcaseChanged) { - MystResourceType7 *resource = static_cast<MystResourceType7 *>(_invokingResource); - _libraryBookcaseMovie = static_cast<MystResourceType6 *>(resource->getSubResource(getVar(303))); + MystAreaActionSwitch *resource = getInvokingResource<MystAreaActionSwitch>(); + _libraryBookcaseMovie = static_cast<MystAreaVideo *>(resource->getSubResource(getVar(303))); _libraryBookcaseSoundId = argv[0]; _libraryBookcaseMoving = true; } diff --git a/engines/mohawk/myst_stacks/preview.h b/engines/mohawk/myst_stacks/preview.h index 0959e935f5..9d833b35e2 100644 --- a/engines/mohawk/myst_stacks/preview.h +++ b/engines/mohawk/myst_stacks/preview.h @@ -40,8 +40,8 @@ public: Preview(MohawkEngine_Myst *vm); ~Preview(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); @@ -56,7 +56,7 @@ private: DECLARE_OPCODE(o_library_init); uint16 _libraryState; // 4 - MystResourceType8 *_library; // 32 + MystAreaImageSwitch *_library; // 32 bool _speechRunning; uint _speechStep; @@ -67,7 +67,7 @@ private: void speech_run(); void speechUpdateCue(); - void libraryBookcaseTransform_run(); + void libraryBookcaseTransform_run() override; }; } // End of namespace MystStacks diff --git a/engines/mohawk/myst_stacks/selenitic.cpp b/engines/mohawk/myst_stacks/selenitic.cpp index 8b95c7fa53..454435cf92 100644 --- a/engines/mohawk/myst_stacks/selenitic.cpp +++ b/engines/mohawk/myst_stacks/selenitic.cpp @@ -31,7 +31,6 @@ #include "common/system.h" #include "common/textconsole.h" -#include "gui/message.h" namespace Mohawk { namespace MystStacks { @@ -39,9 +38,12 @@ namespace MystStacks { Selenitic::Selenitic(MohawkEngine_Myst *vm) : MystScriptParser(vm), _state(vm->_gameState->_selenitic) { setupOpcodes(); - _invokingResource = NULL; _mazeRunnerPosition = 288; _mazeRunnerDirection = 8; + _mazeRunnerDoorOpened = false; + + _soundReceiverDirection = 0; + _soundReceiverStartTime = 0; } Selenitic::~Selenitic() { @@ -669,14 +671,20 @@ void Selenitic::soundReceiverUpdate() { } void Selenitic::soundReceiverDrawView() { + soundReceiverSetSubimageRect(); + soundReceiverDrawAngle(); +} + +void Selenitic::soundReceiverSetSubimageRect() const { uint32 left = ((*_soundReceiverPosition) * 1800) / 3600; - _soundReceiverViewer->_subImages->rect.left = left; - _soundReceiverViewer->_subImages->rect.right = left + 136; + Common::Rect rect = _soundReceiverViewer->getSubImage(0).rect; - _soundReceiverViewer->drawConditionalDataToScreen(0); + rect.left = left; + rect.right = left + 136; - soundReceiverDrawAngle(); + _soundReceiverViewer->setSubImageRect(0, rect); + _soundReceiverViewer->drawConditionalDataToScreen(0); } void Selenitic::soundReceiverDrawAngle() { @@ -770,7 +778,7 @@ uint16 Selenitic::soundLockCurrentSound(uint16 position, bool pixels) { return 0; } -MystResourceType10 *Selenitic::soundLockSliderFromVar(uint16 var) { +MystAreaSlider *Selenitic::soundLockSliderFromVar(uint16 var) { switch (var) { case 20: return _soundLockSlider1; @@ -784,13 +792,13 @@ MystResourceType10 *Selenitic::soundLockSliderFromVar(uint16 var) { return _soundLockSlider5; } - return 0; + return nullptr; } void Selenitic::o_soundLockMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Sound lock move", op); - MystResourceType10 *slider = soundLockSliderFromVar(var); + MystAreaSlider *slider = soundLockSliderFromVar(var); uint16 soundId = soundLockCurrentSound(slider->_pos.y, true); if (_soundLockSoundId != soundId) { @@ -802,7 +810,7 @@ void Selenitic::o_soundLockMove(uint16 op, uint16 var, uint16 argc, uint16 *argv void Selenitic::o_soundLockStartMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Sound lock start move", op); - MystResourceType10 *slider = soundLockSliderFromVar(var); + MystAreaSlider *slider = soundLockSliderFromVar(var); _vm->_cursor->setCursor(700); _vm->_sound->pauseBackgroundMyst(); @@ -814,7 +822,7 @@ void Selenitic::o_soundLockStartMove(uint16 op, uint16 var, uint16 argc, uint16 void Selenitic::o_soundLockEndMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Sound lock end move", op); - MystResourceType10 *slider = soundLockSliderFromVar(var); + MystAreaSlider *slider = soundLockSliderFromVar(var); uint16 *value = &_state.soundLockSliderPositions[0]; switch (var) { @@ -858,7 +866,7 @@ void Selenitic::o_soundLockEndMove(uint16 op, uint16 var, uint16 argc, uint16 *a _vm->_sound->resumeBackgroundMyst(); } -void Selenitic::soundLockCheckSolution(MystResourceType10 *slider, uint16 value, uint16 solution, bool &solved) { +void Selenitic::soundLockCheckSolution(MystAreaSlider *slider, uint16 value, uint16 solution, bool &solved) { slider->drawConditionalDataToScreen(2); _vm->_sound->replaceSoundMyst(soundLockCurrentSound(value / 12, false)); _vm->_system->delayMillis(1500); @@ -926,15 +934,15 @@ void Selenitic::o_soundReceiverEndMove(uint16 op, uint16 var, uint16 argc, uint1 } void Selenitic::o_mazeRunnerCompass_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerCompass = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerCompass = getInvokingResource<MystAreaImageSwitch>(); } void Selenitic::o_mazeRunnerWindow_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerWindow = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerWindow = getInvokingResource<MystAreaImageSwitch>(); } void Selenitic::o_mazeRunnerLight_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerLight = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerLight = getInvokingResource<MystAreaImageSwitch>(); } void Selenitic::soundReceiver_run() { @@ -942,10 +950,13 @@ void Selenitic::soundReceiver_run() { if (_soundReceiverDirection) { uint32 currentTime = _vm->_system->getMillis(); - if (_soundReceiverSpeed == 50 && currentTime > _soundReceiverStartTime + 500) - soundReceiverIncreaseSpeed(); - else if (currentTime > _soundReceiverStartTime + 1000) - soundReceiverIncreaseSpeed(); + if (_soundReceiverSpeed == 50 && currentTime > _soundReceiverStartTime + 500) { + soundReceiverIncreaseSpeed(); + _soundReceiverStartTime = currentTime; + } else if (currentTime > _soundReceiverStartTime + 1000) { + soundReceiverIncreaseSpeed(); + _soundReceiverStartTime = currentTime; + } if (currentTime > _soundReceiverStartTime + 100) soundReceiverUpdate(); @@ -1056,24 +1067,26 @@ void Selenitic::o_soundReceiver_init(uint16 op, uint16 var, uint16 argc, uint16 // Used for Card 1245 (Sound Receiver) _soundReceiverRunning = true; - _soundReceiverRightButton = static_cast<MystResourceType8 *>(_vm->_resources[0]); - _soundReceiverLeftButton = static_cast<MystResourceType8 *>(_vm->_resources[1]); - _soundReceiverSigmaButton = static_cast<MystResourceType8 *>(_vm->_resources[2]); - _soundReceiverSources[4] = static_cast<MystResourceType8 *>(_vm->_resources[3]); - _soundReceiverSources[3] = static_cast<MystResourceType8 *>(_vm->_resources[4]); - _soundReceiverSources[2] = static_cast<MystResourceType8 *>(_vm->_resources[5]); - _soundReceiverSources[1] = static_cast<MystResourceType8 *>(_vm->_resources[6]); - _soundReceiverSources[0] = static_cast<MystResourceType8 *>(_vm->_resources[7]); - _soundReceiverViewer = static_cast<MystResourceType8 *>(_vm->_resources[8]); - _soundReceiverAngle1 = static_cast<MystResourceType8 *>(_vm->_resources[10]); - _soundReceiverAngle2 = static_cast<MystResourceType8 *>(_vm->_resources[11]); - _soundReceiverAngle3 = static_cast<MystResourceType8 *>(_vm->_resources[12]); - _soundReceiverAngle4 = static_cast<MystResourceType8 *>(_vm->_resources[13]); + _soundReceiverRightButton = _vm->getViewResource<MystAreaImageSwitch>(0); + _soundReceiverLeftButton = _vm->getViewResource<MystAreaImageSwitch>(1); + _soundReceiverSigmaButton = _vm->getViewResource<MystAreaImageSwitch>(2); + _soundReceiverSources[4] = _vm->getViewResource<MystAreaImageSwitch>(3); + _soundReceiverSources[3] = _vm->getViewResource<MystAreaImageSwitch>(4); + _soundReceiverSources[2] = _vm->getViewResource<MystAreaImageSwitch>(5); + _soundReceiverSources[1] = _vm->getViewResource<MystAreaImageSwitch>(6); + _soundReceiverSources[0] = _vm->getViewResource<MystAreaImageSwitch>(7); + _soundReceiverViewer = _vm->getViewResource<MystAreaImageSwitch>(8); + _soundReceiverAngle1 = _vm->getViewResource<MystAreaImageSwitch>(10); + _soundReceiverAngle2 = _vm->getViewResource<MystAreaImageSwitch>(11); + _soundReceiverAngle3 = _vm->getViewResource<MystAreaImageSwitch>(12); + _soundReceiverAngle4 = _vm->getViewResource<MystAreaImageSwitch>(13); uint16 currentSource = _state.soundReceiverCurrentSource; _soundReceiverPosition = &_state.soundReceiverPositions[currentSource]; _soundReceiverCurrentSource = _soundReceiverSources[currentSource]; + soundReceiverSetSubimageRect(); + _soundReceiverSigmaPressed = false; } @@ -1081,31 +1094,31 @@ void Selenitic::o_soundLock_init(uint16 op, uint16 var, uint16 argc, uint16 *arg debugC(kDebugScript, "Opcode %d: Sound lock init", op); for (uint i = 0; i < _vm->_resources.size(); i++) { - if (_vm->_resources[i]->type == kMystSlider) { - switch (_vm->_resources[i]->getType8Var()) { + if (_vm->_resources[i]->type == kMystAreaSlider) { + switch (_vm->_resources[i]->getImageSwitchVar()) { case 20: - _soundLockSlider1 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider1 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider1->setStep(_state.soundLockSliderPositions[0]); break; case 21: - _soundLockSlider2 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider2 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider2->setStep(_state.soundLockSliderPositions[1]); break; case 22: - _soundLockSlider3 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider3 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider3->setStep(_state.soundLockSliderPositions[2]); break; case 23: - _soundLockSlider4 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider4 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider4->setStep(_state.soundLockSliderPositions[3]); break; case 24: - _soundLockSlider5 = static_cast<MystResourceType10 *>(_vm->_resources[i]); + _soundLockSlider5 = _vm->getViewResource<MystAreaSlider>(i); _soundLockSlider5->setStep(_state.soundLockSliderPositions[4]); break; } - } else if (_vm->_resources[i]->type == kMystConditionalImage && _vm->_resources[i]->getType8Var() == 28) { - _soundLockButton = static_cast<MystResourceType8 *>(_vm->_resources[i]); + } else if (_vm->_resources[i]->type == kMystAreaImageSwitch && _vm->_resources[i]->getImageSwitchVar() == 28) { + _soundLockButton = _vm->getViewResource<MystAreaImageSwitch>(i); } } @@ -1113,11 +1126,11 @@ void Selenitic::o_soundLock_init(uint16 op, uint16 var, uint16 argc, uint16 *arg } void Selenitic::o_mazeRunnerRight_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerRightButton = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerRightButton = getInvokingResource<MystAreaImageSwitch>(); } void Selenitic::o_mazeRunnerLeft_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { - _mazeRunnerLeftButton = static_cast<MystResourceType8 *>(_invokingResource); + _mazeRunnerLeftButton = getInvokingResource<MystAreaImageSwitch>(); } const uint16 Selenitic::_mazeRunnerMap[300][4] = { diff --git a/engines/mohawk/myst_stacks/selenitic.h b/engines/mohawk/myst_stacks/selenitic.h index c669d01012..fc9649755d 100644 --- a/engines/mohawk/myst_stacks/selenitic.h +++ b/engines/mohawk/myst_stacks/selenitic.h @@ -29,7 +29,7 @@ namespace Mohawk { -class MystResourceType8; +class MystAreaImageSwitch; struct MystScriptEntry; namespace MystStacks { @@ -41,16 +41,16 @@ public: Selenitic(MohawkEngine_Myst *vm); ~Selenitic(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9930; } + virtual uint16 getMap() override { return 9930; } DECLARE_OPCODE(o_mazeRunnerMove); DECLARE_OPCODE(o_mazeRunnerSoundRepeat); @@ -80,43 +80,44 @@ private: bool _soundReceiverRunning; bool _soundReceiverSigmaPressed; // 6 - MystResourceType8 *_soundReceiverSources[5]; // 92 -> 108 - MystResourceType8 *_soundReceiverCurrentSource; // 112 + MystAreaImageSwitch *_soundReceiverSources[5]; // 92 -> 108 + MystAreaImageSwitch *_soundReceiverCurrentSource; // 112 uint16 *_soundReceiverPosition; // 116 uint16 _soundReceiverDirection; // 120 uint16 _soundReceiverSpeed; // 122 uint32 _soundReceiverStartTime; //124 - MystResourceType8 *_soundReceiverViewer; // 128 - MystResourceType8 *_soundReceiverRightButton; // 132 - MystResourceType8 *_soundReceiverLeftButton; // 136 - MystResourceType8 *_soundReceiverAngle1; // 140 - MystResourceType8 *_soundReceiverAngle2; // 144 - MystResourceType8 *_soundReceiverAngle3; // 148 - MystResourceType8 *_soundReceiverAngle4; // 152 - MystResourceType8 *_soundReceiverSigmaButton; // 156 + MystAreaImageSwitch *_soundReceiverViewer; // 128 + MystAreaImageSwitch *_soundReceiverRightButton; // 132 + MystAreaImageSwitch *_soundReceiverLeftButton; // 136 + MystAreaImageSwitch *_soundReceiverAngle1; // 140 + MystAreaImageSwitch *_soundReceiverAngle2; // 144 + MystAreaImageSwitch *_soundReceiverAngle3; // 148 + MystAreaImageSwitch *_soundReceiverAngle4; // 152 + MystAreaImageSwitch *_soundReceiverSigmaButton; // 156 static const uint16 _mazeRunnerMap[300][4]; static const uint8 _mazeRunnerVideos[300][4]; uint16 _mazeRunnerPosition; // 56 uint16 _mazeRunnerDirection; // 58 - MystResourceType8 *_mazeRunnerWindow; // 68 - MystResourceType8 *_mazeRunnerCompass; // 72 - MystResourceType8 *_mazeRunnerLight; // 76 - MystResourceType8 *_mazeRunnerRightButton; // 80 - MystResourceType8 *_mazeRunnerLeftButton; // 84 + MystAreaImageSwitch *_mazeRunnerWindow; // 68 + MystAreaImageSwitch *_mazeRunnerCompass; // 72 + MystAreaImageSwitch *_mazeRunnerLight; // 76 + MystAreaImageSwitch *_mazeRunnerRightButton; // 80 + MystAreaImageSwitch *_mazeRunnerLeftButton; // 84 bool _mazeRunnerDoorOpened; // 160 uint16 _soundLockSoundId; - MystResourceType10 *_soundLockSlider1; // 164 - MystResourceType10 *_soundLockSlider2; // 168 - MystResourceType10 *_soundLockSlider3; // 172 - MystResourceType10 *_soundLockSlider4; // 176 - MystResourceType10 *_soundLockSlider5; // 180 - MystResourceType8 *_soundLockButton; // 184 + MystAreaSlider *_soundLockSlider1; // 164 + MystAreaSlider *_soundLockSlider2; // 168 + MystAreaSlider *_soundLockSlider3; // 172 + MystAreaSlider *_soundLockSlider4; // 176 + MystAreaSlider *_soundLockSlider5; // 180 + MystAreaImageSwitch *_soundLockButton; // 184 void soundReceiverLeftRight(uint direction); void soundReceiverUpdate(); + void soundReceiverSetSubimageRect() const; void soundReceiverDrawView(); void soundReceiverDrawAngle(); void soundReceiverIncreaseSpeed(); @@ -125,8 +126,8 @@ private: void soundReceiverSolution(uint16 source, uint16 &solution, bool &enabled); uint16 soundLockCurrentSound(uint16 position, bool pixels); - MystResourceType10 *soundLockSliderFromVar(uint16 var); - void soundLockCheckSolution(MystResourceType10 *slider, uint16 value, uint16 solution, bool &solved); + MystAreaSlider *soundLockSliderFromVar(uint16 var); + void soundLockCheckSolution(MystAreaSlider *slider, uint16 value, uint16 solution, bool &solved); bool mazeRunnerForwardAllowed(uint16 position); void mazeRunnerUpdateCompass(); diff --git a/engines/mohawk/myst_stacks/slides.cpp b/engines/mohawk/myst_stacks/slides.cpp index a1413f0d71..0560608b24 100644 --- a/engines/mohawk/myst_stacks/slides.cpp +++ b/engines/mohawk/myst_stacks/slides.cpp @@ -29,7 +29,6 @@ #include "mohawk/myst_stacks/slides.h" #include "common/system.h" -#include "gui/message.h" namespace Mohawk { namespace MystStacks { diff --git a/engines/mohawk/myst_stacks/slides.h b/engines/mohawk/myst_stacks/slides.h index fb7868a03c..a0c9ae5821 100644 --- a/engines/mohawk/myst_stacks/slides.h +++ b/engines/mohawk/myst_stacks/slides.h @@ -40,8 +40,8 @@ public: Slides(MohawkEngine_Myst *vm); ~Slides(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp index 1113ceeac9..293c0f96f4 100644 --- a/engines/mohawk/myst_stacks/stoneship.cpp +++ b/engines/mohawk/myst_stacks/stoneship.cpp @@ -50,6 +50,8 @@ Stoneship::Stoneship(MohawkEngine_Myst *vm) : _chestDrawersOpen = 0; _chestAchenarBottomDrawerClosed = 1; + _brotherDoorOpen = 0; + // Drop key if (_state.trapdoorKeyState == 1) _state.trapdoorKeyState = 2; @@ -402,9 +404,9 @@ void Stoneship::o_pumpTurnOff(uint16 op, uint16 var, uint16 argc, uint16 *argv) } for (uint i = 0; i < _vm->_resources.size(); i++) { - MystResource *resource = _vm->_resources[i]; - if (resource->type == kMystConditionalImage && resource->getType8Var() == buttonVar) { - static_cast<MystResourceType8 *>(resource)->drawConditionalDataToScreen(0, true); + MystArea *resource = _vm->_resources[i]; + if (resource->type == kMystAreaImageSwitch && resource->getImageSwitchVar() == buttonVar) { + static_cast<MystAreaImageSwitch *>(resource)->drawConditionalDataToScreen(0, true); break; } } @@ -437,9 +439,9 @@ void Stoneship::o_cabinBookMovie(uint16 op, uint16 var, uint16 argc, uint16 *arg void Stoneship::o_drawerOpenSirius(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Open drawer", op); - MystResourceType8 *drawer = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]); + MystAreaImageSwitch *drawer = _vm->getViewResource<MystAreaImageSwitch>(argv[0]); - if (drawer->getType8Var() == 35) { + if (drawer->getImageSwitchVar() == 35) { drawer->drawConditionalDataToScreen(getVar(102), 0); } else { drawer->drawConditionalDataToScreen(0, 0); @@ -466,7 +468,7 @@ void Stoneship::o_telescopeStart(uint16 op, uint16 var, uint16 argc, uint16 *arg void Stoneship::o_telescopeMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Telescope move", op); - MystResourceType11 *display = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *display = getInvokingResource<MystAreaDrag>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); // Compute telescope position @@ -489,7 +491,7 @@ void Stoneship::o_telescopeStop(uint16 op, uint16 var, uint16 argc, uint16 *argv void Stoneship::o_generatorStart(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Generator start", op); - MystResourceType11 *handle = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *handle = getInvokingResource<MystAreaDrag>(); uint16 soundId = handle->getList1(0); if (soundId) @@ -504,7 +506,7 @@ void Stoneship::o_generatorStart(uint16 op, uint16 var, uint16 argc, uint16 *arg _batteryNextTime = _vm->_system->getMillis() + 1000; // Start handle movie - MystResourceType6 *movie = static_cast<MystResourceType6 *>(handle->getSubResource(0)); + MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0)); movie->playMovie(); soundId = handle->getList2(0); @@ -530,8 +532,8 @@ void Stoneship::o_generatorStop(uint16 op, uint16 var, uint16 argc, uint16 *argv } // Pause handle movie - MystResourceType11 *handle = static_cast<MystResourceType11 *>(_invokingResource); - MystResourceType6 *movie = static_cast<MystResourceType6 *>(handle->getSubResource(0)); + MystAreaDrag *handle = getInvokingResource<MystAreaDrag>(); + MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0)); movie->pauseMovie(true); uint16 soundId = handle->getList3(0); @@ -582,7 +584,7 @@ void Stoneship::batteryDeplete_run() { void Stoneship::o_drawerOpenAchenar(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Open drawer", op); - MystResourceType8 *drawer = static_cast<MystResourceType8 *>(_vm->_resources[argv[0]]); + MystAreaImageSwitch *drawer = _vm->getViewResource<MystAreaImageSwitch>(argv[0]); drawer->drawConditionalDataToScreen(0, 0); _vm->_gfx->runTransition(kTransitionTopToBottom, drawer->getRect(), 25, 5); } @@ -617,7 +619,7 @@ void Stoneship::o_hologramSelectionStart(uint16 op, uint16 var, uint16 argc, uin void Stoneship::o_hologramSelectionMove(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Hologram move", op); - MystResourceType11 *handle = static_cast<MystResourceType11 *>(_invokingResource); + MystAreaDrag *handle = getInvokingResource<MystAreaDrag>(); const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos(); if (handle->getRect().contains(mouse)) { @@ -806,7 +808,7 @@ void Stoneship::o_cloudOrbLeave(uint16 op, uint16 var, uint16 argc, uint16 *argv _cloudOrbMovie->pauseMovie(true); _vm->_sound->replaceSoundMyst(_cloudOrbStopSound); - _vm->_gfx->runTransition(kTransitionTopToBottom, _invokingResource->getRect(), 4, 0); + _vm->_gfx->runTransition(kTransitionTopToBottom, getInvokingResource<MystArea>()->getRect(), 4, 0); } void Stoneship::o_drawerCloseOpened(uint16 op, uint16 var, uint16 argc, uint16 *argv) { @@ -822,20 +824,20 @@ void Stoneship::drawerClose(uint16 drawer) { _vm->drawCardBackground(); _vm->drawResourceImages(); - MystResource *res = _vm->_resources[drawer]; + MystArea *res = _vm->_resources[drawer]; _vm->_gfx->runTransition(kTransitionBottomToTop, res->getRect(), 25, 5); } void Stoneship::o_hologramDisplay_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Hologram display init", op); - _hologramDisplay = static_cast<MystResourceType6 *>(_invokingResource); + _hologramDisplay = getInvokingResource<MystAreaVideo>(); _hologramDisplayPos = 0; } void Stoneship::o_hologramSelection_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Hologram selection init", op); - _hologramSelection = static_cast<MystResourceType6 *>(_invokingResource); + _hologramSelection = getInvokingResource<MystAreaVideo>(); } void Stoneship::batteryGaugeUpdate() { @@ -856,7 +858,7 @@ void Stoneship::o_battery_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) // Used for Card 2160 (Lighthouse Battery Pack Closeup) debugC(kDebugScript, "Opcode %d: Battery init", op); - _batteryGauge = static_cast<MystResourceType8 *>(_invokingResource); + _batteryGauge = getInvokingResource<MystAreaImageSwitch>(); batteryGaugeUpdate(); } @@ -1014,7 +1016,7 @@ void Stoneship::o_achenarDrawers_init(uint16 op, uint16 var, uint16 argc, uint16 void Stoneship::o_cloudOrb_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) { debugC(kDebugScript, "Opcode %d: Cloud orb init", op); - _cloudOrbMovie = static_cast<MystResourceType6 *>(_invokingResource); + _cloudOrbMovie = getInvokingResource<MystAreaVideo>(); _cloudOrbSound = argv[0]; _cloudOrbStopSound = argv[1]; } diff --git a/engines/mohawk/myst_stacks/stoneship.h b/engines/mohawk/myst_stacks/stoneship.h index 4e1b42f26b..776641a787 100644 --- a/engines/mohawk/myst_stacks/stoneship.h +++ b/engines/mohawk/myst_stacks/stoneship.h @@ -40,16 +40,16 @@ public: Stoneship(MohawkEngine_Myst *vm); ~Stoneship(); - void disablePersistentScripts(); - void runPersistentScripts(); + void disablePersistentScripts() override; + void runPersistentScripts() override; private: void setupOpcodes(); - uint16 getVar(uint16 var); - void toggleVar(uint16 var); - bool setVarValue(uint16 var, uint16 value); + uint16 getVar(uint16 var) override; + void toggleVar(uint16 var) override; + bool setVarValue(uint16 var, uint16 value) override; - virtual uint16 getMap() { return 9933; } + virtual uint16 getMap() override { return 9933; } DECLARE_OPCODE(o_pumpTurnOff); DECLARE_OPCODE(o_brotherDoorOpen); @@ -98,7 +98,7 @@ private: bool _batteryGaugeRunning; uint16 _batteryLastCharge; // 92 - MystResourceType8 *_batteryGauge; // 96 + MystAreaImageSwitch *_batteryGauge; // 96 void batteryGaugeUpdate(); void batteryGauge_run(); @@ -113,8 +113,8 @@ private: void drawerClose(uint16 drawer); uint16 _hologramTurnedOn; // 80 - MystResourceType6 *_hologramDisplay; // 84 - MystResourceType6 *_hologramSelection; // 88 + MystAreaVideo *_hologramDisplay; // 84 + MystAreaVideo *_hologramSelection; // 88 uint16 _hologramDisplayPos; bool _tunnelRunning; @@ -135,7 +135,7 @@ private: void telescope_run(); void telescopeLighthouseDraw(); - MystResourceType6 *_cloudOrbMovie; // 136 + MystAreaVideo *_cloudOrbMovie; // 136 uint16 _cloudOrbSound; // 140 uint16 _cloudOrbStopSound; // 142 diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp index 3e54017df8..213a976413 100644 --- a/engines/mohawk/myst_state.cpp +++ b/engines/mohawk/myst_state.cpp @@ -26,11 +26,41 @@ #include "common/debug.h" #include "common/serializer.h" +#include "common/system.h" #include "common/textconsole.h" #include "common/util.h" +#include "graphics/thumbnail.h" + namespace Mohawk { +MystSaveMetadata::MystSaveMetadata() { + saveDay = 0; + saveMonth = 0; + saveYear = 0; + saveHour = 0; + saveMinute = 0; + totalPlayTime = 0; +} + +bool MystSaveMetadata::sync(Common::Serializer &s) { + static const Common::Serializer::Version kCurrentVersion = 1; + + if (!s.syncVersion(kCurrentVersion)) { + return false; + } + + s.syncAsByte(saveDay); + s.syncAsByte(saveMonth); + s.syncAsUint16LE(saveYear); + s.syncAsByte(saveHour); + s.syncAsByte(saveMinute); + s.syncString(saveDescription); + s.syncAsUint32LE(totalPlayTime); + + return true; +} + MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) { // Most of the variables are zero at game start. memset(&_globals, 0, sizeof(_globals)); @@ -76,14 +106,39 @@ MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *sav MystGameState::~MystGameState() { } -Common::StringArray MystGameState::generateSaveGameList() { - return _saveFileMan->listSavefiles("*.mys"); +bool MystGameState::load(int slot) { + if (!loadState(slot)) { + return false; + } + + loadMetadata(slot); + + // Set Channelwood elevator state to down, because we start on the lower level + _channelwood.elevatorState = 0; + + // Switch us back to the intro stack, to the linking book + _vm->changeToStack(kIntroStack, 5, 0, 0); + + // Set our default cursor + _vm->_cursor->showCursor(); + if (_globals.heldPage == 0 || _globals.heldPage > 13) + _vm->setMainCursor(kDefaultMystCursor); + else if (_globals.heldPage < 7) + _vm->setMainCursor(kBluePageCursor); + else if (_globals.heldPage < 13) + _vm->setMainCursor(kRedPageCursor); + else // if (globals.heldPage == 13) + _vm->setMainCursor(kWhitePageCursor); + + return true; } -bool MystGameState::load(const Common::String &filename) { +bool MystGameState::loadState(int slot) { + Common::String filename = buildSaveFilename(slot); Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); - if (!loadFile) + if (!loadFile) { return false; + } debugC(kDebugSaveLoad, "Loading game from '%s'", filename.c_str()); @@ -96,42 +151,54 @@ bool MystGameState::load(const Common::String &filename) { return false; } - Common::Serializer s(loadFile, 0); + Common::Serializer s(loadFile, nullptr); syncGameState(s, size == 664); delete loadFile; - // Set Channelwood elevator state to down, because we start on the lower level - _channelwood.elevatorState = 0; + return true; +} - // Switch us back to the intro stack, to the linking book - _vm->changeToStack(kIntroStack, 5, 0, 0); +void MystGameState::loadMetadata(int slot) { + // Open the metadata file + Common::String filename = buildMetadataFilename(slot); + Common::InSaveFile *metadataFile = _vm->getSaveFileManager()->openForLoading(filename); + if (!metadataFile) { + return; + } - // Set our default cursor - if (_globals.heldPage == 0 || _globals.heldPage > 13) - _vm->setMainCursor(kDefaultMystCursor); - else if (_globals.heldPage < 7) - _vm->setMainCursor(kBluePageCursor); - else if (_globals.heldPage < 13) - _vm->setMainCursor(kRedPageCursor); - else // if (globals.heldPage == 13) - _vm->setMainCursor(kWhitePageCursor); + debugC(kDebugSaveLoad, "Loading metadata from '%s'", filename.c_str()); - return true; + Common::Serializer m(metadataFile, nullptr); + + // Read the metadata file + if (_metadata.sync(m)) { + _vm->setTotalPlayTime(_metadata.totalPlayTime); + } + + delete metadataFile; } -bool MystGameState::save(const Common::String &fname) { - Common::String filename(fname); - // Make sure we have the right extension - if (!filename.hasSuffix(".mys") && !filename.hasSuffix(".MYS")) - filename += ".mys"; +bool MystGameState::save(int slot, const Common::String &desc) { + if (!saveState(slot)) { + return false; + } + + updateMetadateForSaving(desc); + + return saveMetadata(slot); +} +bool MystGameState::saveState(int slot) { + // Make sure we have the right extension + Common::String filename = buildSaveFilename(slot); Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(filename); - if (!saveFile) + if (!saveFile) { return false; + } debugC(kDebugSaveLoad, "Saving game to '%s'", filename.c_str()); - Common::Serializer s(0, saveFile); + Common::Serializer s(nullptr, saveFile); syncGameState(s, _vm->getFeatures() & GF_ME); saveFile->finalize(); delete saveFile; @@ -139,6 +206,101 @@ bool MystGameState::save(const Common::String &fname) { return true; } +Common::String MystGameState::buildSaveFilename(int slot) { + return Common::String::format("myst-%03d.mys", slot); +} + +Common::String MystGameState::buildMetadataFilename(int slot) { + return Common::String::format("myst-%03d.mym", slot); +} + +void MystGameState::updateMetadateForSaving(const Common::String &desc) { + // Update save creation info + TimeDate t; + g_system->getTimeAndDate(t); + _metadata.saveYear = t.tm_year + 1900; + _metadata.saveMonth = t.tm_mon + 1; + _metadata.saveDay = t.tm_mday; + _metadata.saveHour = t.tm_hour; + _metadata.saveMinute = t.tm_min; + _metadata.saveDescription = desc; + _metadata.totalPlayTime = _vm->getTotalPlayTime(); +} + +bool MystGameState::saveMetadata(int slot) { + // Write the metadata to a separate file so that the save files + // are still compatible with the original engine + Common::String metadataFilename = buildMetadataFilename(slot); + Common::OutSaveFile *metadataFile = _saveFileMan->openForSaving(metadataFilename); + if (!metadataFile) { + return false; + } + + // Save the metadata + Common::Serializer m(nullptr, metadataFile); + _metadata.sync(m); + + // Append a thumbnail + Graphics::saveThumbnail(*metadataFile); + + metadataFile->finalize(); + delete metadataFile; + + return true; +} + +SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) { + // Open the metadata file + Common::String filename = buildMetadataFilename(slot); + Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename); + if (!metadataFile) { + return SaveStateDescriptor(); + } + + Common::Serializer m(metadataFile, nullptr); + + // Read the metadata file + Mohawk::MystSaveMetadata metadata; + if (!metadata.sync(m)) { + delete metadataFile; + return SaveStateDescriptor(); + } + + // Set the save description + SaveStateDescriptor desc; + desc.setDescription(metadata.saveDescription); + desc.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay); + desc.setSaveTime(metadata.saveHour, metadata.saveMinute); + desc.setPlayTime(metadata.totalPlayTime); + desc.setThumbnail(Graphics::loadThumbnail(*metadataFile)); + + delete metadataFile; + + return desc; +} + +Common::String MystGameState::querySaveDescription(int slot) { + // Open the metadata file + Common::String filename = buildMetadataFilename(slot); + Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename); + if (!metadataFile) { + return ""; + } + + Common::Serializer m(metadataFile, nullptr); + + // Read the metadata file + Mohawk::MystSaveMetadata metadata; + if (!metadata.sync(m)) { + delete metadataFile; + return ""; + } + + delete metadataFile; + + return metadata.saveDescription; +} + void MystGameState::syncGameState(Common::Serializer &s, bool isME) { // Globals first s.syncAsUint16LE(_globals.u0); @@ -315,13 +477,18 @@ void MystGameState::syncGameState(Common::Serializer &s, bool isME) { warning("Unexpected File Position 0x%03X At End of Save/Load", s.bytesSynced()); } -void MystGameState::deleteSave(const Common::String &saveName) { - debugC(kDebugSaveLoad, "Deleting save file \'%s\'", saveName.c_str()); - _saveFileMan->removeSavefile(saveName.c_str()); +void MystGameState::deleteSave(int slot) { + Common::String filename = buildSaveFilename(slot); + Common::String metadataFilename = buildMetadataFilename(slot); + + debugC(kDebugSaveLoad, "Deleting save file \'%s\'", filename.c_str()); + + g_system->getSavefileManager()->removeSavefile(filename); + g_system->getSavefileManager()->removeSavefile(metadataFilename); } void MystGameState::addZipDest(uint16 stack, uint16 view) { - ZipDests *zipDests = 0; + ZipDests *zipDests = nullptr; // The demo has no zip dest storage if (_vm->getFeatures() & GF_DEMO) diff --git a/engines/mohawk/myst_state.h b/engines/mohawk/myst_state.h index b07a0f2469..7d5f3f7102 100644 --- a/engines/mohawk/myst_state.h +++ b/engines/mohawk/myst_state.h @@ -27,6 +27,8 @@ #include "common/file.h" #include "common/str.h" +#include "engines/savestate.h" + namespace Common { class Serializer; } @@ -35,15 +37,33 @@ namespace Mohawk { class MohawkEngine_Myst; +struct MystSaveMetadata { + uint8 saveDay; + uint8 saveMonth; + uint16 saveYear; + + uint8 saveHour; + uint8 saveMinute; + + uint32 totalPlayTime; + + Common::String saveDescription; + + MystSaveMetadata(); + bool sync(Common::Serializer &s); +}; + class MystGameState { public: MystGameState(MohawkEngine_Myst*, Common::SaveFileManager*); ~MystGameState(); - Common::StringArray generateSaveGameList(); - bool load(const Common::String &); - bool save(const Common::String &); - void deleteSave(const Common::String &); + static SaveStateDescriptor querySaveMetaInfos(int slot); + static Common::String querySaveDescription(int slot); + + bool load(int slot); + bool save(int slot, const Common::String &desc); + static void deleteSave(int slot); void addZipDest(uint16 stack, uint16 view); bool isReachableZipDest(uint16 stack, uint16 view); @@ -268,8 +288,17 @@ public: uint32 generatorDepletionTime; } _stoneship; + MystSaveMetadata _metadata; + private: void syncGameState(Common::Serializer &s, bool isME); + static Common::String buildSaveFilename(int slot); + static Common::String buildMetadataFilename(int slot); + bool loadState(int slot); + void loadMetadata(int slot); + bool saveState(int slot); + void updateMetadateForSaving(const Common::String &desc); + bool saveMetadata(int slot); // The values in these regions are lists of VIEW resources // which correspond to visited zip destinations diff --git a/engines/mohawk/resource.h b/engines/mohawk/resource.h index d9074a5b73..12c5a139e4 100644 --- a/engines/mohawk/resource.h +++ b/engines/mohawk/resource.h @@ -68,6 +68,8 @@ namespace Mohawk { #define ID_VARS MKTAG('V','A','R','S') // Variable Values #define ID_VERS MKTAG('V','E','R','S') // Version Info #define ID_ZIPS MKTAG('Z','I','P','S') // Zip Mode Status +#define ID_META MKTAG('M','E','T','A') // ScummVM save metadata +#define ID_THMB MKTAG('T','H','M','B') // ScummVM save thumbnail // Zoombini Resource FourCC's #define ID_SND MKTAG( 0 ,'S','N','D') // Standard Mohawk Sound diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 898f68c581..aa168a38d8 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -25,6 +25,7 @@ #include "common/keyboard.h" #include "common/translation.h" #include "common/system.h" +#include "gui/saveload.h" #include "mohawk/cursors.h" #include "mohawk/installer_archive.h" @@ -54,9 +55,19 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio _gameOver = false; _activatedSLST = false; _ignoreNextMouseUp = false; - _extrasFile = 0; + _extrasFile = nullptr; _curStack = kStackUnknown; - _hotspots = 0; + _hotspots = nullptr; + _gfx = nullptr; + _externalScriptHandler = nullptr; + _rnd = nullptr; + _scriptMan = nullptr; + _console = nullptr; + _saveLoad = nullptr; + _optionsDialog = nullptr; + _curCard = 0; + _hotspotCount = 0; + _curHotspot = -1; removeTimer(); // NOTE: We can never really support CD swapping. All of the music files @@ -165,13 +176,10 @@ Common::Error MohawkEngine_Riven::run() { changeToCard(6); } else if (ConfMan.hasKey("save_slot")) { // Load game from launcher/command line if requested - uint32 gameToLoad = ConfMan.getInt("save_slot"); - Common::StringArray savedGamesList = _saveLoad->generateSaveGameList(); - if (gameToLoad > savedGamesList.size()) - error ("Could not find saved game"); + int gameToLoad = ConfMan.getInt("save_slot"); // Attempt to load the game. On failure, just send us to the main menu. - if (_saveLoad->loadGame(savedGamesList[gameToLoad]).getCode() != Common::kNoError) { + if (_saveLoad->loadGame(gameToLoad).getCode() != Common::kNoError) { changeToStack(kStackAspit); changeToCard(1); } @@ -723,16 +731,11 @@ void MohawkEngine_Riven::runLoadDialog() { } Common::Error MohawkEngine_Riven::loadGameState(int slot) { - return _saveLoad->loadGame(_saveLoad->generateSaveGameList()[slot]); + return _saveLoad->loadGame(slot); } Common::Error MohawkEngine_Riven::saveGameState(int slot, const Common::String &desc) { - Common::StringArray saveList = _saveLoad->generateSaveGameList(); - - if ((uint)slot < saveList.size()) - _saveLoad->deleteSave(saveList[slot]); - - return _saveLoad->saveGame(desc); + return _saveLoad->saveGame(slot, desc); } Common::String MohawkEngine_Riven::getStackName(uint16 stack) const { diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index 9c23d07c52..3ea50bb38d 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -27,8 +27,6 @@ #include "mohawk/mohawk.h" #include "mohawk/riven_scripts.h" -#include "gui/saveload.h" - #include "common/hashmap.h" #include "common/hash-str.h" #include "common/random.h" diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp index b44fbb828e..db22dde22d 100644 --- a/engines/mohawk/riven_graphics.cpp +++ b/engines/mohawk/riven_graphics.cpp @@ -51,6 +51,8 @@ RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm _creditsImage = 302; _creditsPos = 0; + + _transitionSpeed = 0; } RivenGraphics::~RivenGraphics() { diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp index 6af66f7a2d..755f87767d 100644 --- a/engines/mohawk/riven_saveload.cpp +++ b/engines/mohawk/riven_saveload.cpp @@ -24,25 +24,141 @@ #include "mohawk/riven.h" #include "mohawk/riven_saveload.h" -#include "common/util.h" +#include "common/system.h" +#include "graphics/thumbnail.h" namespace Mohawk { +RivenSaveMetadata::RivenSaveMetadata() { + saveDay = 0; + saveMonth = 0; + saveYear = 0; + saveHour = 0; + saveMinute = 0; + totalPlayTime = 0; +} + +bool RivenSaveMetadata::sync(Common::Serializer &s) { + static const Common::Serializer::Version kCurrentVersion = 1; + + if (!s.syncVersion(kCurrentVersion)) { + return false; + } + + s.syncAsByte(saveDay); + s.syncAsByte(saveMonth); + s.syncAsUint16BE(saveYear); + s.syncAsByte(saveHour); + s.syncAsByte(saveMinute); + s.syncString(saveDescription); + s.syncAsUint32BE(totalPlayTime); + + return true; +} + RivenSaveLoad::RivenSaveLoad(MohawkEngine_Riven *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) { } RivenSaveLoad::~RivenSaveLoad() { } -Common::StringArray RivenSaveLoad::generateSaveGameList() { - return _saveFileMan->listSavefiles("*.rvn"); +Common::String RivenSaveLoad::buildSaveFilename(const int slot) { + return Common::String::format("riven-%03d.rvn", slot); +} + +Common::String RivenSaveLoad::querySaveDescription(const int slot) { + Common::String filename = buildSaveFilename(slot); + Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename); + if (!loadFile) { + return ""; + } + + MohawkArchive mhk; + if (!mhk.openStream(loadFile)) { + return ""; + } + + if (!mhk.hasResource(ID_META, 1)) { + return ""; + } + + Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1); + if (!metaStream) { + return ""; + } + + Common::Serializer serializer = Common::Serializer(metaStream, nullptr); + + RivenSaveMetadata metadata; + if (!metadata.sync(serializer)) { + delete metaStream; + return ""; + } + + delete metaStream; + + return metadata.saveDescription; } -Common::Error RivenSaveLoad::loadGame(Common::String filename) { +SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) { + Common::String filename = buildSaveFilename(slot); + Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename); + if (!loadFile) { + return SaveStateDescriptor(); + } + + MohawkArchive mhk; + if (!mhk.openStream(loadFile)) { + return SaveStateDescriptor(); + } + + if (!mhk.hasResource(ID_META, 1)) { + return SaveStateDescriptor(); + } + + Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1); + if (!metaStream) { + return SaveStateDescriptor(); + } + + Common::Serializer serializer = Common::Serializer(metaStream, nullptr); + + RivenSaveMetadata metadata; + if (!metadata.sync(serializer)) { + delete metaStream; + return SaveStateDescriptor(); + } + + SaveStateDescriptor descriptor; + descriptor.setDescription(metadata.saveDescription); + descriptor.setPlayTime(metadata.totalPlayTime); + descriptor.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay); + descriptor.setSaveTime(metadata.saveHour, metadata.saveMinute); + + delete metaStream; + + if (!mhk.hasResource(ID_THMB, 1)) { + return descriptor; + } + + Common::SeekableReadStream *thmbStream = mhk.getResource(ID_THMB, 1); + if (!thmbStream) { + return descriptor; + } + + descriptor.setThumbnail(Graphics::loadThumbnail(*thmbStream)); + + delete thmbStream; + + return descriptor; +} + +Common::Error RivenSaveLoad::loadGame(const int slot) { if (_vm->getFeatures() & GF_DEMO) // Don't load games in the demo return Common::kNoError; - Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); + Common::String filename = buildSaveFilename(slot); + Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); if (!loadFile) return Common::kReadingFailed; @@ -72,8 +188,11 @@ Common::Error RivenSaveLoad::loadGame(Common::String filename) { Common::Array<uint32> rawVariables; while (!vars->eos()) { - vars->readUint32BE(); // Unknown (Stack?) - vars->readUint32BE(); // Unknown (0 or 1) + // The original engine stores the variables values in an array. All the slots in + // the array may not be in use, which is why it needs a reference counter and + // a flag to tell if the value has been set. + vars->readUint32BE(); // Reference counter + vars->readUint32BE(); // Variable initialized flag rawVariables.push_back(vars->readUint32BE()); } @@ -144,6 +263,20 @@ Common::Error RivenSaveLoad::loadGame(Common::String filename) { } delete zips; + + // Load the ScummVM specific save metadata + if (mhk->hasResource(ID_META, 1)) { + Common::SeekableReadStream *metadataStream = mhk->getResource(ID_META, 1); + Common::Serializer serializer = Common::Serializer(metadataStream, nullptr); + + RivenSaveMetadata metadata; + metadata.sync(serializer); + + // Set the saved total play time + _vm->setTotalPlayTime(metadata.totalPlayTime); + + delete metadataStream; + } delete mhk; return Common::kNoError; @@ -162,14 +295,18 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genVARSSection() { Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic(); for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) { - stream->writeUint32BE(0); // Unknown - stream->writeUint32BE(0); // Unknown + stream->writeUint32BE(1); // Reference counter + stream->writeUint32BE(1); // Variable initialized flag stream->writeUint32BE(it->_value); } return stream; } +static int stringCompareToIgnoreCase(const Common::String &s1, const Common::String &s2) { + return s1.compareToIgnoreCase(s2) < 0; +} + Common::MemoryWriteStreamDynamic *RivenSaveLoad::genNAMESection() { Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic(); @@ -181,8 +318,28 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genNAMESection() { curPos += it->_key.size() + 1; } - for (uint16 i = 0; i < _vm->_vars.size(); i++) - stream->writeUint16BE(i); + // The original engine does not store the variables in a HashMap, but in a "NameList" + // for the keys and an array for the values. The NameList data structure maintains an array + // of indices in the string table sorted by case insensitive key alphabetical order. + // It is used to perform fast key -> index lookups. + // ScummVM does not need the sorted array, but has to write it anyway for the saved games + // to be compatible with original engine. + Common::Array<Common::String> sortedKeys; + for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) { + sortedKeys.push_back(it->_key); + } + Common::sort(sortedKeys.begin(), sortedKeys.end(), stringCompareToIgnoreCase); + + for (uint i = 0; i < sortedKeys.size(); i++) { + uint16 varIndex = 0; + for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) { + if (it->_key == sortedKeys[i]) { + stream->writeUint16BE(varIndex); + break; + } + varIndex++; + } + } for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) { stream->write(it->_key.c_str(), it->_key.size()); @@ -206,7 +363,35 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genZIPSSection() { return stream; } -Common::Error RivenSaveLoad::saveGame(Common::String filename) { +Common::MemoryWriteStreamDynamic *RivenSaveLoad::genTHMBSection() const { + Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic(); + + Graphics::saveThumbnail(*stream); + + return stream; +} + +Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::String &desc) const { + Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic(); + Common::Serializer serializer = Common::Serializer(nullptr, stream); + + TimeDate t; + _vm->_system->getTimeAndDate(t); + + RivenSaveMetadata metadata; + metadata.saveDay = t.tm_mday; + metadata.saveMonth = t.tm_mon + 1; + metadata.saveYear = t.tm_year + 1900; + metadata.saveHour = t.tm_hour; + metadata.saveMinute = t.tm_min; + metadata.saveDescription = desc; + metadata.totalPlayTime = _vm->getTotalPlayTime(); + metadata.sync(serializer); + + return stream; +} + +Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &description) { // NOTE: This code is designed to only output a Mohawk archive // for a Riven saved game. It's hardcoded to do this because // (as of right now) this is the only place in the engine @@ -214,13 +399,7 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) { // games need this, we should think about coming up with some // more common way of outputting resources to an archive. - // TODO: Make these saves work with the original interpreter. - // Not sure why they don't work yet (they still can be loaded - // by ScummVM). - - // Make sure we have the right extension - if (!filename.matchString("*.rvn", true)) - filename += ".rvn"; + Common::String filename = buildSaveFilename(slot); // Convert class variables to variable numbers _vm->_vars["currentstackid"] = _vm->getCurStack(); @@ -232,16 +411,20 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) { debug (0, "Saving game to \'%s\'", filename.c_str()); - Common::MemoryWriteStreamDynamic *versSection = genVERSSection(); + Common::MemoryWriteStreamDynamic *metaSection = genMETASection(description); Common::MemoryWriteStreamDynamic *nameSection = genNAMESection(); + Common::MemoryWriteStreamDynamic *thmbSection = genTHMBSection(); Common::MemoryWriteStreamDynamic *varsSection = genVARSSection(); + Common::MemoryWriteStreamDynamic *versSection = genVERSSection(); Common::MemoryWriteStreamDynamic *zipsSection = genZIPSSection(); // Let's calculate the file size! - uint32 fileSize = 142; - fileSize += versSection->size(); + uint32 fileSize = 194; + fileSize += metaSection->size(); fileSize += nameSection->size(); + fileSize += thmbSection->size(); fileSize += varsSection->size(); + fileSize += versSection->size(); fileSize += zipsSection->size(); // MHWK Header (8 bytes - total: 8) @@ -254,109 +437,151 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) { saveFile->writeUint16BE(1); // Compaction -- original saves have this too saveFile->writeUint32BE(fileSize); // Subtract off the MHWK header size saveFile->writeUint32BE(28); // Absolute offset: right after both headers - saveFile->writeUint16BE(70); // File Table Offset - saveFile->writeUint16BE(44); // File Table Size (4 bytes count + 4 entries * 10 bytes per entry) + saveFile->writeUint16BE(102); // File Table Offset + saveFile->writeUint16BE(64); // File Table Size (4 bytes count + 6 entries * 10 bytes per entry) // Type Table (4 bytes - total: 32) - saveFile->writeUint16BE(36); // String table offset After the Type Table Entries - saveFile->writeUint16BE(4); // 4 Type Table Entries + saveFile->writeUint16BE(52); // String table offset After the Type Table Entries + saveFile->writeUint16BE(6); // 6 Type Table Entries - // Hardcode Entries (32 bytes - total: 64) - saveFile->writeUint32BE(ID_VERS); - saveFile->writeUint16BE(46); // Resource table offset - saveFile->writeUint16BE(38); // String table offset + // Hardcode Entries (48 bytes - total: 80) + // The original engine relies on the entries being sorted by tag alphabetical order + // to optimize its lookup algorithm. + saveFile->writeUint32BE(ID_META); + saveFile->writeUint16BE(66); // Resource table offset + saveFile->writeUint16BE(54); // String table offset saveFile->writeUint32BE(ID_NAME); - saveFile->writeUint16BE(52); - saveFile->writeUint16BE(40); + saveFile->writeUint16BE(72); + saveFile->writeUint16BE(56); - saveFile->writeUint32BE(ID_VARS); + saveFile->writeUint32BE(ID_THMB); + saveFile->writeUint16BE(78); saveFile->writeUint16BE(58); - saveFile->writeUint16BE(42); + + saveFile->writeUint32BE(ID_VARS); + saveFile->writeUint16BE(84); + saveFile->writeUint16BE(60); + + saveFile->writeUint32BE(ID_VERS); + saveFile->writeUint16BE(90); + saveFile->writeUint16BE(62); saveFile->writeUint32BE(ID_ZIPS); + saveFile->writeUint16BE(96); saveFile->writeUint16BE(64); - saveFile->writeUint16BE(44); - // Pseudo-String Table (2 bytes - total: 66) + // Pseudo-String Table (2 bytes - total: 82) saveFile->writeUint16BE(0); // We don't need a name list - // Psuedo-Name Tables (8 bytes - total: 74) + // Pseudo-Name Tables (12 bytes - total: 94) + saveFile->writeUint16BE(0); + saveFile->writeUint16BE(0); saveFile->writeUint16BE(0); saveFile->writeUint16BE(0); saveFile->writeUint16BE(0); saveFile->writeUint16BE(0); - // VERS Section (Resource Table) (6 bytes - total: 80) + // META Section (Resource Table) (6 bytes - total: 100) saveFile->writeUint16BE(1); saveFile->writeUint16BE(1); saveFile->writeUint16BE(1); - // NAME Section (Resource Table) (6 bytes - total: 86) + // NAME Section (Resource Table) (6 bytes - total: 106) saveFile->writeUint16BE(1); saveFile->writeUint16BE(1); saveFile->writeUint16BE(2); - // VARS Section (Resource Table) (6 bytes - total: 92) + // THMB Section (Resource Table) (6 bytes - total: 112) saveFile->writeUint16BE(1); saveFile->writeUint16BE(1); saveFile->writeUint16BE(3); - // ZIPS Section (Resource Table) (6 bytes - total: 98) + // VARS Section (Resource Table) (6 bytes - total: 118) saveFile->writeUint16BE(1); saveFile->writeUint16BE(1); saveFile->writeUint16BE(4); - // File Table (4 bytes - total: 102) - saveFile->writeUint32BE(4); + // VERS Section (Resource Table) (6 bytes - total: 124) + saveFile->writeUint16BE(1); + saveFile->writeUint16BE(1); + saveFile->writeUint16BE(5); - // VERS Section (File Table) (10 bytes - total: 112) - saveFile->writeUint32BE(142); - saveFile->writeUint16BE(versSection->size() & 0xFFFF); - saveFile->writeByte((versSection->size() & 0xFF0000) >> 16); + // ZIPS Section (Resource Table) (6 bytes - total: 130) + saveFile->writeUint16BE(1); + saveFile->writeUint16BE(1); + saveFile->writeUint16BE(6); + + // File Table (4 bytes - total: 134) + saveFile->writeUint32BE(6); + + // META Section (File Table) (10 bytes - total: 144) + saveFile->writeUint32BE(194); + saveFile->writeUint16BE(metaSection->size() & 0xFFFF); + saveFile->writeByte((metaSection->size() & 0xFF0000) >> 16); saveFile->writeByte(0); saveFile->writeUint16BE(0); - // NAME Section (File Table) (10 bytes - total: 122) - saveFile->writeUint32BE(142 + versSection->size()); + // NAME Section (File Table) (10 bytes - total: 154) + saveFile->writeUint32BE(194 + metaSection->size()); saveFile->writeUint16BE(nameSection->size() & 0xFFFF); saveFile->writeByte((nameSection->size() & 0xFF0000) >> 16); saveFile->writeByte(0); saveFile->writeUint16BE(0); - // VARS Section (File Table) (10 bytes - total: 132) - saveFile->writeUint32BE(142 + versSection->size() + nameSection->size()); + // THMB Section (File Table) (10 bytes - total: 164) + saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size()); + saveFile->writeUint16BE(thmbSection->size() & 0xFFFF); + saveFile->writeByte((thmbSection->size() & 0xFF0000) >> 16); + saveFile->writeByte(0); + saveFile->writeUint16BE(0); + + // VARS Section (File Table) (10 bytes - total: 174) + saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size()); saveFile->writeUint16BE(varsSection->size() & 0xFFFF); saveFile->writeByte((varsSection->size() & 0xFF0000) >> 16); saveFile->writeByte(0); saveFile->writeUint16BE(0); - // ZIPS Section (File Table) (10 bytes - total: 142) - saveFile->writeUint32BE(142 + versSection->size() + nameSection->size() + varsSection->size()); + // VERS Section (File Table) (10 bytes - total: 184) + saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size() + varsSection->size()); + saveFile->writeUint16BE(versSection->size() & 0xFFFF); + saveFile->writeByte((versSection->size() & 0xFF0000) >> 16); + saveFile->writeByte(0); + saveFile->writeUint16BE(0); + + // ZIPS Section (File Table) (10 bytes - total: 194) + saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size() + varsSection->size() + versSection->size()); saveFile->writeUint16BE(zipsSection->size() & 0xFFFF); saveFile->writeByte((zipsSection->size() & 0xFF0000) >> 16); saveFile->writeByte(0); saveFile->writeUint16BE(0); - saveFile->write(versSection->getData(), versSection->size()); + saveFile->write(metaSection->getData(), metaSection->size()); saveFile->write(nameSection->getData(), nameSection->size()); + saveFile->write(thmbSection->getData(), thmbSection->size()); saveFile->write(varsSection->getData(), varsSection->size()); + saveFile->write(versSection->getData(), versSection->size()); saveFile->write(zipsSection->getData(), zipsSection->size()); saveFile->finalize(); delete saveFile; - delete versSection; + delete metaSection; delete nameSection; + delete thmbSection; delete varsSection; + delete versSection; delete zipsSection; return Common::kNoError; } -void RivenSaveLoad::deleteSave(Common::String saveName) { - debug (0, "Deleting save file \'%s\'", saveName.c_str()); - _saveFileMan->removeSavefile(saveName); +void RivenSaveLoad::deleteSave(const int slot) { + Common::String filename = buildSaveFilename(slot); + + debug (0, "Deleting save file \'%s\'", filename.c_str()); + g_system->getSavefileManager()->removeSavefile(filename); } } // End of namespace Mohawk diff --git a/engines/mohawk/riven_saveload.h b/engines/mohawk/riven_saveload.h index a6ddce5713..34bfbdc434 100644 --- a/engines/mohawk/riven_saveload.h +++ b/engines/mohawk/riven_saveload.h @@ -23,10 +23,13 @@ #ifndef MOHAWK_SAVELOAD_H #define MOHAWK_SAVELOAD_H +#include "common/serializer.h" #include "common/savefile.h" #include "common/str.h" #include "common/memstream.h" +#include "engines/savestate.h" + namespace Mohawk { class MohawkEngine_Riven; @@ -36,23 +39,45 @@ enum { kDVDSaveGameVersion = 0x00010100 }; +struct RivenSaveMetadata { + uint8 saveDay; + uint8 saveMonth; + uint16 saveYear; + + uint8 saveHour; + uint8 saveMinute; + + uint32 totalPlayTime; + + Common::String saveDescription; + + RivenSaveMetadata(); + bool sync(Common::Serializer &s); +}; + class RivenSaveLoad { public: RivenSaveLoad(MohawkEngine_Riven*, Common::SaveFileManager*); ~RivenSaveLoad(); - Common::StringArray generateSaveGameList(); - Common::Error loadGame(Common::String); - Common::Error saveGame(Common::String); - void deleteSave(Common::String); + Common::Error loadGame(const int slot); + Common::Error saveGame(const int slot, const Common::String &description); + static void deleteSave(const int slot); + + static SaveStateDescriptor querySaveMetaInfos(const int slot); + static Common::String querySaveDescription(const int slot); private: MohawkEngine_Riven *_vm; Common::SaveFileManager *_saveFileMan; - Common::MemoryWriteStreamDynamic *genVERSSection(); + static Common::String buildSaveFilename(const int slot); + Common::MemoryWriteStreamDynamic *genNAMESection(); + Common::MemoryWriteStreamDynamic *genMETASection(const Common::String &desc) const; + Common::MemoryWriteStreamDynamic *genTHMBSection() const; Common::MemoryWriteStreamDynamic *genVARSSection(); + Common::MemoryWriteStreamDynamic *genVERSSection(); Common::MemoryWriteStreamDynamic *genZIPSSection(); }; diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp index 198627e012..38cb0b3608 100644 --- a/engines/mohawk/sound.cpp +++ b/engines/mohawk/sound.cpp @@ -21,13 +21,14 @@ */ #include "common/debug.h" +#include "common/events.h" #include "common/system.h" -#include "common/util.h" #include "common/textconsole.h" +#include "audio/mididrv.h" #include "audio/midiparser.h" -#include "audio/musicplugin.h" #include "audio/audiostream.h" +#include "audio/decoders/adpcm.h" #include "audio/decoders/mp3.h" #include "audio/decoders/raw.h" #include "audio/decoders/wave.h" @@ -163,8 +164,26 @@ Audio::SoundHandle *Sound::replaceSoundMyst(uint16 id, byte volume, bool loop) { void Sound::playSoundBlocking(uint16 id, byte volume) { Audio::SoundHandle *handle = playSound(id, volume); - while (_vm->_mixer->isSoundHandleActive(*handle)) + while (_vm->_mixer->isSoundHandleActive(*handle) && !_vm->shouldQuit()) { + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_SPACE: + _vm->pauseGame(); + break; + default: + break; + } + default: + break; + } + } + + // Cut down on CPU usage _vm->_system->delayMillis(10); + } } void Sound::playMidi(uint16 id) { @@ -625,7 +644,7 @@ uint16 Sound::convertMystID(uint16 id) { return id; } -Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) { +void Sound::replaceBackgroundMyst(uint16 id, uint16 volume) { debug(0, "Replacing background sound with %d", id); // TODO: The original engine does fading @@ -641,8 +660,11 @@ Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) { // Check if sound is already playing if (_mystBackgroundSound.type == kUsedHandle && _vm->_mixer->isSoundHandleActive(_mystBackgroundSound.handle) - && _vm->getResourceName(ID_MSND, convertMystID(_mystBackgroundSound.id)).hasPrefix(prefix)) - return &_mystBackgroundSound.handle; + && _vm->getResourceName(ID_MSND, convertMystID(_mystBackgroundSound.id)).hasPrefix(prefix)) { + // The sound is already playing, just change the volume + changeBackgroundVolumeMyst(volume); + return; + } // Stop old background sound stopBackgroundMyst(); @@ -659,10 +681,7 @@ Audio::SoundHandle *Sound::replaceBackgroundMyst(uint16 id, uint16 volume) { Audio::AudioStream *audStream = Audio::makeLoopingAudioStream(rewindStream, 0); _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_mystBackgroundSound.handle, audStream, -1, volume >> 8); - return &_mystBackgroundSound.handle; } - - return NULL; } void Sound::stopBackgroundMyst() { diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h index 75c9492d96..f09706e155 100644 --- a/engines/mohawk/sound.h +++ b/engines/mohawk/sound.h @@ -26,9 +26,7 @@ #include "common/scummsys.h" #include "common/str.h" -#include "audio/audiostream.h" #include "audio/mixer.h" -#include "audio/decoders/adpcm.h" #include "mohawk/mohawk.h" #include "mohawk/resource.h" @@ -36,6 +34,10 @@ class MidiDriver; class MidiParser; +namespace Audio { +class RewindableAudioStream; +} + namespace Mohawk { #define MAX_CHANNELS 2 // Can there be more than 2? @@ -136,7 +138,7 @@ public: // Myst-specific sound functions Audio::SoundHandle *replaceSoundMyst(uint16 id, byte volume = Audio::Mixer::kMaxChannelVolume, bool loop = false); - Audio::SoundHandle *replaceBackgroundMyst(uint16 id, uint16 volume = 0xFFFF); + void replaceBackgroundMyst(uint16 id, uint16 volume = 0xFFFF); void pauseBackgroundMyst(); void resumeBackgroundMyst(); void stopBackgroundMyst(); diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index ff4a69cd28..eec543235e 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -146,7 +146,7 @@ VideoHandle::VideoHandle(const VideoHandle &handle) : _ptr(handle._ptr) { VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) { // Set dithering enabled, if required - _enableDither = _vm->getGameType() == GType_MYST && !(_vm->getFeatures() & GF_ME); + _enableDither = (_vm->getGameType() == GType_MYST || _vm->getGameType() == GType_MAKINGOF) && !(_vm->getFeatures() & GF_ME); } VideoManager::~VideoManager() { @@ -184,7 +184,7 @@ void VideoManager::playMovieBlocking(const Common::String &fileName, uint16 x, u } ptr->start(); - waitUntilMovieEnds(ptr); + waitUntilMovieEnds(VideoHandle(ptr)); } void VideoManager::playMovieBlockingCentered(const Common::String &fileName, bool clearScreen) { @@ -200,7 +200,7 @@ void VideoManager::playMovieBlockingCentered(const Common::String &fileName, boo ptr->center(); ptr->start(); - waitUntilMovieEnds(ptr); + waitUntilMovieEnds(VideoHandle(ptr)); } void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) { @@ -278,7 +278,7 @@ VideoHandle VideoManager::playMovie(const Common::String &fileName) { return VideoHandle(); ptr->start(); - return ptr; + return VideoHandle(ptr); } VideoHandle VideoManager::playMovie(uint16 id) { @@ -287,7 +287,7 @@ VideoHandle VideoManager::playMovie(uint16 id) { return VideoHandle(); ptr->start(); - return ptr; + return VideoHandle(ptr); } bool VideoManager::updateMovies() { @@ -317,50 +317,13 @@ bool VideoManager::updateMovies() { // Check if we need to draw a frame if (video->needsUpdate()) { - const Graphics::Surface *frame = video->decodeNextFrame(); - Graphics::Surface *convertedFrame = 0; - - if (frame && (*it)->isEnabled()) { - Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); - - if (frame->format != pixelFormat) { - // We don't support downconverting to 8bpp without having - // support in the codec. Set _enableDither if shows up. - if (pixelFormat.bytesPerPixel == 1) { - warning("Cannot convert high color video frame to 8bpp"); - (*it)->close(); - it = _videos.erase(it); - continue; - } - - // Convert to the current screen format - convertedFrame = frame->convertTo(pixelFormat, video->getPalette()); - frame = convertedFrame; - } else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) { - // Set the palette when running in 8bpp mode only - // Don't do this for Myst, which has its own per-stack handling - if (_vm->getGameType() != GType_MYST) - _vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256); - } - - // Clip the width/height to make sure we stay on the screen (Myst does this a few times) - uint16 width = MIN<int32>(video->getWidth(), _vm->_system->getWidth() - (*it)->getX()); - uint16 height = MIN<int32>(video->getHeight(), _vm->_system->getHeight() - (*it)->getY()); - _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, (*it)->getX(), (*it)->getY(), width, height); - - // We've drawn something to the screen, make sure we update it + if (drawNextFrame(*it)) { updateScreen = true; - - // Delete 8bpp conversion surface - if (convertedFrame) { - convertedFrame->free(); - delete convertedFrame; - } } } // Check the video time - _vm->doVideoTimer(*it, false); + _vm->doVideoTimer(VideoHandle(*it), false); // Remember to increase the iterator it++; @@ -370,6 +333,74 @@ bool VideoManager::updateMovies() { return updateScreen; } +bool VideoManager::drawNextFrame(VideoEntryPtr videoEntry) { + Video::VideoDecoder *video = videoEntry->_video; + const Graphics::Surface *frame = video->decodeNextFrame(); + + if (!frame || !videoEntry->isEnabled()) { + return false; + } + + Graphics::Surface *convertedFrame = 0; + Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); + + if (frame->format != pixelFormat) { + // We don't support downconverting to 8bpp without having + // support in the codec. Set _enableDither if shows up. + if (pixelFormat.bytesPerPixel == 1) { + warning("Cannot convert high color video frame to 8bpp"); + return false; + } + + // Convert to the current screen format + convertedFrame = frame->convertTo(pixelFormat, video->getPalette()); + frame = convertedFrame; + } else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) { + // Set the palette when running in 8bpp mode only + // Don't do this for Myst, which has its own per-stack handling + if (_vm->getGameType() != GType_MYST) + _vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256); + } + + // Clip the video to make sure it stays on the screen (Myst does this a few times) + Common::Rect targetRect = Common::Rect(video->getWidth(), video->getHeight()); + targetRect.translate(videoEntry->getX(), videoEntry->getY()); + + Common::Rect frameRect = Common::Rect(video->getWidth(), video->getHeight()); + + if (targetRect.left < 0) { + frameRect.left -= targetRect.left; + targetRect.left = 0; + } + + if (targetRect.top < 0) { + frameRect.top -= targetRect.top; + targetRect.top = 0; + } + + if (targetRect.right > _vm->_system->getWidth()) { + frameRect.right -= targetRect.right - _vm->_system->getWidth(); + targetRect.right = _vm->_system->getWidth(); + } + + if (targetRect.bottom > _vm->_system->getHeight()) { + frameRect.bottom -= targetRect.bottom - _vm->_system->getHeight(); + targetRect.bottom = _vm->_system->getHeight(); + } + + _vm->_system->copyRectToScreen(frame->getBasePtr(frameRect.left, frameRect.top), frame->pitch, + targetRect.left, targetRect.top, targetRect.width(), targetRect.height()); + + // Delete 8bpp conversion surface + if (convertedFrame) { + convertedFrame->free(); + delete convertedFrame; + } + + // We've drawn something to the screen, make sure we update it + return true; +} + void VideoManager::activateMLST(uint16 mlstId, uint16 card) { Common::SeekableReadStream *mlstStream = _vm->getResource(ID_MLST, card); uint16 recordCount = mlstStream->readUint16BE(); @@ -430,7 +461,7 @@ VideoHandle VideoManager::playMovieRiven(uint16 id) { ptr->start(); } - return ptr; + return VideoHandle(ptr); } } @@ -445,7 +476,7 @@ void VideoManager::playMovieBlockingRiven(uint16 id) { ptr->moveTo(_mlstRecords[i].left, _mlstRecords[i].top); ptr->setVolume(_mlstRecords[i].volume); ptr->start(); - waitUntilMovieEnds(ptr); + waitUntilMovieEnds(VideoHandle(ptr)); return; } } @@ -522,7 +553,7 @@ VideoHandle VideoManager::findVideoHandleRiven(uint16 id) { if (_mlstRecords[i].code == id) for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++) if ((*it)->getID() == _mlstRecords[i].movieID) - return *it; + return VideoHandle(*it); return VideoHandle(); } @@ -533,7 +564,7 @@ VideoHandle VideoManager::findVideoHandle(uint16 id) { for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++) if ((*it)->getID() == id) - return *it; + return VideoHandle(*it); return VideoHandle(); } @@ -544,7 +575,7 @@ VideoHandle VideoManager::findVideoHandle(const Common::String &fileName) { for (VideoList::iterator it = _videos.begin(); it != _videos.end(); it++) if ((*it)->getFileName().equalsIgnoreCase(fileName)) - return *it; + return VideoHandle(*it); return VideoHandle(); } @@ -558,12 +589,10 @@ bool VideoManager::isVideoPlaying() { } void VideoManager::drawVideoFrame(VideoHandle handle, const Audio::Timestamp &time) { - // FIXME: This should be done separately from the "playing" - // videos eventually. assert(handle); handle->seek(time); - updateMovies(); - handle->close(); + drawNextFrame(handle._ptr); + handle->stop(); } VideoManager::VideoList::iterator VideoManager::findEntry(VideoEntryPtr ptr) { diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 106a32f8e2..d0edab9def 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -293,7 +293,7 @@ private: /** * Constructor for internal VideoManager use */ - VideoHandle(VideoEntryPtr ptr); + explicit VideoHandle(VideoEntryPtr ptr); /** * The video entry this is associated with @@ -350,6 +350,8 @@ private: VideoList::iterator findEntry(VideoEntryPtr ptr); void removeEntry(VideoEntryPtr ptr); + bool drawNextFrame(VideoEntryPtr videoEntry); + // Dithering control bool _enableDither; void checkEnableDither(VideoEntryPtr &entry); diff --git a/engines/mohawk/view.cpp b/engines/mohawk/view.cpp index 1aaf32ea78..70d20270a5 100644 --- a/engines/mohawk/view.cpp +++ b/engines/mohawk/view.cpp @@ -37,6 +37,23 @@ Module::~Module() { } Feature::Feature(View *view) : _view(view) { + _next = _prev = nullptr; + _drawProc = nullptr; + _moveProc = nullptr; + _doneProc = nullptr; + _frameProc = nullptr; + _timeProc = nullptr; + _region = 0; + _id = 0; + _scrbId = 0; + _storedScrbId = 0; + _flags = 0; + _nextTime = 0; + _delayTime = 0; + _dirty = false; + _needsReset = false; + _justReset = false; + _done = false; } Feature::~Feature() { @@ -75,11 +92,10 @@ void Feature::setNodeDefaults(Feature *prev, Feature *next) { _flags = 0; - _dirty = 1; - _needsReset = 1; - _justReset = 0; // old - _notifyDone = 0; - _done = 0; // new + _dirty = true; + _needsReset = true; + _justReset = false; // old + _done = false; // new _nextTime = 0; _delayTime = 0; @@ -107,11 +123,11 @@ void Feature::resetFeatureScript(uint16 enabled, uint16 scrbId) { resetFrame(); _nextTime = 0; // New feature code uses _view->_lastIdleTime, but should be equivalent. _data.enabled = enabled; - _dirty = 1; + _dirty = true; finishResetFeatureScript(); - _needsReset = 0; + _needsReset = false; if (_region) { // TODO: mark _region as dirty @@ -123,7 +139,6 @@ void Feature::resetFeatureScript(uint16 enabled, uint16 scrbId) { void Feature::resetFeature(bool notifyDone, Module::FeatureProc doneProc, uint16 scrbId) { resetFeatureScript(1, scrbId); _doneProc = doneProc; - _notifyDone = notifyDone; } void Feature::hide(bool clip) { @@ -159,7 +174,7 @@ void Feature::moveAndUpdate(Common::Point newPos) { return; _nextTime = 0; - _dirty = 1; + _dirty = true; // TODO: mark _data.bounds as dirty if (_data.bitmapIds[0]) @@ -228,7 +243,7 @@ void OldFeature::resetScript() { } void OldFeature::finishResetFeatureScript() { - _justReset = 1; + _justReset = true; if (_flags & kFeatureOldAdjustByPos) { Common::SeekableReadStream *ourSCRB = _view->getSCRB(_data.scrbIndex, _scrbId); @@ -240,6 +255,13 @@ void OldFeature::finishResetFeatureScript() { } NewFeature::NewFeature(View *view) : Feature(view) { + _unknown168 = 0; + _pickupProc = nullptr; + _dropProc = nullptr; + _dragMoveProc = nullptr; + _oldMoveProc = nullptr; + _dragFlags = 0; + _oldFlags = 0; } NewFeature::~NewFeature() { @@ -307,7 +329,7 @@ void NewFeature::resetScript() { } void NewFeature::finishResetFeatureScript() { - _done = 0; + _done = false; } View::View(MohawkEngine *vm) : _vm(vm) { @@ -319,6 +341,12 @@ View::View(MohawkEngine *vm) : _vm(vm) { _compoundSHAPGroups[i] = 0; } _numSCRBGroups = 0; + + _lastIdleTime = 0; + _needsUpdate = false; + _gfx = nullptr; + _rootNode = nullptr; + _cursorNode = nullptr; } View::~View() { @@ -347,7 +375,7 @@ void View::idleView() { } if (node->_drawProc) (_currentModule->*(node->_drawProc))(node); - node->_dirty = 0; + node->_dirty = false; } if (_needsUpdate) { diff --git a/engines/mohawk/view.h b/engines/mohawk/view.h index 47853f056f..463715b765 100644 --- a/engines/mohawk/view.h +++ b/engines/mohawk/view.h @@ -138,11 +138,10 @@ public: uint32 _flags; uint32 _nextTime; uint32 _delayTime; - uint16 _dirty; // byte in old - byte _needsReset; - byte _justReset; // old - byte _notifyDone; // old - byte _done; // new + bool _dirty; // byte in old + bool _needsReset; + bool _justReset; // old + bool _done; // new FeatureData _data; @@ -192,13 +191,6 @@ protected: void finishResetFeatureScript(); }; -#define NUM_SYNC_CHANNELS 17 -struct SyncChannel { - uint16 masterId; - byte state; - bool alternate; -}; - class View { public: View(MohawkEngine *vm); @@ -234,7 +226,6 @@ public: void sortView(); uint32 _lastIdleTime; - SyncChannel _syncChannels[NUM_SYNC_CHANNELS]; virtual uint32 getTime() = 0; |