diff options
-rw-r--r-- | engines/sci/engine/script.cpp | 88 |
1 files changed, 73 insertions, 15 deletions
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 8ccedc0c00..34504a8041 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -139,7 +139,7 @@ const byte hoyle4SignaturePortFix[] = { 0x38, 0xbc, 0x02, // pushi 02bc 0x38, 0x20, 0x03, // pushi 0320 0x46, // calle [xxxx] [xxxx] [xx] - 43, +5, // [skip 5 bytes] + +5, 43, // [skip 5 bytes] 0x30, 0x27, 0x00, // bnt 0027 -> end of routine 0x87, 0x00, // lap 00 0x30, 0x19, 0x00, // bnt 0019 -> fade out @@ -188,6 +188,57 @@ const SciScriptSignature hoyle4Signatures[] = { { 0, NULL, 0, 0, NULL, NULL } }; + +// this is called on every death dialog. Problem is at least the german +// version of lsl6 gets title text that is far too long for the +// available temp space resulting in temp space corruption +// This patch moves the title text around, so this overflow +// doesn't happen anymore. We would otherwise get a crash +// calling for invalid views (this happens of course also +// in sierra sci) +const byte larry6SignatureDeathDialog[] = { + 7, + 0x3e, 0x33, 0x01, // link 0133 (offset 0x20) + 0x35, 0xff, // ldi ff + 0xa3, 0x00, // sal 00 + +255, 0, + +255, 0, + +170, 12, // [skip 680 bytes] + 0x8f, 0x01, // lsp 01 (offset 0x2cf) + 0x7a, // push2 + 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e + 0x36, // push + 0x43, 0x7c, 0x0e, // kMessage[7c] 0e + +90, 10, // [skip 90 bytes] + 0x38, 0xd6, 0x00, // pushi 00d6 (offset 0x335) + 0x78, // push1 + 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e + 0x36, // push + +76, 11, // [skip 76 bytes] + 0x38, 0xcd, 0x00, // pushi 00cd (offset 0x38b) + 0x39, 0x03, // pushi 03 + 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e + 0x36, + 0 +}; + +const uint16 larry6PatchDeathDialog[] = { + 0x3e, 0x00, 0x02, // link 0200 + PATCH_ADDTOOFFSET | +687, + 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140 + PATCH_ADDTOOFFSET | +98, + 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140 + PATCH_ADDTOOFFSET | +82, + 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140 + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature larry6Signatures[] = { + { 82, "death dialog memory corruption", CONSTANT_LE_32(0x3501333e), 0, larry6SignatureDeathDialog, larry6PatchDeathDialog }, + { 0, NULL, 0, 0, NULL, NULL } +}; + // will actually patch previously found signature area void Script::applyPatch(const uint16 *patch, byte *scriptData, const uint32 scriptSize, int32 signatureOffset) { int32 offset = signatureOffset; @@ -222,8 +273,9 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr uint32 offset = DWordOffset + signature->magicOffset; uint32 byteOffset = offset; const byte *signatureData = signature->data; - byte matchBytesCount = *signatureData++; - while (matchBytesCount) { + byte matchAdjust = 1; + while (matchAdjust) { + byte matchBytesCount = *signatureData++; if ((byteOffset + matchBytesCount) > scriptSize) // Out-Of-Bounds? break; if (memcmp(signatureData, &scriptData[byteOffset], matchBytesCount)) // Byte-Mismatch? @@ -231,12 +283,11 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr // those bytes matched, adjust offsets accordingly signatureData += matchBytesCount; byteOffset += matchBytesCount; - // get next byte count and offset - matchBytesCount = *signatureData++; - if (matchBytesCount) - byteOffset += *signatureData++; + // get offset... + matchAdjust = *signatureData++; + byteOffset += matchAdjust; } - if (!matchBytesCount) // all matches worked? + if (!matchAdjust) // all matches worked? return offset; } DWordOffset++; @@ -246,14 +297,21 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr } void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) { - if (g_sci->getGameId() == GID_HOYLE4) { - const SciScriptSignature *signatureTable = hoyle4Signatures; + const SciScriptSignature *signatureTable = NULL; + if (g_sci->getGameId() == GID_HOYLE4) + signatureTable = hoyle4Signatures; + if (g_sci->getGameId() == GID_LSL6) + signatureTable = larry6Signatures; + + if (signatureTable) { while (signatureTable->data) { - int32 foundOffset = findSignature(signatureTable, scriptData, scriptSize); - if (foundOffset != -1) { - // found, so apply the patch - warning("matched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset); - applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset); + if (scriptNr == signatureTable->scriptNr) { + int32 foundOffset = findSignature(signatureTable, scriptData, scriptSize); + if (foundOffset != -1) { + // found, so apply the patch + warning("matched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset); + applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset); + } } signatureTable++; } |