diff options
-rw-r--r-- | sword2/console.cpp | 7 | ||||
-rw-r--r-- | sword2/controls.cpp | 4 | ||||
-rw-r--r-- | sword2/driver/rdwin.cpp | 2 | ||||
-rw-r--r-- | sword2/interpreter.cpp | 114 | ||||
-rw-r--r-- | sword2/mouse.cpp | 16 | ||||
-rw-r--r-- | sword2/sword2.cpp | 37 | ||||
-rw-r--r-- | sword2/sword2.h | 7 |
7 files changed, 103 insertions, 84 deletions
diff --git a/sword2/console.cpp b/sword2/console.cpp index f09d268731..76a96ea7fb 100644 --- a/sword2/console.cpp +++ b/sword2/console.cpp @@ -154,6 +154,7 @@ void Debugger::postEnter() { bool Debugger::Cmd_Exit(int argc, const char **argv) { _detach_now = true; + _vm->clearInputEvents(); return false; } @@ -584,15 +585,15 @@ bool Debugger::Cmd_Var(int argc, const char **argv) { } bool Debugger::Cmd_Rect(int argc, const char **argv) { - uint32 filter = _vm->setEventFilter(0); + uint32 filter = _vm->setInputEventFilter(0); _definingRectangles = !_definingRectangles; if (_definingRectangles) { - _vm->setEventFilter(filter & ~(RD_LEFTBUTTONUP | RD_RIGHTBUTTONUP)); + _vm->setInputEventFilter(filter & ~(RD_LEFTBUTTONUP | RD_RIGHTBUTTONUP)); DebugPrintf("Mouse rectangles enabled\n"); } else { - _vm->setEventFilter(filter | RD_LEFTBUTTONUP | RD_RIGHTBUTTONUP); + _vm->setInputEventFilter(filter | RD_LEFTBUTTONUP | RD_RIGHTBUTTONUP); DebugPrintf("Mouse rectangles disabled\n"); } diff --git a/sword2/controls.cpp b/sword2/controls.cpp index d4817153b8..c677e3f4b2 100644 --- a/sword2/controls.cpp +++ b/sword2/controls.cpp @@ -280,7 +280,7 @@ void Dialog::setResult(int result) { } int Dialog::runModal() { - uint32 oldFilter = _vm->setEventFilter(0); + uint32 oldFilter = _vm->setInputEventFilter(0); int i; @@ -386,7 +386,7 @@ int Dialog::runModal() { setResult(0); } - _vm->setEventFilter(oldFilter); + _vm->setInputEventFilter(oldFilter); return _result; } diff --git a/sword2/driver/rdwin.cpp b/sword2/driver/rdwin.cpp index d5c2a1b54f..bfdeb4ad3d 100644 --- a/sword2/driver/rdwin.cpp +++ b/sword2/driver/rdwin.cpp @@ -57,7 +57,7 @@ void Screen::markAsDirty(int16 x0, int16 y0, int16 x1, int16 y1) { */ void Screen::updateDisplay(bool redrawScene) { - _vm->parseEvents(); + _vm->parseInputEvents(); fadeServer(); if (redrawScene) { diff --git a/sword2/interpreter.cpp b/sword2/interpreter.cpp index 171c13dbf2..3f979220db 100644 --- a/sword2/interpreter.cpp +++ b/sword2/interpreter.cpp @@ -21,6 +21,7 @@ #include "common/stdafx.h" #include "common/util.h" #include "sword2/sword2.h" +#include "sword2/defs.h" #include "sword2/interpreter.h" #include "sword2/logic.h" #include "sword2/memory.h" @@ -256,54 +257,20 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { debug(4, "Resume script %d with offset %d", scriptNumber, ip); } - // WORKAROUND: The dreaded pyramid bug makes the torch untakeable when - // you speak to Titipoco. This is because one of the conditions for the - // torch to be takeable is that Titipoco isn't doing anything out of - // the ordinary. Global variable 913 has to be 0 to signify that he is - // in his "idle" state. - // - // Unfortunately, simply the act of speaking to him sets variable 913 - // to 1 (probably to stop him from turning around every now and then). - // The script may then go on to set the variable to different values - // to trigger various behaviours in him, but if you have run out of - // these cases the script won't ever set it back to 0 again. - // - // So if his click hander (action script number 2) finishes, and - // variable 913 is 1, we set it back to 0 manually. - - bool checkPyramidBug = false; - - // WORKAROUND for bug #1214168: The not-at-all dreaded mop bug. - // - // At the London Docks, global variable 1003 keeps track of Nico: - // - // 0: Hiding behind the first crate. - // 1: Hiding behind the second crate. - // 2: Standing in plain view on the deck. - // 3: Hiding on the roof. - // - // The bug happens when trying to pick up the mop while hiding on the - // roof. Nico climbs down, the mop is picked up, but the variable - // remains set to 3. Visually, everything looks ok. But as far as the - // scripts are concerned, she's still hiding up on the roof. This is - // not fatal, but leads to a number of glitches until the state is - // corrected. E.g. trying to climb back up the ladder will cause Nico - // to climb down again. - // - // Global variable 1017 keeps track of the mop. Setting it to 2 means - // that the mop has been picked up. We should be able to use that as - // the signal that Nico's state needs to be updated as well. There are - // a number of other possible workarounds, but this is the closest - // point I've found to where Nico's state should have been updated, had - // the script been correct. + // There are a couple of known script bugs related to interacting with + // certain objects. We try to work around a few of them. bool checkMopBug = false; + bool checkPyramidBug = false; + bool checkElevatorBug = false; if (scriptNumber == 2) { - if (strcmp((char *)header->name, "titipoco_81") == 0) - checkPyramidBug = true; - else if (strcmp((char *)header->name, "mop_73") == 0) + if (strcmp((char *)header->name, "mop_73") == 0) checkMopBug = true; + else if (strcmp((char *)header->name, "titipoco_81") == 0) + checkPyramidBug = true; + else if (strcmp((char *)header->name, "lift_82") == 0) + checkElevatorBug = true; } code += noScripts * sizeof(int32); @@ -356,13 +323,42 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { // End the script runningScript = false; - // WORKAROUND: Pyramid Bug. See explanation above. + // WORKAROUND: The dreaded pyramid bug makes the torch + // untakeable when you speak to Titipoco. This is + // because one of the conditions for the torch to be + // takeable is that Titipoco isn't doing anything out + // of the ordinary. Global variable 913 has to be 0 to + // signify that he is in his "idle" state. + // + // Unfortunately, simply the act of speaking to him + // sets variable 913 to 1 (probably to stop him from + // turning around every now and then). The script may + // then go on to set the variable to different values + // to trigger various behaviours in him, but if you + // have run out of these cases the script won't ever + // set it back to 0 again. + // + // So if his click hander finishes, and variable 913 is + // 1, we set it back to 0 manually. if (checkPyramidBug && _scriptVars[913] == 1) { - warning("Working around Titipoco script bug (the \"Pyramid Bug\")"); + warning("Working around pyramid bug: Resetting Titipoco's state"); _scriptVars[913] = 0; } + // WORKAROUND: The not-so-known-but-should-be-dreaded + // elevator bug. + // + // The click handler for the top of the elevator only + // handles using the elevator, not examining it. When + // examining it, the mouse cursor is removed but never + // restored. + + if (checkElevatorBug && Logic::_scriptVars[RIGHT_BUTTON]) { + warning("Working around elevator bug: Restoring mouse pointer"); + fnAddHuman(NULL); + } + debug(9, "CP_END_SCRIPT"); break; case CP_QUIT: @@ -450,10 +446,34 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { Read16ip(parameter); value = pop(); - // WORKAROUND: Mop bug. See explanation above. + // WORKAROUND for bug #1214168: The not-at-all dreaded + // mop bug. + // + // At the London Docks, global variable 1003 keeps + // track of Nico: + // + // 0: Hiding behind the first crate. + // 1: Hiding behind the second crate. + // 2: Standing in plain view on the deck. + // 3: Hiding on the roof. + // + // The bug happens when trying to pick up the mop while + // hiding on the roof. Nico climbs down, the mop is + // picked up, but the variable remains set to 3. + // Visually, everything looks ok. But as far as the + // scripts are concerned, she's still hiding up on the + // roof. This is not fatal, but leads to a number of + // glitches until the state is corrected. E.g. trying + // to climb back up the ladder will cause Nico to climb + // down again. + // + // Global variable 1017 keeps track of the mop. Setting + // it to 2 means that the mop has been picked up. We + // use that as the signal that Nico's state needs to be + // updated as well. if (checkMopBug && parameter == 1017 && _scriptVars[1003] != 2) { - warning("Working around Mop script bug: Setting Nico state"); + warning("Working around mop bug: Setting Nico's state"); _scriptVars[1003] = 2; } diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp index 176ae7579a..c12258c07b 100644 --- a/sword2/mouse.cpp +++ b/sword2/mouse.cpp @@ -794,21 +794,7 @@ void Mouse::normalMouse() { Logic::_scriptVars[EXIT_CLICK_ID] = 0; Logic::_scriptVars[EXIT_FADING] = 0; - // WORKAROUND: Examining the lift while at the top of the - // pyramid causes the game to hang. - // - // Actually, what happens is that the elevator's click handler - // (action script 2) disables the mouse cursor. Then it checks - // if the user clicked the left button, in which case it - // triggers the "going down" animation. - // - // If the user didn't click the left button, the script will - // terminate. With the mouse cursor still disabled. Ouch! - - if (_mouseTouching == 2773 && !Logic::_scriptVars[LEFT_BUTTON]) { - warning("Working around elevator script bug"); - } else - _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); + _vm->_logic->setPlayerActionEvent(CUR_PLAYER_ID, _mouseTouching); byte buf1[NAME_LEN], buf2[NAME_LEN]; diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp index 06363f51f5..a0d8d27d22 100644 --- a/sword2/sword2.cpp +++ b/sword2/sword2.cpp @@ -260,7 +260,7 @@ int Sword2Engine::init(GameDetector &detector) { // During normal gameplay, we care neither about mouse button releases // nor the scroll wheel. - setEventFilter(RD_LEFTBUTTONUP | RD_RIGHTBUTTONUP | RD_WHEELUP | RD_WHEELDOWN); + setInputEventFilter(RD_LEFTBUTTONUP | RD_RIGHTBUTTONUP | RD_WHEELUP | RD_WHEELDOWN); setupPersistentResources(); initialiseFontResourceFlags(); @@ -463,18 +463,29 @@ KeyboardEvent *Sword2Engine::keyboardEvent() { return &_keyboardEvent; } -uint32 Sword2Engine::setEventFilter(uint32 filter) { - uint32 oldFilter = _eventFilter; +uint32 Sword2Engine::setInputEventFilter(uint32 filter) { + uint32 oldFilter = _inputEventFilter; - _eventFilter = filter; + _inputEventFilter = filter; return oldFilter; } /** + * Clear the input events. This is so that we won't get any keyboard repeat + * right after using the debugging console. + */ + +void Sword2Engine::clearInputEvents() { + _keyboardEvent.pending = false; + _keyboardEvent.repeat = 0; + _mouseEvent.pending = false; +} + +/** * OSystem Event Handler. Full of cross platform goodness and 99% fat free! */ -void Sword2Engine::parseEvents() { +void Sword2Engine::parseInputEvents() { OSystem::Event event; uint32 now = _system->getMillis(); @@ -482,7 +493,7 @@ void Sword2Engine::parseEvents() { while (_system->pollEvent(event)) { switch (event.type) { case OSystem::EVENT_KEYDOWN: - if (!(_eventFilter & RD_KEYDOWN)) { + if (!(_inputEventFilter & RD_KEYDOWN)) { _keyboardEvent.pending = true; _keyboardEvent.repeat = now + 400; _keyboardEvent.ascii = event.kbd.ascii; @@ -494,42 +505,42 @@ void Sword2Engine::parseEvents() { _keyboardEvent.repeat = 0; break; case OSystem::EVENT_MOUSEMOVE: - if (!(_eventFilter & RD_KEYDOWN)) { + if (!(_inputEventFilter & RD_KEYDOWN)) { _mouse->setPos(event.mouse.x, event.mouse.y - MENUDEEP); } break; case OSystem::EVENT_LBUTTONDOWN: - if (!(_eventFilter & RD_LEFTBUTTONDOWN)) { + if (!(_inputEventFilter & RD_LEFTBUTTONDOWN)) { _mouseEvent.pending = true; _mouseEvent.buttons = RD_LEFTBUTTONDOWN; } break; case OSystem::EVENT_RBUTTONDOWN: - if (!(_eventFilter & RD_RIGHTBUTTONDOWN)) { + if (!(_inputEventFilter & RD_RIGHTBUTTONDOWN)) { _mouseEvent.pending = true; _mouseEvent.buttons = RD_RIGHTBUTTONDOWN; } break; case OSystem::EVENT_LBUTTONUP: - if (!(_eventFilter & RD_LEFTBUTTONUP)) { + if (!(_inputEventFilter & RD_LEFTBUTTONUP)) { _mouseEvent.pending = true; _mouseEvent.buttons = RD_LEFTBUTTONUP; } break; case OSystem::EVENT_RBUTTONUP: - if (!(_eventFilter & RD_RIGHTBUTTONUP)) { + if (!(_inputEventFilter & RD_RIGHTBUTTONUP)) { _mouseEvent.pending = true; _mouseEvent.buttons = RD_RIGHTBUTTONUP; } break; case OSystem::EVENT_WHEELUP: - if (!(_eventFilter & RD_WHEELUP)) { + if (!(_inputEventFilter & RD_WHEELUP)) { _mouseEvent.pending = true; _mouseEvent.buttons = RD_WHEELUP; } break; case OSystem::EVENT_WHEELDOWN: - if (!(_eventFilter & RD_WHEELDOWN)) { + if (!(_inputEventFilter & RD_WHEELDOWN)) { _mouseEvent.pending = true; _mouseEvent.buttons = RD_WHEELDOWN; } diff --git a/sword2/sword2.h b/sword2/sword2.h index ffbe086b24..370046beee 100644 --- a/sword2/sword2.h +++ b/sword2/sword2.h @@ -97,7 +97,7 @@ struct StartUp { class Sword2Engine : public Engine { private: - uint32 _eventFilter; + uint32 _inputEventFilter; // The event "buffers" MouseEvent _mouseEvent; @@ -161,9 +161,10 @@ public: uint32 _controlsFontId; uint32 _redFontId; - uint32 setEventFilter(uint32 filter); + uint32 setInputEventFilter(uint32 filter); - void parseEvents(); + void clearInputEvents(); + void parseInputEvents(); bool checkForMouseEvents(); MouseEvent *mouseEvent(); |