MYST3: Prevent loading from the GMM while the game is not interactive

Also honor quit requests while in inner loops.
Fixes #1369.
This commit is contained in:
Bastien Bouclet 2017-09-24 16:37:10 +02:00
parent 8843400444
commit a13e3f7bdd
4 changed files with 60 additions and 55 deletions

View file

@ -71,6 +71,7 @@ Myst3Engine::Myst3Engine(OSystem *syst, const Myst3GameDescription *version) :
_inputSpacePressed(false), _inputEnterPressed(false), _inputSpacePressed(false), _inputEnterPressed(false),
_inputEscapePressed(false), _inputTildePressed(false), _inputEscapePressed(false), _inputTildePressed(false),
_inputEscapePressedNotConsumed(false), _inputEscapePressedNotConsumed(false),
_interactive(false),
_menuAction(0), _projectorBackground(0), _menuAction(0), _projectorBackground(0),
_shakeEffect(0), _rotationEffect(0), _backgroundSoundScriptLastRoomId(0), _shakeEffect(0), _rotationEffect(0), _backgroundSoundScriptLastRoomId(0),
_transition(0), _frameLimiter(0), _inventoryManualHide(false) { _transition(0), _frameLimiter(0), _inventoryManualHide(false) {
@ -198,7 +199,7 @@ Common::Error Myst3Engine::run() {
while (!shouldQuit()) { while (!shouldQuit()) {
runNodeBackgroundScripts(); runNodeBackgroundScripts();
processInput(false); processInput(true);
updateCursor(); updateCursor();
if (_menuAction) { if (_menuAction) {
@ -417,9 +418,8 @@ void Myst3Engine::updateCursor() {
} }
} }
void Myst3Engine::processInput(bool lookOnly) { void Myst3Engine::processInput(bool interactive) {
// Process events _interactive = interactive;
Common::Event event;
if (_state->hasVarGamePadUpPressed()) { if (_state->hasVarGamePadUpPressed()) {
// Reset the gamepad directions once they had a chance to be read by the scripts // 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; bool shouldInteractWithHoveredElement = false;
// Process events
Common::Event event;
while (getEventManager()->pollEvent(event)) { while (getEventManager()->pollEvent(event)) {
if (_state->hasVarGamePadUpPressed()) { if (_state->hasVarGamePadUpPressed()) {
processEventForGamepad(event); processEventForGamepad(event);
@ -448,8 +450,8 @@ void Myst3Engine::processInput(bool lookOnly) {
} else if (event.type == Common::EVENT_LBUTTONDOWN) { } else if (event.type == Common::EVENT_LBUTTONDOWN) {
shouldInteractWithHoveredElement = true; shouldInteractWithHoveredElement = true;
} else if (event.type == Common::EVENT_RBUTTONDOWN) { } else if (event.type == Common::EVENT_RBUTTONDOWN) {
// Skip the event when in look only mode // Skip the event when in non-interactive mode
if (lookOnly) if (!interactive)
continue; continue;
// Nothing to do if not in cube view // Nothing to do if not in cube view
if (_state->getViewType() != kCube) if (_state->getViewType() != kCube)
@ -489,7 +491,7 @@ void Myst3Engine::processInput(bool lookOnly) {
break; break;
case Common::KEYCODE_F5: case Common::KEYCODE_F5:
// Open main menu // Open main menu
if (_cursor->isVisible() && !lookOnly) { if (_cursor->isVisible() && interactive) {
if (_state->getLocationRoom() != 901) if (_state->getLocationRoom() != 901)
_menu->goToNode(100); _menu->goToNode(100);
} }
@ -532,8 +534,8 @@ void Myst3Engine::processInput(bool lookOnly) {
// The input state variables need to be set before calling the scripts // The input state variables need to be set before calling the scripts
updateInputState(); updateInputState();
if (shouldInteractWithHoveredElement) { if (shouldInteractWithHoveredElement && interactive) {
interactWithHoveredElement(lookOnly); interactWithHoveredElement();
} }
// Open main menu // Open main menu
@ -542,7 +544,7 @@ void Myst3Engine::processInput(bool lookOnly) {
// need to be honored after leaving the inner script loop, // need to be honored after leaving the inner script loop,
// especially when the script loop was cancelled due to pressing // especially when the script loop was cancelled due to pressing
// escape. // escape.
if (_inputEscapePressedNotConsumed && !lookOnly) { if (_inputEscapePressedNotConsumed && interactive) {
_inputEscapePressedNotConsumed = false; _inputEscapePressedNotConsumed = false;
if (_cursor->isVisible() && _state->hasVarMenuEscapePressed()) { if (_cursor->isVisible() && _state->hasVarMenuEscapePressed()) {
if (_state->getLocationRoom() != 901) if (_state->getLocationRoom() != 901)
@ -623,11 +625,7 @@ void Myst3Engine::resetInput() {
} }
} }
void Myst3Engine::interactWithHoveredElement(bool lookOnly) { void Myst3Engine::interactWithHoveredElement() {
// Skip the event when in look only mode
if (lookOnly)
return;
if (isInventoryVisible() && _inventory->isMouseInside()) { if (isInventoryVisible() && _inventory->isMouseInside()) {
uint16 hoveredInventory = _inventory->hoveredItem(); uint16 hoveredInventory = _inventory->hoveredItem();
if (hoveredInventory > 0) { if (hoveredInventory > 0) {
@ -769,9 +767,10 @@ void Myst3Engine::setupTransition() {
void Myst3Engine::drawTransition(TransitionType transitionType) { void Myst3Engine::drawTransition(TransitionType transitionType) {
if (_transition) { if (_transition) {
_interactive = false; // Don't allow loading while drawing transitions
_transition->draw(transitionType); _transition->draw(transitionType);
delete _transition; delete _transition;
_transition = 0; _transition = nullptr;
} }
} }
@ -1207,7 +1206,7 @@ void Myst3Engine::playSimpleMovie(uint16 id, bool fullframe, bool refreshAmbient
movie.update(); movie.update();
// Process events // Process events
processInput(true); processInput(false);
// Handle skipping // Handle skipping
if (_inputSpacePressed || _inputEscapePressed) { if (_inputSpacePressed || _inputEscapePressed) {
@ -1426,7 +1425,7 @@ void Myst3Engine::dragSymbol(uint16 var, uint16 id) {
NodePtr nodeData = _db->getNodeData(_state->getLocationNode(), _state->getLocationRoom(), _state->getLocationAge()); NodePtr nodeData = _db->getNodeData(_state->getLocationNode(), _state->getLocationRoom(), _state->getLocationAge());
while (inputValidatePressed() && !shouldQuit()) { while (inputValidatePressed() && !shouldQuit()) {
processInput(true); processInput(false);
HotSpot *hovered = getHoveredHotspot(nodeData, var); HotSpot *hovered = getHoveredHotspot(nodeData, var);
drag.setFrame(hovered ? 2 : 1); 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()); NodePtr nodeData = _db->getNodeData(_state->getLocationNode(), _state->getLocationRoom(), _state->getLocationAge());
while (inputValidatePressed() && !shouldQuit()) { while (inputValidatePressed() && !shouldQuit()) {
processInput(true); processInput(false);
HotSpot *hovered = getHoveredHotspot(nodeData, itemVar); HotSpot *hovered = getHoveredHotspot(nodeData, itemVar);
drag.setFrame(hovered ? hoverFrame : frame); drag.setFrame(hovered ? hoverFrame : frame);
@ -1479,7 +1478,11 @@ void Myst3Engine::dragItem(uint16 statusVar, uint16 movie, uint16 frame, uint16
} }
bool Myst3Engine::canLoadGameStateCurrently() { 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) { Common::Error Myst3Engine::loadGameState(int slot) {
@ -1552,7 +1555,7 @@ void Myst3Engine::animateDirectionChange(float targetPitch, float targetHeading,
if (numTicks != 0.0f) { if (numTicks != 0.0f) {
while (1) { while (1) {
uint elapsedTicks = _state->getTickCount() - startTick; uint elapsedTicks = _state->getTickCount() - startTick;
if (elapsedTicks >= numTicks) if (elapsedTicks >= numTicks || shouldQuit())
break; break;
float step; float step;

View file

@ -173,7 +173,7 @@ public:
void drawFrame(bool noSwap = false); void drawFrame(bool noSwap = false);
void processInput(bool lookOnly); void processInput(bool interactive);
void updateInputState(); void updateInputState();
void resetInput(); void resetInput();
@ -217,6 +217,8 @@ private:
bool _inputEscapePressedNotConsumed; bool _inputEscapePressedNotConsumed;
bool _inputTildePressed; bool _inputTildePressed;
bool _interactive;
uint32 _backgroundSoundScriptLastRoomId; uint32 _backgroundSoundScriptLastRoomId;
/** /**
@ -238,7 +240,7 @@ private:
bool isInventoryVisible(); bool isInventoryVisible();
void interactWithHoveredElement(bool lookOnly); void interactWithHoveredElement();
void processEventForGamepad(const Common::Event &event); void processEventForGamepad(const Common::Event &event);
friend class Console; friend class Console;

View file

@ -148,11 +148,11 @@ void Puzzles::_drawForVarHelper(int16 var, int32 startValue, int32 endValue) {
_vm->_state->setVar(var2, varValue); _vm->_state->setVar(var2, varValue);
} }
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
currentTick = _vm->_state->getTickCount(); currentTick = _vm->_state->getTickCount();
if (currentTick > endTick) if (currentTick > endTick || _vm->shouldQuit())
break; break;
} }
} }
@ -164,8 +164,8 @@ void Puzzles::_drawForVarHelper(int16 var, int32 startValue, int32 endValue) {
void Puzzles::_drawXTicks(uint16 ticks) { void Puzzles::_drawXTicks(uint16 ticks) {
uint32 endTick = _vm->_state->getTickCount() + ticks; uint32 endTick = _vm->_state->getTickCount() + ticks;
while (_vm->_state->getTickCount() < endTick) { while (_vm->_state->getTickCount() < endTick && !_vm->shouldQuit()) {
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }
} }
@ -411,7 +411,7 @@ void Puzzles::resonanceRingsLaunchBall() {
int32 boardMoviePlaying; int32 boardMoviePlaying;
do { do {
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
ballMoviePlaying = _vm->_state->getVar(27); ballMoviePlaying = _vm->_state->getVar(27);
@ -477,7 +477,7 @@ void Puzzles::resonanceRingsLaunchBall() {
_vm->_ambient->playCurrentNode(100, 2); _vm->_ambient->playCurrentNode(100, 2);
} }
} while (ballMoviePlaying || boardMoviePlaying); } while ((ballMoviePlaying || boardMoviePlaying) && !_vm->shouldQuit());
_vm->_state->setResonanceRingsSolved(!ballShattered); _vm->_state->setResonanceRingsSolved(!ballShattered);
} }

View file

@ -300,7 +300,7 @@ bool Script::run(const Common::Array<Opcode> *script) {
c.script = script; c.script = script;
c.op = script->begin(); c.op = script->begin();
while (c.op != script->end()) { while (c.op != script->end() && !_vm->shouldQuit()) {
runOp(c, *c.op); runOp(c, *c.op);
if (c.endScript || c.op == script->end()) if (c.endScript || c.op == script->end())
@ -1736,7 +1736,7 @@ void Script::leverDrag(Context &c, const Opcode &cmd) {
_vm->_state->setVar(var, position); _vm->_state->setVar(var, position);
// Draw a frame // Draw a frame
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
mousePressed = _vm->getEventManager()->getButtonState() & Common::EventManager::LBUTTON; mousePressed = _vm->getEventManager()->getButtonState() & Common::EventManager::LBUTTON;
@ -1752,7 +1752,7 @@ void Script::leverDrag(Context &c, const Opcode &cmd) {
_vm->runScriptsFromNode(abs(script)); _vm->runScriptsFromNode(abs(script));
} }
if (!mousePressed) if (!mousePressed || _vm->shouldQuit())
break; break;
} }
@ -1799,7 +1799,7 @@ void Script::leverDragPositions(Context &c, const Opcode &cmd) {
_vm->_state->setVar(var, position); _vm->_state->setVar(var, position);
// Draw a frame // Draw a frame
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
mousePressed = _vm->inputValidatePressed(); mousePressed = _vm->inputValidatePressed();
@ -1815,7 +1815,7 @@ void Script::leverDragPositions(Context &c, const Opcode &cmd) {
_vm->runScriptsFromNode(abs(script)); _vm->runScriptsFromNode(abs(script));
} }
if (!mousePressed) if (!mousePressed || _vm->shouldQuit())
break; break;
} }
@ -1851,7 +1851,7 @@ void Script::leverDragXY(Context &c, const Opcode &cmd) {
_vm->_state->setVar(varY, distanceY); _vm->_state->setVar(varY, distanceY);
// Draw a frame // Draw a frame
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
mousePressed = _vm->getEventManager()->getButtonState() & Common::EventManager::LBUTTON; mousePressed = _vm->getEventManager()->getButtonState() & Common::EventManager::LBUTTON;
@ -1860,7 +1860,7 @@ void Script::leverDragXY(Context &c, const Opcode &cmd) {
// Run script // Run script
if (script) if (script)
_vm->runScriptsFromNode(script); _vm->runScriptsFromNode(script);
} while (mousePressed); } while (mousePressed && !_vm->shouldQuit());
} }
void Script::itemDrag(Context &c, const Opcode &cmd) { 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(); dragging |= _vm->_state->hasVarGamePadActionPressed() && _vm->_state->getGamePadActionPressed();
_vm->_state->setDragEnded(!dragging); _vm->_state->setDragEnded(!dragging);
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
if (!dragWithDirectionKeys) { if (!dragWithDirectionKeys) {
@ -1946,9 +1946,9 @@ void Script::runScriptWhileDragging(Context &c, const Opcode &cmd) {
} }
_vm->runScriptsFromNode(script); _vm->runScriptsFromNode(script);
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} while (dragging); } while (dragging && !_vm->shouldQuit());
if (dragWithDirectionKeys) { if (dragWithDirectionKeys) {
_vm->_state->setDragWithDirectionKeys(false); _vm->_state->setDragWithDirectionKeys(false);
@ -2119,8 +2119,8 @@ void Script::drawXTicks(Context &c, const Opcode &cmd) {
uint32 endTick = _vm->_state->getTickCount() + cmd.args[0]; uint32 endTick = _vm->_state->getTickCount() + cmd.args[0];
while (_vm->_state->getTickCount() < endTick) { while (_vm->_state->getTickCount() < endTick && !_vm->shouldQuit()) {
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }
} }
@ -2128,8 +2128,8 @@ void Script::drawXTicks(Context &c, const Opcode &cmd) {
void Script::drawWhileCond(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]); debugC(kDebugScript, "Opcode %d: While condition %d, draw", cmd.op, cmd.args[0]);
while (_vm->_state->evaluate(cmd.args[0]) && !_vm->inputEscapePressed()) { while (_vm->_state->evaluate(cmd.args[0]) && !_vm->inputEscapePressed() && !_vm->shouldQuit()) {
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _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); } while (c.op != c.script->end() && c.op->op != whileEndCommand.op);
} }
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }
@ -2161,13 +2161,13 @@ void Script::whileEnd(Context &c, const Opcode &cmd) {
void Script::runScriptWhileCond(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]); 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->runScriptsFromNode(cmd.args[1]);
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }
@ -2182,7 +2182,7 @@ void Script::runScriptWhileCondEachXFrames(Context &c, const Opcode &cmd) {
uint nextScript = _vm->_state->getTickCount() + firstStep; 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) { if (_vm->_state->getTickCount() >= nextScript) {
nextScript = _vm->_state->getTickCount() + step; nextScript = _vm->_state->getTickCount() + step;
@ -2190,11 +2190,11 @@ void Script::runScriptWhileCondEachXFrames(Context &c, const Opcode &cmd) {
_vm->runScriptsFromNode(cmd.args[1]); _vm->runScriptsFromNode(cmd.args[1]);
} }
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }
@ -2300,7 +2300,7 @@ void Script::runScriptForVarDrawTicksHelper(uint16 var, int32 startValue, int32
} }
} }
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
currentTick = _vm->_state->getTickCount(); currentTick = _vm->_state->getTickCount();
@ -2327,7 +2327,7 @@ void Script::runScriptForVarDrawTicksHelper(uint16 var, int32 startValue, int32
_vm->runScriptsFromNode(script); _vm->runScriptsFromNode(script);
for (uint i = _vm->_state->getTickCount(); i < endTick; i = _vm->_state->getTickCount()) { for (uint i = _vm->_state->getTickCount(); i < endTick; i = _vm->_state->getTickCount()) {
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }
@ -2528,8 +2528,8 @@ void Script::soundPlayBlocking(Context &c, const Opcode &cmd) {
return; return;
} }
while (_vm->_sound->isPlaying(soundId) && !_vm->inputEscapePressed()) { while (_vm->_sound->isPlaying(soundId) && !_vm->inputEscapePressed() && !_vm->shouldQuit()) {
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }
} }
@ -2853,7 +2853,7 @@ void Script::movieSetStartupSoundVolumeH(Context &c, const Opcode &cmd) {
void Script::drawOneFrame(Context &c, const Opcode &cmd) { void Script::drawOneFrame(Context &c, const Opcode &cmd) {
debugC(kDebugScript, "Opcode %d: Draw one frame", cmd.op); debugC(kDebugScript, "Opcode %d: Draw one frame", cmd.op);
_vm->processInput(true); _vm->processInput(false);
_vm->drawFrame(); _vm->drawFrame();
} }