aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk/riven_card.cpp
diff options
context:
space:
mode:
authorBastien Bouclet2017-08-11 19:05:28 +0200
committerBastien Bouclet2017-08-11 19:05:55 +0200
commitee588a8c33b3f75c9ee64ca28ef5010e292b2458 (patch)
treed2061c30bc238291d9144f36be3bf53a634e6f43 /engines/mohawk/riven_card.cpp
parentc28d246cb0d8ad7773eef8008fd18dae53abbdbf (diff)
downloadscummvm-rg350-ee588a8c33b3f75c9ee64ca28ef5010e292b2458.tar.gz
scummvm-rg350-ee588a8c33b3f75c9ee64ca28ef5010e292b2458.tar.bz2
scummvm-rg350-ee588a8c33b3f75c9ee64ca28ef5010e292b2458.zip
MOHAWK: Riven: Patch an invalid card change when entering Gehn's office
Fixes #10118.
Diffstat (limited to 'engines/mohawk/riven_card.cpp')
-rw-r--r--engines/mohawk/riven_card.cpp115
1 files changed, 107 insertions, 8 deletions
diff --git a/engines/mohawk/riven_card.cpp b/engines/mohawk/riven_card.cpp
index 3aab79d82f..feea22a663 100644
--- a/engines/mohawk/riven_card.cpp
+++ b/engines/mohawk/riven_card.cpp
@@ -130,13 +130,7 @@ void RivenCard::applyPatches(uint16 id) {
forwardEnabled.index
};
- // Script data is expected to be in big endian
- for (uint i = 0; i < ARRAYSIZE(patchData); i++) {
- patchData[i] = TO_BE_16(patchData[i]);
- }
-
- Common::MemoryReadStream patchStream((const byte *)(patchData), ARRAYSIZE(patchData) * sizeof(uint16));
- RivenScriptPtr patchScript = _vm->_scriptMan->readScript(&patchStream);
+ RivenScriptPtr patchScript = _vm->_scriptMan->readScriptFromData(patchData, ARRAYSIZE(patchData));
// Append the patch to the existing script
RivenScriptPtr loadScript = getScript(kCardLoadScript);
@@ -145,6 +139,111 @@ void RivenCard::applyPatches(uint16 id) {
debugC(kRivenDebugPatches, "Applied fix always enabled forward hotspot in card %x", globalId);
}
+ // In Gehn's office, after having encountered him once before and coming back
+ // with the trap book, the draw update script of card 1 tries to switch to
+ // card 2 while still loading card 1. Switching cards is not allowed during
+ // draw update scripts, resulting in an use after free crash.
+ //
+ // Here we backport the fix that has been made in the DVD version to the CD version.
+ //
+ // Script before patch:
+ // == Script 1 ==
+ // type: CardUpdate
+ // switch (agehn) {
+ // case 1:
+ // switch (atrapbook) {
+ // case 1:
+ // obutton = 1;
+ // transition(16);
+ // switchCard(2);
+ // break;
+ // }
+ // break;
+ // case 2:
+ // activatePLST(5);
+ // break;
+ // case 3:
+ // activatePLST(5);
+ // break;
+ // }
+ //
+ //
+ // Script after patch:
+ // == Script 1 ==
+ // type: CardUpdate
+ // switch (agehn) {
+ // case 1:
+ // switch (atrapbook) {
+ // case 1:
+ // obutton = 1;
+ // activatePLST(6);
+ // break;
+ // }
+ // break;
+ // case 2:
+ // activatePLST(5);
+ // break;
+ // case 3:
+ // activatePLST(5);
+ // break;
+ // }
+ //
+ // == Script 2 ==
+ // type: CardEnter
+ // switch (agehn) {
+ // case 1:
+ // switch (atrapbook) {
+ // case 1:
+ // transition(16);
+ // switchCard(2);
+ // break;
+ // }
+ // break;
+ // }
+ if (globalId == 0x2E76 && !(_vm->getFeatures() & GF_DVD)) {
+ uint16 aGehnVariable = _vm->getStack()->getIdFromName(kVariableNames, "agehn");
+ uint16 aTrapBookVariable = _vm->getStack()->getIdFromName(kVariableNames, "atrapbook");
+ uint16 patchData[] = {
+ 1, // Command count in script
+ kRivenCommandSwitch,
+ 2, // Unused
+ aGehnVariable,
+ 1, // Branches count
+
+ 1, // agehn == 1 branch
+ 1, // Command count in sub-script
+ kRivenCommandSwitch,
+ 2, // Unused
+ aTrapBookVariable,
+ 1, // Branches count
+
+ 1, // atrapbook == 1 branch
+ 2, // Command count in sub-script
+ kRivenCommandTransition,
+ 1, // Argument count
+ kRivenTransitionBlend,
+ kRivenCommandChangeCard,
+ 1, // Argument count
+ 2 // Card id
+ };
+
+ // Add the new script to the list
+ RivenTypedScript patchScript;
+ patchScript.type = kCardEnterScript;
+ patchScript.script = _vm->_scriptMan->readScriptFromData(patchData, ARRAYSIZE(patchData));
+ _scripts.push_back(patchScript);
+
+ // Add a black picture to the card's list to be able to use it in the second part of the patch
+ Picture blackPicture;
+ blackPicture.index = 6;
+ blackPicture.id = 117;
+ blackPicture.rect = Common::Rect(608, 392);
+ _pictureList.push_back(blackPicture);
+
+ debugC(kRivenDebugPatches, "Applied invalid card change during screen update (1/2) to card %x", globalId);
+ // The second part of this patch is in the script patches
+ }
+
// Apply script patches
for (uint i = 0; i < _scripts.size(); i++) {
_scripts[i].script->applyCardPatches(_vm, globalId, _scripts[i].type, 0xFFFF);
@@ -698,7 +797,7 @@ RivenScriptPtr RivenCard::onKeyAction(RivenKeyAction keyAction) {
static const char *upNames [] = { "up", nullptr };
static const char *downNames [] = { "down", nullptr };
- static const char **hotspotNames;
+ const char **hotspotNames = nullptr;
switch (keyAction) {
case kKeyActionMoveForward:
hotspotNames = forwardNames;