From a13e3f7bdd851c37b0782d6d29f588711adfb65c Mon Sep 17 00:00:00 2001 From: Bastien Bouclet Date: Sun, 24 Sep 2017 16:37:10 +0200 Subject: [PATCH] MYST3: Prevent loading from the GMM while the game is not interactive Also honor quit requests while in inner loops. Fixes #1369. --- engines/myst3/myst3.cpp | 45 +++++++++++++++++---------------- engines/myst3/myst3.h | 6 +++-- engines/myst3/puzzles.cpp | 12 ++++----- engines/myst3/script.cpp | 52 +++++++++++++++++++-------------------- 4 files changed, 60 insertions(+), 55 deletions(-) diff --git a/engines/myst3/myst3.cpp b/engines/myst3/myst3.cpp index 11f6e893e56..6a7b0191400 100644 --- a/engines/myst3/myst3.cpp +++ b/engines/myst3/myst3.cpp @@ -71,6 +71,7 @@ Myst3Engine::Myst3Engine(OSystem *syst, const Myst3GameDescription *version) : _inputSpacePressed(false), _inputEnterPressed(false), _inputEscapePressed(false), _inputTildePressed(false), _inputEscapePressedNotConsumed(false), + _interactive(false), _menuAction(0), _projectorBackground(0), _shakeEffect(0), _rotationEffect(0), _backgroundSoundScriptLastRoomId(0), _transition(0), _frameLimiter(0), _inventoryManualHide(false) { @@ -198,7 +199,7 @@ Common::Error Myst3Engine::run() { while (!shouldQuit()) { runNodeBackgroundScripts(); - processInput(false); + processInput(true); updateCursor(); if (_menuAction) { @@ -417,9 +418,8 @@ void Myst3Engine::updateCursor() { } } -void Myst3Engine::processInput(bool lookOnly) { - // Process events - Common::Event event; +void Myst3Engine::processInput(bool interactive) { + _interactive = interactive; if (_state->hasVarGamePadUpPressed()) { // Reset the gamepad directions once they had a chance to be read by the scripts @@ -432,6 +432,8 @@ void Myst3Engine::processInput(bool lookOnly) { bool shouldInteractWithHoveredElement = false; + // Process events + Common::Event event; while (getEventManager()->pollEvent(event)) { if (_state->hasVarGamePadUpPressed()) { processEventForGamepad(event); @@ -448,8 +450,8 @@ void Myst3Engine::processInput(bool lookOnly) { } else if (event.type == Common::EVENT_LBUTTONDOWN) { shouldInteractWithHoveredElement = true; } else if (event.type == Common::EVENT_RBUTTONDOWN) { - // Skip the event when in look only mode - if (lookOnly) + // Skip the event when in non-interactive mode + if (!interactive) continue; // Nothing to do if not in cube view if (_state->getViewType() != kCube) @@ -489,7 +491,7 @@ void Myst3Engine::processInput(bool lookOnly) { break; case Common::KEYCODE_F5: // Open main menu - if (_cursor->isVisible() && !lookOnly) { + if (_cursor->isVisible() && interactive) { if (_state->getLocationRoom() != 901) _menu->goToNode(100); } @@ -532,8 +534,8 @@ void Myst3Engine::processInput(bool lookOnly) { // The input state variables need to be set before calling the scripts updateInputState(); - if (shouldInteractWithHoveredElement) { - interactWithHoveredElement(lookOnly); + if (shouldInteractWithHoveredElement && interactive) { + interactWithHoveredElement(); } // Open main menu @@ -542,7 +544,7 @@ void Myst3Engine::processInput(bool lookOnly) { // need to be honored after leaving the inner script loop, // especially when the script loop was cancelled due to pressing // escape. - if (_inputEscapePressedNotConsumed && !lookOnly) { + if (_inputEscapePressedNotConsumed && interactive) { _inputEscapePressedNotConsumed = false; if (_cursor->isVisible() && _state->hasVarMenuEscapePressed()) { if (_state->getLocationRoom() != 901) @@ -623,11 +625,7 @@ void Myst3Engine::resetInput() { } } -void Myst3Engine::interactWithHoveredElement(bool lookOnly) { - // Skip the event when in look only mode - if (lookOnly) - return; - +void Myst3Engine::interactWithHoveredElement() { if (isInventoryVisible() && _inventory->isMouseInside()) { uint16 hoveredInventory = _inventory->hoveredItem(); if (hoveredInventory > 0) { @@ -769,9 +767,10 @@ void Myst3Engine::setupTransition() { void Myst3Engine::drawTransition(TransitionType transitionType) { if (_transition) { + _interactive = false; // Don't allow loading while drawing transitions _transition->draw(transitionType); delete _transition; - _transition = 0; + _transition = nullptr; } } @@ -1207,7 +1206,7 @@ void Myst3Engine::playSimpleMovie(uint16 id, bool fullframe, bool refreshAmbient movie.update(); // Process events - processInput(true); + processInput(false); // Handle skipping if (_inputSpacePressed || _inputEscapePressed) { @@ -1426,7 +1425,7 @@ void Myst3Engine::dragSymbol(uint16 var, uint16 id) { NodePtr nodeData = _db->getNodeData(_state->getLocationNode(), _state->getLocationRoom(), _state->getLocationAge()); while (inputValidatePressed() && !shouldQuit()) { - processInput(true); + processInput(false); HotSpot *hovered = getHoveredHotspot(nodeData, var); drag.setFrame(hovered ? 2 : 1); @@ -1457,7 +1456,7 @@ void Myst3Engine::dragItem(uint16 statusVar, uint16 movie, uint16 frame, uint16 NodePtr nodeData = _db->getNodeData(_state->getLocationNode(), _state->getLocationRoom(), _state->getLocationAge()); while (inputValidatePressed() && !shouldQuit()) { - processInput(true); + processInput(false); HotSpot *hovered = getHoveredHotspot(nodeData, itemVar); drag.setFrame(hovered ? hoverFrame : frame); @@ -1479,7 +1478,11 @@ void Myst3Engine::dragItem(uint16 statusVar, uint16 movie, uint16 frame, uint16 } bool Myst3Engine::canLoadGameStateCurrently() { - return true; + // Loading from the GMM is only possible when the game is interactive + // This is to prevent loading from inner loops. Loading while + // in an inner loop can cause the exit condition to never happen, + // or can unload required resources. + return _interactive; } Common::Error Myst3Engine::loadGameState(int slot) { @@ -1552,7 +1555,7 @@ void Myst3Engine::animateDirectionChange(float targetPitch, float targetHeading, if (numTicks != 0.0f) { while (1) { uint elapsedTicks = _state->getTickCount() - startTick; - if (elapsedTicks >= numTicks) + if (elapsedTicks >= numTicks || shouldQuit()) break; float step; diff --git a/engines/myst3/myst3.h b/engines/myst3/myst3.h index a4758171f7b..296f8aecb92 100644 --- a/engines/myst3/myst3.h +++ b/engines/myst3/myst3.h @@ -173,7 +173,7 @@ public: void drawFrame(bool noSwap = false); - void processInput(bool lookOnly); + void processInput(bool interactive); void updateInputState(); void resetInput(); @@ -217,6 +217,8 @@ private: bool _inputEscapePressedNotConsumed; bool _inputTildePressed; + bool _interactive; + uint32 _backgroundSoundScriptLastRoomId; /** @@ -238,7 +240,7 @@ private: bool isInventoryVisible(); - void interactWithHoveredElement(bool lookOnly); + void interactWithHoveredElement(); void processEventForGamepad(const Common::Event &event); friend class Console; diff --git a/engines/myst3/puzzles.cpp b/engines/myst3/puzzles.cpp index 1b9cec208ac..93b65d6be62 100644 --- a/engines/myst3/puzzles.cpp +++ b/engines/myst3/puzzles.cpp @@ -148,11 +148,11 @@ void Puzzles::_drawForVarHelper(int16 var, int32 startValue, int32 endValue) { _vm->_state->setVar(var2, varValue); } - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); currentTick = _vm->_state->getTickCount(); - if (currentTick > endTick) + if (currentTick > endTick || _vm->shouldQuit()) break; } } @@ -164,8 +164,8 @@ void Puzzles::_drawForVarHelper(int16 var, int32 startValue, int32 endValue) { void Puzzles::_drawXTicks(uint16 ticks) { uint32 endTick = _vm->_state->getTickCount() + ticks; - while (_vm->_state->getTickCount() < endTick) { - _vm->processInput(true); + while (_vm->_state->getTickCount() < endTick && !_vm->shouldQuit()) { + _vm->processInput(false); _vm->drawFrame(); } } @@ -411,7 +411,7 @@ void Puzzles::resonanceRingsLaunchBall() { int32 boardMoviePlaying; do { - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); ballMoviePlaying = _vm->_state->getVar(27); @@ -477,7 +477,7 @@ void Puzzles::resonanceRingsLaunchBall() { _vm->_ambient->playCurrentNode(100, 2); } - } while (ballMoviePlaying || boardMoviePlaying); + } while ((ballMoviePlaying || boardMoviePlaying) && !_vm->shouldQuit()); _vm->_state->setResonanceRingsSolved(!ballShattered); } diff --git a/engines/myst3/script.cpp b/engines/myst3/script.cpp index 3568c45019c..bce713e545e 100644 --- a/engines/myst3/script.cpp +++ b/engines/myst3/script.cpp @@ -300,7 +300,7 @@ bool Script::run(const Common::Array *script) { c.script = script; c.op = script->begin(); - while (c.op != script->end()) { + while (c.op != script->end() && !_vm->shouldQuit()) { runOp(c, *c.op); if (c.endScript || c.op == script->end()) @@ -1736,7 +1736,7 @@ void Script::leverDrag(Context &c, const Opcode &cmd) { _vm->_state->setVar(var, position); // Draw a frame - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); mousePressed = _vm->getEventManager()->getButtonState() & Common::EventManager::LBUTTON; @@ -1752,7 +1752,7 @@ void Script::leverDrag(Context &c, const Opcode &cmd) { _vm->runScriptsFromNode(abs(script)); } - if (!mousePressed) + if (!mousePressed || _vm->shouldQuit()) break; } @@ -1799,7 +1799,7 @@ void Script::leverDragPositions(Context &c, const Opcode &cmd) { _vm->_state->setVar(var, position); // Draw a frame - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); mousePressed = _vm->inputValidatePressed(); @@ -1815,7 +1815,7 @@ void Script::leverDragPositions(Context &c, const Opcode &cmd) { _vm->runScriptsFromNode(abs(script)); } - if (!mousePressed) + if (!mousePressed || _vm->shouldQuit()) break; } @@ -1851,7 +1851,7 @@ void Script::leverDragXY(Context &c, const Opcode &cmd) { _vm->_state->setVar(varY, distanceY); // Draw a frame - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); mousePressed = _vm->getEventManager()->getButtonState() & Common::EventManager::LBUTTON; @@ -1860,7 +1860,7 @@ void Script::leverDragXY(Context &c, const Opcode &cmd) { // Run script if (script) _vm->runScriptsFromNode(script); - } while (mousePressed); + } while (mousePressed && !_vm->shouldQuit()); } void Script::itemDrag(Context &c, const Opcode &cmd) { @@ -1889,7 +1889,7 @@ void Script::runScriptWhileDragging(Context &c, const Opcode &cmd) { dragging |= _vm->_state->hasVarGamePadActionPressed() && _vm->_state->getGamePadActionPressed(); _vm->_state->setDragEnded(!dragging); - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); if (!dragWithDirectionKeys) { @@ -1946,9 +1946,9 @@ void Script::runScriptWhileDragging(Context &c, const Opcode &cmd) { } _vm->runScriptsFromNode(script); - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); - } while (dragging); + } while (dragging && !_vm->shouldQuit()); if (dragWithDirectionKeys) { _vm->_state->setDragWithDirectionKeys(false); @@ -2119,8 +2119,8 @@ void Script::drawXTicks(Context &c, const Opcode &cmd) { uint32 endTick = _vm->_state->getTickCount() + cmd.args[0]; - while (_vm->_state->getTickCount() < endTick) { - _vm->processInput(true); + while (_vm->_state->getTickCount() < endTick && !_vm->shouldQuit()) { + _vm->processInput(false); _vm->drawFrame(); } } @@ -2128,8 +2128,8 @@ void Script::drawXTicks(Context &c, const Opcode &cmd) { void Script::drawWhileCond(Context &c, const Opcode &cmd) { debugC(kDebugScript, "Opcode %d: While condition %d, draw", cmd.op, cmd.args[0]); - while (_vm->_state->evaluate(cmd.args[0]) && !_vm->inputEscapePressed()) { - _vm->processInput(true); + while (_vm->_state->evaluate(cmd.args[0]) && !_vm->inputEscapePressed() && !_vm->shouldQuit()) { + _vm->processInput(false); _vm->drawFrame(); } } @@ -2147,7 +2147,7 @@ void Script::whileStart(Context &c, const Opcode &cmd) { } while (c.op != c.script->end() && c.op->op != whileEndCommand.op); } - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); } @@ -2161,13 +2161,13 @@ void Script::whileEnd(Context &c, const Opcode &cmd) { void Script::runScriptWhileCond(Context &c, const Opcode &cmd) { debugC(kDebugScript, "Opcode %d: While condition %d, run script %d", cmd.op, cmd.args[0], cmd.args[1]); - while (_vm->_state->evaluate(cmd.args[0])) { + while (_vm->_state->evaluate(cmd.args[0]) && !_vm->shouldQuit()) { _vm->runScriptsFromNode(cmd.args[1]); - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); } - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); } @@ -2182,7 +2182,7 @@ void Script::runScriptWhileCondEachXFrames(Context &c, const Opcode &cmd) { uint nextScript = _vm->_state->getTickCount() + firstStep; - while (_vm->_state->evaluate(cmd.args[0])) { + while (_vm->_state->evaluate(cmd.args[0]) && !_vm->shouldQuit()) { if (_vm->_state->getTickCount() >= nextScript) { nextScript = _vm->_state->getTickCount() + step; @@ -2190,11 +2190,11 @@ void Script::runScriptWhileCondEachXFrames(Context &c, const Opcode &cmd) { _vm->runScriptsFromNode(cmd.args[1]); } - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); } - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); } @@ -2300,7 +2300,7 @@ void Script::runScriptForVarDrawTicksHelper(uint16 var, int32 startValue, int32 } } - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); currentTick = _vm->_state->getTickCount(); @@ -2327,7 +2327,7 @@ void Script::runScriptForVarDrawTicksHelper(uint16 var, int32 startValue, int32 _vm->runScriptsFromNode(script); for (uint i = _vm->_state->getTickCount(); i < endTick; i = _vm->_state->getTickCount()) { - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); } @@ -2528,8 +2528,8 @@ void Script::soundPlayBlocking(Context &c, const Opcode &cmd) { return; } - while (_vm->_sound->isPlaying(soundId) && !_vm->inputEscapePressed()) { - _vm->processInput(true); + while (_vm->_sound->isPlaying(soundId) && !_vm->inputEscapePressed() && !_vm->shouldQuit()) { + _vm->processInput(false); _vm->drawFrame(); } } @@ -2853,7 +2853,7 @@ void Script::movieSetStartupSoundVolumeH(Context &c, const Opcode &cmd) { void Script::drawOneFrame(Context &c, const Opcode &cmd) { debugC(kDebugScript, "Opcode %d: Draw one frame", cmd.op); - _vm->processInput(true); + _vm->processInput(false); _vm->drawFrame(); }