mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-04 09:18:38 +00:00
MOHAWK: Riven: Patch an invalid card change when entering Gehn's office
Fixes #10118.
This commit is contained in:
parent
c28d246cb0
commit
ee588a8c33
@ -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;
|
||||
|
@ -179,6 +179,16 @@ RivenScriptPtr RivenScriptManager::createScriptFromData(uint16 commandCount, ...
|
||||
return readScript(&readStream);
|
||||
}
|
||||
|
||||
RivenScriptPtr RivenScriptManager::readScriptFromData(uint16 *data, uint16 size) {
|
||||
// Script data is expected to be in big endian
|
||||
for (uint i = 0; i < size; i++) {
|
||||
data[i] = TO_BE_16(data[i]);
|
||||
}
|
||||
|
||||
Common::MemoryReadStream patchStream((const byte *)(data), size * sizeof(uint16));
|
||||
return _vm->_scriptMan->readScript(&patchStream);
|
||||
}
|
||||
|
||||
RivenScriptPtr RivenScriptManager::createScriptWithCommand(RivenCommand *command) {
|
||||
assert(command);
|
||||
|
||||
@ -312,6 +322,29 @@ void RivenScript::applyCardPatches(MohawkEngine_Riven *vm, uint32 cardGlobalId,
|
||||
debugC(kRivenDebugPatches, "Applied missing closing sound patch to card %x", cardGlobalId);
|
||||
}
|
||||
|
||||
// Second part of the patch to fix the invalid card change when entering Gehn's office
|
||||
// The first part is in the card patches.
|
||||
if (cardGlobalId == 0x2E76 && scriptType == kCardUpdateScript && !(vm->getFeatures() & GF_DVD)) {
|
||||
shouldApplyPatches = true;
|
||||
|
||||
for (uint i = 0; i < _commands.size(); i++) {
|
||||
int transitionIndex = -1;
|
||||
if (_commands[i]->getType() == kRivenCommandTransition) {
|
||||
transitionIndex = i;
|
||||
}
|
||||
if (transitionIndex >= 0) {
|
||||
_commands.remove_at(transitionIndex + 1);
|
||||
_commands.remove_at(transitionIndex);
|
||||
|
||||
RivenSimpleCommand::ArgumentArray arguments;
|
||||
arguments.push_back(6);
|
||||
_commands.push_back(RivenCommandPtr(new RivenSimpleCommand(vm, kRivenCommandActivatePLST, arguments)));
|
||||
}
|
||||
}
|
||||
|
||||
debugC(kRivenDebugPatches, "Applied invalid card change during screen update (2/2) to card %x", cardGlobalId);
|
||||
}
|
||||
|
||||
if (shouldApplyPatches) {
|
||||
for (uint i = 0; i < _commands.size(); i++) {
|
||||
_commands[i]->applyCardPatches(cardGlobalId, scriptType, hotspotId);
|
||||
|
@ -170,6 +170,14 @@ public:
|
||||
/** Read a single script from a stream */
|
||||
RivenScriptPtr readScript(Common::ReadStream *stream);
|
||||
|
||||
/**
|
||||
* Read a script from an array of uint16
|
||||
* @param data Script data array. Will be modified.
|
||||
* @param size Number of uint16 in data
|
||||
* @return
|
||||
*/
|
||||
RivenScriptPtr readScriptFromData(uint16 *data, uint16 size);
|
||||
|
||||
/** Create a script from the caller provided arguments containing raw data */
|
||||
RivenScriptPtr createScriptFromData(uint16 commandCount, ...);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user