diff options
Diffstat (limited to 'engines/mohawk')
41 files changed, 1668 insertions, 1187 deletions
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/detection.cpp b/engines/mohawk/detection.cpp index 926c296257..a64d7ff7df 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,6 +36,7 @@ #ifdef ENABLE_MYST #include "mohawk/myst.h" +#include "mohawk/myst_state.h" #endif #ifdef ENABLE_RIVEN @@ -52,7 +54,7 @@ struct MohawkGameDescription { }; const char* MohawkEngine::getGameId() const { - return _gameDescription->desc.gameid; + return _gameDescription->desc.gameId; } uint32 MohawkEngine::getFeatures() const { @@ -159,10 +161,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; } @@ -184,13 +200,18 @@ public: virtual SaveStateList listSaves(const char *target) 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::listSaves(const char *target) const { @@ -198,12 +219,15 @@ SaveStateList MohawkMetaEngine::listSaves(const char *target) const { SaveStateList saveList; // Loading games is only supported in Myst/Riven currently. +#ifdef ENABLE_MYST if (strstr(target, "myst")) { - filenames = g_system->getSavefileManager()->listSavefiles("*.mys"); + filenames = Mohawk::MystGameState::generateSaveGameList(); for (uint32 i = 0; i < filenames.size(); i++) saveList.push_back(SaveStateDescriptor(i, filenames[i])); - } else if (strstr(target, "riven")) { + } else +#endif + if (strstr(target, "riven")) { filenames = g_system->getSavefileManager()->listSavefiles("*.rvn"); for (uint32 i = 0; i < filenames.size(); i++) @@ -215,15 +239,35 @@ SaveStateList MohawkMetaEngine::listSaves(const char *target) const { 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 = Mohawk::MystGameState::generateSaveGameList(); + Mohawk::MystGameState::deleteSave(filenames[slot]); + } else +#endif + if (strstr(target, "riven")) { Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.rvn"); g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str()); } } +SaveStateDescriptor MohawkMetaEngine::querySaveMetaInfos(const char *target, int slot) const { +#ifdef ENABLE_MYST + if (strstr(target, "myst")) { + Common::StringArray filenames = Mohawk::MystGameState::generateSaveGameList(); + + if (slot >= (int) filenames.size()) { + return SaveStateDescriptor(); + } + + return Mohawk::MystGameState::querySaveMetaInfos(filenames[slot]); + } else +#endif + { + return SaveStateDescriptor(); + } +} + bool MohawkMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { const Mohawk::MohawkGameDescription *gd = (const Mohawk::MohawkGameDescription *)desc; diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h index 97d2932d57..7941a0d51a 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 @@ -34,7 +41,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -52,7 +59,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_DEMO }, GType_MYST, GF_DEMO, @@ -70,7 +77,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -88,7 +95,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -106,7 +113,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -124,7 +131,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -142,7 +149,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::JA_JPN, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -160,7 +167,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -178,7 +185,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_MAKING_OF }, GType_MAKINGOF, 0, @@ -196,7 +203,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::JA_JPN, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_MAKING_OF }, GType_MAKINGOF, 0, @@ -214,7 +221,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -232,7 +239,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -250,7 +257,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -268,7 +275,7 @@ static const MohawkGameDescription gameDescriptions[] = { Common::PL_POL, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, @@ -2698,7 +2705,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST }, GType_MYST, 0, @@ -2713,7 +2720,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_MAKING_OF }, GType_MAKINGOF, 0, @@ -2728,7 +2735,7 @@ static const MohawkGameDescription fallbackDescs[] = { Common::UNK_LANG, Common::kPlatformWindows, ADGF_UNSTABLE, - GUIO1(GUIO_NOASPECT) + GUI_OPTIONS_MYST_ME }, GType_MYST, GF_ME, diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp index ffc455286f..6c6ae9e77f 100644 --- a/engines/mohawk/dialogs.cpp +++ b/engines/mohawk/dialogs.cpp @@ -24,6 +24,7 @@ #include "mohawk/dialogs.h" #include "gui/gui-manager.h" +#include "gui/saveload.h" #include "gui/ThemeEngine.h" #include "gui/widget.h" #include "common/system.h" @@ -82,35 +83,47 @@ enum { kWaterCmd = 'WATR', kDropCmd = 'DROP', kMapCmd = 'SMAP', - kMenuCmd = 'MENU' + kMenuCmd = 'MENU', + kSaveCmd = 'SAVE', + kLoadCmd = 'LOAD', + kQuitCmd = 'QUIT' }; #ifdef ENABLE_MYST -MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) { +MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::Dialog(0, 0, 360, 200), _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; + _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); } MystOptionsDialog::~MystOptionsDialog() { + delete _loadDialog; + delete _saveDialog; } void MystOptionsDialog::open() { @@ -133,6 +146,44 @@ void MystOptionsDialog::open() { _zipModeCheckbox->setState(_vm->_gameState->_globals.zipMode); _transitionsCheckbox->setState(_vm->_gameState->_globals.transitions); + + _loadButton->setEnabled(_vm->canLoadGameStateCurrently()); + _saveButton->setEnabled(_vm->canSaveGameStateCurrently()); +} + +void MystOptionsDialog::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 MystOptionsDialog::load() { + int slot = _loadDialog->runModalWithCurrentTarget(); + + if (slot >= 0) { + _vm->loadGameState(slot); + close(); + } +} + +void MystOptionsDialog::reflowLayout() { + const int screenW = g_system->getOverlayWidth(); + const int screenH = g_system->getOverlayHeight(); + + // Center the dialog + _x = (screenW - getWidth()) / 2; + _y = (screenH - getHeight()) / 2; + + Dialog::reflowLayout(); } void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { @@ -144,18 +195,39 @@ 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 kLoadCmd: + load(); + break; + case kSaveCmd: + save(); + 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; + case GUI::kCloseCmd: + close(); break; default: - GUI::OptionsDialog::handleCommand(sender, cmd, data); + GUI::Dialog::handleCommand(sender, cmd, data); } } diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h index 7470cd3acd..bc25c72a43 100644 --- a/engines/mohawk/dialogs.h +++ b/engines/mohawk/dialogs.h @@ -32,6 +32,10 @@ #include "gui/widget.h" #include "gui/widgets/list.h" +namespace GUI { +class SaveLoadChooser; +} + namespace Mohawk { class MohawkEngine; @@ -70,20 +74,32 @@ public: class MohawkEngine_Myst; -class MystOptionsDialog : public GUI::OptionsDialog { +class MystOptionsDialog : public GUI::Dialog { public: MystOptionsDialog(MohawkEngine_Myst *vm); ~MystOptionsDialog(); void open(); + virtual void reflowLayout() override; 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; + + GUI::ButtonWidget *_loadButton; + GUI::ButtonWidget *_saveButton; + + GUI::SaveLoadChooser *_loadDialog; + GUI::SaveLoadChooser *_saveDialog; + + void save(); + void load(); }; #endif diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index b6a6c27329..c16fab9131 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,9 +230,9 @@ Common::Error MohawkEngine_Myst::run() { _cursor->showCursor(); // Load game from launcher/command line if requested - if (ConfMan.hasKey("save_slot") && canLoadGameStateCurrently()) { + if (ConfMan.hasKey("save_slot") && hasGameSaveSupport()) { uint32 gameToLoad = ConfMan.getInt("save_slot"); - Common::StringArray savedGamesList = _gameState->generateSaveGameList(); + Common::StringArray savedGamesList = MystGameState::generateSaveGameList(); if (gameToLoad > savedGamesList.size()) error ("Could not find saved game"); _gameState->load(savedGamesList[gameToLoad]); @@ -284,7 +263,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 +303,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 +327,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 +355,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 +405,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 +495,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 +505,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 +533,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 +580,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 +602,16 @@ 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)); + _needsUpdate = true; + } } // Make sure we have the right cursor showing - _dragResource = 0; - _hoverResource = 0; + _hoverResource = nullptr; _curResource = -1; checkCurrentResource(); @@ -671,13 +637,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 +660,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 +679,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 +704,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 +770,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 +777,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 +901,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 +916,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 +964,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 +1007,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 +1076,42 @@ 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(MystGameState::generateSaveGameList()[slot])) return Common::kNoError; return Common::kUnknownError; } Common::Error MohawkEngine_Myst::saveGameState(int slot, const Common::String &desc) { - Common::StringArray saveList = _gameState->generateSaveGameList(); + Common::StringArray saveList = MystGameState::generateSaveGameList(); if ((uint)slot < saveList.size()) - _gameState->deleteSave(saveList[slot]); + MystGameState::deleteSave(saveList[slot]); + + return _gameState->save(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 +1164,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..5db9697a78 100644 --- a/engines/mohawk/myst_graphics.cpp +++ b/engines/mohawk/myst_graphics.cpp @@ -40,7 +40,7 @@ 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"); @@ -73,7 +73,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 @@ -95,7 +95,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) { dataStream->seek(0); } - MohawkSurface *mhkSurface = 0; + MohawkSurface *mhkSurface = nullptr; if (isPict) { Image::PICTDecoder pict; @@ -103,6 +103,8 @@ 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); @@ -225,9 +227,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 +289,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 +371,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 +643,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 diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h index 6281c94cc8..93e388cb83 100644 --- a/engines/mohawk/myst_graphics.h +++ b/engines/mohawk/myst_graphics.h @@ -61,8 +61,8 @@ public: 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; diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp index 487d0f45fe..04e7c5a9b7 100644 --- a/engines/mohawk/myst_scripts.cpp +++ b/engines/mohawk/myst_scripts.cpp @@ -29,6 +29,7 @@ #include "mohawk/video.h" #include "common/system.h" +#include "common/memstream.h" #include "common/textconsole.h" #include "gui/message.h" @@ -38,7 +39,7 @@ MystScriptEntry::MystScriptEntry() { type = kMystScriptNone; var = 0; argc = 0; - argv = 0; + argv = nullptr; resourceId = 0; u1 = 0; } @@ -81,7 +82,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 +155,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 +261,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 +323,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 +336,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 +349,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 +390,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 +399,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 +408,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 +417,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 +426,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 +434,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 +446,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 +461,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 +510,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 +529,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 +554,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 +585,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 +680,15 @@ 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 (soundList[i] == kMystSoundActionChangeVolume || soundList[i] > 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::MemoryReadStream stream = Common::MemoryReadStream((const byte *) argv, argc * sizeof(uint16)); - delete[] soundList; - soundList = NULL; - delete[] soundListVolume; - soundListVolume = NULL; + MystSoundBlock soundBlock = _vm->readSoundBlock(&stream); + _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 0718f8e683..21c3042359 100644 --- a/engines/mohawk/myst_stacks/channelwood.cpp +++ b/engines/mohawk/myst_stacks/channelwood.cpp @@ -363,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--) { @@ -377,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; @@ -386,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) { @@ -401,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) { @@ -419,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(); @@ -439,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); @@ -461,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); @@ -475,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); @@ -484,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 @@ -500,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)) { @@ -516,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); @@ -528,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) @@ -551,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)) { @@ -567,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); @@ -579,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)) { @@ -595,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); @@ -621,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); } } @@ -680,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++) { @@ -747,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..b4a2076528 100644 --- a/engines/mohawk/myst_stacks/credits.cpp +++ b/engines/mohawk/myst_stacks/credits.cpp @@ -37,6 +37,7 @@ namespace MystStacks { Credits::Credits(MohawkEngine_Myst *vm) : MystScriptParser(vm) { setupOpcodes(); + _curImage = 0; } Credits::~Credits() { @@ -66,8 +67,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..1d733d8100 100644 --- a/engines/mohawk/myst_stacks/intro.cpp +++ b/engines/mohawk/myst_stacks/intro.cpp @@ -170,7 +170,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.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 9ad1635757..9d23d2fb10 100644 --- a/engines/mohawk/myst_stacks/myst.cpp +++ b/engines/mohawk/myst_stacks/myst.cpp @@ -50,14 +50,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 +628,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 +766,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 +865,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 +1256,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 +1356,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 +1381,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 +1390,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 +1403,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 +1471,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 +1481,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 +1511,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 +1809,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 +1818,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 +1833,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 +1869,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 +2143,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 +2192,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 +2267,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 +2304,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 +2331,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 +2373,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 +2391,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 +2411,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 +2440,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 +2717,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 +2840,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 +2879,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 +2890,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 +2982,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 +3026,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 +3034,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) @@ -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]; @@ -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..5402e5a581 100644 --- a/engines/mohawk/myst_stacks/selenitic.cpp +++ b/engines/mohawk/myst_stacks/selenitic.cpp @@ -39,9 +39,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 +672,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 +779,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 +793,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 +811,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 +823,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 +867,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 +935,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 +951,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 +1068,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 +1095,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 +1127,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.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..06cd69b23c 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)); @@ -77,28 +107,15 @@ MystGameState::~MystGameState() { } Common::StringArray MystGameState::generateSaveGameList() { - return _saveFileMan->listSavefiles("*.mys"); + return g_system->getSavefileManager()->listSavefiles("*.mys"); } bool MystGameState::load(const Common::String &filename) { - Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); - if (!loadFile) - return false; - - debugC(kDebugSaveLoad, "Loading game from '%s'", filename.c_str()); - - // First, let's make sure we're using a saved game file from this version of Myst - // By checking length of file... - int32 size = loadFile->size(); - if (size != 664 && size != 601) { - warning("Incompatible saved game version"); - delete loadFile; + if (!loadState(filename)) { return false; } - Common::Serializer s(loadFile, 0); - syncGameState(s, size == 664); - delete loadFile; + loadMetadata(filename); // Set Channelwood elevator state to down, because we start on the lower level _channelwood.elevatorState = 0; @@ -119,19 +136,76 @@ bool MystGameState::load(const Common::String &filename) { return true; } -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::loadState(const Common::String &filename) { + Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); + if (!loadFile) { + return false; + } + + debugC(kDebugSaveLoad, "Loading game from '%s'", filename.c_str()); + + // First, let's make sure we're using a saved game file from this version of Myst + // By checking length of file... + int32 size = loadFile->size(); + if (size != 664 && size != 601) { + warning("Incompatible saved game version"); + delete loadFile; + return false; + } + + Common::Serializer s(loadFile, nullptr); + syncGameState(s, size == 664); + delete loadFile; + + return true; +} + +void MystGameState::loadMetadata(const Common::String &filename) { + // Open the metadata file + Common::InSaveFile *metadataFile = openMetadataFile(filename); + if (!metadataFile) { + return; + } + + debugC(kDebugSaveLoad, "Loading metadata from '%s'", filename.c_str()); + + 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 &filename) { + // Make sure the description does not have an extension + Common::String desc = filename; + if (filename.hasSuffix(".mys") || filename.hasSuffix(".MYS")) { + desc = removeExtension(filename); + } + + if (!saveState(desc)) { + return false; + } + + updateMetadateForSaving(desc); + + return saveMetadata(desc); +} + +bool MystGameState::saveState(const Common::String &desc) { + // Make sure we have the right extension + Common::String filename = desc + ".mys"; 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 +213,88 @@ bool MystGameState::save(const Common::String &fname) { return true; } +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(const Common::String &desc) { + // Write the metadata to a separate file so that the save files + // are still compatible with the original engine + Common::String metadataFilename = desc + ".mym"; + 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(const Common::String filename) { + SaveStateDescriptor desc; + desc.setDescription(filename); + + // Open the metadata file + Common::InSaveFile *metadataFile = openMetadataFile(filename); + if (!metadataFile) { + return desc; + } + + Common::Serializer m(metadataFile, nullptr); + + // Read the metadata file + Mohawk::MystSaveMetadata metadata; + if (!metadata.sync(m)) { + delete metadataFile; + return desc; + } + + // Set the save description + 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::InSaveFile *MystGameState::openMetadataFile(const Common::String &filename) { + // Remove the extension + Common::String baseName = removeExtension(filename); + + // Open the metadata file + return g_system->getSavefileManager()->openForLoading(baseName + ".mym"); +} + +Common::String MystGameState::removeExtension(const Common::String &filename) { + Common::String baseName = filename; + for (uint i = 0; i < 4; i++) { + baseName.deleteLastChar(); + } + return baseName; +} + void MystGameState::syncGameState(Common::Serializer &s, bool isME) { // Globals first s.syncAsUint16LE(_globals.u0); @@ -317,11 +473,14 @@ void MystGameState::syncGameState(Common::Serializer &s, bool isME) { void MystGameState::deleteSave(const Common::String &saveName) { debugC(kDebugSaveLoad, "Deleting save file \'%s\'", saveName.c_str()); - _saveFileMan->removeSavefile(saveName.c_str()); + Common::String basename = removeExtension(saveName); + + g_system->getSavefileManager()->removeSavefile(saveName); + g_system->getSavefileManager()->removeSavefile(basename + ".mym"); } 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..50359a5b52 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 Common::StringArray generateSaveGameList(); + static SaveStateDescriptor querySaveMetaInfos(const Common::String filename); + + bool load(const Common::String &filename); + bool save(const Common::String &filename); + static void deleteSave(const Common::String &saveName); 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::InSaveFile *openMetadataFile(const Common::String &filename); + bool loadState(const Common::String &filename); + void loadMetadata(const Common::String &filename); + bool saveState(const Common::String &desc); + void updateMetadateForSaving(const Common::String &desc); + bool saveMetadata(const Common::String &desc); + static Common::String removeExtension(const Common::String &filename); // The values in these regions are lists of VIEW resources // which correspond to visited zip destinations diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp index 198627e012..a2c08d4a92 100644 --- a/engines/mohawk/sound.cpp +++ b/engines/mohawk/sound.cpp @@ -21,6 +21,7 @@ */ #include "common/debug.h" +#include "common/events.h" #include "common/system.h" #include "common/util.h" #include "common/textconsole.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..c62e6e9874 100644 --- a/engines/mohawk/sound.h +++ b/engines/mohawk/sound.h @@ -136,7 +136,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); |