From 4f08292c8c082361af7212e3951af4b1b6c45199 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Fri, 22 Jul 2016 19:20:05 -0400 Subject: TITANIC: Add support for arbitrary window event targets Also moved all standard game event methods to CMainGameWindow. This will allow for the Continue Save dialog to be added in and get events instead of the game window --- engines/titanic/detection.cpp | 5 +- engines/titanic/events.cpp | 143 ++-------------------- engines/titanic/events.h | 79 +++++++----- engines/titanic/game_state.cpp | 2 +- engines/titanic/main_game_window.cpp | 147 +++++++++++++++++++++-- engines/titanic/main_game_window.h | 42 ++++++- engines/titanic/pet_control/pet_rooms_glyphs.cpp | 4 +- engines/titanic/titanic.cpp | 27 +++++ engines/titanic/titanic.h | 8 ++ engines/titanic/true_talk/tt_npc_script.cpp | 2 +- 10 files changed, 282 insertions(+), 177 deletions(-) diff --git a/engines/titanic/detection.cpp b/engines/titanic/detection.cpp index ca4db961b2..a9878d9da7 100644 --- a/engines/titanic/detection.cpp +++ b/engines/titanic/detection.cpp @@ -127,8 +127,9 @@ SaveStateList TitanicMetaEngine::listSaves(const char *target) const { if (in) { Titanic::CompressedFile file; file.open(in); - Titanic::CProjectItem::readSavegameHeader(&file, header); - saveList.push_back(SaveStateDescriptor(slot, header._saveName)); + + if (Titanic::CProjectItem::readSavegameHeader(&file, header)) + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); if (header._thumbnail) { header._thumbnail->free(); diff --git a/engines/titanic/events.cpp b/engines/titanic/events.cpp index ff425abcde..381d371a68 100644 --- a/engines/titanic/events.cpp +++ b/engines/titanic/events.cpp @@ -30,9 +30,8 @@ namespace Titanic { -Events::Events(TitanicEngine *vm): _vm(vm), _specialButtons(0), - _frameCounter(1), _priorFrameTime(0), _priorLeftDownTime(0), - _priorMiddleDownTime(0), _priorRightDownTime(0) { +Events::Events(TitanicEngine *vm): _vm(vm), _frameCounter(1), + _priorFrameTime(0) { } void Events::pollEvents() { @@ -45,29 +44,29 @@ void Events::pollEvents() { switch (event.type) { case Common::EVENT_MOUSEMOVE: _mousePos = event.mouse; - mouseMove(); + eventTarget()->mouseMove(_mousePos); break; case Common::EVENT_LBUTTONDOWN: _mousePos = event.mouse; - leftButtonDown(); + eventTarget()->leftButtonDown(_mousePos); break; case Common::EVENT_LBUTTONUP: _mousePos = event.mouse; - leftButtonUp(); + eventTarget()->leftButtonUp(_mousePos); break; case Common::EVENT_MBUTTONDOWN: _mousePos = event.mouse; - middleButtonDown(); + eventTarget()->middleButtonDown(_mousePos); break; case Common::EVENT_MBUTTONUP: _mousePos = event.mouse; - middleButtonUp(); + eventTarget()->middleButtonUp(_mousePos); break; case Common::EVENT_KEYDOWN: - keyDown(event.kbd); + eventTarget()->keyDown(event.kbd); break; case Common::EVENT_KEYUP: - keyUp(event.kbd); + eventTarget()->keyUp(event.kbd); break; default: break; @@ -87,7 +86,7 @@ bool Events::checkForNextFrameCounter() { _priorFrameTime = milli; // Handle any idle updates - onIdle(); + eventTarget()->onIdle(); // Give time to the debugger _vm->_debugger->onFrame(); @@ -105,128 +104,6 @@ uint32 Events::getTicksCount() const { return g_system->getMillis(); } -void Events::onIdle() { - if (!_vm->_window->_inputAllowed) - return; - CGameManager *gameManager = _vm->_window->_gameManager; - if (!gameManager) - return; - - // Let the game manager perform any game updates - gameManager->update(); - - if (gameManager->_gameState._quitGame) { - // Game needs to shut down - _vm->quitGame(); - } -} - -#define HANDLE_MESSAGE(METHOD) if (_vm->_window->_inputAllowed) { \ - _vm->_window->_gameManager->_inputTranslator.METHOD(_specialButtons, Point(_mousePos.x, _mousePos.y)); \ - _vm->_window->mouseChanged(); \ - } - - -void Events::mouseMove() { - HANDLE_MESSAGE(mouseMove) -} - -void Events::leftButtonDown() { - _specialButtons |= MK_LBUTTON; - - if ((getTicksCount() - _priorLeftDownTime) < DOUBLE_CLICK_TIME) { - _priorLeftDownTime = 0; - leftButtonDoubleClick(); - } else { - _priorLeftDownTime = getTicksCount(); - HANDLE_MESSAGE(leftButtonDown) - } -} - -void Events::leftButtonUp() { - _specialButtons &= ~MK_LBUTTON; - HANDLE_MESSAGE(leftButtonUp) -} - -void Events::leftButtonDoubleClick() { - HANDLE_MESSAGE(leftButtonDoubleClick) -} - -void Events::middleButtonDown() { - _specialButtons |= MK_MBUTTON; - - if ((getTicksCount() - _priorMiddleDownTime) < DOUBLE_CLICK_TIME) { - _priorMiddleDownTime = 0; - middleButtonDoubleClick(); - } else { - _priorMiddleDownTime = getTicksCount(); - HANDLE_MESSAGE(middleButtonDown) - } -} - -void Events::middleButtonUp() { - _specialButtons &= ~MK_MBUTTON; - HANDLE_MESSAGE(middleButtonUp) -} - -void Events::middleButtonDoubleClick() { - HANDLE_MESSAGE(middleButtonDoubleClick) -} - -void Events::rightButtonDown() { - _specialButtons |= MK_RBUTTON; - - if ((getTicksCount() - _priorRightDownTime) < DOUBLE_CLICK_TIME) { - _priorRightDownTime = 0; - rightButtonDoubleClick(); - } else { - _priorRightDownTime = getTicksCount(); - HANDLE_MESSAGE(rightButtonDown) - } -} - -void Events::rightButtonUp() { - _specialButtons &= ~MK_RBUTTON; - HANDLE_MESSAGE(rightButtonUp) -} - -void Events::rightButtonDoubleClick() { - HANDLE_MESSAGE(rightButtonDoubleClick) -} - -void Events::charPress(char c) { - -} - -void Events::keyDown(Common::KeyState keyState) { - handleKbdSpecial(keyState); - - if (keyState.keycode == Common::KEYCODE_d && (keyState.flags & Common::KBD_CTRL)) { - // Attach to the debugger - _vm->_debugger->attach(); - _vm->_debugger->onFrame(); - } - - if (_vm->_window->_inputAllowed) - _vm->_window->_gameManager->_inputTranslator.keyDown(keyState); -} - -void Events::keyUp(Common::KeyState keyState) { - handleKbdSpecial(keyState); -} - -void Events::handleKbdSpecial(Common::KeyState keyState) { - if (keyState.flags & Common::KBD_CTRL) - _specialButtons |= MK_CONTROL; - else - _specialButtons &= ~MK_CONTROL; - - if (keyState.flags & Common::KBD_SHIFT) - _specialButtons |= MK_SHIFT; - else - _specialButtons &= ~MK_SHIFT; -} - void Events::sleep(uint time) { uint32 delayEnd = g_system->getMillis() + time; diff --git a/engines/titanic/events.h b/engines/titanic/events.h index ab3d755535..68666c7c46 100644 --- a/engines/titanic/events.h +++ b/engines/titanic/events.h @@ -25,6 +25,8 @@ #include "common/scummsys.h" #include "common/events.h" +#include "common/stack.h" +#include "support/rect.h" namespace Titanic { @@ -39,16 +41,41 @@ enum SpecialButtons { class TitanicEngine; +/** + * A base class for windows that can receive event messages + */ +class CEventTarget { +public: + virtual ~CEventTarget() {} + + /** + * Called to handle any regular updates the game requires + */ + virtual void onIdle() {} + + /** + * Mouse/key event handlers + */ + virtual void mouseMove(const Point &mousePos) {} + virtual void leftButtonDown(const Point &mousePos) {} + virtual void leftButtonUp(const Point &mousePos) {} + virtual void leftButtonDoubleClick(const Point &mousePos) {} + virtual void middleButtonDown(const Point &mousePos) {} + virtual void middleButtonUp(const Point &mousePos) {} + virtual void middleButtonDoubleClick(const Point &mousePos) {} + virtual void rightButtonDown(const Point &mousePos) {} + virtual void rightButtonUp(const Point &mousePos) {} + virtual void keyDown(Common::KeyState keyState) {} + virtual void keyUp(Common::KeyState keyState) {} +}; + class Events { private: TitanicEngine *_vm; + Common::Stack _eventTargets; uint32 _frameCounter; uint32 _priorFrameTime; - uint32 _priorLeftDownTime; - uint32 _priorMiddleDownTime; - uint32 _priorRightDownTime; Common::Point _mousePos; - uint _specialButtons; /** * Check whether it's time to display the next screen frame @@ -56,28 +83,31 @@ private: bool checkForNextFrameCounter(); /** - * Called to handle any regular updates the game requires + * Return the currently active event target */ - void onIdle(); - - void mouseMove(); - void leftButtonDown(); - void leftButtonUp(); - void leftButtonDoubleClick(); - void middleButtonDown(); - void middleButtonUp(); - void middleButtonDoubleClick(); - void rightButtonDown(); - void rightButtonUp(); - void rightButtonDoubleClick(); - void charPress(char c); - void keyDown(Common::KeyState keyState); - void keyUp(Common::KeyState keyState); - void handleKbdSpecial(Common::KeyState keyState); + CEventTarget *eventTarget() const { + return _eventTargets.top(); + } public: Events(TitanicEngine *vm); ~Events() {} + /** + * Adds a new event target to the top of the list. It will get + * all events generated until such time as another is pushed on + * top of it, or the removeTarget method is called + */ + void addTarget(CEventTarget *target) { + _eventTargets.push(target); + } + + /** + * Removes the currently active event target + */ + void removeTarget() { + _eventTargets.pop(); + } + /** * Check for any pending events */ @@ -99,13 +129,6 @@ public: */ uint32 getTicksCount() const; - /** - * Return whether a given special key is currently pressed - */ - bool isSpecialPressed(SpecialButtons btn) const { return _specialButtons; } - - uint getSpecialButtons() const { return _specialButtons; } - /** * Sleep for a specified period of time */ diff --git a/engines/titanic/game_state.cpp b/engines/titanic/game_state.cpp index 6c81bc8699..f7ae304b29 100644 --- a/engines/titanic/game_state.cpp +++ b/engines/titanic/game_state.cpp @@ -120,7 +120,7 @@ void CGameState::changeView(CViewItem *newView, CMovieClip *clip) { oldView->leaveView(newView); // If Shift key is pressed, skip showing the transition clip - if (g_vm->_events->isSpecialPressed(MK_SHIFT)) + if (g_vm->_window->isSpecialPressed(MK_SHIFT)) clip = nullptr; if (_mode == GSMODE_2) { diff --git a/engines/titanic/main_game_window.cpp b/engines/titanic/main_game_window.cpp index 3c549c4e89..736154a502 100644 --- a/engines/titanic/main_game_window.cpp +++ b/engines/titanic/main_game_window.cpp @@ -20,16 +20,19 @@ * */ +#include "common/config-manager.h" #include "titanic/titanic.h" -#include "titanic/main_game_window.h" #include "titanic/game_manager.h" #include "titanic/game_view.h" +#include "titanic/main_game_window.h" #include "titanic/messages/messages.h" #include "titanic/pet_control/pet_control.h" namespace Titanic { -CMainGameWindow::CMainGameWindow(TitanicEngine *vm): _vm(vm) { +CMainGameWindow::CMainGameWindow(TitanicEngine *vm): _vm(vm), + _specialButtons(0), _priorLeftDownTime(0), + _priorMiddleDownTime(0), _priorRightDownTime(0) { _gameView = nullptr; _gameManager = nullptr; _project = nullptr; @@ -37,6 +40,12 @@ CMainGameWindow::CMainGameWindow(TitanicEngine *vm): _vm(vm) { _image = nullptr; _cursor = nullptr; _pendingLoadSlot = -1; + + // Set the window as an event target + vm->_events->addTarget(this); +} + +CMainGameWindow::~CMainGameWindow() { } bool CMainGameWindow::Create() { @@ -53,14 +62,11 @@ void CMainGameWindow::applicationStarting() { // Set up the game project, and get game slot int saveSlot = loadGame(); assert(_project); - + // Set the video mode CScreenManager *screenManager = CScreenManager::setCurrent(); screenManager->setMode(640, 480, 16, 0, true); - // TODO: Remove initial background and palette - - // Create game view and manager _gameView = new CSTGameView(this); _gameManager = new CGameManager(_project, _gameView); @@ -98,7 +104,10 @@ int CMainGameWindow::loadGame() { } int CMainGameWindow::selectSavegame() { - // TODO: For now, hardcoded to -1 for new saves + // If the user selected a savegame from the launcher, return it + if (ConfMan.hasKey("save_slot")) + return ConfMan.getInt("save_slot"); + return -1; } @@ -111,7 +120,7 @@ void CMainGameWindow::setActiveView(CViewItem *viewItem) { _gameView->createSurface(key); } } - + void CMainGameWindow::draw() { if (_gameManager) { if (!_gameView->_surface) { @@ -202,4 +211,126 @@ void CMainGameWindow::loadGame(int slotId) { _gameManager->_gameState.setMode(GSMODE_PENDING_LOAD); } +void CMainGameWindow::onIdle() { + if (!_inputAllowed) + return; + CGameManager *gameManager = _gameManager; + if (!gameManager) + return; + + // Let the game manager perform any game updates + gameManager->update(); + + if (gameManager->_gameState._quitGame) { + // Game needs to shut down + _vm->quitGame(); + } +} + +#define HANDLE_MESSAGE(METHOD) if (_inputAllowed) { \ + _gameManager->_inputTranslator.METHOD(_specialButtons, mousePos); \ + mouseChanged(); \ + } + + +void CMainGameWindow::mouseMove(const Point &mousePos) { + HANDLE_MESSAGE(mouseMove) +} + +void CMainGameWindow::leftButtonDown(const Point &mousePos) { + _specialButtons |= MK_LBUTTON; + + if ((_vm->_events->getTicksCount() - _priorLeftDownTime) < DOUBLE_CLICK_TIME) { + _priorLeftDownTime = 0; + leftButtonDoubleClick(mousePos); + } else { + _priorLeftDownTime = _vm->_events->getTicksCount(); + HANDLE_MESSAGE(leftButtonDown) + } +} + +void CMainGameWindow::leftButtonUp(const Point &mousePos) { + _specialButtons &= ~MK_LBUTTON; + HANDLE_MESSAGE(leftButtonUp) +} + +void CMainGameWindow::leftButtonDoubleClick(const Point &mousePos) { + HANDLE_MESSAGE(leftButtonDoubleClick) +} + +void CMainGameWindow::middleButtonDown(const Point &mousePos) { + _specialButtons |= MK_MBUTTON; + + if ((_vm->_events->getTicksCount() - _priorMiddleDownTime) < DOUBLE_CLICK_TIME) { + _priorMiddleDownTime = 0; + middleButtonDoubleClick(mousePos); + } else { + _priorMiddleDownTime = _vm->_events->getTicksCount(); + HANDLE_MESSAGE(middleButtonDown) + } +} + +void CMainGameWindow::middleButtonUp(const Point &mousePos) { + _specialButtons &= ~MK_MBUTTON; + HANDLE_MESSAGE(middleButtonUp) +} + +void CMainGameWindow::middleButtonDoubleClick(const Point &mousePos) { + HANDLE_MESSAGE(middleButtonDoubleClick) +} + +void CMainGameWindow::rightButtonDown(const Point &mousePos) { + _specialButtons |= MK_RBUTTON; + + if ((_vm->_events->getTicksCount() - _priorRightDownTime) < DOUBLE_CLICK_TIME) { + _priorRightDownTime = 0; + rightButtonDoubleClick(mousePos); + } else { + _priorRightDownTime = _vm->_events->getTicksCount(); + HANDLE_MESSAGE(rightButtonDown) + } +} + +void CMainGameWindow::rightButtonUp(const Point &mousePos) { + _specialButtons &= ~MK_RBUTTON; + HANDLE_MESSAGE(rightButtonUp) +} + +void CMainGameWindow::rightButtonDoubleClick(const Point &mousePos) { + HANDLE_MESSAGE(rightButtonDoubleClick) +} + +void CMainGameWindow::charPress(char c) { + +} + +void CMainGameWindow::keyDown(Common::KeyState keyState) { + handleKbdSpecial(keyState); + + if (keyState.keycode == Common::KEYCODE_d && (keyState.flags & Common::KBD_CTRL)) { + // Attach to the debugger + _vm->_debugger->attach(); + _vm->_debugger->onFrame(); + } + + if (_inputAllowed) + _gameManager->_inputTranslator.keyDown(keyState); +} + +void CMainGameWindow::keyUp(Common::KeyState keyState) { + handleKbdSpecial(keyState); +} + +void CMainGameWindow::handleKbdSpecial(Common::KeyState keyState) { + if (keyState.flags & Common::KBD_CTRL) + _specialButtons |= MK_CONTROL; + else + _specialButtons &= ~MK_CONTROL; + + if (keyState.flags & Common::KBD_SHIFT) + _specialButtons |= MK_SHIFT; + else + _specialButtons &= ~MK_SHIFT; +} + } // End of namespace Titanic diff --git a/engines/titanic/main_game_window.h b/engines/titanic/main_game_window.h index 18c03942ce..7a651ec970 100644 --- a/engines/titanic/main_game_window.h +++ b/engines/titanic/main_game_window.h @@ -29,16 +29,22 @@ #include "titanic/game_view.h" #include "titanic/support/image.h" #include "titanic/core/project_item.h" +#include "titanic/events.h" namespace Titanic { class TitanicEngine; -class CMainGameWindow { +class CMainGameWindow : public CEventTarget { private: TitanicEngine *_vm; int _pendingLoadSlot; - + uint _specialButtons; + uint32 _priorFrameTime; + uint32 _priorLeftDownTime; + uint32 _priorMiddleDownTime; + uint32 _priorRightDownTime; +private: /** * Checks for the presence of any savegames and, if present, * lets the user pick one to resume @@ -65,6 +71,12 @@ private: * Draws all the items within the view */ void drawViewContents(CScreenManager *screenManager); + + void leftButtonDoubleClick(const Point &mousePos); + void middleButtonDoubleClick(const Point &mousePos); + void rightButtonDoubleClick(const Point &mousePos); + void charPress(char c); + void handleKbdSpecial(Common::KeyState keyState); public: CGameView *_gameView; CGameManager *_gameManager; @@ -74,6 +86,22 @@ public: void *_cursor; public: CMainGameWindow(TitanicEngine *vm); + virtual ~CMainGameWindow(); + + /** + * Called to handle any regular updates the game requires + */ + void onIdle(); + + virtual void mouseMove(const Point &mousePos); + virtual void leftButtonDown(const Point &mousePos); + virtual void leftButtonUp(const Point &mousePos); + virtual void middleButtonDown(const Point &mousePos); + virtual void middleButtonUp(const Point &mousePos); + virtual void rightButtonDown(const Point &mousePos); + virtual void rightButtonUp(const Point &mousePos); + virtual void keyDown(Common::KeyState keyState); + virtual void keyUp(Common::KeyState keyState); /** * Creates the window @@ -104,6 +132,16 @@ public: * Schedules a savegame to be loaded */ void loadGame(int slotId); + + /* + * Return whether a given special key is currently pressed + */ + bool isSpecialPressed(SpecialButtons btn) const { return _specialButtons; } + + /** + * Returns the bitset of the currently pressed special buttons + */ + uint getSpecialButtons() const { return _specialButtons; } }; } // End of namespace Titanic diff --git a/engines/titanic/pet_control/pet_rooms_glyphs.cpp b/engines/titanic/pet_control/pet_rooms_glyphs.cpp index 5de814af24..810342a23e 100644 --- a/engines/titanic/pet_control/pet_rooms_glyphs.cpp +++ b/engines/titanic/pet_control/pet_rooms_glyphs.cpp @@ -103,7 +103,7 @@ void CPetRoomsGlyph::drawAt(CScreenManager *screenManager, const Point &pt, bool void CPetRoomsGlyph::selectGlyph(const Point &topLeft, const Point &pt) { if (isAssigned()) { - bool isShiftPressed = g_vm->_events->getSpecialButtons() & MK_SHIFT; + bool isShiftPressed = g_vm->_window->getSpecialButtons() & MK_SHIFT; if (isShiftPressed) { int selection = getSelection(topLeft, pt); @@ -116,7 +116,7 @@ void CPetRoomsGlyph::selectGlyph(const Point &topLeft, const Point &pt) { } bool CPetRoomsGlyph::dragGlyph(const Point &topLeft, CMouseDragStartMsg *msg) { - bool isShiftPressed = g_vm->_events->getSpecialButtons() & MK_SHIFT; + bool isShiftPressed = g_vm->_window->getSpecialButtons() & MK_SHIFT; CPetControl *petControl = getPetControl(); if (!isShiftPressed && petControl) { diff --git a/engines/titanic/titanic.cpp b/engines/titanic/titanic.cpp index 7b91a1a630..dfb68fd9d5 100644 --- a/engines/titanic/titanic.cpp +++ b/engines/titanic/titanic.cpp @@ -181,4 +181,31 @@ CString TitanicEngine::generateSaveName(int slot) { return CString::format("%s.%03d", _targetName.c_str(), slot); } +CString TitanicEngine::getSavegameName(int slot) { + // Try and open up the savegame for access + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading( + generateSaveName(slot)); + + if (in) { + // Read in the savegame header data + CompressedFile file; + file.open(in); + + TitanicSavegameHeader header; + bool isValid = CProjectItem::readSavegameHeader(&file, header); + if (header._thumbnail) { + header._thumbnail->free(); + delete header._thumbnail; + } + + file.close(); + + if (isValid) + // Set the name text + return header._saveName; + } + + return CString(); +} + } // End of namespace Titanic diff --git a/engines/titanic/titanic.h b/engines/titanic/titanic.h index dd289714c9..ec015551b8 100644 --- a/engines/titanic/titanic.h +++ b/engines/titanic/titanic.h @@ -70,6 +70,8 @@ enum TitanicDebugChannels { #define TOTAL_ITEMS 46 #define TOTAL_ROOMS 34 +#define MAX_SAVES 99 + struct TitanicGameDescription; class TitanicEngine; @@ -159,6 +161,12 @@ public: * @param slot Slot number */ CString generateSaveName(int slot); + + /** + * Checks whether a savegame exists for the given slot, + * and if it exists, returns it's description + */ + CString getSavegameName(int slot); }; extern TitanicEngine *g_vm; diff --git a/engines/titanic/true_talk/tt_npc_script.cpp b/engines/titanic/true_talk/tt_npc_script.cpp index 70953914fa..8cce90ebff 100644 --- a/engines/titanic/true_talk/tt_npc_script.cpp +++ b/engines/titanic/true_talk/tt_npc_script.cpp @@ -416,7 +416,7 @@ void TTnpcScript::loadBody(SimpleFile *file) { for (uint idx = 0; idx < _ranges.size(); ++idx) { TTscriptRange &item = _ranges[idx]; - if (item._id == id) { + if (item._id == (uint)id) { item._priorIndex = val; break; } -- cgit v1.2.3