From 6a3251649010e0488046c5c994b600b5c831a209 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 7 Apr 2018 11:02:09 -0400 Subject: XEEN: Cache mouse clicks as well as keyboard in EventsManager This allows the well open door/gate, shoot at enemies, then close to work with the mouse as well as the keyboard. The pending event queue has also been limited to 5 pending events. Trust me, you don't want to spent time spamming Shoot at a high level monster that can't reach you, only for when it's killed to have to wait several minutes whilst your party keeps shooting. --- engines/xeen/dialogs/dialogs.cpp | 78 ++++++++++++++------------- engines/xeen/dialogs/dialogs_input.cpp | 9 ++-- engines/xeen/events.cpp | 52 ++++++++++-------- engines/xeen/events.h | 58 ++++++++++++++++++-- engines/xeen/interface.cpp | 6 +-- engines/xeen/scripts.cpp | 4 +- engines/xeen/worldofxeen/worldofxeen_menu.cpp | 8 ++- 7 files changed, 132 insertions(+), 83 deletions(-) diff --git a/engines/xeen/dialogs/dialogs.cpp b/engines/xeen/dialogs/dialogs.cpp index f404996b56..1b99ec6978 100644 --- a/engines/xeen/dialogs/dialogs.cpp +++ b/engines/xeen/dialogs/dialogs.cpp @@ -66,51 +66,55 @@ bool ButtonContainer::checkEvents(XeenEngine *vm) { EventsManager &events = *vm->_events; Party &party = *vm->_party; Windows &windows = *_vm->_windows; + PendingEvent event; + const Common::Rect WAIT_BOUNDS(8, 8, 224, 140); _buttonValue = 0; - if (events._leftButton) { - Common::Point pt = events._mousePos; - - // Check for party member glyphs being clicked - Common::Rect r(0, 0, 32, 32); - for (uint idx = 0; idx < party._activeParty.size(); ++idx) { - r.moveTo(Res.CHAR_FACES_X[idx], 150); - if (r.contains(pt)) { - _buttonValue = Common::KEYCODE_F1 + idx; - break; + if (events.getEvent(event)) { + if (event._leftButton) { + Common::Point pt = events._mousePos; + + // Check for party member glyphs being clicked + Common::Rect r(0, 0, 32, 32); + for (uint idx = 0; idx < party._activeParty.size(); ++idx) { + r.moveTo(Res.CHAR_FACES_X[idx], 150); + if (r.contains(pt)) { + _buttonValue = Common::KEYCODE_F1 + idx; + break; + } } - } - // Check whether any button is selected - for (uint i = 0; i < _buttons.size(); ++i) { - if (_buttons[i]._bounds.contains(pt)) { - events.debounceMouse(); + // Check whether any button is selected + for (uint i = 0; i < _buttons.size(); ++i) { + if (_buttons[i]._bounds.contains(pt)) { + events.debounceMouse(); - _buttonValue = _buttons[i]._value; - break; + _buttonValue = _buttons[i]._value; + break; + } + } + + if (!_buttonValue && WAIT_BOUNDS.contains(pt)) { + _buttonValue = Common::KEYCODE_SPACE; + return true; } - } - if (!_buttonValue && Common::Rect(8, 8, 224, 135).contains(pt)) { - _buttonValue = 1; - return true; + } else if (event.isKeyboard()) { + const Common::KeyCode &keycode = event._keyState.keycode; + + if (keycode == Common::KEYCODE_KP8) + _buttonValue = Common::KEYCODE_UP; + else if (keycode == Common::KEYCODE_KP2) + _buttonValue = Common::KEYCODE_DOWN; + else if (keycode == Common::KEYCODE_KP_ENTER) + _buttonValue = Common::KEYCODE_RETURN; + else if (keycode != Common::KEYCODE_LCTRL && keycode != Common::KEYCODE_RCTRL + && keycode != Common::KEYCODE_LALT && keycode != Common::KEYCODE_RALT) + _buttonValue = keycode; + + if (_buttonValue) + _buttonValue |= (event._keyState.flags & ~Common::KBD_STICKY) << 16; } - } else if (events.isKeyPending()) { - Common::KeyState keyState; - events.getKey(keyState); - - if (keyState.keycode == Common::KEYCODE_KP8) - _buttonValue = Common::KEYCODE_UP; - else if (keyState.keycode == Common::KEYCODE_KP2) - _buttonValue = Common::KEYCODE_DOWN; - else if (keyState.keycode == Common::KEYCODE_KP_ENTER) - _buttonValue = Common::KEYCODE_RETURN; - else if (keyState.keycode != Common::KEYCODE_LCTRL && keyState.keycode != Common::KEYCODE_RCTRL - && keyState.keycode != Common::KEYCODE_LALT && keyState.keycode != Common::KEYCODE_RALT) - _buttonValue = keyState.keycode; - - if (_buttonValue) - _buttonValue |= (keyState.flags & ~Common::KBD_STICKY) << 16; } if (_buttonValue) { diff --git a/engines/xeen/dialogs/dialogs_input.cpp b/engines/xeen/dialogs/dialogs_input.cpp index b259908fe0..214aa28e5c 100644 --- a/engines/xeen/dialogs/dialogs_input.cpp +++ b/engines/xeen/dialogs/dialogs_input.cpp @@ -86,7 +86,7 @@ Common::KeyState Input::waitForKey(const Common::String &msg) { bool flag = !_vm->_startupWindowActive && !windows[25]._enabled && _vm->_mode != MODE_FF && _vm->_mode != MODE_17; - Common::KeyState ks; + PendingEvent pe; while (!_vm->shouldExit()) { events.updateGameCounter(); @@ -100,11 +100,8 @@ Common::KeyState Input::waitForKey(const Common::String &msg) { windows[3].update(); events.wait(1); - - if (events.isKeyPending()) { - events.getKey(ks); + if (events.getEvent(pe) && pe.isKeyboard()) break; - } } _window->writeString(""); @@ -113,7 +110,7 @@ Common::KeyState Input::waitForKey(const Common::String &msg) { intf._tillMove = oldTillMove; intf._upDoorText = oldUpDoorText; - return ks; + return pe._keyState; } void Input::animateCursor() { diff --git a/engines/xeen/events.cpp b/engines/xeen/events.cpp index 6ceef4406b..7a0a5127cc 100644 --- a/engines/xeen/events.cpp +++ b/engines/xeen/events.cpp @@ -33,7 +33,7 @@ namespace Xeen { EventsManager::EventsManager(XeenEngine *vm) : _vm(vm), _playTime(0), _frameCounter(0), _priorFrameCounterTime(0), _gameCounter(0), - _leftButton(false), _rightButton(false), _sprites("mouse.icn") { + _mousePressed(false), _sprites("mouse.icn") { Common::fill(&_gameCounters[0], &_gameCounters[6], 0); } @@ -80,24 +80,23 @@ void EventsManager::pollEvents() { _vm->_debugger->attach(); _vm->_debugger->onFrame(); } else { - _keys.push(event.kbd); + addEvent(event.kbd); } break; case Common::EVENT_MOUSEMOVE: _mousePos = event.mouse; break; case Common::EVENT_LBUTTONDOWN: - _leftButton = true; - return; - case Common::EVENT_LBUTTONUP: - _leftButton = false; + _mousePressed = true; + addEvent(true, false); return; case Common::EVENT_RBUTTONDOWN: - _rightButton = true; - return; + _mousePressed = true; + addEvent(false, true); + case Common::EVENT_LBUTTONUP: case Common::EVENT_RBUTTONUP: - _rightButton = false; - break; + _mousePressed = false; + return; default: break; } @@ -110,31 +109,38 @@ void EventsManager::pollEventsAndWait() { } void EventsManager::clearEvents() { - _keys.clear(); - _leftButton = _rightButton = false; - + _pendingEvents.clear(); + _mousePressed = false; } void EventsManager::debounceMouse() { - while (_leftButton && !_vm->shouldExit()) { + while (_mousePressed && !_vm->shouldExit()) { pollEventsAndWait(); } } -bool EventsManager::getKey(Common::KeyState &key) { - if (_keys.empty()) { + +void EventsManager::addEvent(const Common::KeyState &keyState) { + if (_pendingEvents.size() < MAX_PENDING_EVENTS) + _pendingEvents.push(PendingEvent(keyState)); +} + +void EventsManager::addEvent(bool leftButton, bool rightButton) { + if (_pendingEvents.size() < MAX_PENDING_EVENTS) + _pendingEvents.push(PendingEvent(leftButton, rightButton)); +} + + +bool EventsManager::getEvent(PendingEvent &pe) { + if (_pendingEvents.empty()) { return false; } else { - key = _keys.pop(); + pe = _pendingEvents.pop(); return true; } } -bool EventsManager::isKeyPending() const { - return !_keys.empty(); -} - bool EventsManager::isKeyMousePressed() { - bool result = _leftButton || _rightButton || isKeyPending(); + bool result = isEventPending(); debounceMouse(); clearEvents(); @@ -144,7 +150,7 @@ bool EventsManager::isKeyMousePressed() { bool EventsManager::wait(uint numFrames, bool interruptable) { while (!_vm->shouldExit() && timeElapsed() < numFrames) { pollEventsAndWait(); - if (interruptable && (_leftButton || _rightButton || isKeyPending())) + if (interruptable && isEventPending()) return true; } diff --git a/engines/xeen/events.h b/engines/xeen/events.h index 0ef2c3a9e7..80ce83aacb 100644 --- a/engines/xeen/events.h +++ b/engines/xeen/events.h @@ -32,9 +32,30 @@ namespace Xeen { #define GAME_FRAME_RATE (1000 / 50) #define GAME_FRAME_TIME 50 +#define MAX_PENDING_EVENTS 5 class XeenEngine; +struct PendingEvent { + Common::KeyState _keyState; + bool _leftButton; + bool _rightButton; + + PendingEvent() : _leftButton(false), _rightButton(false) {} + PendingEvent(const Common::KeyState &keyState) : _keyState(keyState), _leftButton(false), _rightButton(false) {} + PendingEvent(bool leftButton, bool rightButton) : _leftButton(leftButton), _rightButton(rightButton) {} + + /** + * Returns true if a keyboard event is pending + */ + bool isKeyboard() const { return _keyState.keycode != Common::KEYCODE_INVALID; } + + /** + * Returns ture if a mouse button event is pending + */ + bool isMouse() const { return _leftButton || _rightButton; } +}; + class EventsManager { private: XeenEngine *_vm; @@ -43,19 +64,18 @@ private: uint32 _gameCounter; uint32 _gameCounters[6]; uint32 _playTime; - Common::Queue _keys; + Common::Queue _pendingEvents; SpriteResource _sprites; + bool _mousePressed; /** * Handles moving to the next game frame */ void nextFrame(); public: - bool _leftButton, _rightButton; Common::Point _mousePos; public: EventsManager(XeenEngine *vm); - ~EventsManager(); /* @@ -78,17 +98,45 @@ public: */ bool isCursorVisible(); + /** + * Polls the ScummVM backend for any pending events + */ void pollEvents(); + /** + * Polls for events, and wait a slight delay. This ensures the game doesn't use up 100% of the CPU + */ void pollEventsAndWait(); + /** + * Clears all pending events + */ void clearEvents(); + /** + * Waits for a mouse press to be released + */ void debounceMouse(); - bool getKey(Common::KeyState &key); + /** + * Adds a keyboard event to the queue + */ + void addEvent(const Common::KeyState &keyState); + + /** + * Adds a mouse button event to the queue + */ + void addEvent(bool leftButton, bool rightButton); - bool isKeyPending() const; + /** + * Returns the next pending key/mouse press, if any + */ + bool getEvent(PendingEvent &pe); + + /** + * Returns true if a key or mouse event is pending + */ + bool isEventPending() const { return !_pendingEvents.empty(); } /** * Returns true if a key or mouse press is pending diff --git a/engines/xeen/interface.cpp b/engines/xeen/interface.cpp index 8e52aae7ae..88b33c4164 100644 --- a/engines/xeen/interface.cpp +++ b/engines/xeen/interface.cpp @@ -262,7 +262,6 @@ void Interface::perform() { Party &party = *_vm->_party; Scripts &scripts = *_vm->_scripts; Sound &sound = *_vm->_sound; - const Common::Rect WAIT_BOUNDS(8, 8, 224, 140); do { // Draw the next frame @@ -276,10 +275,7 @@ void Interface::perform() { if (g_vm->shouldExit() || g_vm->isLoadPending() || party._dead) return; - if (events._leftButton && WAIT_BOUNDS.contains(events._mousePos)) - _buttonValue = Common::KEYCODE_SPACE; - else - checkEvents(g_vm); + checkEvents(g_vm); } while (!_buttonValue && events.timeElapsed() < 1); } while (!_buttonValue); diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp index 92204fc5ac..7d36b83f34 100644 --- a/engines/xeen/scripts.cpp +++ b/engines/xeen/scripts.cpp @@ -214,7 +214,7 @@ int Scripts::checkEvents() { MazeObject &selectedObj = map._mobData._objects[intf._objNumber]; if (selectedObj._spriteId == (ccNum ? 15 : 16)) { - for (uint idx = 0; idx < MIN((int)map._mobData._objects.size(), 16); ++idx) { + for (int idx = 0; idx < MIN((int)map._mobData._objects.size(), 16); ++idx) { MazeObject &obj = map._mobData._objects[idx]; if (obj._spriteId == (ccNum ? 62 : 57)) { selectedObj._id = idx; @@ -223,7 +223,7 @@ int Scripts::checkEvents() { } } } else if (selectedObj._spriteId == 73) { - for (uint idx = 0; idx < MIN((int)map._mobData._objects.size(), 16); ++idx) { + for (int idx = 0; idx < MIN((int)map._mobData._objects.size(), 16); ++idx) { MazeObject &obj = map._mobData._objects[idx]; if (obj._spriteId == 119) { selectedObj._id = idx; diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.cpp b/engines/xeen/worldofxeen/worldofxeen_menu.cpp index 8356794ef7..a4a4b0277b 100644 --- a/engines/xeen/worldofxeen/worldofxeen_menu.cpp +++ b/engines/xeen/worldofxeen/worldofxeen_menu.cpp @@ -110,11 +110,9 @@ void MainMenuContainer::execute() { } else { // No active dialog. If Escape pressed, exit game entirely. Otherwise, // open up the main menu dialog - if (events.isKeyPending()) { - Common::KeyState key; - if (events.getKey(key) && key.keycode == Common::KEYCODE_ESCAPE) - g_vm->_gameMode = GMODE_QUIT; - } + PendingEvent pe; + if (events.getEvent(pe) && pe._keyState.keycode == Common::KEYCODE_ESCAPE) + g_vm->_gameMode = GMODE_QUIT; events.clearEvents(); showMenuDialog(); -- cgit v1.2.3