aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mohawk/riven.cpp1
-rw-r--r--engines/mohawk/riven.h3
-rw-r--r--engines/mohawk/riven_card.cpp6
-rw-r--r--engines/mohawk/riven_scripts.cpp69
-rw-r--r--engines/mohawk/riven_scripts.h23
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;