diff options
Diffstat (limited to 'engines/mohawk')
-rw-r--r-- | engines/mohawk/riven.cpp | 1 | ||||
-rw-r--r-- | engines/mohawk/riven.h | 3 | ||||
-rw-r--r-- | engines/mohawk/riven_card.cpp | 6 | ||||
-rw-r--r-- | engines/mohawk/riven_scripts.cpp | 69 | ||||
-rw-r--r-- | engines/mohawk/riven_scripts.h | 23 |
5 files changed, 98 insertions, 4 deletions
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 21cc701255..495f399de7 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -72,6 +72,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio _inventory = nullptr; DebugMan.addDebugChannel(kRivenDebugScript, "Script", "Track Script Execution"); + DebugMan.addDebugChannel(kRivenDebugPatches, "Patches", "Track Script Patching"); // 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 diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index 0bd6fc66c9..608ebddb84 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -65,7 +65,8 @@ enum { // Engine Debug Flags enum { - kRivenDebugScript = (1 << 0) + kRivenDebugScript = (1 << 0), + kRivenDebugPatches = (1 << 1) }; struct ZipMode { diff --git a/engines/mohawk/riven_card.cpp b/engines/mohawk/riven_card.cpp index 1d08cf51ac..ed3f739cb7 100644 --- a/engines/mohawk/riven_card.cpp +++ b/engines/mohawk/riven_card.cpp @@ -63,6 +63,12 @@ void RivenCard::loadCardResource(uint16 id) { _zipModePlace = inStream->readUint16BE(); _scripts = _vm->_scriptMan->readScripts(inStream); + // Apply script patches for this card + uint32 globalId = _vm->getStack()->getCardGlobalId(id); + for (uint i = 0; i < _scripts.size(); i++) { + _scripts[i].script->applyCardPatches(_vm, globalId, _scripts[i].type); + } + delete inStream; } diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index f9da8a11f9..3086b681c5 100644 --- a/engines/mohawk/riven_scripts.cpp +++ b/engines/mohawk/riven_scripts.cpp @@ -249,6 +249,53 @@ const char *RivenScript::getTypeName(uint16 type) { return names[type]; } +void RivenScript::applyCardPatches(MohawkEngine_Riven *vm, uint32 cardGlobalId, int scriptType) { + bool shouldApplyPatches = false; + + // On Prison Island when pressing the dome viewer switch to close the dome, + // the game schedules an ambient sound change using kRivenCommandStoreMovieOpcode + // but does not play the associated video in a blocking way. The stored opcode + // is not immediately used, stays in memory and may be triggered by some + // other action. (Bug #9958) + // We replace kRivenCommandStoreMovieOpcode by kRivenCommandActivateSLST + // to make the ambient sound change happen immediately. + // + // Script before patch: + // playMovieBlocking(3); // Dome closing + // playMovie(4); // Dome spinning up + // activatePLST(2); // Dome closed + // playMovieBlocking(4); // Dome spinning up + // storeMovieOpcode(1, 0, 0, 40, 2); // Schedule ambient sound change to "dome spinning" + // after movie 1 finishes blocking playback + // playMovie(1); // Dome spinning + // + // Script after patch: + // playMovieBlocking(3); // Dome closing + // playMovie(4); // Dome spinning up + // activatePLST(2); // Dome closed + // playMovieBlocking(4); // Dome spinning up + // activateSLST(2); // Ambient sound change to "dome spinning" + // playMovie(1); // Dome spinning + if (cardGlobalId == 0x1AC1 && scriptType == kCardEnterScript) { + shouldApplyPatches = true; + for (uint i = 0; i < _commands.size(); i++) { + if (_commands[i]->getType() == kRivenCommandStoreMovieOpcode) { + RivenSimpleCommand::ArgumentArray arguments; + arguments.push_back(2); + _commands[i] = RivenCommandPtr(new RivenSimpleCommand(vm, kRivenCommandActivateSLST, arguments)); + debugC(kRivenDebugPatches, "Applied immediate ambient sound patch to card %x", cardGlobalId); + break; + } + } + } + + if (shouldApplyPatches) { + for (uint i = 0; i < _commands.size(); i++) { + _commands[i]->applyCardPatches(cardGlobalId, scriptType); + } + } +} + RivenScriptPtr &operator+=(RivenScriptPtr &lhs, const RivenScriptPtr &rhs) { if (rhs) { *lhs += *rhs; @@ -691,6 +738,10 @@ void RivenSimpleCommand::execute() { (this->*(_opcodes[_type].proc)) (_type, _arguments); } +RivenCommandType RivenSimpleCommand::getType() const { + return _type; +} + RivenSwitchCommand::RivenSwitchCommand(MohawkEngine_Riven *vm) : RivenCommand(vm), _variableId(0) { @@ -768,6 +819,16 @@ void RivenSwitchCommand::execute() { } } +RivenCommandType RivenSwitchCommand::getType() const { + return kRivenCommandSwitch; +} + +void RivenSwitchCommand::applyCardPatches(uint32 globalId, int scriptType) { + for (uint i = 0; i < _branches.size(); i++) { + _branches[i].script->applyCardPatches(_vm, globalId, scriptType); + } +} + RivenStackChangeCommand::RivenStackChangeCommand(MohawkEngine_Riven *vm, uint16 stackId, uint32 globalCardId, bool byStackId) : RivenCommand(vm), _stackId(stackId), @@ -813,6 +874,10 @@ void RivenStackChangeCommand::dump(byte tabs) { debugN("changeStack(%d, %d);\n", _stackId, _cardId); } +RivenCommandType RivenStackChangeCommand::getType() const { + return kRivenCommandChangeStack; +} + RivenTimerCommand::RivenTimerCommand(MohawkEngine_Riven *vm, const Common::SharedPtr<RivenStack::TimerProc> &timerProc) : RivenCommand(vm), _timerProc(timerProc) { @@ -828,4 +893,8 @@ void RivenTimerCommand::dump(byte tabs) { debugN("doTimer();\n"); } +RivenCommandType RivenTimerCommand::getType() const { + return kRivenCommandTimer; +} + } // End of namespace Mohawk diff --git a/engines/mohawk/riven_scripts.h b/engines/mohawk/riven_scripts.h index d5bce5bf44..c3e95427c1 100644 --- a/engines/mohawk/riven_scripts.h +++ b/engines/mohawk/riven_scripts.h @@ -87,7 +87,8 @@ enum RivenCommandType { kRivenCommandActivateBLST = 43, kRivenCommandActivateFLST = 44, kRivenCommandZipMode = 45, - kRivenCommandActivateMLST = 46 + kRivenCommandActivateMLST = 46, + kRivenCommandTimer = 1001 }; class MohawkEngine_Riven; @@ -127,6 +128,9 @@ public: /** Print script details to the standard output */ void dumpScript(byte tabs); + /** Apply patches to card script to fix bugs in the original game scripts */ + void applyCardPatches(MohawkEngine_Riven *vm, uint32 cardGlobalId, int scriptType); + /** Append the commands of the other script to this script */ RivenScript &operator+=(const RivenScript &other); @@ -249,6 +253,12 @@ public: /** Execute the command */ virtual void execute() = 0; + /** Get the command's type */ + virtual RivenCommandType getType() const = 0; + + /** Apply card patches for the command's sub-scripts */ + virtual void applyCardPatches(uint32 globalId, int scriptType) {} + protected: MohawkEngine_Riven *_vm; }; @@ -263,21 +273,24 @@ protected: class RivenSimpleCommand : public RivenCommand { public: static RivenSimpleCommand *createFromStream(MohawkEngine_Riven *vm, RivenCommandType type, Common::ReadStream *stream); + + typedef Common::Array<uint16> ArgumentArray; + + RivenSimpleCommand(MohawkEngine_Riven *vm, RivenCommandType type, const ArgumentArray &arguments); virtual ~RivenSimpleCommand(); // RivenCommand API virtual void dump(byte tabs) override; virtual void execute() override; + virtual RivenCommandType getType() const override; private: - typedef Common::Array<uint16> ArgumentArray; typedef void (RivenSimpleCommand::*OpcodeProcRiven)(uint16 op, const ArgumentArray &args); struct RivenOpcode { OpcodeProcRiven proc; const char *desc; }; - RivenSimpleCommand(MohawkEngine_Riven *vm, RivenCommandType type, const ArgumentArray &arguments); void setupOpcodes(); Common::String describe() const; @@ -342,6 +355,8 @@ public: // RivenCommand API virtual void dump(byte tabs) override; virtual void execute() override; + virtual RivenCommandType getType() const override; + virtual void applyCardPatches(uint32 globalId, int scriptType) override; private: RivenSwitchCommand(MohawkEngine_Riven *vm); @@ -372,6 +387,7 @@ public: // RivenCommand API virtual void dump(byte tabs) override; virtual void execute() override; + virtual RivenCommandType getType() const override; private: uint16 _stackId; @@ -392,6 +408,7 @@ public: // RivenCommand API virtual void dump(byte tabs) override; virtual void execute() override; + virtual RivenCommandType getType() const override; private: Common::SharedPtr<RivenStack::TimerProc> _timerProc; |