diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 9307081254b5..7a8119f7622a 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -72,8 +72,6 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio DebugMan.addDebugChannel(kRivenDebugScript, "Script", "Track Script Execution"); - removeTimer(); - // NOTE: We can never really support CD swapping. All of the music files // (*_Sounds.mhk) are stored on disc 1. They are copied to the hard drive // during install and used from there. The same goes for the extras.mhk @@ -195,7 +193,6 @@ Common::Error MohawkEngine_Riven::run() { void MohawkEngine_Riven::doFrame() { // Update background running things - checkTimer(); _sound->updateSLST(); _video->updateMovies(); @@ -425,7 +422,7 @@ void MohawkEngine_Riven::changeToCard(uint16 dest) { void MohawkEngine_Riven::refreshCard() { // Clear any timer still floating around - removeTimer(); + _stack->removeTimer(); _card->enter(true); @@ -471,27 +468,6 @@ Common::Error MohawkEngine_Riven::saveGameState(int slot, const Common::String & return _saveLoad->saveGame(slot, desc); } -void MohawkEngine_Riven::installTimer(TimerProc *proc, uint32 time) { - removeTimer(); - _timerProc = Common::SharedPtr(proc); - _timerTime = time + getTotalPlayTime(); -} - -void MohawkEngine_Riven::checkTimer() { - if (!_timerProc) - return; - - // NOTE: If the specified timer function is called, it is its job to remove the timer! - if (getTotalPlayTime() >= _timerTime) { - (*_timerProc)(); - } -} - -void MohawkEngine_Riven::removeTimer() { - _timerProc.reset(); - _timerTime = 0; -} - void MohawkEngine_Riven::addZipVisitedCard(uint16 cardId, uint16 cardNameId) { Common::String cardName = getStack()->getName(kCardNames, cardNameId); if (cardName.empty()) diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index 32863d6ecff1..f74d1c706b13 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -99,11 +99,6 @@ class MohawkEngine_Riven : public MohawkEngine { Common::Error saveGameState(int slot, const Common::String &desc); bool hasFeature(EngineFeature f) const; - typedef Common::Functor0 TimerProc; - -#define TIMER(cls, method) \ - new Common::Functor0Mem(this, &cls::method) - void doFrame(); private: @@ -123,10 +118,6 @@ class MohawkEngine_Riven : public MohawkEngine { // Variables void initVars(); - // Timer - Common::SharedPtr _timerProc; - uint32 _timerTime; - void pauseEngineIntern(bool) override; public: // Stack/card/script funtions @@ -153,11 +144,6 @@ class MohawkEngine_Riven : public MohawkEngine { bool _activatedSLST; void runLoadDialog(); void delay(uint32 ms); - - // Timer - void installTimer(TimerProc *proc, uint32 time); - void checkTimer(); - void removeTimer(); }; } // End of namespace Mohawk diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index 8c5cab17f46b..a9b64d6ce718 100644 --- a/engines/mohawk/riven_scripts.cpp +++ b/engines/mohawk/riven_scripts.cpp @@ -817,4 +817,19 @@ void RivenStackChangeCommand::dump(byte tabs) { debugN("changeStack(%d, %d);\n", _stackId, _cardId); } +RivenTimerCommand::RivenTimerCommand(MohawkEngine_Riven *vm, const Common::SharedPtr &timerProc) : + RivenCommand(vm), + _timerProc(timerProc) { + +} + +void RivenTimerCommand::execute() { + (*_timerProc)(); +} + +void RivenTimerCommand::dump(byte tabs) { + printTabs(tabs); + debugN("doTimer();\n"); +} + } // End of namespace Mohawk diff --git a/engines/mohawk/riven_scripts.h b/engines/mohawk/riven_scripts.h index cac01fbcead5..37bdc062d446 100644 --- a/engines/mohawk/riven_scripts.h +++ b/engines/mohawk/riven_scripts.h @@ -23,6 +23,8 @@ #ifndef RIVEN_SCRIPTS_H #define RIVEN_SCRIPTS_H +#include "mohawk/riven_stack.h" + #include "common/str-array.h" #include "common/ptr.h" #include "common/textconsole.h" @@ -91,6 +93,7 @@ enum RivenCommandType { class MohawkEngine_Riven; class RivenCommand; class RivenScript; +class RivenScriptManager; struct MLSTRecord; typedef Common::SharedPtr RivenScriptPtr; @@ -362,6 +365,18 @@ class RivenStackChangeCommand : public RivenCommand { bool _byStackId; // Otherwise by stack name id }; +class RivenTimerCommand : public RivenCommand { +public: + RivenTimerCommand(MohawkEngine_Riven *vm, const Common::SharedPtr &timerProc); + + // RivenCommand API + virtual void dump(byte tabs) override; + virtual void execute() override; + +private: + Common::SharedPtr _timerProc; +}; + } // End of namespace Mohawk #undef DECLARE_OPCODE diff --git a/engines/mohawk/riven_stack.cpp b/engines/mohawk/riven_stack.cpp index 03426193144a..6fbfa544f5f1 100644 --- a/engines/mohawk/riven_stack.cpp +++ b/engines/mohawk/riven_stack.cpp @@ -40,6 +40,8 @@ RivenStack::RivenStack(MohawkEngine_Riven *vm, uint16 id) : _id(id), _mouseIsDown(false), _keyPressed(Common::KEYCODE_INVALID) { + removeTimer(); + loadResourceNames(); loadCardIdMap(); setCurrentStackVariable(); @@ -282,6 +284,8 @@ void RivenStack::onFrame() { return; } + checkTimer(); + _vm->_gfx->updateEffects(); RivenScriptPtr script(new RivenScript()); @@ -315,6 +319,33 @@ Common::Point RivenStack::getMouseDragStartPosition() const { return _mouseDragStartPosition; } +void RivenStack::installTimer(TimerProc *proc, uint32 time) { + removeTimer(); + _timerProc = Common::SharedPtr(proc); + _timerTime = time + _vm->getTotalPlayTime(); +} + +void RivenStack::checkTimer() { + if (!_timerProc) { + return; + } + + // NOTE: If the specified timer function is called, it is its job to remove the timer! + + // Timers are queued as script commands so that they don't run when the doFrame method + // is called from an inner game loop. + if (_vm->getTotalPlayTime() >= _timerTime) { + RivenScriptPtr script = _vm->_scriptMan->createScriptWithCommand( + new RivenTimerCommand(_vm, _timerProc)); + _vm->_scriptMan->runScript(script, true); + } +} + +void RivenStack::removeTimer() { + _timerProc.reset(); + _timerTime = 0; +} + RivenNameList::RivenNameList() { } diff --git a/engines/mohawk/riven_stack.h b/engines/mohawk/riven_stack.h index a70faf3fc250..96bd07b04c2c 100644 --- a/engines/mohawk/riven_stack.h +++ b/engines/mohawk/riven_stack.h @@ -81,6 +81,8 @@ class RivenStack { RivenStack(MohawkEngine_Riven *vm, uint16 id); virtual ~RivenStack(); + typedef Common::Functor0 TimerProc; + /** Get the id of the stack */ uint16 getId() const; @@ -112,6 +114,9 @@ class RivenStack { /** Install a timer for the current card if one is defined */ virtual void installCardTimer(); + /** Clear any currently installed timer */ + void removeTimer(); + /** Handle a mouse down event */ void onMouseDown(const Common::Point &mouse); @@ -162,6 +167,9 @@ class RivenStack { /** Register an external command for use by the scripts */ void registerCommand(const Common::String &name, ExternalCommand *command); + /** Register a proc for planned execution */ + void installTimer(TimerProc *proc, uint32 time); + private: typedef Common::HashMap, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> CommandsMap; @@ -170,9 +178,13 @@ class RivenStack { #method, new Common::Functor2Mem(this, &cls::method) \ ) +#define TIMER(cls, method) \ + new Common::Functor0Mem(this, &cls::method) + void loadResourceNames(); void loadCardIdMap(); void setCurrentStackVariable(); + void checkTimer(); uint16 _id; @@ -192,6 +204,10 @@ class RivenStack { bool _mouseIsDown; Common::Point _mousePosition; Common::Point _mouseDragStartPosition; + + // Timer + Common::SharedPtr _timerProc; + uint32 _timerTime; }; namespace RivenStacks { diff --git a/engines/mohawk/riven_stacks/bspit.cpp b/engines/mohawk/riven_stacks/bspit.cpp index 1676eb014777..53d0330880b9 100644 --- a/engines/mohawk/riven_stacks/bspit.cpp +++ b/engines/mohawk/riven_stacks/bspit.cpp @@ -282,7 +282,7 @@ void BSpit::xbupdateboiler(uint16 argc, uint16 *argv) { void BSpit::ytramTrapTimer() { // Remove this timer - _vm->removeTimer(); + removeTimer(); // Check if we've caught a Ytram checkYtramCatch(true); @@ -296,7 +296,7 @@ void BSpit::xbsettrap(uint16 argc, uint16 *argv) { _vm->_vars["bytramtime"] = timeUntilCatch + _vm->getTotalPlayTime(); // And set the timer too - _vm->installTimer(TIMER(BSpit, ytramTrapTimer), timeUntilCatch); + installTimer(TIMER(BSpit, ytramTrapTimer), timeUntilCatch); } void BSpit::checkYtramCatch(bool playSound) { @@ -307,7 +307,7 @@ void BSpit::checkYtramCatch(bool playSound) { // If the trap still has not gone off, reinstall our timer // This is in case you set the trap, walked away, and returned if (_vm->getTotalPlayTime() < ytramTime) { - _vm->installTimer(TIMER(BSpit, ytramTrapTimer), ytramTime - _vm->getTotalPlayTime()); + installTimer(TIMER(BSpit, ytramTrapTimer), ytramTime - _vm->getTotalPlayTime()); return; } diff --git a/engines/mohawk/riven_stacks/gspit.cpp b/engines/mohawk/riven_stacks/gspit.cpp index 50d3aa34a426..305ea677c95b 100644 --- a/engines/mohawk/riven_stacks/gspit.cpp +++ b/engines/mohawk/riven_stacks/gspit.cpp @@ -425,7 +425,7 @@ void GSpit::catherineViewerIdleTimer() { video->play(); // Reset the timer - _vm->installTimer(TIMER(GSpit, catherineViewerIdleTimer), video->getDuration() + _vm->_rnd->getRandomNumber(60) * 1000); + installTimer(TIMER(GSpit, catherineViewerIdleTimer), video->getDuration() + _vm->_rnd->getRandomNumber(60) * 1000); } void GSpit::xglview_prisonon(uint16 argc, uint16 *argv) { @@ -473,7 +473,7 @@ void GSpit::xglview_prisonon(uint16 argc, uint16 *argv) { } // Create the timer for the next video - _vm->installTimer(TIMER(GSpit, catherineViewerIdleTimer), timeUntilNextMovie); + installTimer(TIMER(GSpit, catherineViewerIdleTimer), timeUntilNextMovie); } void GSpit::xglview_prisonoff(uint16 argc, uint16 *argv) { @@ -483,7 +483,7 @@ void GSpit::xglview_prisonoff(uint16 argc, uint16 *argv) { _vm->_vars["glview"] = 0; // Remove the timer we set in xglview_prisonon() - _vm->removeTimer(); + removeTimer(); // Play the 'turn off' movie after stopping any videos still playing _vm->_video->closeVideos(); diff --git a/engines/mohawk/riven_stacks/jspit.cpp b/engines/mohawk/riven_stacks/jspit.cpp index 31968dd28b07..216fdd5745b6 100644 --- a/engines/mohawk/riven_stacks/jspit.cpp +++ b/engines/mohawk/riven_stacks/jspit.cpp @@ -570,7 +570,7 @@ void JSpit::sunnersPlayVideo(RivenVideo *video, uint32 destCardGlobalId, bool su void JSpit::sunnersTopStairsTimer() { // If the sunners are gone, we have no video to play if (_vm->_vars["jsunners"] != 0) { - _vm->removeTimer(); + removeTimer(); return; } @@ -595,13 +595,13 @@ void JSpit::sunnersTopStairsTimer() { sunnerTime = timerTime + _vm->getTotalPlayTime(); } - _vm->installTimer(TIMER(JSpit, sunnersTopStairsTimer), timerTime); + installTimer(TIMER(JSpit, sunnersTopStairsTimer), timerTime); } void JSpit::sunnersMidStairsTimer() { // If the sunners are gone, we have no video to play if (_vm->_vars["jsunners"] != 0) { - _vm->removeTimer(); + removeTimer(); return; } @@ -634,13 +634,13 @@ void JSpit::sunnersMidStairsTimer() { sunnerTime = timerTime + _vm->getTotalPlayTime(); } - _vm->installTimer(TIMER(JSpit, sunnersMidStairsTimer), timerTime); + installTimer(TIMER(JSpit, sunnersMidStairsTimer), timerTime); } void JSpit::sunnersLowerStairsTimer() { // If the sunners are gone, we have no video to play if (_vm->_vars["jsunners"] != 0) { - _vm->removeTimer(); + removeTimer(); return; } @@ -665,13 +665,13 @@ void JSpit::sunnersLowerStairsTimer() { sunnerTime = timerTime + _vm->getTotalPlayTime(); } - _vm->installTimer(TIMER(JSpit, sunnersLowerStairsTimer), timerTime); + installTimer(TIMER(JSpit, sunnersLowerStairsTimer), timerTime); } void JSpit::sunnersBeachTimer() { // If the sunners are gone, we have no video to play if (_vm->_vars["jsunners"] != 0) { - _vm->removeTimer(); + removeTimer(); return; } @@ -700,7 +700,7 @@ void JSpit::sunnersBeachTimer() { sunnerTime = timerTime + _vm->getTotalPlayTime(); } - _vm->installTimer(TIMER(JSpit, sunnersBeachTimer), timerTime); + installTimer(TIMER(JSpit, sunnersBeachTimer), timerTime); } void JSpit::xjschool280_resetleft(uint16 argc, uint16 *argv) { @@ -786,16 +786,16 @@ void JSpit::xjatboundary(uint16 argc, uint16 *argv) { void JSpit::installCardTimer() { switch (getCurrentCardGlobalId()) { case 0x77d6: // Sunners, top of stairs - _vm->installTimer(TIMER(JSpit, sunnersTopStairsTimer), 500); + installTimer(TIMER(JSpit, sunnersTopStairsTimer), 500); break; case 0x79bd: // Sunners, middle of stairs - _vm->installTimer(TIMER(JSpit, sunnersMidStairsTimer), 500); + installTimer(TIMER(JSpit, sunnersMidStairsTimer), 500); break; case 0x7beb: // Sunners, bottom of stairs - _vm->installTimer(TIMER(JSpit, sunnersLowerStairsTimer), 500); + installTimer(TIMER(JSpit, sunnersLowerStairsTimer), 500); break; case 0xb6ca: // Sunners, shoreline - _vm->installTimer(TIMER(JSpit, sunnersBeachTimer), 500); + installTimer(TIMER(JSpit, sunnersBeachTimer), 500); break; default: RivenStack::installCardTimer(); diff --git a/engines/mohawk/riven_stacks/pspit.cpp b/engines/mohawk/riven_stacks/pspit.cpp index 6fb5478aefa1..4281e7980e40 100644 --- a/engines/mohawk/riven_stacks/pspit.cpp +++ b/engines/mohawk/riven_stacks/pspit.cpp @@ -80,7 +80,7 @@ void PSpit::catherineIdleTimer() { _vm->_vars["pcathtime"] = timeUntilNextMovie + _vm->getTotalPlayTime(); - _vm->installTimer(TIMER(PSpit, catherineIdleTimer), timeUntilNextMovie); + installTimer(TIMER(PSpit, catherineIdleTimer), timeUntilNextMovie); } void PSpit::xpisland990_elevcombo(uint16 argc, uint16 *argv) { @@ -131,7 +131,7 @@ void PSpit::installCardTimer() { if (getCurrentCardGlobalId() == 0x3a85) { // Top of elevator on prison island // Handle Catherine hardcoded videos - _vm->installTimer(TIMER(PSpit, catherineIdleTimer), _vm->_rnd->getRandomNumberRng(1, 33) * 1000); + installTimer(TIMER(PSpit, catherineIdleTimer), _vm->_rnd->getRandomNumberRng(1, 33) * 1000); } else { RivenStack::installCardTimer(); } diff --git a/engines/mohawk/riven_stacks/rspit.cpp b/engines/mohawk/riven_stacks/rspit.cpp index bfb305e41591..f99b7f4f39f1 100644 --- a/engines/mohawk/riven_stacks/rspit.cpp +++ b/engines/mohawk/riven_stacks/rspit.cpp @@ -76,7 +76,7 @@ void RSpit::rebelPrisonWindowTimer() { _vm->_vars["rvillagetime"] = timeUntilNextVideo + _vm->getTotalPlayTime(); // Reinstall this timer with the new time - _vm->installTimer(TIMER(RSpit, rebelPrisonWindowTimer), timeUntilNextVideo); + installTimer(TIMER(RSpit, rebelPrisonWindowTimer), timeUntilNextVideo); } void RSpit::xrwindowsetup(uint16 argc, uint16 *argv) { @@ -86,7 +86,7 @@ void RSpit::xrwindowsetup(uint16 argc, uint16 *argv) { // If we have time leftover from a previous run, set up the timer again if (_vm->getTotalPlayTime() < villageTime) { - _vm->installTimer(TIMER(RSpit, rebelPrisonWindowTimer), villageTime - _vm->getTotalPlayTime()); + installTimer(TIMER(RSpit, rebelPrisonWindowTimer), villageTime - _vm->getTotalPlayTime()); return; } @@ -109,7 +109,7 @@ void RSpit::xrwindowsetup(uint16 argc, uint16 *argv) { // the timer to reinstall itself... // Install our timer and we're on our way - _vm->installTimer(TIMER(RSpit, rebelPrisonWindowTimer), timeUntilNextVideo); + installTimer(TIMER(RSpit, rebelPrisonWindowTimer), timeUntilNextVideo); }