diff options
Diffstat (limited to 'engines/sci/engine/script_patches.cpp')
-rw-r--r-- | engines/sci/engine/script_patches.cpp | 1594 |
1 files changed, 1036 insertions, 558 deletions
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 6293fb42ae..8f05cc1453 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -25,6 +25,7 @@ #include "sci/engine/script.h" #include "sci/engine/state.h" #include "sci/engine/features.h" +#include "sci/engine/script_patches.h" #include "common/util.h" @@ -76,72 +77,29 @@ namespace Sci { // You have to use the exact same order in both the table and the enum, otherwise // it won't work. -#define SIG_END 0xFFFF -#define SIG_MISMATCH 0xFFFE -#define SIG_COMMANDMASK 0xF000 -#define SIG_VALUEMASK 0x0FFF -#define SIG_BYTEMASK 0x00FF -#define SIG_MAGICDWORD 0xF000 -#define SIG_ADDTOOFFSET 0xE000 -#define SIG_SELECTOR16 0x9000 -#define SIG_SELECTOR8 0x8000 -#define SIG_UINT16 0x1000 -#define SIG_BYTE 0x0000 - -#define PATCH_END SIG_END -#define PATCH_COMMANDMASK SIG_COMMANDMASK -#define PATCH_VALUEMASK SIG_VALUEMASK -#define PATCH_BYTEMASK SIG_BYTEMASK -#define PATCH_ADDTOOFFSET SIG_ADDTOOFFSET -#define PATCH_GETORIGINALBYTE 0xD000 -#define PATCH_GETORIGINALBYTEADJUST 0xC000 -#define PATCH_SELECTOR16 SIG_SELECTOR16 -#define PATCH_SELECTOR8 SIG_SELECTOR8 -#define PATCH_UINT16 SIG_UINT16 -#define PATCH_BYTE SIG_BYTE - -// defines maximum scratch area for getting original bytes from unpatched script data -#define PATCH_VALUELIMIT 4096 - -struct SciScriptPatcherEntry { - bool active; - uint16 scriptNr; - const char *description; - int16 applyCount; - uint32 magicDWord; - int magicOffset; - const uint16 *signatureData; - const uint16 *patchData; -}; - -#define SCI_SIGNATUREENTRY_TERMINATOR { false, 0, NULL, 0, 0, 0, NULL, NULL } - -struct SciScriptPatcherSelector { - const char *name; - int16 id; -}; - -SciScriptPatcherSelector selectorTable[] = { - { "cycles", -1, }, // system selector - { "seconds", -1, }, // system selector - { "init", -1, }, // system selector - { "dispose", -1, }, // system selector - { "new", -1, }, // system selector - { "curEvent", -1, }, // system selector - { "disable", -1, }, // system selector - { "show", -1, }, // system selector - { "x", -1, }, // system selector - { "cel", -1, }, // system selector - { "setMotion", -1, }, // system selector - { "deskSarg", -1, }, // Gabriel Knight - { "localize", -1, }, // Freddy Pharkas - { "put", -1, }, // Police Quest 1 VGA - { "solvePuzzle", -1, }, // Quest For Glory 3 - { "timesShownID", -1, }, // Space Quest 1 VGA - { "startText", -1, }, // King's Quest 6 CD / Laura Bow 2 CD for audio+text support - { "startAudio", -1, }, // King's Quest 6 CD / Laura Bow 2 CD for audio+text support - { "modNum", -1, }, // King's Quest 6 CD / Laura Bow 2 CD for audio+text support - { NULL, -1 } +static const char *const selectorNameTable[] = { + "cycles", // system selector + "seconds", // system selector + "init", // system selector + "dispose", // system selector + "new", // system selector + "curEvent", // system selector + "disable", // system selector + "doit", // system selector + "show", // system selector + "x", // system selector + "cel", // system selector + "setMotion", // system selector + "overlay", // system selector + "deskSarg", // Gabriel Knight + "localize", // Freddy Pharkas + "put", // Police Quest 1 VGA + "solvePuzzle", // Quest For Glory 3 + "timesShownID", // Space Quest 1 VGA + "startText", // King's Quest 6 CD / Laura Bow 2 CD for audio+text support + "startAudio", // King's Quest 6 CD / Laura Bow 2 CD for audio+text support + "modNum", // King's Quest 6 CD / Laura Bow 2 CD for audio+text support + NULL }; enum ScriptPatcherSelectors { @@ -152,10 +110,12 @@ enum ScriptPatcherSelectors { SELECTOR_new, SELECTOR_curEvent, SELECTOR_disable, + SELECTOR_doit, SELECTOR_show, SELECTOR_x, SELECTOR_cel, SELECTOR_setMotion, + SELECTOR_overlay, SELECTOR_deskSarg, SELECTOR_localize, SELECTOR_put, @@ -186,32 +146,32 @@ enum ScriptPatcherSelectors { // We fix the script by patching in a jump to the proper code inside fawaz::doit. // Responsible method: fawaz::handleEvent // Fixes bug: #6402 -const uint16 camelotSignaturePeepingTom[] = { - 0x72, SIG_MAGICDWORD, SIG_UINT16 + 0x7e, 0x07, // lofsa fawaz <-- start of proper initializion code +static const uint16 camelotSignaturePeepingTom[] = { + 0x72, SIG_MAGICDWORD, SIG_UINT16(0x077e), // lofsa fawaz <-- start of proper initializion code 0xa1, 0xb9, // sag b9h - SIG_ADDTOOFFSET +571, // skip 571 bytes + SIG_ADDTOOFFSET(+571), // skip 571 bytes 0x39, 0x7a, // pushi 7a <-- initialization code when walking automatically 0x78, // push1 0x7a, // push2 - 0x38, SIG_UINT16 + 0xa9, 0x00, // pushi 00a9 - script 169 + 0x38, SIG_UINT16(0x00a9), // + 0xa9, 0x00, // pushi 00a9 - script 169 0x78, // push1 0x43, 0x02, 0x04, // call kScriptID 0x36, // push 0x81, 0x00, // lag 00 0x4a, 0x06, // send 06 - 0x32, SIG_UINT16 + 0x20, 0x05, // jmp [end of fawaz::handleEvent] + 0x32, SIG_UINT16(0x0520), // jmp [end of fawaz::handleEvent] SIG_END }; -const uint16 camelotPatchPeepingTom[] = { - PATCH_ADDTOOFFSET +576, - 0x32, PATCH_UINT16 + 0xbd, 0xfd, // jmp to fawaz::doit / properly init peepingTom code +static const uint16 camelotPatchPeepingTom[] = { + PATCH_ADDTOOFFSET(+576), + 0x32, PATCH_UINT16(0xfdbd), // jmp to fawaz::doit / properly init peepingTom code PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry camelotSignatures[] = { - { true, 62, "fix peepingTom Sierra bug", 1, 0, 0, camelotSignaturePeepingTom, camelotPatchPeepingTom }, +// script, description, signature patch +static const SciScriptPatcherEntry camelotSignatures[] = { + { true, 62, "fix peepingTom Sierra bug", 1, camelotSignaturePeepingTom, camelotPatchPeepingTom }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -224,7 +184,7 @@ SciScriptPatcherEntry camelotSignatures[] = { // Applies to at least: PC-CD // Responsible method: stayAndHelp::changeState // Fixes bug: #5107 -const uint16 ecoquest1SignatureStayAndHelp[] = { +static const uint16 ecoquest1SignatureStayAndHelp[] = { 0x3f, 0x01, // link 01 0x87, 0x01, // lap param[1] 0x65, 0x14, // aTop state @@ -236,12 +196,12 @@ const uint16 ecoquest1SignatureStayAndHelp[] = { 0x76, // push0 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off) SIG_MAGICDWORD, - 0x38, SIG_UINT16 + 0x22, 0x01, // pushi 0122 + 0x38, SIG_UINT16(0x0122), // pushi 0122 0x78, // push1 0x76, // push0 0x81, 0x00, // lag global[0] 0x4a, 0x06, // send 06 - call ego::setMotion(0) - 0x39, SIG_SELECTOR8 + SELECTOR_init, // pushi "init" + 0x39, SIG_SELECTOR8(init), // pushi "init" 0x39, 0x04, // pushi 04 0x76, // push0 0x76, // push0 @@ -253,34 +213,34 @@ const uint16 ecoquest1SignatureStayAndHelp[] = { SIG_END }; -const uint16 ecoquest1PatchStayAndHelp[] = { +static const uint16 ecoquest1PatchStayAndHelp[] = { 0x87, 0x01, // lap param[1] 0x65, 0x14, // aTop state 0x36, // push 0x2f, 0x22, // bt [next state] (this optimization saves 6 bytes) 0x39, 0x00, // pushi 0 (wasting 1 byte here) 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off) - 0x38, PATCH_UINT16 + 0x22, 0x01, // pushi 0122 + 0x38, PATCH_UINT16(0x0122), // pushi 0122 0x78, // push1 0x76, // push0 0x81, 0x00, // lag global[0] 0x4a, 0x06, // send 06 - call ego::setMotion(0) - 0x39, PATCH_SELECTOR8 + SELECTOR_init, // pushi "init" + 0x39, PATCH_SELECTOR8(init), // pushi "init" 0x39, 0x06, // pushi 06 0x39, 0x02, // pushi 02 (additional 2 bytes) 0x76, // push0 0x76, // push0 0x39, 0x17, // pushi 17 0x7c, // pushSelf - 0x38, PATCH_UINT16 + 0x80, 0x02, // pushi 280 (additional 3 bytes) + 0x38, PATCH_UINT16(0x0280), // pushi 280 (additional 3 bytes) 0x51, 0x82, // class EcoNarrator 0x4a, 0x10, // send 10 - call EcoNarrator::init(2, 0, 0, 23, self, 640) PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry ecoquest1Signatures[] = { - { true, 660, "CD: bad messagebox and freeze", 1, 0, 0, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp }, +// script, description, signature patch +static const SciScriptPatcherEntry ecoquest1Signatures[] = { + { true, 660, "CD: bad messagebox and freeze", 1, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -291,7 +251,7 @@ SciScriptPatcherEntry ecoquest1Signatures[] = { // is resetted every time, which means the previous text isn't available // anymore. We have to patch the code because of that. // Fixes bug: #4993 -const uint16 ecoquest2SignatureEcorder[] = { +static const uint16 ecoquest2SignatureEcorder[] = { 0x31, 0x22, // bnt [next state] 0x39, 0x0a, // pushi 0a 0x5b, 0x04, 0x1e, // lea temp[1e] @@ -303,14 +263,14 @@ const uint16 ecoquest2SignatureEcorder[] = { 0x39, 0x66, // pushi 66 0x39, 0x17, // pushi 17 0x39, 0x69, // pushi 69 - 0x38, PATCH_UINT16 + 0x31, 0x26, // pushi 2631 + 0x38, PATCH_UINT16(0x2631), // pushi 2631 0x39, 0x6a, // pushi 6a 0x39, 0x64, // pushi 64 0x43, 0x1b, 0x14, // call kDisplay 0x35, 0x0a, // ldi 0a 0x65, 0x20, // aTop ticks 0x33, // jmp [end] - SIG_ADDTOOFFSET +1, // [skip 1 byte] + SIG_ADDTOOFFSET(+1), // [skip 1 byte] 0x3c, // dup 0x35, 0x03, // ldi 03 0x1a, // eq? @@ -318,25 +278,25 @@ const uint16 ecoquest2SignatureEcorder[] = { SIG_END }; -const uint16 ecoquest2PatchEcorder[] = { +static const uint16 ecoquest2PatchEcorder[] = { 0x2f, 0x02, // bt [to pushi 07] 0x3a, // toss 0x48, // ret - 0x38, PATCH_UINT16 + 0x07, 0x00, // pushi 07 (parameter count) (waste 1 byte) + 0x38, PATCH_UINT16(0x0007), // pushi 07 (parameter count) (waste 1 byte) 0x39, 0x0b, // push (FillBoxAny) 0x39, 0x1d, // pushi 29d 0x39, 0x73, // pushi 115d 0x39, 0x5e, // pushi 94d - 0x38, PATCH_UINT16 + 0xd7, 0x00, // pushi 215d + 0x38, PATCH_UINT16(0x00d7), // pushi 215d 0x78, // push1 (visual screen) - 0x38, PATCH_UINT16 + 0x17, 0x00, // pushi 17 (color) (waste 1 byte) + 0x38, PATCH_UINT16(0x0017), // pushi 17 (color) (waste 1 byte) 0x43, 0x6c, 0x0e, // call kGraph - 0x38, PATCH_UINT16 + 0x05, 0x00, // pushi 05 (parameter count) (waste 1 byte) + 0x38, PATCH_UINT16(0x0005), // pushi 05 (parameter count) (waste 1 byte) 0x39, 0x0c, // pushi 12d (UpdateBox) 0x39, 0x1d, // pushi 29d 0x39, 0x73, // pushi 115d 0x39, 0x5e, // pushi 94d - 0x38, PATCH_UINT16 + 0xd7, 0x00, // pushi 215d + 0x38, PATCH_UINT16(0x00d7), // pushi 215d 0x43, 0x6c, 0x0a, // call kGraph PATCH_END }; @@ -347,8 +307,8 @@ const uint16 ecoquest2PatchEcorder[] = { // kGraphFillBoxAny and kGraphUpdateBox), as there isn't enough space to patch // the function otherwise. // Fixes bug: #6467 -const uint16 ecoquest2SignatureEcorderTutorial[] = { - 0x30, SIG_UINT16 + 0x23, 0x00, // bnt [next state] +static const uint16 ecoquest2SignatureEcorderTutorial[] = { + 0x30, SIG_UINT16(0x0023), // bnt [next state] 0x39, 0x0a, // pushi 0a 0x5b, 0x04, 0x1f, // lea temp[1f] 0x36, // push @@ -359,7 +319,7 @@ const uint16 ecoquest2SignatureEcorderTutorial[] = { 0x39, 0x66, // pushi 66 0x39, 0x17, // pushi 17 0x39, 0x69, // pushi 69 - 0x38, SIG_UINT16 + 0x31, 0x26, // pushi 2631 + 0x38, SIG_UINT16(0x2631), // pushi 2631 0x39, 0x6a, // pushi 6a 0x39, 0x64, // pushi 64 0x43, 0x1b, 0x14, // call kDisplay @@ -370,7 +330,7 @@ const uint16 ecoquest2SignatureEcorderTutorial[] = { SIG_END }; -const uint16 ecoquest2PatchEcorderTutorial[] = { +static const uint16 ecoquest2PatchEcorderTutorial[] = { 0x31, 0x23, // bnt [next state] (save 1 byte) // The parameter count below should be 7, but we're out of bytes // to patch! A workaround has been added because of this @@ -380,7 +340,7 @@ const uint16 ecoquest2PatchEcorderTutorial[] = { 0x39, 0x1d, // pushi 29d 0x39, 0x73, // pushi 115d 0x39, 0x5e, // pushi 94d - 0x38, PATCH_UINT16 + 0xd7, 0x00, // pushi 215d + 0x38, PATCH_UINT16(0x00d7), // pushi 215d 0x78, // push1 (visual screen) 0x39, 0x17, // pushi 17 (color) 0x43, 0x6c, 0x0e, // call kGraph @@ -392,21 +352,21 @@ const uint16 ecoquest2PatchEcorderTutorial[] = { 0x39, 0x1d, // pushi 29d 0x39, 0x73, // pushi 115d 0x39, 0x5e, // pushi 94d - 0x38, PATCH_UINT16 + 0xd7, 0x00, // pushi 215d + 0x38, PATCH_UINT16(0x00d7), // pushi 215d 0x43, 0x6c, 0x0a, // call kGraph // We are out of bytes to patch at this point, // so we skip 494 (0x1EE) bytes to reuse this code: // ldi 1e // aTop 20 // jmp 030e (jump to end) - 0x32, PATCH_UINT16 + 0xee, 0x01, // skip 494 (0x1EE) bytes + 0x32, PATCH_UINT16(0x01ee), // skip 494 (0x1EE) bytes PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry ecoquest2Signatures[] = { - { true, 50, "initial text not removed on ecorder", 1, 0, 0, ecoquest2SignatureEcorder, ecoquest2PatchEcorder }, - { true, 333, "initial text not removed on ecorder tutorial",1, 0, 0, ecoquest2SignatureEcorderTutorial, ecoquest2PatchEcorderTutorial }, +// script, description, signature patch +static const SciScriptPatcherEntry ecoquest2Signatures[] = { + { true, 50, "initial text not removed on ecorder", 1, ecoquest2SignatureEcorder, ecoquest2PatchEcorder }, + { true, 333, "initial text not removed on ecorder tutorial", 1, ecoquest2SignatureEcorderTutorial, ecoquest2PatchEcorderTutorial }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -416,26 +376,26 @@ SciScriptPatcherEntry ecoquest2Signatures[] = { // infinite loop. This script bug was not apparent in SSCI, probably because // event handling was slightly different there, so it was never discovered. // Fixes bug: #5120 -const uint16 fanmadeSignatureInfiniteLoop[] = { - 0x38, SIG_UINT16 + 0x4c, 0x00, // pushi 004c +static const uint16 fanmadeSignatureInfiniteLoop[] = { + 0x38, SIG_UINT16(0x004c), // pushi 004c 0x39, 0x00, // pushi 00 0x87, 0x01, // lap 01 0x4b, 0x04, // send 04 SIG_MAGICDWORD, 0x18, // not - 0x30, SIG_UINT16 + 0x2f, 0x00, // bnt 002f [06a5] --> jmp ffbc [0664] --> BUG! infinite loop + 0x30, SIG_UINT16(0x002f), // bnt 002f [06a5] --> jmp ffbc [0664] --> BUG! infinite loop SIG_END }; -const uint16 fanmadePatchInfiniteLoop[] = { - PATCH_ADDTOOFFSET | +10, - 0x30, SIG_UINT16 + 0x32, 0x00, // bnt 0032 [06a8] --> pushi 004c +static const uint16 fanmadePatchInfiniteLoop[] = { + PATCH_ADDTOOFFSET(+10), + 0x30, SIG_UINT16(0x0032), // bnt 0032 [06a8] --> pushi 004c PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry fanmadeSignatures[] = { - { true, 999, "infinite loop on typo", 1, 0, 0, fanmadeSignatureInfiniteLoop, fanmadePatchInfiniteLoop }, +// script, description, signature patch +static const SciScriptPatcherEntry fanmadeSignatures[] = { + { true, 999, "infinite loop on typo", 1, fanmadeSignatureInfiniteLoop, fanmadePatchInfiniteLoop }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -449,7 +409,7 @@ SciScriptPatcherEntry fanmadeSignatures[] = { // The "score" code is already buggy and sets volume to 0 when playing // Applies to at least: English PC-CD // Responsible method: unknown -const uint16 freddypharkasSignatureScoreDisposal[] = { +static const uint16 freddypharkasSignatureScoreDisposal[] = { 0x67, 0x32, // pTos 32 (selector theAudCount) 0x78, // push1 SIG_MAGICDWORD, @@ -460,10 +420,10 @@ const uint16 freddypharkasSignatureScoreDisposal[] = { SIG_END }; -const uint16 freddypharkasPatchScoreDisposal[] = { - 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0000 - 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0000 - 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0000 +static const uint16 freddypharkasPatchScoreDisposal[] = { + 0x34, PATCH_UINT16(0x0000), // ldi 0000 + 0x34, PATCH_UINT16(0x0000), // ldi 0000 + 0x34, PATCH_UINT16(0x0000), // ldi 0000 PATCH_END }; @@ -475,8 +435,8 @@ const uint16 freddypharkasPatchScoreDisposal[] = { // this fixes the issue. // Applies to at least: English PC-CD // Responsible method: rm235::init and sEnterFrom500::changeState -const uint16 freddypharkasSignatureCanisterHang[] = { - 0x38, SIG_SELECTOR16 + SELECTOR_disable, // pushi disable +static const uint16 freddypharkasSignatureCanisterHang[] = { + 0x38, SIG_SELECTOR16(disable), // pushi disable 0x7a, // push2 SIG_MAGICDWORD, 0x39, 0x07, // pushi 07 @@ -486,12 +446,12 @@ const uint16 freddypharkasSignatureCanisterHang[] = { SIG_END }; -const uint16 freddypharkasPatchCanisterHang[] = { - PATCH_ADDTOOFFSET | +3, +static const uint16 freddypharkasPatchCanisterHang[] = { + PATCH_ADDTOOFFSET(+3), 0x78, // push1 - PATCH_ADDTOOFFSET | +2, + PATCH_ADDTOOFFSET(+2), 0x33, 0x00, // ldi 00 (waste 2 bytes) - PATCH_ADDTOOFFSET | +3, + PATCH_ADDTOOFFSET(+3), 0x06, // send 06 - call IconBar::disable(7) PATCH_END }; @@ -506,27 +466,27 @@ const uint16 freddypharkasPatchCanisterHang[] = { // We just reuse the active event, thus removing the duplicate kGetEvent call. // Applies to at least: English PC-CD, German Floppy, English Mac // Responsible method: lowerLadder::doit and highLadder::doit -const uint16 freddypharkasSignatureLadderEvent[] = { +static const uint16 freddypharkasSignatureLadderEvent[] = { 0x39, SIG_MAGICDWORD, - SIG_SELECTOR8 + SELECTOR_new, // pushi new + SIG_SELECTOR8(new), // pushi new 0x76, // push0 - 0x38, SIG_SELECTOR16 + SELECTOR_curEvent, // pushi curEvent + 0x38, SIG_SELECTOR16(curEvent), // pushi curEvent 0x76, // push0 0x81, 0x50, // lag global[50] 0x4a, 0x04, // send 04 - read User::curEvent 0x4a, 0x04, // send 04 - call curEvent::new 0xa5, 0x00, // sat temp[0] - 0x38, SIG_SELECTOR16 + SELECTOR_localize, + 0x38, SIG_SELECTOR16(localize), 0x76, // push0 0x4a, 0x04, // send 04 - call curEvent::localize SIG_END }; -const uint16 freddypharkasPatchLadderEvent[] = { +static const uint16 freddypharkasPatchLadderEvent[] = { 0x34, 0x00, 0x00, // ldi 0000 (waste 3 bytes, overwrites first 2 pushes) - PATCH_ADDTOOFFSET | +8, + PATCH_ADDTOOFFSET(+8), 0xa5, 0x00, // sat temp[0] (waste 2 bytes, overwrites 2nd send) - PATCH_ADDTOOFFSET | +2, + PATCH_ADDTOOFFSET(+2), 0x34, 0x00, 0x00, // ldi 0000 0x34, 0x00, 0x00, // ldi 0000 (waste 6 bytes, overwrites last 3 opcodes) PATCH_END @@ -537,29 +497,29 @@ const uint16 freddypharkasPatchLadderEvent[] = { // so we revert the script back to using the values of the DOS script. // Applies to at least: English Mac // Responsible method: unknown -const uint16 freddypharkasSignatureMacInventory[] = { +static const uint16 freddypharkasSignatureMacInventory[] = { SIG_MAGICDWORD, 0x39, 0x23, // pushi 23 0x39, 0x74, // pushi 74 0x78, // push1 - 0x38, SIG_UINT16 + 0x74, 0x01, // pushi 0174 (on mac it's actually 0x01, 0x74) + 0x38, SIG_UINT16(0x0174), // pushi 0174 (on mac it's actually 0x01, 0x74) 0x85, 0x15, // lat 15 SIG_END }; -const uint16 freddypharkasPatchMacInventory[] = { +static const uint16 freddypharkasPatchMacInventory[] = { 0x39, 0x02, // pushi 02 (now matches the DOS version) - PATCH_ADDTOOFFSET +23, + PATCH_ADDTOOFFSET(+23), 0x39, 0x04, // pushi 04 (now matches the DOS version) PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry freddypharkasSignatures[] = { - { true, 0, "CD: score early disposal", 1, 0, 0, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal }, - { true, 15, "Mac: broken inventory", 1, 0, 0, freddypharkasSignatureMacInventory, freddypharkasPatchMacInventory }, - { true, 235, "CD: canister pickup hang", 3, 0, 0, freddypharkasSignatureCanisterHang, freddypharkasPatchCanisterHang }, - { true, 320, "ladder event issue", 2, 0, 0, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent }, +// script, description, signature patch +static const SciScriptPatcherEntry freddypharkasSignatures[] = { + { true, 0, "CD: score early disposal", 1, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal }, + { true, 15, "Mac: broken inventory", 1, freddypharkasSignatureMacInventory, freddypharkasPatchMacInventory }, + { true, 235, "CD: canister pickup hang", 3, freddypharkasSignatureCanisterHang, freddypharkasPatchCanisterHang }, + { true, 320, "ladder event issue", 2, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -568,25 +528,25 @@ SciScriptPatcherEntry freddypharkasSignatures[] = { // this is not enough time to get to the door, so we patch that to 23 seconds // Applies to at least: English PC-CD, German PC-CD, English Mac // Responsible method: daySixBeignet::changeState -const uint16 gk1SignatureDay6PoliceBeignet[] = { +static const uint16 gk1SignatureDay6PoliceBeignet[] = { 0x35, 0x04, // ldi 04 0x1a, // eq? - 0x30, SIG_ADDTOOFFSET +2, // bnt [next state check] - 0x38, SIG_SELECTOR16 + SELECTOR_dispose, // pushi dispose + 0x30, SIG_ADDTOOFFSET(+2), // bnt [next state check] + 0x38, SIG_SELECTOR16(dispose), // pushi dispose 0x76, // push0 - 0x72, SIG_ADDTOOFFSET +2, // lofsa deskSarg - 0x4a, SIG_UINT16 + 0x04, 0x00, // send 04 + 0x72, SIG_ADDTOOFFSET(+2), // lofsa deskSarg + 0x4a, SIG_UINT16(0x0004), // send 04 SIG_MAGICDWORD, - 0x34, SIG_UINT16 + 0xdc, 0x00, // ldi 220 - 0x65, SIG_ADDTOOFFSET +1, // aTop cycles (1a for PC, 1c for Mac) + 0x34, SIG_UINT16(0x00dc), // ldi 220 + 0x65, SIG_ADDTOOFFSET(+1), // aTop cycles (1a for PC, 1c for Mac) 0x32, // jmp [end] SIG_END }; -const uint16 gk1PatchDay6PoliceBeignet[] = { - PATCH_ADDTOOFFSET +16, - 0x34, PATCH_UINT16 + 0x17, 0x00, // ldi 23 - 0x65, PATCH_GETORIGINALBYTEADJUST +20, +2, // aTop seconds (1c for PC, 1e for Mac) +static const uint16 gk1PatchDay6PoliceBeignet[] = { + PATCH_ADDTOOFFSET(+16), + 0x34, PATCH_UINT16(0x0017), // ldi 23 + 0x65, PATCH_GETORIGINALBYTEADJUST(+20, +2), // aTop seconds (1c for PC, 1e for Mac) PATCH_END }; @@ -594,42 +554,42 @@ const uint16 gk1PatchDay6PoliceBeignet[] = { // this is not enough time to get to the door, so we patch it to 42 seconds // Applies to at least: English PC-CD, German PC-CD, English Mac // Responsible method: sargSleeping::changeState -const uint16 gk1SignatureDay6PoliceSleep[] = { +static const uint16 gk1SignatureDay6PoliceSleep[] = { 0x35, 0x08, // ldi 08 0x1a, // eq? - 0x31, SIG_ADDTOOFFSET +1, // bnt [next state check] + 0x31, SIG_ADDTOOFFSET(+1), // bnt [next state check] SIG_MAGICDWORD, - 0x34, SIG_UINT16 + 0xdc, 0x00, // ldi 220 - 0x65, SIG_ADDTOOFFSET +1, // aTop cycles (1a for PC, 1c for Mac) + 0x34, SIG_UINT16(0x00dc), // ldi 220 + 0x65, SIG_ADDTOOFFSET(+1), // aTop cycles (1a for PC, 1c for Mac) 0x32, // jmp [end] 0 }; -const uint16 gk1PatchDay6PoliceSleep[] = { - PATCH_ADDTOOFFSET +5, - 0x34, SIG_UINT16 + 0x2a, 0x00, // ldi 42 - 0x65, PATCH_GETORIGINALBYTEADJUST +9, +2, // aTop seconds (1c for PC, 1e for Mac) +static const uint16 gk1PatchDay6PoliceSleep[] = { + PATCH_ADDTOOFFSET(+5), + 0x34, SIG_UINT16(0x002a), // ldi 42 + 0x65, PATCH_GETORIGINALBYTEADJUST(+9, +2), // aTop seconds (1c for PC, 1e for Mac) PATCH_END }; // startOfDay5::changeState (20h) - when gabriel goes to the phone the script will hang // Applies to at least: English PC-CD, German PC-CD, English Mac // Responsible method: startOfDay5::changeState -const uint16 gk1SignatureDay5PhoneFreeze[] = { +static const uint16 gk1SignatureDay5PhoneFreeze[] = { 0x4a, - SIG_MAGICDWORD, SIG_UINT16 + 0x0c, 0x00, // send 0c + SIG_MAGICDWORD, SIG_UINT16(0x000c), // send 0c 0x35, 0x03, // ldi 03 - 0x65, SIG_ADDTOOFFSET +1, // aTop cycles - 0x32, SIG_ADDTOOFFSET +2, // jmp [end] + 0x65, SIG_ADDTOOFFSET(+1), // aTop cycles + 0x32, SIG_ADDTOOFFSET(+2), // jmp [end] 0x3c, // dup 0x35, 0x21, // ldi 21 SIG_END }; -const uint16 gk1PatchDay5PhoneFreeze[] = { - PATCH_ADDTOOFFSET +3, +static const uint16 gk1PatchDay5PhoneFreeze[] = { + PATCH_ADDTOOFFSET(+3), 0x35, 0x06, // ldi 01 - 0x65, PATCH_GETORIGINALBYTEADJUST +6, +6, // aTop ticks + 0x65, PATCH_GETORIGINALBYTEADJUST(+6, +6), // aTop ticks PATCH_END }; @@ -644,33 +604,33 @@ const uint16 gk1PatchDay5PhoneFreeze[] = { // Applies to at least: English Floppy // Responsible method: Interrogation::dispose // TODO: Check, if English Mac is affected too and if this patch applies -const uint16 gk1SignatureInterrogationBug[] = { +static const uint16 gk1SignatureInterrogationBug[] = { SIG_MAGICDWORD, 0x65, 0x4c, // aTop 4c 0x67, 0x50, // pTos 50 - 0x34, SIG_UINT16 + 0x10, 0x27, // ldi 2710 + 0x34, SIG_UINT16(0x2710), // ldi 2710 0x1e, // gt? 0x31, 0x08, // bnt 08 [05a0] 0x67, 0x50, // pTos 50 - 0x34, SIG_UINT16 + 0x10, 0x27, // ldi 2710 + 0x34, SIG_UINT16(0x2710), // ldi 2710 0x04, // sub 0x65, 0x50, // aTop 50 0x63, 0x50, // pToa 50 0x31, 0x15, // bnt 15 [05b9] 0x39, 0x0e, // pushi 0e 0x76, // push0 - 0x4a, SIG_UINT16 + 0x04, 0x00, // send 0004 + 0x4a, SIG_UINT16(0x0004), // send 0004 0xa5, 0x00, // sat 00 - 0x38, SIG_SELECTOR16 + SELECTOR_dispose, // pushi dispose + 0x38, SIG_SELECTOR16(dispose), // pushi dispose 0x76, // push0 0x63, 0x50, // pToa 50 - 0x4a, SIG_UINT16 + 0x04, 0x00, // send 0004 + 0x4a, SIG_UINT16(0x0004), // send 0004 0x85, 0x00, // lat 00 0x65, 0x50, // aTop 50 SIG_END }; -const uint16 gk1PatchInterrogationBug[] = { +static const uint16 gk1PatchInterrogationBug[] = { 0x65, 0x4c, // aTop 4c 0x63, 0x50, // pToa 50 0x31, 0x15, // bnt 15 [05b9] @@ -678,29 +638,29 @@ const uint16 gk1PatchInterrogationBug[] = { 0x76, // push0 0x4a, 0x04, 0x00, // send 0004 0xa5, 0x00, // sat 00 - 0x38, SIG_SELECTOR16 + SELECTOR_dispose, // pushi dispose + 0x38, SIG_SELECTOR16(dispose), // pushi dispose 0x76, // push0 0x63, 0x50, // pToa 50 0x4a, 0x04, 0x00, // send 0004 0x85, 0x00, // lat 00 0x65, 0x50, // aTop 50 0x67, 0x50, // pTos 50 - 0x34, PATCH_UINT16 + 0x10, 0x27, // ldi 2710 + 0x34, PATCH_UINT16(0x2710), // ldi 2710 0x1e, // gt? 0x31, 0x08, // bnt 08 [05b9] 0x67, 0x50, // pTos 50 - 0x34, PATCH_UINT16 + 0x10, 0x27, // ldi 2710 + 0x34, PATCH_UINT16(0x2710), // ldi 2710 0x04, // sub 0x65, 0x50, // aTop 50 PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry gk1Signatures[] = { - { true, 51, "interrogation bug", 1, 0, 0, gk1SignatureInterrogationBug, gk1PatchInterrogationBug }, - { true, 212, "day 5 phone freeze", 1, 0, 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze }, - { true, 230, "day 6 police beignet timer issue", 1, 0, 0, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet }, - { true, 230, "day 6 police sleep timer issue", 1, 0, 0, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep }, +// script, description, signature patch +static const SciScriptPatcherEntry gk1Signatures[] = { + { true, 51, "interrogation bug", 1, gk1SignatureInterrogationBug, gk1PatchInterrogationBug }, + { true, 212, "day 5 phone freeze", 1, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze }, + { true, 230, "day 6 police beignet timer issue", 1, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet }, + { true, 230, "day 6 police sleep timer issue", 1, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -710,19 +670,19 @@ SciScriptPatcherEntry gk1Signatures[] = { // is later used to set master volume. This issue makes sierra sci set // the volume to max. We fix the export, so volume won't get modified in // those cases. -const uint16 kq5SignatureCdHarpyVolume[] = { +static const uint16 kq5SignatureCdHarpyVolume[] = { SIG_MAGICDWORD, - 0x80, SIG_UINT16 + 0x91, 0x01, // lag global[191h] + 0x80, SIG_UINT16(0x0191), // lag global[191h] 0x18, // not - 0x30, SIG_UINT16 + 0x2c, 0x00, // bnt [jump further] (jumping, if global 191h is 1) + 0x30, SIG_UINT16(0x002c), // bnt [jump further] (jumping, if global 191h is 1) 0x35, 0x01, // ldi 01 - 0xa0, SIG_UINT16 + 0x91, 0x01, // sag global[191h] (setting global 191h to 1) - 0x38, SIG_UINT16 + 0x7b, 0x01, // pushi 017b + 0xa0, SIG_UINT16(0x0191), // sag global[191h] (setting global 191h to 1) + 0x38, SIG_UINT16(0x017b), // pushi 017b 0x76, // push0 0x81, 0x01, // lag global[1] 0x4a, 0x04, // send 04 - read KQ5::masterVolume 0xa5, 0x03, // sat temp[3] (store volume in temp 3) - 0x38, SIG_UINT16 + 0x7b, 0x01, // pushi 017b + 0x38, SIG_UINT16(0x017b), // pushi 017b 0x76, // push0 0x81, 0x01, // lag global[1] 0x4a, 0x04, // send 04 - read KQ5::masterVolume @@ -732,18 +692,18 @@ const uint16 kq5SignatureCdHarpyVolume[] = { SIG_END }; -const uint16 kq5PatchCdHarpyVolume[] = { - 0x38, PATCH_UINT16 + 0x2f, 0x02, // pushi 022f (selector theVol) (3 new bytes) +static const uint16 kq5PatchCdHarpyVolume[] = { + 0x38, PATCH_UINT16(0x022f), // pushi 022f (selector theVol) (3 new bytes) 0x76, // push0 (1 new byte) 0x51, 0x88, // class SpeakTimer (2 new bytes) 0x4a, 0x04, // send 04 (2 new bytes) -> read SpeakTimer::theVol 0xa5, 0x03, // sat temp[3] (2 new bytes) -> write to temp 3 - 0x80, PATCH_UINT16 + 0x91, 0x01, // lag global[191h] + 0x80, PATCH_UINT16(0x0191), // lag global[191h] // saving 1 byte due optimization - 0x2e, PATCH_UINT16 + 0x23, 0x00, // bt [jump further] (jumping, if global 191h is 1) + 0x2e, PATCH_UINT16(0x0023), // bt [jump further] (jumping, if global 191h is 1) 0x35, 0x01, // ldi 01 - 0xa0, PATCH_UINT16 + 0x91, 0x01, // sag global[191h] (setting global 191h to 1) - 0x38, PATCH_UINT16 + 0x7b, 0x01, // pushi 017b + 0xa0, PATCH_UINT16(0x0191), // sag global[191h] (setting global 191h to 1) + 0x38, PATCH_UINT16(0x017b), // pushi 017b 0x76, // push0 0x81, 0x01, // lag global[1] 0x4a, 0x04, // send 04 - read KQ5::masterVolume @@ -770,24 +730,24 @@ const uint16 kq5PatchCdHarpyVolume[] = { // See also the warning+comment in Object::initBaseObject // // Fixes bug: #4964 -const uint16 kq5SignatureWitchCageInit[] = { - SIG_UINT16 + 0x00, 0x00, // top - SIG_UINT16 + 0x00, 0x00, // left - SIG_UINT16 + 0x00, 0x00, // bottom - SIG_UINT16 + 0x00, 0x00, // right - SIG_UINT16 + 0x00, 0x00, // extra property #1 +static const uint16 kq5SignatureWitchCageInit[] = { + SIG_UINT16(0x0000), // top + SIG_UINT16(0x0000), // left + SIG_UINT16(0x0000), // bottom + SIG_UINT16(0x0000), // right + SIG_UINT16(0x0000), // extra property #1 SIG_MAGICDWORD, - SIG_UINT16 + 0x7a, 0x00, // extra property #2 - SIG_UINT16 + 0xc8, 0x00, // extra property #3 - SIG_UINT16 + 0xa3, 0x00, // extra property #4 + SIG_UINT16(0x007a), // extra property #2 + SIG_UINT16(0x00c8), // extra property #3 + SIG_UINT16(0x00a3), // extra property #4 SIG_END }; -const uint16 kq5PatchWitchCageInit[] = { - PATCH_UINT16 + 0x00, 0x00, // top - PATCH_UINT16 + 0x7a, 0x00, // left - PATCH_UINT16 + 0xc8, 0x00, // bottom - PATCH_UINT16 + 0xa3, 0x00, // right +static const uint16 kq5PatchWitchCageInit[] = { + PATCH_UINT16(0x0000), // top + PATCH_UINT16(0x007a), // left + PATCH_UINT16(0x00c8), // bottom + PATCH_UINT16(0x00a3), // right PATCH_END }; @@ -805,25 +765,25 @@ const uint16 kq5PatchWitchCageInit[] = { // changes to GameFeatures::detectsetCursorType() ) and breaking savegame // compatibilty between the DOS and Windows CD versions of KQ5. // TODO: Investigate these side effects more closely. -const uint16 kq5SignatureWinGMSignals[] = { +static const uint16 kq5SignatureWinGMSignals[] = { SIG_MAGICDWORD, - 0x80, SIG_UINT16 + 0x90, 0x01, // lag 0x190 + 0x80, SIG_UINT16(0x0190), // lag 0x190 0x18, // not - 0x30, SIG_UINT16 + 0x1b, 0x00, // bnt +0x001B + 0x30, SIG_UINT16(0x001b), // bnt +0x001B 0x89, 0x57, // lsg 0x57 SIG_END }; -const uint16 kq5PatchWinGMSignals[] = { - 0x34, PATCH_UINT16 + 0x01, 0x00, // ldi 0x0001 +static const uint16 kq5PatchWinGMSignals[] = { + 0x34, PATCH_UINT16(0x0001), // ldi 0x0001 PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry kq5Signatures[] = { - { true, 0, "CD: harpy volume change", 1, 0, 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume }, - { true, 200, "CD: witch cage init", 1, 0, 0, kq5SignatureWitchCageInit, kq5PatchWitchCageInit }, - { false, 124, "Win: GM Music signal checks", 4, 0, 0, kq5SignatureWinGMSignals, kq5PatchWinGMSignals }, +// script, description, signature patch +static const SciScriptPatcherEntry kq5Signatures[] = { + { true, 0, "CD: harpy volume change", 1, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume }, + { true, 200, "CD: witch cage init", 1, kq5SignatureWitchCageInit, kq5PatchWitchCageInit }, + { false, 124, "Win: GM Music signal checks", 4, kq5SignatureWinGMSignals, kq5PatchWinGMSignals }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -837,7 +797,7 @@ SciScriptPatcherEntry kq5Signatures[] = { // constantly restarting (since it's being looped anyway), thus the normal // game speech can work while the baby cry sound is heard. // Fixes bug: #4955 -const uint16 kq6SignatureDuplicateBabyCry[] = { +static const uint16 kq6SignatureDuplicateBabyCry[] = { SIG_MAGICDWORD, 0x83, 0x00, // lal 00 0x31, 0x1e, // bnt 1e [07f4] @@ -847,7 +807,7 @@ const uint16 kq6SignatureDuplicateBabyCry[] = { SIG_END }; -const uint16 kq6PatchDuplicateBabyCry[] = { +static const uint16 kq6PatchDuplicateBabyCry[] = { 0x48, // ret PATCH_END }; @@ -860,9 +820,9 @@ const uint16 kq6PatchDuplicateBabyCry[] = { // Applies to at least: PC-CD, English PC floppy, German PC floppy, English Mac // Responsible method: KqInv::showSelf // Fixes bug: #5681 -const uint16 kq6SignatureInventoryStackFix[] = { +static const uint16 kq6SignatureInventoryStackFix[] = { 0x67, 0x30, // pTos state - 0x34, SIG_UINT16 + 0x00, 0x20, // ldi 2000 + 0x34, SIG_UINT16(0x2000), // ldi 2000 0x12, // and 0x18, // not 0x31, 0x04, // bnt [not first refresh] @@ -870,10 +830,10 @@ const uint16 kq6SignatureInventoryStackFix[] = { SIG_MAGICDWORD, 0x65, 0x1e, // aTop curIcon 0x67, 0x30, // pTos state - 0x34, SIG_UINT16 + 0xff, 0xdf, // ldi dfff + 0x34, SIG_UINT16(0xdfff), // ldi dfff 0x12, // and 0x65, 0x30, // aTop state - 0x38, SIG_SELECTOR16 + SELECTOR_show, // pushi "show" ("show" is e1h for KQ6CD) + 0x38, SIG_SELECTOR16(show), // pushi "show" ("show" is e1h for KQ6CD) 0x78, // push1 0x87, 0x00, // lap param[0] 0x31, 0x04, // bnt [use global for show] @@ -882,18 +842,18 @@ const uint16 kq6SignatureInventoryStackFix[] = { 0x81, 0x00, // lag global[0] 0x36, // push 0x54, 0x06, // self 06 (KqInv::show) - 0x31, SIG_ADDTOOFFSET + 1, // bnt [exit menu code] (0x08 for PC, 0x07 for mac) + 0x31, SIG_ADDTOOFFSET(+1), // bnt [exit menu code] (0x08 for PC, 0x07 for mac) 0x39, 0x39, // pushi 39 0x76, // push0 0x54, 0x04, // self 04 (KqInv::doit) SIG_END // followed by jmp (0x32 for PC, 0x33 for mac) }; -const uint16 kq6PatchInventoryStackFix[] = { +static const uint16 kq6PatchInventoryStackFix[] = { 0x67, 0x30, // pTos state 0x3c, // dup (1 more byte, needed for patch) 0x3c, // dup (1 more byte, saves 1 byte later) - 0x34, PATCH_UINT16 + 0x00, 0x20, // ldi 2000 + 0x34, PATCH_UINT16(0x2000), // ldi 2000 0x12, // and 0x2f, 0x02, // bt [not first refresh] - saves 3 bytes in total 0x65, 0x1e, // aTop curIcon @@ -901,8 +861,8 @@ const uint16 kq6PatchInventoryStackFix[] = { 0x12, // and 0x65, 0x30, // aTop state 0x38, // pushi "show" - PATCH_GETORIGINALBYTE +22, - PATCH_GETORIGINALBYTE +23, + PATCH_GETORIGINALBYTE(+22), + PATCH_GETORIGINALBYTE(+23), 0x78, // push1 0x87, 0x00, // lap param[0] 0x31, 0x04, // bnt [call show using global 0] @@ -911,8 +871,8 @@ const uint16 kq6PatchInventoryStackFix[] = { 0x89, 0x00, // lsg global[0], save 1 byte total, see above 0x54, 0x06, // self 06 (call x::show) 0x31, // bnt [menu exit code] - PATCH_GETORIGINALBYTEADJUST +39, +6,// dynamic offset must be 0x0E for PC and 0x0D for mac - 0x34, PATCH_UINT16 + 0x00, 0x20, // ldi 2000 + PATCH_GETORIGINALBYTEADJUST(+39, +6),// dynamic offset must be 0x0E for PC and 0x0D for mac + 0x34, PATCH_UINT16(0x2000), // ldi 2000 0x12, // and 0x2f, 0x05, // bt [to return] 0x39, 0x39, // pushi 39 @@ -922,28 +882,83 @@ const uint16 kq6PatchInventoryStackFix[] = { PATCH_END }; +// The "Drink Me" bottle code doesn't repaint the AddToPics elements to the screen, +// when Alexander returns back from the effect of the bottle. +// It's pretty strange that Sierra didn't find this bug, because it occurs when +// drinking the bottle right on the screen, where the bottle is found. +// This bug also occurs in Sierra SCI. +// Applies to at least: PC-CD, English PC floppy, German PC floppy, English Mac +// Responsible method: drinkMeScript::changeState +// Fixes bug: #5252 +static const uint16 kq6SignatureDrinkMeFix[] = { + SIG_MAGICDWORD, + 0x3c, // dup + 0x35, 0x0f, // ldi 0f + 0x1a, // eq? + 0x30, SIG_UINT16(0x00a4), // bnt [skip to next check] + SIG_ADDTOOFFSET(+161), + 0x32, SIG_UINT16(0x007f), // jmp [return] + 0x3c, // dup + 0x35, 0x10, // ldi 10 + 0x1a, // eq? + 0x31, 0x07, // bnt [skip to next check] + 0x35, 0x03, // ldi 03 + 0x65, 0x1a, // aTop (cycles) + 0x32, SIG_UINT16(0x0072), // jmp [return] + 0x3c, // dup + 0x35, 0x11, // ldi 11 + 0x1a, // eq? + 0x31, 0x13, // bnt [skip to next check] + SIG_ADDTOOFFSET(+20), + 0x35, 0x12, // ldi 12 + SIG_ADDTOOFFSET(+23), + 0x35, 0x13, // ldi 13 + SIG_END +}; + +static const uint16 kq6PatchDrinkMeFix[] = { + PATCH_ADDTOOFFSET(+5), // skip to bnt offset + PATCH_GETORIGINALBYTEADJUST(+5, +13), // adjust jump to [check for 11h code] + PATCH_ADDTOOFFSET(+162), + 0x39, PATCH_SELECTOR8(doit), // pushi (doit) + 0x76, // push0 + 0x81, 0x0a, // lag 0a + 0x4a, 0x04, // send 04 (call addToPics::doit) + 0x3a, // toss + 0x48, // ret + PATCH_ADDTOOFFSET(+8), // skip to check 11h code + 0x35, 0x10, // ldi 10 instead of 11 + PATCH_ADDTOOFFSET(+23), // skip to check 12h code + 0x35, 0x11, // ldi 11 instead of 12 + PATCH_ADDTOOFFSET(+23), // skip to check 13h code + 0x35, 0x12, // ldi 12 instead of 13 + PATCH_END +}; + // Audio + subtitles support - SHARED! - used for King's Quest 6 and Laura Bow 2 // this patch gets enabled, when the user selects "both" in the ScummVM "Speech + Subtitles" menu // We currently use global 98d to hold a kMemory pointer. +// Applies to at least: KQ6 PC-CD, LB2 PC-CD // Patched method: Messager::sayNext / lb2Messager::sayNext (always use text branch) -const uint16 kq6laurabow2CDSignatureAudioTextSupport1[] = { +static const uint16 kq6laurabow2CDSignatureAudioTextSupport1[] = { 0x89, 0x5a, // lsg global[5a] 0x35, 0x02, // ldi 02 0x12, // and SIG_MAGICDWORD, 0x31, 0x13, // bnt [audio call] - 0x38, SIG_SELECTOR16 + SELECTOR_modNum, // pushi modNum + 0x38, SIG_SELECTOR16(modNum), // pushi modNum SIG_END }; -const uint16 kq6laurabow2CDPatchAudioTextSupport1[] = { - PATCH_ADDTOOFFSET +5, +static const uint16 kq6laurabow2CDPatchAudioTextSupport1[] = { + PATCH_ADDTOOFFSET(+5), 0x33, 0x13, // jmp [audio call] PATCH_END }; +// Applies to at least: KQ6 PC-CD, LB2 PC-CD // Patched method: Messager::sayNext / lb2Messager::sayNext (allocate audio memory) -const uint16 kq6laurabow2CDSignatureAudioTextSupport2[] = { +static const uint16 kq6laurabow2CDSignatureAudioTextSupport2[] = { 0x7a, // push2 0x78, // push1 0x39, 0x0c, // pushi 0c @@ -952,14 +967,15 @@ const uint16 kq6laurabow2CDSignatureAudioTextSupport2[] = { SIG_END }; -const uint16 kq6laurabow2CDPatchAudioTextSupport2[] = { - PATCH_ADDTOOFFSET +7, +static const uint16 kq6laurabow2CDPatchAudioTextSupport2[] = { + PATCH_ADDTOOFFSET(+7), 0xa1, 98, // sag global[98d] PATCH_END }; +// Applies to at least: KQ6 PC-CD, LB2 PC-CD // Patched method: Messager::sayNext / lb2Messager::sayNext (release audio memory) -const uint16 kq6laurabow2CDSignatureAudioTextSupport3[] = { +static const uint16 kq6laurabow2CDSignatureAudioTextSupport3[] = { 0x7a, // push2 0x39, 0x03, // pushi 03 SIG_MAGICDWORD, @@ -968,19 +984,30 @@ const uint16 kq6laurabow2CDSignatureAudioTextSupport3[] = { SIG_END }; -const uint16 kq6laurabow2CDPatchAudioTextSupport3[] = { - PATCH_ADDTOOFFSET +3, +static const uint16 kq6laurabow2CDPatchAudioTextSupport3[] = { + PATCH_ADDTOOFFSET(+3), 0x89, 98, // lsg global[98d] PATCH_END }; +// startText call gets acc = 0 for text-only and acc = 2 for audio+text +// Applies to at least: KQ6 PC-CD, LB2 PC-CD // Patched method: Narrator::say (use audio memory) -const uint16 kq6laurabow2CDSignatureAudioTextSupport4[] = { +static const uint16 kq6laurabow2CDSignatureAudioTextSupport4[] = { + // set caller property code + 0x31, 0x08, // bnt [set acc to 0 for caller] + 0x87, 0x02, // lap param[2] + 0x31, 0x04, // bnt [set acc to 0 for caller] + 0x87, 0x02, // lap param[2] + 0x33, 0x02, // jmp [set caller] + 0x35, 0x00, // ldi 00 + 0x65, 0x68, // aTop caller + // call startText + startAudio code 0x89, 0x5a, // lsg global[5a] 0x35, 0x01, // ldi 01 0x12, // and 0x31, 0x08, // bnt [skip code] - 0x38, SIG_SELECTOR16 + SELECTOR_startText, // pushi startText + 0x38, SIG_SELECTOR16(startText), // pushi startText 0x78, // push1 0x8f, 0x01, // lsp param[1] 0x54, 0x06, // self 06 @@ -989,49 +1016,297 @@ const uint16 kq6laurabow2CDSignatureAudioTextSupport4[] = { 0x12, // and 0x31, 0x08, // bnt [skip code] SIG_MAGICDWORD, - 0x38, SIG_SELECTOR16 + SELECTOR_startAudio, // pushi startAudio + 0x38, SIG_SELECTOR16(startAudio), // pushi startAudio 0x78, // push1 0x8f, 0x01, // lsp param[1] 0x54, 0x06, // self 06 SIG_END }; -const uint16 kq6laurabow2CDPatchAudioTextSupport4[] = { - PATCH_ADDTOOFFSET +5, - 0x18, // not (never jump here) - 0x18, // not (never jump here) - PATCH_ADDTOOFFSET +19, +static const uint16 kq6laurabow2CDPatchAudioTextSupport4[] = { + 0x31, 0x02, // bnt [set caller] + 0x87, 0x02, // lap param[2] + 0x65, 0x68, // aTop caller + 0x81, 0x5a, // lag global[5a] + 0x78, // push1 + 0x12, // and + 0x31, 0x11, // bnt [skip startText code] + 0x81, 0x5a, // lag global[5a] + 0x7a, // push2 + 0x12, // and + 0x33, 0x03, // skip over 3 unused bytes + PATCH_ADDTOOFFSET(+22), 0x89, 98, // lsp global[98d] PATCH_END }; +// Applies to at least: KQ6 PC-CD, LB2 PC-CD // Patched method: Talker::display/Narrator::say (remove reset saved mouse cursor code) // code would screw over mouse cursor -const uint16 kq6laurabow2CDSignatureAudioTextSupport5[] = { +static const uint16 kq6laurabow2CDSignatureAudioTextSupport5[] = { SIG_MAGICDWORD, 0x35, 0x00, // ldi 00 0x65, 0x82, // aTop saveCursor SIG_END }; -const uint16 kq6laurabow2CDPatchAudioTextSupport5[] = { +static const uint16 kq6laurabow2CDPatchAudioTextSupport5[] = { 0x18, 0x18, 0x18, 0x18, // waste bytes, do nothing PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry kq6Signatures[] = { - { true, 481, "duplicate baby cry", 1, 0, 0, kq6SignatureDuplicateBabyCry, kq6PatchDuplicateBabyCry }, - { true, 907, "inventory stack fix", 1, 0, 0, kq6SignatureInventoryStackFix, kq6PatchInventoryStackFix }, +// Additional patch specifically for King's Quest 6 +// Fixes text window placement, when in "dual" mode +// Applies to at least: PC-CD +// Patched method: Kq6Talker::init +static const uint16 kq6CDSignatureAudioTextSupport1[] = { + SIG_MAGICDWORD, + 0x89, 0x5a, // lsg global[5a] + 0x35, 0x02, // ldi 02 + 0x1a, // eq? + 0x31, SIG_ADDTOOFFSET(+1), // bnt [jump-to-text-code] + 0x78, // push1 + SIG_END +}; + +static const uint16 kq6CDPatchAudioTextSupport1[] = { + PATCH_ADDTOOFFSET(+4), + 0x12, // and + PATCH_END +}; + +// Additional patch specifically for King's Quest 6 +// Fixes low-res portrait staying on screen for hi-res mode +// Applies to at least: PC-CD +// Patched method: Talker::startText +// this method is called by Narrator::say and acc is 0 for text-only and 2 for dual mode (audio+text) +static const uint16 kq6CDSignatureAudioTextSupport2[] = { + SIG_MAGICDWORD, + 0x3f, 0x01, // link 01 + 0x63, 0x8a, // pToa viewInPrint + 0x18, // not + 0x31, 0x06, // bnt [skip following code] + 0x38, SIG_UINT16(0x00e1), // pushi 00e1 + 0x76, // push0 + 0x54, 0x04, // self 04 + SIG_END +}; + +static const uint16 kq6CDPatchAudioTextSupport2[] = { + PATCH_ADDTOOFFSET(+2), + 0x67, 0x8a, // pTos viewInPrint + 0x14, // or + 0x2f, // bt [skip following code] + PATCH_END +}; + +// Additional patch specifically for King's Quest 6 +// Fixes special windows, used for example in the Pawn shop (room 280), +// when the man in a robe complains about no more mints. +// We have to change even more code, because the game uses PODialog class for +// text windows and myDialog class for audio. Both are saved to KQ6Print::dialog +// Sadly PODialog is created during KQ6Print::addText, myDialog is set during +// KQ6Print::showSelf, which is called much later and KQ6Print::addText requires +// KQ6Print::dialog to be set, which means we have to set it before calling addText +// for audio mode, otherwise the user would have to click to get those windows disposed. +// Applies to at least: PC-CD +// Patched method: KQ6Print::say +static const uint16 kq6CDSignatureAudioTextSupport3[] = { + 0x31, 0x6e, // bnt [to text code] + SIG_ADDTOOFFSET(+85), + SIG_MAGICDWORD, + 0x8f, 0x01, // lsp param[1] + 0x35, 0x01, // ldi 01 + 0x1a, // eq? + 0x31, 0x0c, // bnt [code to set property repressText to 1] + 0x38, // pushi (selector addText) + SIG_ADDTOOFFSET(+9), // skip addText-calling code + 0x33, 0x10, // jmp [to ret] + 0x35, 0x01, // ldi 01 + 0x65, 0x2e, // aTop repressText + 0x33, 0x0a, // jmp [to ret] + SIG_END +}; + +static const uint16 kq6CDPatchAudioTextSupport3[] = { + 0x31, 0x5c, // adjust jump to reuse audio mode addText-calling code + PATCH_ADDTOOFFSET(102), + 0x48, // ret + 0x48, // ret (waste byte) + 0x72, 0x0e, 0x00, // lofsa myDialog + 0x65, 0x12, // aTop dialog + 0x33, 0xed, // jump back to audio mode addText-calling code + PATCH_END +}; + +// Additional patch specifically for King's Quest 6 +// Fixes text-window size for hires portraits mode +// Otherwise at least at the end some text-windows will be way too small +// Applies to at least: PC-CD +// Patched method: Talker::init +static const uint16 kq6CDSignatureAudioTextSupport4[] = { + SIG_MAGICDWORD, + 0x63, 0x94, // pToa raving + 0x31, 0x0a, // bnt [no rave code] + 0x35, 0x00, // ldi 00 + SIG_ADDTOOFFSET(6), // skip reset of bust, eyes and mouth + 0x33, 0x24, // jmp [to super class code] + SIG_END +}; + +static const uint16 kq6CDPatchAudioTextSupport4[] = { + PATCH_ADDTOOFFSET(+12), + 0x33, PATCH_GETORIGINALBYTEADJUST(+13, -6), // adjust jump to also include setSize call + PATCH_END +}; + +// Fixes text window placement, when dual mode is active (Guards in room 220) +// Applies to at least: PC-CD +// Patched method: tlkGateGuard1::init & tlkGateGuard2::init +static const uint16 kq6CDSignatureAudioTextSupportGuards[] = { + SIG_MAGICDWORD, + 0x89, 0x5a, // lsg global[5a] + 0x35, 0x01, // ldi 01 + 0x1a, // eq? + SIG_END // followed by bnt for Guard1 and bt for Guard2 +}; + +static const uint16 kq6CDPatchAudioTextSupportGuards[] = { + PATCH_ADDTOOFFSET(+2), + 0x35, 0x02, // ldi 02 + 0x1c, // ne? + PATCH_END +}; + +// Fixes text window placement, when portrait+text is shown (Stepmother in room 250) +// Applies to at least: PC-CD +// Patched method: tlkStepmother::init +static const uint16 kq6CDSignatureAudioTextSupportStepmother[] = { + SIG_MAGICDWORD, + 0x89, 0x5a, // lsg global[5a] + 0x35, 0x02, // ldi 02 + 0x12, // and + 0x31, // bnt [jump-for-text-code] + SIG_END +}; + +static const uint16 kq6CDPatchAudioTextSupportJumpAlways[] = { + PATCH_ADDTOOFFSET(+4), + 0x1a, // eq? + PATCH_END +}; + +// Fixes "Girl In The Tower" to get played in dual mode as well +// Applies to at least: PC-CD +// Patched method: rm740::cue +static const uint16 kq6CDSignatureAudioTextSupportGirlInTheTower[] = { + SIG_MAGICDWORD, + 0x89, 0x5a, // lsg global[5a] + 0x35, 0x02, // ldi 02 + 0x1a, // eq? + 0x31, // bnt [jump-for-text-code] + SIG_END +}; + +static const uint16 kq6CDPatchAudioTextSupportGirlInTheTower[] = { + PATCH_ADDTOOFFSET(+4), + 0x12, // and + PATCH_END +}; + +// Additional patch specifically for King's Quest 6 +// Adds another button state for the text/audio button. We currently use the "speech" view for "dual" mode. +// View 947, loop 9, cel 0+1 -> "text" +// View 947, loop 8, cel 0+1 -> "speech" +// View 947, loop 12, cel 0+1 -> "dual" (TODO: inject our own 2 views for the new "dual" mode) +// Applies to at least: PC-CD +// Patched method: iconTextSwitch::show, iconTextSwitch::doit +static const uint16 kq6CDSignatureAudioTextMenuSupport[] = { + SIG_MAGICDWORD, + 0x89, 0x5a, // lsg global[5a] + 0x35, 0x02, // ldi 02 + 0x1a, // eq? + 0x31, 0x06, // bnt [set text view] + 0x35, 0x08, // ldi 08 + 0x65, 0x14, // aTop loop + 0x33, 0x04, // jmp [skip over text view] + 0x35, 0x09, // ldi 09 + 0x65, 0x14, // aTop loop + SIG_ADDTOOFFSET(+102), // skip to iconTextSwitch::doit code + 0x89, 0x5a, // lsg global[5a] + 0x3c, // dup + 0x35, 0x01, // ldi 01 + 0x1a, // eq? + 0x31, 0x06, // bnt [set text mode] + 0x35, 0x02, // ldi 02 + 0xa1, 0x5a, // sag global[5a] + 0x33, 0x0a, // jmp [skip over text mode code] + 0x3c, // dup + 0x35, 0x02, // ldi 02 + 0x1a, // eq? + 0x31, 0x04, // bnt [skip over text ode code] + 0x35, 0x01, // ldi 01 + 0xa1, 0x5a, // sag global[5a] + 0x3a, // toss + 0x67, 0x14, // pTos loop + 0x35, 0x09, // ldi 09 + 0x1a, // eq? + 0x31, 0x04, // bnt [set text view] + 0x35, 0x08, // ldi 08 + 0x33, 0x02, // jmp [skip text view] + 0x35, 0x09, // ldi 09 + 0x65, 0x14, // aTop loop + SIG_END +}; + +static const uint16 kq6CDPatchAudioTextMenuSupport[] = { + PATCH_ADDTOOFFSET(+13), + 0x33, 0x79, // jmp to new text+dual code + PATCH_ADDTOOFFSET(+104), // seek to iconTextSwitch::doit + 0x81, 0x5a, // lag global[5a] + 0x78, // push1 + 0x02, // add + 0xa1, 0x5a, // sag global[5a] + 0x36, // push + 0x35, 0x03, // ldi 03 + 0x1e, // gt? + 0x31, 0x03, // bnt [skip over] + 0x78, // push1 + 0xa9, 0x5a, // ssg global[5a] + 0x33, 0x17, // jmp [iconTextSwitch::show call] + // additional code for iconTextSwitch::show + 0x89, 0x5a, // lsg global[5a] + 0x35, 0x01, // ldi 01 + 0x1a, // eq? + 0x31, 0x04, // bnt [dual mode] + 0x35, 0x09, // ldi 09 + 0x33, 0x02, // jmp [skip over dual mode] + 0x35, 0x0c, // ldi 0c (view 947, loop 12, cel 0+1 is our "dual" view, injected by view.cpp) + 0x65, 0x14, // aTop loop + 0x32, PATCH_UINT16(0xff75), // jmp [back to iconTextSwitch::show] + PATCH_END +}; + +// script, description, signature patch +static const SciScriptPatcherEntry kq6Signatures[] = { + { true, 481, "duplicate baby cry", 1, kq6SignatureDuplicateBabyCry, kq6PatchDuplicateBabyCry }, + { true, 907, "inventory stack fix", 1, kq6SignatureInventoryStackFix, kq6PatchInventoryStackFix }, + { true, 87, "Drink Me bottle fix", 1, kq6SignatureDrinkMeFix, kq6PatchDrinkMeFix }, // King's Quest 6 and Laura Bow 2 share basic patches for audio + text support - // *** King's Quest 6 audio + text support - CURRENTLY DISABLED *** - // TODO: fix window placement (currently part of the text windows go off-screen) - // TODO: fix hi-res portraits mode graphic glitches - { false, 924, "CD: audio + text support 1", 1, 0, 0, kq6laurabow2CDSignatureAudioTextSupport1, kq6laurabow2CDPatchAudioTextSupport1 }, - { false, 924, "CD: audio + text support 2", 1, 0, 0, kq6laurabow2CDSignatureAudioTextSupport2, kq6laurabow2CDPatchAudioTextSupport2 }, - { false, 924, "CD: audio + text support 3", 1, 0, 0, kq6laurabow2CDSignatureAudioTextSupport3, kq6laurabow2CDPatchAudioTextSupport3 }, - { false, 928, "CD: audio + text support 4", 1, 0, 0, kq6laurabow2CDSignatureAudioTextSupport4, kq6laurabow2CDPatchAudioTextSupport4 }, - { false, 928, "CD: audio + text support 5", 2, 0, 0, kq6laurabow2CDSignatureAudioTextSupport5, kq6laurabow2CDPatchAudioTextSupport5 }, + // *** King's Quest 6 audio + text support *** + { false, 924, "CD: audio + text support KQ6&LB2 1", 1, kq6laurabow2CDSignatureAudioTextSupport1, kq6laurabow2CDPatchAudioTextSupport1 }, + { false, 924, "CD: audio + text support KQ6&LB2 2", 1, kq6laurabow2CDSignatureAudioTextSupport2, kq6laurabow2CDPatchAudioTextSupport2 }, + { false, 924, "CD: audio + text support KQ6&LB2 3", 1, kq6laurabow2CDSignatureAudioTextSupport3, kq6laurabow2CDPatchAudioTextSupport3 }, + { false, 928, "CD: audio + text support KQ6&LB2 4", 1, kq6laurabow2CDSignatureAudioTextSupport4, kq6laurabow2CDPatchAudioTextSupport4 }, + { false, 928, "CD: audio + text support KQ6&LB2 5", 2, kq6laurabow2CDSignatureAudioTextSupport5, kq6laurabow2CDPatchAudioTextSupport5 }, + { false, 909, "CD: audio + text support KQ6 1", 2, kq6CDSignatureAudioTextSupport1, kq6CDPatchAudioTextSupport1 }, + { false, 928, "CD: audio + text support KQ6 2", 1, kq6CDSignatureAudioTextSupport2, kq6CDPatchAudioTextSupport2 }, + { false, 104, "CD: audio + text support KQ6 3", 1, kq6CDSignatureAudioTextSupport3, kq6CDPatchAudioTextSupport3 }, + { false, 928, "CD: audio + text support KQ6 4", 1, kq6CDSignatureAudioTextSupport4, kq6CDPatchAudioTextSupport4 }, + { false, 1009, "CD: audio + text support KQ6 Guards", 2, kq6CDSignatureAudioTextSupportGuards, kq6CDPatchAudioTextSupportGuards }, + { false, 1027, "CD: audio + text support KQ6 Stepmother", 1, kq6CDSignatureAudioTextSupportStepmother, kq6CDPatchAudioTextSupportJumpAlways }, + { false, 740, "CD: audio + text support KQ6 Girl In The Tower", 1, kq6CDSignatureAudioTextSupportGirlInTheTower, kq6CDPatchAudioTextSupportGirlInTheTower }, + { false, 903, "CD: audio + text support KQ6 menu", 1, kq6CDSignatureAudioTextMenuSupport, kq6CDPatchAudioTextMenuSupport }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1048,36 +1323,36 @@ SciScriptPatcherEntry kq6Signatures[] = { // Applies to at least: German floppy // Responsible method: unknown // Fixes bug: #5264 -const uint16 longbowSignatureShowHandCode[] = { +static const uint16 longbowSignatureShowHandCode[] = { 0x78, // push1 0x78, // push1 - 0x72, SIG_ADDTOOFFSET +2, // lofsa (letter, that was typed) + 0x72, SIG_ADDTOOFFSET(+2), // lofsa (letter, that was typed) 0x36, // push - 0x40, SIG_ADDTOOFFSET +2, // call + 0x40, SIG_ADDTOOFFSET(+2), // call 0x02, // perform the call above with 2 parameters 0x36, // push - 0x40, SIG_ADDTOOFFSET +2, // call + 0x40, SIG_ADDTOOFFSET(+2), // call SIG_MAGICDWORD, 0x02, // perform the call above with 2 parameters - 0x38, SIG_SELECTOR16 + SELECTOR_setMotion, // pushi "setMotion" (0x11c in Longbow German) - 0x39, SIG_SELECTOR8 + SELECTOR_x, // pushi "x" (0x04 in Longbow German) + 0x38, SIG_SELECTOR16(setMotion), // pushi "setMotion" (0x11c in Longbow German) + 0x39, SIG_SELECTOR8(x), // pushi "x" (0x04 in Longbow German) 0x51, 0x1e, // class MoveTo SIG_END }; -const uint16 longbowPatchShowHandCode[] = { +static const uint16 longbowPatchShowHandCode[] = { 0x39, 0x01, // pushi 1 (combine the two push1's in one, like in the English version) - PATCH_ADDTOOFFSET +3, // leave the lofsa call untouched + PATCH_ADDTOOFFSET(+3), // leave the lofsa call untouched // The following will remove the duplicate call - 0x32, PATCH_UINT16 + 0x02, 0x00, // jmp 02 - skip 2 bytes (the remainder of the first call) + 0x32, PATCH_UINT16(0x0002), // jmp 02 - skip 2 bytes (the remainder of the first call) 0x48, // ret (dummy, should never be reached) 0x48, // ret (dummy, should never be reached) PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry longbowSignatures[] = { - { true, 210, "hand code crash", 5, 0, 0, longbowSignatureShowHandCode, longbowPatchShowHandCode }, +// script, description, signature patch +static const SciScriptPatcherEntry longbowSignatures[] = { + { true, 210, "hand code crash", 5, longbowSignatureShowHandCode, longbowPatchShowHandCode }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1098,28 +1373,28 @@ SciScriptPatcherEntry longbowSignatures[] = { // Applies to at least: English floppy // Responsible method: rm63Script::handleEvent // Fixes bug: #6346 -const uint16 larry2SignatureWearParachutePoints[] = { +static const uint16 larry2SignatureWearParachutePoints[] = { 0x35, 0x01, // ldi 01 0xa1, SIG_MAGICDWORD, 0x8e, // sag 8e - 0x80, SIG_UINT16 + 0xe0, 0x01, // lag 1e0 + 0x80, SIG_UINT16(0x01e0), // lag 1e0 0x18, // not - 0x30, SIG_UINT16 + 0x0f, 0x00, // bnt [don't give points] + 0x30, SIG_UINT16(0x000f), // bnt [don't give points] 0x35, 0x01, // ldi 01 0xa0, 0xe0, 0x01, // sag 1e0 SIG_END }; -const uint16 larry2PatchWearParachutePoints[] = { - PATCH_ADDTOOFFSET +4, - 0x80, PATCH_UINT16 + 0x5a, 0x00, // lag 5a (global 90) - PATCH_ADDTOOFFSET +6, - 0xa0, PATCH_UINT16 + 0x5a, 0x00, // sag 5a (global 90) +static const uint16 larry2PatchWearParachutePoints[] = { + PATCH_ADDTOOFFSET(+4), + 0x80, PATCH_UINT16(0x005a), // lag 5a (global 90) + PATCH_ADDTOOFFSET(+6), + 0xa0, PATCH_UINT16(0x005a), // sag 5a (global 90) PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry larry2Signatures[] = { - { true, 63, "plane: no points for wearing plane", 1, 0, 0, larry2SignatureWearParachutePoints, larry2PatchWearParachutePoints }, +// script, description, signature patch +static const SciScriptPatcherEntry larry2Signatures[] = { + { true, 63, "plane: no points for wearing plane", 1, larry2SignatureWearParachutePoints, larry2PatchWearParachutePoints }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1131,24 +1406,24 @@ SciScriptPatcherEntry larry2Signatures[] = { // Because of that the talking head of Patti is drawn over the textbox. A translation oversight. // Applies to at least: German floppy // Responsible method: none, position of talker object on screen needs to get modified -const uint16 larry5SignatureGermanEndingPattiTalker[] = { +static const uint16 larry5SignatureGermanEndingPattiTalker[] = { SIG_MAGICDWORD, - SIG_UINT16 + 0x6e, 0x00, // object pattiTalker::x (110) - SIG_UINT16 + 0xb4, 0x00, // object pattiTalker::y (180) - SIG_ADDTOOFFSET + 469, // verify that it's really the German version + SIG_UINT16(0x006e), // object pattiTalker::x (110) + SIG_UINT16(0x00b4), // object pattiTalker::y (180) + SIG_ADDTOOFFSET(+469), // verify that it's really the German version 0x59, 0x6f, 0x75, // (object name) "You" 0x23, 0x47, 0x44, 0x75, // "#GDu" SIG_END }; -const uint16 larry5PatchGermanEndingPattiTalker[] = { - PATCH_UINT16 + 0x5a, 0x00, // change pattiTalker::x to 90 +static const uint16 larry5PatchGermanEndingPattiTalker[] = { + PATCH_UINT16(0x005a), // change pattiTalker::x to 90 PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry larry5Signatures[] = { - { true, 380, "German-only: Enlarge Patti Textbox", 1, 0, 0, larry5SignatureGermanEndingPattiTalker, larry5PatchGermanEndingPattiTalker }, +// script, description, signature patch +static const SciScriptPatcherEntry larry5Signatures[] = { + { true, 380, "German-only: Enlarge Patti Textbox", 1, larry5SignatureGermanEndingPattiTalker, larry5PatchGermanEndingPattiTalker }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1162,50 +1437,50 @@ SciScriptPatcherEntry larry5Signatures[] = { // in sierra sci) // Applies to at least: German PC-CD // Responsible method: unknown -const uint16 larry6SignatureDeathDialog[] = { +static const uint16 larry6SignatureDeathDialog[] = { SIG_MAGICDWORD, - 0x3e, SIG_UINT16 + 0x33, 0x01, // link 0133 (offset 0x20) + 0x3e, SIG_UINT16(0x0133), // link 0133 (offset 0x20) 0x35, 0xff, // ldi ff 0xa3, 0x00, // sal 00 - SIG_ADDTOOFFSET +680, // [skip 680 bytes] + SIG_ADDTOOFFSET(+680), // [skip 680 bytes] 0x8f, 0x01, // lsp 01 (offset 0x2cf) 0x7a, // push2 - 0x5a, SIG_UINT16 + 0x04, 0x00, SIG_UINT16 + 0x0e, 0x01, // lea 0004 010e + 0x5a, SIG_UINT16(0x0004), SIG_UINT16(0x010e), // lea 0004 010e 0x36, // push 0x43, 0x7c, 0x0e, // kMessage[7c] 0e - SIG_ADDTOOFFSET +90, // [skip 90 bytes] - 0x38, SIG_UINT16 + 0xd6, 0x00, // pushi 00d6 (offset 0x335) + SIG_ADDTOOFFSET(+90), // [skip 90 bytes] + 0x38, SIG_UINT16(0x00d6), // pushi 00d6 (offset 0x335) 0x78, // push1 - 0x5a, SIG_UINT16 + 0x04, 0x00, SIG_UINT16 + 0x0e, 0x01, // lea 0004 010e + 0x5a, SIG_UINT16(0x0004), SIG_UINT16(0x010e), // lea 0004 010e 0x36, // push - SIG_ADDTOOFFSET +76, // [skip 76 bytes] - 0x38, SIG_UINT16 + 0xcd, 0x00, // pushi 00cd (offset 0x38b) + SIG_ADDTOOFFSET(+76), // [skip 76 bytes] + 0x38, SIG_UINT16(0x00cd), // pushi 00cd (offset 0x38b) 0x39, 0x03, // pushi 03 - 0x5a, SIG_UINT16 + 0x04, 0x00, SIG_UINT16 + 0x0e, 0x01, // lea 0004 010e + 0x5a, SIG_UINT16(0x0004), SIG_UINT16(0x010e), // lea 0004 010e 0x36, SIG_END }; -const uint16 larry6PatchDeathDialog[] = { +static const uint16 larry6PatchDeathDialog[] = { 0x3e, 0x00, 0x02, // link 0200 - PATCH_ADDTOOFFSET +687, - 0x5a, PATCH_UINT16 + 0x04, 0x00, PATCH_UINT16 + 0x40, 0x01, // lea 0004 0140 - PATCH_ADDTOOFFSET +98, - 0x5a, PATCH_UINT16 + 0x04, 0x00, PATCH_UINT16 + 0x40, 0x01, // lea 0004 0140 - PATCH_ADDTOOFFSET +82, - 0x5a, PATCH_UINT16 + 0x04, 0x00, PATCH_UINT16 + 0x40, 0x01, // lea 0004 0140 + PATCH_ADDTOOFFSET(+687), + 0x5a, PATCH_UINT16(0x0004), PATCH_UINT16(0x0140), // lea 0004 0140 + PATCH_ADDTOOFFSET(+98), + 0x5a, PATCH_UINT16(0x0004), PATCH_UINT16(0x0140), // lea 0004 0140 + PATCH_ADDTOOFFSET(+82), + 0x5a, PATCH_UINT16(0x0004), PATCH_UINT16(0x0140), // lea 0004 0140 PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry larry6Signatures[] = { - { true, 82, "death dialog memory corruption", 1, 0, 0, larry6SignatureDeathDialog, larry6PatchDeathDialog }, +// script, description, signature patch +static const SciScriptPatcherEntry larry6Signatures[] = { + { true, 82, "death dialog memory corruption", 1, larry6SignatureDeathDialog, larry6PatchDeathDialog }, SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== // Laura Bow 2 -// +// // Moving away the painting in the room with the hidden safe is problematic // for the CD version of the game. safePic::doVerb gets triggered by the mouse-click. // This method sets local 0 as signal, which is only meant to get handled, when @@ -1230,18 +1505,18 @@ SciScriptPatcherEntry larry6Signatures[] = { // Applies to at least: English PC-CD // Responsible method: rm560::doit // Fixes bug: #6460 -const uint16 laurabow2CDSignaturePaintingClosing[] = { +static const uint16 laurabow2CDSignaturePaintingClosing[] = { 0x39, 0x04, // pushi 04 (cel) 0x76, // push0 SIG_MAGICDWORD, 0x7a, // push2 - 0x38, SIG_UINT16 + 0x31, 0x02, // pushi 0231h (561) + 0x38, SIG_UINT16(0x0231), // pushi 0231h (561) 0x76, // push0 0x43, 0x02, 0x04, // kScriptID (get export 0 of script 561) 0x4a, 0x04, // send 04 (gets safePicture::cel) 0x18, // not 0x31, 0x21, // bnt [exit] - 0x38, SIG_UINT16 + 0x83, 0x02, // pushi 0283h + 0x38, SIG_UINT16(0x0283), // pushi 0283h 0x76, // push0 0x7a, // push2 0x39, 0x20, // pushi 20 @@ -1257,20 +1532,20 @@ const uint16 laurabow2CDSignaturePaintingClosing[] = { SIG_END }; -const uint16 laurabow2CDPatchPaintingClosing[] = { - PATCH_ADDTOOFFSET +2, +static const uint16 laurabow2CDPatchPaintingClosing[] = { + PATCH_ADDTOOFFSET(+2), 0x3c, // dup (1 additional byte) 0x76, // push0 0x3c, // dup (1 additional byte) 0xab, 0x00, // ssl local[0] -> reset safePic signal 0x7a, // push2 - 0x38, PATCH_UINT16 + 0x31, 0x02, // pushi 0231h (561) + 0x38, PATCH_UINT16(0x0231), // pushi 0231h (561) 0x76, // push0 0x43, 0x02, 0x04, // kScriptID (get export 0 of script 561) 0x4a, 0x04, // send 04 (gets safePicture::cel) 0x1a, // eq? 0x31, 0x1d, // bnt [exit] - 0x38, PATCH_UINT16 + 0x83, 0x02, // pushi 0283h + 0x38, PATCH_UINT16(0x0283), // pushi 0283h 0x76, // push0 0x7a, // push2 0x39, 0x20, // pushi 20 @@ -1303,16 +1578,16 @@ const uint16 laurabow2CDPatchPaintingClosing[] = { // Applies to at least: English PC-CD // Responsible method: LB2::newRoom, LB2::handsOff, LB2::handsOn // Fixes bug: #6440 -const uint16 laurabow2CDSignatureFixProblematicIconBar[] = { +static const uint16 laurabow2CDSignatureFixProblematicIconBar[] = { SIG_MAGICDWORD, - 0x38, SIG_UINT16 + 0xf1, 0x00, // pushi 00f1 (disable) - hardcoded, we only want to patch the CD version + 0x38, SIG_UINT16(0x00f1), // pushi 00f1 (disable) - hardcoded, we only want to patch the CD version 0x76, // push0 0x81, 0x45, // lag global[45] 0x4a, 0x04, // send 04 SIG_END }; -const uint16 laurabow2CDPatchFixProblematicIconBar[] = { +static const uint16 laurabow2CDPatchFixProblematicIconBar[] = { 0x35, 0x00, // ldi 00 0xa1, 0x74, // sag 74h 0x35, 0x00, // ldi 00 (waste bytes) @@ -1320,17 +1595,105 @@ const uint16 laurabow2CDPatchFixProblematicIconBar[] = { PATCH_END }; +// Laura Bow 2 CD resets the audio mode to speech on init/restart +// We already sync the settings from ScummVM (see SciEngine::syncIngameAudioOptions()) +// and this script code would make it impossible to see the intro using "dual" mode w/o using debugger command +// That's why we remove the corresponding code +// Patched method: LB2::init, rm100::init +static const uint16 laurabow2CDSignatureAudioTextSupportModeReset[] = { + SIG_MAGICDWORD, + 0x35, 0x02, // ldi 02 + 0xa1, 0x5a, // sag global[5a] + SIG_END +}; + +static const uint16 laurabow2CDPatchAudioTextSupportModeReset[] = { + 0x34, PATCH_UINT16(0x0001), // ldi 0001 (waste bytes) + 0x18, // not (waste bytes) + PATCH_END +}; + +// Directly use global 5a for view-cel id +// That way it's possible to use a new "dual" mode view in the game menu +// View 995, loop 13, cel 0 -> "text" +// View 995, loop 13, cel 1 -> "speech" +// View 995, loop 13, cel 2 -> "dual" (TODO: inject our own view for the new "dual" mode) +// Patched method: gcWin::open +static const uint16 laurabow2CDSignatureAudioTextMenuSupport1[] = { + SIG_MAGICDWORD, + 0x89, 0x5a, // lsg global[5a] + 0x35, 0x02, // ldi 02 + 0x1a, // eq? + 0x36, // push + SIG_END +}; + +static const uint16 laurabow2CDPatchAudioTextMenuSupport1[] = { + PATCH_ADDTOOFFSET(+2), + 0x35, 0x01, // ldi 01 + 0x04, // sub + PATCH_END +}; + +// Adds another button state for the text/audio button. We currently use the "speech" view for "dual" mode. +// TODO: inject our own 2 views for the new "dual" mode +// Patched method: iconMode::doit +static const uint16 laurabow2CDSignatureAudioTextMenuSupport2[] = { + SIG_MAGICDWORD, + 0x89, 0x5a, // lsg global[5a] + 0x3c, // dup + 0x1a, // eq? + 0x31, 0x0a, // bnt [set text mode] + 0x35, 0x02, // ldi 02 + 0xa1, 0x5a, // sag global[5a] + 0x35, 0x01, // ldi 01 + 0xa5, 0x00, // sat temp[0] + 0x33, 0x0e, // jmp [draw cel code] + 0x3c, // dup + 0x35, 0x02, // ldi 02 + 0x1a, // eq? + 0x31, 0x08, // bnt [draw cel code] + 0x35, 0x01, // ldi 01 + 0xa1, 0x5a, // sag global[5a] + 0x35, 0x00, // ldi 00 + 0xa5, 0x00, // sat temp[0] + 0x3a, // toss + SIG_END +}; + +static const uint16 laurabow2CDPatchAudioTextMenuSupport2[] = { + 0x81, 0x5a, // lag global[5a] + 0x78, // push1 + 0x02, // add + 0xa1, 0x5a, // sag global[5a] + 0x36, // push + 0x35, 0x03, // ldi 03 + 0x1e, // gt? + 0x31, 0x03, // bnt [skip over] + 0x78, // push1 + 0xa9, 0x5a, // ssg global[5a] + 0x89, 0x5a, // lsg global[5a] + 0x35, 0x01, // ldi 01 + 0x04, // sub + 0xa5, 0x00, // sat temp[0] - calculate global[5a] - 1 to use as view cel id + 0x33, 0x07, // jmp [draw cel code, don't do toss] + PATCH_END +}; -// script, description, signature patch -SciScriptPatcherEntry laurabow2Signatures[] = { - { true, 560, "CD: painting closing immediately", 1, 0, 0, laurabow2CDSignaturePaintingClosing, laurabow2CDPatchPaintingClosing }, - { true, 0, "CD: fix problematic icon bar", 1, 0, 0, laurabow2CDSignatureFixProblematicIconBar, laurabow2CDPatchFixProblematicIconBar }, +// script, description, signature patch +static const SciScriptPatcherEntry laurabow2Signatures[] = { + { true, 560, "CD: painting closing immediately", 1, laurabow2CDSignaturePaintingClosing, laurabow2CDPatchPaintingClosing }, + { true, 0, "CD: fix problematic icon bar", 1, laurabow2CDSignatureFixProblematicIconBar, laurabow2CDPatchFixProblematicIconBar }, // King's Quest 6 and Laura Bow 2 share basic patches for audio + text support - { false, 924, "CD: audio + text support 1", 1, 0, 0, kq6laurabow2CDSignatureAudioTextSupport1, kq6laurabow2CDPatchAudioTextSupport1 }, - { false, 924, "CD: audio + text support 2", 1, 0, 0, kq6laurabow2CDSignatureAudioTextSupport2, kq6laurabow2CDPatchAudioTextSupport2 }, - { false, 924, "CD: audio + text support 3", 1, 0, 0, kq6laurabow2CDSignatureAudioTextSupport3, kq6laurabow2CDPatchAudioTextSupport3 }, - { false, 928, "CD: audio + text support 4", 1, 0, 0, kq6laurabow2CDSignatureAudioTextSupport4, kq6laurabow2CDPatchAudioTextSupport4 }, - { false, 928, "CD: audio + text support 5", 2, 0, 0, kq6laurabow2CDSignatureAudioTextSupport5, kq6laurabow2CDPatchAudioTextSupport5 }, + { false, 924, "CD: audio + text support 1", 1, kq6laurabow2CDSignatureAudioTextSupport1, kq6laurabow2CDPatchAudioTextSupport1 }, + { false, 924, "CD: audio + text support 2", 1, kq6laurabow2CDSignatureAudioTextSupport2, kq6laurabow2CDPatchAudioTextSupport2 }, + { false, 924, "CD: audio + text support 3", 1, kq6laurabow2CDSignatureAudioTextSupport3, kq6laurabow2CDPatchAudioTextSupport3 }, + { false, 928, "CD: audio + text support 4", 1, kq6laurabow2CDSignatureAudioTextSupport4, kq6laurabow2CDPatchAudioTextSupport4 }, + { false, 928, "CD: audio + text support 5", 2, kq6laurabow2CDSignatureAudioTextSupport5, kq6laurabow2CDPatchAudioTextSupport5 }, + { false, 0, "CD: audio + text support disable mode reset", 1, laurabow2CDSignatureAudioTextSupportModeReset, laurabow2CDPatchAudioTextSupportModeReset }, + { false, 100, "CD: audio + text support disable mode reset", 1, laurabow2CDSignatureAudioTextSupportModeReset, laurabow2CDPatchAudioTextSupportModeReset }, + { false, 24, "CD: audio + text support LB2 menu 1", 1, laurabow2CDSignatureAudioTextMenuSupport1, laurabow2CDPatchAudioTextMenuSupport1 }, + { false, 24, "CD: audio + text support LB2 menu 2", 1, laurabow2CDSignatureAudioTextMenuSupport2, laurabow2CDPatchAudioTextMenuSupport2 }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1339,7 +1702,7 @@ SciScriptPatcherEntry laurabow2Signatures[] = { // MG::replay somewhat calculates the savedgame-id used when saving again // this doesn't work right and we remove the code completely. // We set the savedgame-id directly right after restoring in kRestoreGame. -const uint16 mothergoose256SignatureReplay[] = { +static const uint16 mothergoose256SignatureReplay[] = { 0x36, // push 0x35, SIG_MAGICDWORD, 0x20, // ldi 20 0x04, // sub @@ -1347,32 +1710,32 @@ const uint16 mothergoose256SignatureReplay[] = { SIG_END }; -const uint16 mothergoose256PatchReplay[] = { - 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0000 (dummy) - 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0000 (dummy) +static const uint16 mothergoose256PatchReplay[] = { + 0x34, PATCH_UINT16(0x0000), // ldi 0000 (dummy) + 0x34, PATCH_UINT16(0x0000), // ldi 0000 (dummy) PATCH_END }; // when saving, it also checks if the savegame ID is below 13. // we change this to check if below 113 instead -const uint16 mothergoose256SignatureSaveLimit[] = { +static const uint16 mothergoose256SignatureSaveLimit[] = { 0x89, SIG_MAGICDWORD, 0xb3, // lsg global[b3] 0x35, 0x0d, // ldi 0d 0x20, // ge? SIG_END }; -const uint16 mothergoose256PatchSaveLimit[] = { - PATCH_ADDTOOFFSET | +2, +static const uint16 mothergoose256PatchSaveLimit[] = { + PATCH_ADDTOOFFSET(+2), 0x35, 0x0d + SAVEGAMEID_OFFICIALRANGE_START, // ldi 113d PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry mothergoose256Signatures[] = { - { true, 0, "replay save issue", 1, 0, 0, mothergoose256SignatureReplay, mothergoose256PatchReplay }, - { true, 0, "save limit dialog (SCI1.1)", 1, 0, 0, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit }, - { true, 994, "save limit dialog (SCI1)", 1, 0, 0, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit }, +// script, description, signature patch +static const SciScriptPatcherEntry mothergoose256Signatures[] = { + { true, 0, "replay save issue", 1, mothergoose256SignatureReplay, mothergoose256PatchReplay }, + { true, 0, "save limit dialog (SCI1.1)", 1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit }, + { true, 994, "save limit dialog (SCI1)", 1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1389,13 +1752,13 @@ SciScriptPatcherEntry mothergoose256Signatures[] = { // Applies to at least: English floppy // Responsible method: putGun::changeState (script 341) // Fixes bug: #5705 / #6400 -const uint16 pq1vgaSignaturePutGunInLockerBug[] = { +static const uint16 pq1vgaSignaturePutGunInLockerBug[] = { 0x35, 0x00, // ldi 00 0x1a, // eq? 0x31, 0x25, // bnt [next state check] - SIG_ADDTOOFFSET +22, // [skip 22 bytes] + SIG_ADDTOOFFSET(+22), // [skip 22 bytes] SIG_MAGICDWORD, - 0x38, SIG_SELECTOR16 + SELECTOR_put, // pushi "put" + 0x38, SIG_SELECTOR16(put), // pushi "put" 0x78, // push1 0x76, // push0 0x81, 0x00, // lag 00 @@ -1407,17 +1770,17 @@ const uint16 pq1vgaSignaturePutGunInLockerBug[] = { 0x35, 0x01, // ldi 01 0x1a, // eq? 0x31, 0x08, // bnt [end of method] - 0x39, SIG_SELECTOR8 + SELECTOR_dispose, // pushi "dispose" + 0x39, SIG_SELECTOR8(dispose), // pushi "dispose" 0x76, // push0 - 0x72, SIG_UINT16 + 0x88, 0x00, // lofsa 0088 + 0x72, SIG_UINT16(0x0088), // lofsa 0088 0x4a, 0x04, // send 04 - locker::dispose SIG_END }; -const uint16 pq1vgaPatchPutGunInLockerBug[] = { - PATCH_ADDTOOFFSET +3, +static const uint16 pq1vgaPatchPutGunInLockerBug[] = { + PATCH_ADDTOOFFSET(+3), 0x31, 0x1c, // bnt [next state check] - PATCH_ADDTOOFFSET +22, + PATCH_ADDTOOFFSET(+22), 0x35, 0x02, // ldi 02 0x65, 0x1c, // aTop 1c (set timer to 2 seconds) 0x33, 0x17, // jmp [end of method] @@ -1425,7 +1788,7 @@ const uint16 pq1vgaPatchPutGunInLockerBug[] = { 0x35, 0x01, // ldi 01 0x1a, // eq? 0x31, 0x11, // bnt [end of method] - 0x38, PATCH_SELECTOR16 + SELECTOR_put, // pushi "put" + 0x38, PATCH_SELECTOR16(put), // pushi "put" 0x78, // push1 0x76, // push0 0x81, 0x00, // lag 00 @@ -1433,9 +1796,42 @@ const uint16 pq1vgaPatchPutGunInLockerBug[] = { PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry pq1vgaSignatures[] = { - { true, 341, "put gun in locker bug", 1, 0, 0, pq1vgaSignaturePutGunInLockerBug, pq1vgaPatchPutGunInLockerBug }, +// When restoring a saved game, which was made while driving around, +// the game didn't redraw the map. This also happened in Sierra SCI. +// +// The map is a picture resource and drawn over the main picture. +// This is called an "overlay" in SCI. This wasn't implemented properly. +// We fix it by actually implementing it properly. +// +// Applies to at least: English floppy +// Responsible method: rm500::init, changeOverlay::changeState (script 500) +// Fixes bug: #5016 +static const uint16 pq1vgaSignatureMapSaveRestoreBug[] = { + 0x39, 0x04, // pushi 04 + SIG_ADDTOOFFSET(+2), // skip either lsg global[f9] or pTos register + SIG_MAGICDWORD, + 0x38, 0x64, 0x80, // pushi 8064 + 0x76, // push0 + 0x89, 0x28, // lsg global[28] + 0x43, 0x08, 0x08, // kDrawPic (8) + SIG_END +}; + +static const uint16 pq1vgaPatchMapSaveRestoreBug[] = { + 0x38, PATCH_SELECTOR16(overlay), // pushi "overlay" + 0x7a, // push2 + 0x89, 0xf9, // lsg global[f9] + 0x39, 0x64, // pushi 64 (no transition) + 0x81, 0x02, // lag global[02] (current room object) + 0x4a, 0x08, // send 08 + 0x18, // not (waste byte) + PATCH_END +}; + +// script, description, signature patch +static const SciScriptPatcherEntry pq1vgaSignatures[] = { + { true, 341, "put gun in locker bug", 1, pq1vgaSignaturePutGunInLockerBug, pq1vgaPatchPutGunInLockerBug }, + { true, 500, "map save/restore bug", 2, pq1vgaSignatureMapSaveRestoreBug, pq1vgaPatchMapSaveRestoreBug }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1450,9 +1846,9 @@ SciScriptPatcherEntry pq1vgaSignatures[] = { // We just reuse the active event, thus removing the duplicate kGetEvent call. // Applies to at least: English floppy // Responsible method: pointBox::doit -const uint16 qfg1vgaSignatureFightEvents[] = { +static const uint16 qfg1vgaSignatureFightEvents[] = { 0x39, SIG_MAGICDWORD, - SIG_SELECTOR8 + SELECTOR_new, // pushi "new" + SIG_SELECTOR8(new), // pushi "new" 0x76, // push0 0x51, 0x07, // class Event 0x4a, 0x04, // send 04 - call Event::new @@ -1471,8 +1867,8 @@ const uint16 qfg1vgaSignatureFightEvents[] = { SIG_END }; -const uint16 qfg1vgaPatchFightEvents[] = { - 0x38, PATCH_SELECTOR16 + SELECTOR_curEvent, // pushi 15a (selector curEvent) +static const uint16 qfg1vgaPatchFightEvents[] = { + 0x38, PATCH_SELECTOR16(curEvent), // pushi 15a (selector curEvent) 0x76, // push0 0x81, 0x50, // lag global[50] 0x4a, 0x04, // send 04 - read User::curEvent -> needs one byte more than previous code @@ -1500,27 +1896,27 @@ const uint16 qfg1vgaPatchFightEvents[] = { // Fixes bug: #6139. // Patch 1: Increase temp space -const uint16 qfg1vgaSignatureTempSpace[] = { +static const uint16 qfg1vgaSignatureTempSpace[] = { SIG_MAGICDWORD, 0x3f, 0xba, // link 0xba 0x87, 0x00, // lap 0 SIG_END }; -const uint16 qfg1vgaPatchTempSpace[] = { +static const uint16 qfg1vgaPatchTempSpace[] = { 0x3f, 0xca, // link 0xca PATCH_END }; // Patch 2: Move the pointer used for the window header a little bit -const uint16 qfg1vgaSignatureDialogHeader[] = { +static const uint16 qfg1vgaSignatureDialogHeader[] = { SIG_MAGICDWORD, 0x5b, 0x04, 0x80, // lea temp[0x80] 0x36, // push SIG_END }; -const uint16 qfg1vgaPatchDialogHeader[] = { +static const uint16 qfg1vgaPatchDialogHeader[] = { 0x5b, 0x04, 0x90, // lea temp[0x90] PATCH_END }; @@ -1534,18 +1930,18 @@ const uint16 qfg1vgaPatchDialogHeader[] = { // the crusher, ego is supposed to move close to position 79, 165. We change it // to 85, 165, which is not an edge case thus the freeze is avoided. // Fixes bug: #6180 -const uint16 qfg1vgaSignatureMoveToCrusher[] = { +static const uint16 qfg1vgaSignatureMoveToCrusher[] = { SIG_MAGICDWORD, 0x51, 0x1f, // class Motion 0x36, // push 0x39, 0x4f, // pushi 4f (79 - x) - 0x38, SIG_UINT16 + 0xa5, 0x00, // pushi 00a5 (165 - y) + 0x38, SIG_UINT16(0x00a5), // pushi 00a5 (165 - y) 0x7c, // pushSelf SIG_END }; -const uint16 qfg1vgaPatchMoveToCrusher[] = { - PATCH_ADDTOOFFSET +3, +static const uint16 qfg1vgaPatchMoveToCrusher[] = { + PATCH_ADDTOOFFSET(+3), 0x39, 0x55, // pushi 55 (85 - x) PATCH_END }; @@ -1554,7 +1950,7 @@ const uint16 qfg1vgaPatchMoveToCrusher[] = { // spot when sneaking. In GuardsTrumpet::changeState, we change the final // location where Ego is moved from 111, 111 to 114, 114. // Fixes bug: #6248 -const uint16 qfg1vgaSignatureMoveToCastleGate[] = { +static const uint16 qfg1vgaSignatureMoveToCastleGate[] = { SIG_MAGICDWORD, 0x51, 0x1f, // class MoveTo 0x36, // push @@ -1564,8 +1960,8 @@ const uint16 qfg1vgaSignatureMoveToCastleGate[] = { SIG_END }; -const uint16 qfg1vgaPatchMoveToCastleGate[] = { - PATCH_ADDTOOFFSET +3, +static const uint16 qfg1vgaPatchMoveToCastleGate[] = { + PATCH_ADDTOOFFSET(+3), 0x39, 0x72, // pushi 72 (114 - x) PATCH_END }; @@ -1576,12 +1972,12 @@ const uint16 qfg1vgaPatchMoveToCastleGate[] = { // Applies to at least: English floppy // Responsible method: smallMonster::doVerb // Fixes bug #6249 -const uint16 qfg1vgaSignatureCheetaurDescription[] = { +static const uint16 qfg1vgaSignatureCheetaurDescription[] = { SIG_MAGICDWORD, - 0x34, SIG_UINT16 + 0xb8, 0x01, // ldi 01b8 + 0x34, SIG_UINT16(0x01b8), // ldi 01b8 0x1a, // eq? 0x31, 0x16, // bnt 16 - 0x38, SIG_UINT16 + 0x27, 0x01, // pushi 0127 + 0x38, SIG_UINT16(0x0127), // pushi 0127 0x39, 0x06, // pushi 06 0x39, 0x03, // pushi 03 0x78, // push1 @@ -1589,8 +1985,8 @@ const uint16 qfg1vgaSignatureCheetaurDescription[] = { SIG_END }; -const uint16 qfg1vgaPatchCheetaurDescription[] = { - PATCH_ADDTOOFFSET +14, +static const uint16 qfg1vgaPatchCheetaurDescription[] = { + PATCH_ADDTOOFFSET(+14), 0x39, 0x11, // pushi 11 -> monster type cheetaur PATCH_END }; @@ -1608,22 +2004,22 @@ const uint16 qfg1vgaPatchCheetaurDescription[] = { // Applies to at least: English floppy // Responsible method: happyFace::changeState, door11::doit // Fixes bug #6181 -const uint16 qfg1vgaSignatureFunnyRoomFix[] = { +static const uint16 qfg1vgaSignatureFunnyRoomFix[] = { 0x65, 0x14, // aTop 14 (state) 0x36, // push 0x3c, // dup 0x35, 0x00, // ldi 00 0x1a, // eq? - 0x30, SIG_UINT16 + 0x25, 0x00, // bnt 0025 [-> next state] + 0x30, SIG_UINT16(0x0025), // bnt 0025 [-> next state] SIG_MAGICDWORD, 0x35, 0x01, // ldi 01 0xa3, 0x4e, // sal 4e SIG_END }; -const uint16 qfg1vgaPatchFunnyRoomFix[] = { - PATCH_ADDTOOFFSET +3, - 0x2e, PATCH_UINT16 + 0x29, 0x00, // bt 0029 [-> next state] - saves 4 bytes +static const uint16 qfg1vgaPatchFunnyRoomFix[] = { + PATCH_ADDTOOFFSET(+3), + 0x2e, PATCH_UINT16(0x0029), // bt 0029 [-> next state] - saves 4 bytes 0x35, 0x01, // ldi 01 0xa3, 0x4e, // sal 4e 0xa3, 0x05, // sal 05 (sets local 5 to 1) @@ -1631,16 +2027,16 @@ const uint16 qfg1vgaPatchFunnyRoomFix[] = { PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry qfg1vgaSignatures[] = { - { true, 215, "fight event issue", 1, 0, 0, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents }, - { true, 216, "weapon master event issue", 1, 0, 0, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents }, - { true, 814, "window text temp space", 1, 0, 0, qfg1vgaSignatureTempSpace, qfg1vgaPatchTempSpace }, - { true, 814, "dialog header offset", 3, 0, 0, qfg1vgaSignatureDialogHeader, qfg1vgaPatchDialogHeader }, - { true, 331, "moving to crusher", 1, 0, 0, qfg1vgaSignatureMoveToCrusher, qfg1vgaPatchMoveToCrusher }, - { true, 41, "moving to castle gate", 1, 0, 0, qfg1vgaSignatureMoveToCastleGate, qfg1vgaPatchMoveToCastleGate }, - { true, 210, "cheetaur description fixed", 1, 0, 0, qfg1vgaSignatureCheetaurDescription, qfg1vgaPatchCheetaurDescription }, - { true, 96, "funny room script bug fixed", 1, 0, 0, qfg1vgaSignatureFunnyRoomFix, qfg1vgaPatchFunnyRoomFix }, +// script, description, signature patch +static const SciScriptPatcherEntry qfg1vgaSignatures[] = { + { true, 215, "fight event issue", 1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents }, + { true, 216, "weapon master event issue", 1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents }, + { true, 814, "window text temp space", 1, qfg1vgaSignatureTempSpace, qfg1vgaPatchTempSpace }, + { true, 814, "dialog header offset", 3, qfg1vgaSignatureDialogHeader, qfg1vgaPatchDialogHeader }, + { true, 331, "moving to crusher", 1, qfg1vgaSignatureMoveToCrusher, qfg1vgaPatchMoveToCrusher }, + { true, 41, "moving to castle gate", 1, qfg1vgaSignatureMoveToCastleGate, qfg1vgaPatchMoveToCastleGate }, + { true, 210, "cheetaur description fixed", 1, qfg1vgaSignatureCheetaurDescription, qfg1vgaPatchCheetaurDescription }, + { true, 96, "funny room script bug fixed", 1, qfg1vgaSignatureFunnyRoomFix, qfg1vgaPatchFunnyRoomFix }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1658,9 +2054,9 @@ SciScriptPatcherEntry qfg1vgaSignatures[] = { // and text entry refreshes whenever a button is pressed, and prevent possible // crashes because of these constant quick object reallocations. // Fixes bug: #5096 -const uint16 qfg2SignatureImportDialog[] = { +static const uint16 qfg2SignatureImportDialog[] = { 0x63, SIG_MAGICDWORD, 0x20, // pToa text - 0x30, SIG_UINT16 + 0x0b, 0x00, // bnt [next state] + 0x30, SIG_UINT16(0x000b), // bnt [next state] 0x7a, // push2 0x39, 0x03, // pushi 03 0x36, // push @@ -1670,21 +2066,21 @@ const uint16 qfg2SignatureImportDialog[] = { SIG_END }; -const uint16 qfg2PatchImportDialog[] = { - PATCH_ADDTOOFFSET +5, +static const uint16 qfg2PatchImportDialog[] = { + PATCH_ADDTOOFFSET(+5), 0x48, // ret PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry qfg2Signatures[] = { - { true, 944, "import dialog continuous calls", 1, 0, 0, qfg2SignatureImportDialog, qfg2PatchImportDialog }, +// script, description, signature patch +static const SciScriptPatcherEntry qfg2Signatures[] = { + { true, 944, "import dialog continuous calls", 1, qfg2SignatureImportDialog, qfg2PatchImportDialog }, SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== // Patch for the import screen in QFG3, same as the one for QFG2 above -const uint16 qfg3SignatureImportDialog[] = { +static const uint16 qfg3SignatureImportDialog[] = { 0x63, SIG_MAGICDWORD, 0x2a, // pToa text 0x31, 0x0b, // bnt [next state] 0x7a, // push2 @@ -1696,8 +2092,8 @@ const uint16 qfg3SignatureImportDialog[] = { SIG_END }; -const uint16 qfg3PatchImportDialog[] = { - PATCH_ADDTOOFFSET +4, +static const uint16 qfg3PatchImportDialog[] = { + PATCH_ADDTOOFFSET(+4), 0x48, // ret PATCH_END }; @@ -1720,7 +2116,7 @@ const uint16 qfg3PatchImportDialog[] = { // Applies to at least: English, German, Italian, French, Spanish Floppy // Responsible method: unknown // Fixes bug: #5172 -const uint16 qfg3SignatureWooDialog[] = { +static const uint16 qfg3SignatureWooDialog[] = { SIG_MAGICDWORD, 0x67, 0x12, // pTos 12 (query) 0x35, 0xb6, // ldi b6 @@ -1730,9 +2126,9 @@ const uint16 qfg3SignatureWooDialog[] = { 0x35, 0x9b, // ldi 9b 0x1a, // eq? 0x31, 0x0c, // bnt 0c - 0x38, SIG_SELECTOR16 + SELECTOR_solvePuzzle, // pushi 0297 + 0x38, SIG_SELECTOR16(solvePuzzle), // pushi 0297 0x7a, // push2 - 0x38, SIG_UINT16 + 0x0c, 0x01, // pushi 010c + 0x38, SIG_UINT16(0x010c), // pushi 010c 0x7a, // push2 0x81, 0x00, // lag 00 0x4a, 0x08, // send 08 @@ -1741,16 +2137,16 @@ const uint16 qfg3SignatureWooDialog[] = { SIG_END }; -const uint16 qfg3PatchWooDialog[] = { - PATCH_ADDTOOFFSET +0x29, +static const uint16 qfg3PatchWooDialog[] = { + PATCH_ADDTOOFFSET(+0x29), 0x33, 0x11, // jmp to 0x6a2, the call to hero::solvePuzzle for 0xFFFC PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry qfg3Signatures[] = { - { true, 944, "import dialog continuous calls", 1, 0, 0, qfg3SignatureImportDialog, qfg3PatchImportDialog }, - { true, 440, "dialog crash when asking about Woo", 1, 0, 0, qfg3SignatureWooDialog, qfg3PatchWooDialog }, +// script, description, signature patch +static const SciScriptPatcherEntry qfg3Signatures[] = { + { true, 944, "import dialog continuous calls", 1, qfg3SignatureImportDialog, qfg3PatchImportDialog }, + { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialog, qfg3PatchWooDialog }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1762,29 +2158,61 @@ SciScriptPatcherEntry qfg3Signatures[] = { // we could either calculate property count differently somehow fixing this // but I think just patching it out is cleaner. // Fixes bug: #5093 -const uint16 sq4FloppySignatureEndlessFlight[] = { +static const uint16 sq4FloppySignatureEndlessFlight[] = { 0x39, 0x04, // pushi 04 (selector x) SIG_MAGICDWORD, 0x78, // push1 0x67, 0x08, // pTos 08 (property x) - 0x63, SIG_ADDTOOFFSET + 1, // pToa (invalid property) - 44h for English floppy, 4ch for German floppy + 0x63, SIG_ADDTOOFFSET(+1), // pToa (invalid property) - 44h for English floppy, 4ch for German floppy 0x02, // add SIG_END }; -const uint16 sq4FloppyPatchEndlessFlight[] = { - PATCH_ADDTOOFFSET +5, +static const uint16 sq4FloppyPatchEndlessFlight[] = { + PATCH_ADDTOOFFSET(+5), 0x35, 0x03, // ldi 03 (which would be the content of the property) PATCH_END }; +// Floppy-only: When the player tries to throw something at the sequel police in Space Quest X (zero g zone), +// the game will first show a textbox and then cause a signature mismatch in ScummVM/ +// crash the whole game in Sierra SCI/display garbage (the latter when the Sierra "patch" got applied). +// +// All of this is caused by a typo in the script. Right after the code for showing the textbox, +// there is more similar code for showing another textbox, but without a pointer to the text. +// This has to be a typo, because there is no unused text to be found within that script. +// +// Sierra's "patch" didn't include a proper fix (as in a modified script). Instead they shipped a dummy +// text resource, which somewhat "solved" the issue in Sierra SCI, but it still showed another textbox +// with garbage in it. Funnily Sierra must have known that, because that new text resource contains: +// "Hi! This is a kludge!" +// +// We properly fix it by removing the faulty code. +// Applies to at least: English Floppy +// Responsible method: sp1::doVerb +// Fixes bug: found by SCI developer +static const uint16 sq4FloppySignatureThrowStuffAtSequelPoliceBug[] = { + 0x47, 0xff, 0x00, 0x02, // call export 255_0, 2 + 0x3a, // toss + SIG_MAGICDWORD, + 0x36, // push + 0x47, 0xff, 0x00, 0x02, // call export 255_0, 2 + SIG_END +}; + +static const uint16 sq4FloppyPatchThrowStuffAtSequelPoliceBug[] = { + PATCH_ADDTOOFFSET(+5), + 0x48, // ret + PATCH_END +}; + // The scripts in SQ4CD support simultaneous playing of speech and subtitles, // but this was not available as an option. The following two patches enable // this functionality in the game's GUI options dialog. // Patch 1: iconTextSwitch::show, called when the text options button is shown. // This is patched to add the "Both" text resource (i.e. we end up with // "Speech", "Text" and "Both") -const uint16 sq4CdSignatureTextOptionsButton[] = { +static const uint16 sq4CdSignatureTextOptionsButton[] = { SIG_MAGICDWORD, 0x35, 0x01, // ldi 0x01 0xa1, 0x53, // sag 0x53 @@ -1795,8 +2223,8 @@ const uint16 sq4CdSignatureTextOptionsButton[] = { SIG_END }; -const uint16 sq4CdPatchTextOptionsButton[] = { - PATCH_ADDTOOFFSET +7, +static const uint16 sq4CdPatchTextOptionsButton[] = { + PATCH_ADDTOOFFSET(+7), 0x39, 0x0b, // pushi 0x0b PATCH_END }; @@ -1804,7 +2232,7 @@ const uint16 sq4CdPatchTextOptionsButton[] = { // Patch 2: Adjust a check in babbleIcon::init, which handles the babble icon // (e.g. the two guys from Andromeda) shown when dying/quitting. // Fixes bug: #6068 -const uint16 sq4CdSignatureBabbleIcon[] = { +static const uint16 sq4CdSignatureBabbleIcon[] = { SIG_MAGICDWORD, 0x89, 0x5a, // lsg 5a 0x35, 0x02, // ldi 02 @@ -1813,7 +2241,7 @@ const uint16 sq4CdSignatureBabbleIcon[] = { SIG_END }; -const uint16 sq4CdPatchBabbleIcon[] = { +static const uint16 sq4CdPatchBabbleIcon[] = { 0x89, 0x5a, // lsg 5a 0x35, 0x01, // ldi 01 0x1a, // eq? @@ -1825,7 +2253,7 @@ const uint16 sq4CdPatchBabbleIcon[] = { // when the text options button is clicked: "Speech", "Text" and "Both". // Refer to the patch above for additional details. // iconTextSwitch::doit (called when the text options button is clicked) -const uint16 sq4CdSignatureTextOptions[] = { +static const uint16 sq4CdSignatureTextOptions[] = { SIG_MAGICDWORD, 0x89, 0x5a, // lsg 0x5a (load global 90 to stack) 0x3c, // dup @@ -1842,14 +2270,14 @@ const uint16 sq4CdSignatureTextOptions[] = { 0x35, 0x01, // ldi 0x01 0xa1, 0x5a, // sag 0x5a (save acc to global 90) 0x3a, // toss - 0x38, SIG_SELECTOR16 + SELECTOR_show, // pushi 0x00d9 + 0x38, SIG_SELECTOR16(show), // pushi 0x00d9 0x76, // push0 0x54, 0x04, // self 0x04 0x48, // ret SIG_END }; -const uint16 sq4CdPatchTextOptions[] = { +static const uint16 sq4CdPatchTextOptions[] = { 0x89, 0x5a, // lsg 0x5a (load global 90 to stack) 0x3c, // dup 0x35, 0x03, // ldi 0x03 (acc = 3) @@ -1862,18 +2290,19 @@ const uint16 sq4CdPatchTextOptions[] = { 0x35, 0x01, // ldi 0x01 (reset acc to 1) 0xa1, 0x5a, // sag 0x5a (save acc to global 90) 0x33, 0x03, // jmp 0x03 (jump over the wasted bytes below) - 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0x0000 (waste 3 bytes) + 0x34, PATCH_UINT16(0x0000), // ldi 0x0000 (waste 3 bytes) 0x3a, // toss // (the rest of the code is the same) PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry sq4Signatures[] = { - { true, 298, "Floppy: endless flight", 1, 0, 0, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight }, - { true, 818, "CD: Speech and subtitles option", 1, 0, 0, sq4CdSignatureTextOptions, sq4CdPatchTextOptions }, - { true, 0, "CD: Babble icon speech and subtitles fix", 1, 0, 0, sq4CdSignatureBabbleIcon, sq4CdPatchBabbleIcon }, - { true, 818, "CD: Speech and subtitles option button", 1, 0, 0, sq4CdSignatureTextOptionsButton, sq4CdPatchTextOptionsButton }, +// script, description, signature patch +static const SciScriptPatcherEntry sq4Signatures[] = { + { true, 298, "Floppy: endless flight", 1, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight }, + { true, 700, "Floppy: throw stuff at sequel police bug", 1, sq4FloppySignatureThrowStuffAtSequelPoliceBug, sq4FloppyPatchThrowStuffAtSequelPoliceBug }, + { true, 818, "CD: Speech and subtitles option", 1, sq4CdSignatureTextOptions, sq4CdPatchTextOptions }, + { true, 0, "CD: Babble icon speech and subtitles fix", 1, sq4CdSignatureBabbleIcon, sq4CdPatchBabbleIcon }, + { true, 818, "CD: Speech and subtitles option button", 1, sq4CdSignatureTextOptionsButton, sq4CdPatchTextOptionsButton }, SCI_SIGNATUREENTRY_TERMINATOR }; @@ -1888,26 +2317,26 @@ SciScriptPatcherEntry sq4Signatures[] = { // The same issue happens in Sierra SCI. // We simply set the correct starting cel number to fix the bug. // Responsible method: robotIntoShip::changeState(9) -const uint16 sq1vgaSignatureUlenceFlatsTimepodGfxGlitch[] = { - 0x39, - SIG_MAGICDWORD, SIG_SELECTOR8 + SELECTOR_cel, // pushi "cel" +static const uint16 sq1vgaSignatureUlenceFlatsTimepodGfxGlitch[] = { + 0x39, + SIG_MAGICDWORD, SIG_SELECTOR8(cel), // pushi "cel" 0x78, // push1 0x39, 0x0a, // pushi 0x0a (set ship::cel to 10) - 0x38, SIG_UINT16 + 0xa0, 0x00, // pushi 0x00a0 (ship::setLoop) + 0x38, SIG_UINT16(0x00a0), // pushi 0x00a0 (ship::setLoop) SIG_END }; -const uint16 sq1vgaPatchUlenceFlatsTimepodGfxGlitch[] = { - PATCH_ADDTOOFFSET +3, +static const uint16 sq1vgaPatchUlenceFlatsTimepodGfxGlitch[] = { + PATCH_ADDTOOFFSET(+3), 0x39, 0x09, // pushi 0x09 (set ship::cel to 9) PATCH_END }; -const uint16 sq1vgaSignatureEgoShowsCard[] = { +static const uint16 sq1vgaSignatureEgoShowsCard[] = { SIG_MAGICDWORD, - 0x38, SIG_SELECTOR16 + SELECTOR_timesShownID, // push "timesShownID" + 0x38, SIG_SELECTOR16(timesShownID), // push "timesShownID" 0x78, // push1 - 0x38, SIG_SELECTOR16 + SELECTOR_timesShownID, // push "timesShownID" + 0x38, SIG_SELECTOR16(timesShownID), // push "timesShownID" 0x76, // push0 0x51, 0x7c, // class DeltaurRegion 0x4a, 0x04, // send 0x04 (get timesShownID) @@ -1925,8 +2354,8 @@ const uint16 sq1vgaSignatureEgoShowsCard[] = { // Note that this script patch is merely a reordering of the // instructions in the original script. -const uint16 sq1vgaPatchEgoShowsCard[] = { - 0x38, PATCH_SELECTOR16 + SELECTOR_timesShownID, // push "timesShownID" +static const uint16 sq1vgaPatchEgoShowsCard[] = { + 0x38, PATCH_SELECTOR16(timesShownID), // push "timesShownID" 0x76, // push0 0x51, 0x7c, // class DeltaurRegion 0x4a, 0x04, // send 0x04 (get timesShownID) @@ -1934,7 +2363,7 @@ const uint16 sq1vgaPatchEgoShowsCard[] = { 0x35, 0x01, // ldi 1 0x02, // add 0x36, // push (this push corresponds to the wrong one above) - 0x38, PATCH_SELECTOR16 + SELECTOR_timesShownID, // push "timesShownID" + 0x38, PATCH_SELECTOR16(timesShownID), // push "timesShownID" 0x78, // push1 0x36, // push 0x51, 0x7c, // class DeltaurRegion @@ -1945,11 +2374,12 @@ const uint16 sq1vgaPatchEgoShowsCard[] = { }; -// script, description, signature patch -SciScriptPatcherEntry sq1vgaSignatures[] = { - { true, 45, "Ulence Flats: timepod graphic glitch", 1, 0, 0, sq1vgaSignatureUlenceFlatsTimepodGfxGlitch, sq1vgaPatchUlenceFlatsTimepodGfxGlitch }, - { true, 58, "Sarien armory droid zapping ego first time", 1, 0, 0, sq1vgaSignatureEgoShowsCard, sq1vgaPatchEgoShowsCard }, - SCI_SIGNATUREENTRY_TERMINATOR}; +// script, description, signature patch +static const SciScriptPatcherEntry sq1vgaSignatures[] = { + { true, 45, "Ulence Flats: timepod graphic glitch", 1, sq1vgaSignatureUlenceFlatsTimepodGfxGlitch, sq1vgaPatchUlenceFlatsTimepodGfxGlitch }, + { true, 58, "Sarien armory droid zapping ego first time", 1, sq1vgaSignatureEgoShowsCard, sq1vgaPatchEgoShowsCard }, + SCI_SIGNATUREENTRY_TERMINATOR +}; // =========================================================================== // The toolbox in sq5 is buggy. When you click on the upper part of the "put @@ -1973,10 +2403,10 @@ SciScriptPatcherEntry sq1vgaSignatures[] = { // Applies to at least: English/German/French PC floppy // Responsible method: takeTool::changeState // Fixes bug: #6457 -const uint16 sq5SignatureToolboxFix[] = { +static const uint16 sq5SignatureToolboxFix[] = { 0x31, 0x13, // bnt [check for state 1] SIG_MAGICDWORD, - 0x38, SIG_UINT16 + 0xaa, 0x00, // pushi 00aa + 0x38, SIG_UINT16(0x00aa), // pushi 00aa 0x39, 0x05, // pushi 05 0x39, 0x16, // pushi 16 0x76, // push0 @@ -1985,7 +2415,7 @@ const uint16 sq5SignatureToolboxFix[] = { 0x7c, // pushSelf 0x81, 0x5b, // lag 5b 0x4a, 0x0e, // send 0e - 0x32, SIG_UINT16 + 0x88, 0x00, // jmp [end-of-method] + 0x32, SIG_UINT16(0x0088), // jmp [end-of-method] 0x3c, // dup 0x35, 0x01, // ldi 01 0x1a, // eq? @@ -1993,9 +2423,9 @@ const uint16 sq5SignatureToolboxFix[] = { SIG_END }; -const uint16 sq5PatchToolboxFix[] = { +static const uint16 sq5PatchToolboxFix[] = { 0x31, 0x41, // bnt [check for state 2] - PATCH_ADDTOOFFSET +16, // skip to jmp offset + PATCH_ADDTOOFFSET(+16), // skip to jmp offset 0x35, 0x01, // ldi 01 0x65, 0x14, // aTop [state] 0x36, 0x00, 0x00, // ldi 0000 (waste 3 bytes) @@ -2003,15 +2433,33 @@ const uint16 sq5PatchToolboxFix[] = { PATCH_END }; -// script, description, signature patch -SciScriptPatcherEntry sq5Signatures[] = { - { true, 226, "toolbox fix", 1, 0, 0, sq5SignatureToolboxFix, sq5PatchToolboxFix }, +// script, description, signature patch +static const SciScriptPatcherEntry sq5Signatures[] = { + { true, 226, "toolbox fix", 1, sq5SignatureToolboxFix, sq5PatchToolboxFix }, SCI_SIGNATUREENTRY_TERMINATOR }; +// ================================================================================= + +ScriptPatcher::ScriptPatcher() { + int selectorCount = ARRAYSIZE(selectorNameTable); + int selectorNr; + + // Allocate table for selector-IDs and initialize that table as well + _selectorIdTable = new Selector[ selectorCount ]; + for (selectorNr = 0; selectorNr < selectorCount; selectorNr++) + _selectorIdTable[selectorNr] = -1; + + _runtimeTable = NULL; +} + +ScriptPatcher::~ScriptPatcher() { + delete[] _runtimeTable; + delete[] _selectorIdTable; +} // will actually patch previously found signature area -void Script::patcherApplyPatch(const SciScriptPatcherEntry *patchEntry, byte *scriptData, const uint32 scriptSize, int32 signatureOffset, const bool isMacSci11) { +void ScriptPatcher::applyPatch(const SciScriptPatcherEntry *patchEntry, byte *scriptData, const uint32 scriptSize, int32 signatureOffset, const bool isMacSci11) { const uint16 *patchData = patchEntry->patchData; byte orgData[PATCH_VALUELIMIT]; int32 offset = signatureOffset; @@ -2028,12 +2476,12 @@ void Script::patcherApplyPatch(const SciScriptPatcherEntry *patchEntry, byte *sc uint16 patchCommand = patchWord & PATCH_COMMANDMASK; uint16 patchValue = patchWord & PATCH_VALUEMASK; switch (patchCommand) { - case PATCH_ADDTOOFFSET: { + case PATCH_CODE_ADDTOOFFSET: { // add value to offset offset += patchValue; break; } - case PATCH_GETORIGINALBYTE: { + case PATCH_CODE_GETORIGINALBYTE: { // get original byte from script if (patchValue >= orgDataSize) error("Script-Patcher: can not get requested original byte from script"); @@ -2041,7 +2489,7 @@ void Script::patcherApplyPatch(const SciScriptPatcherEntry *patchEntry, byte *sc offset++; break; } - case PATCH_GETORIGINALBYTEADJUST: { + case PATCH_CODE_GETORIGINALBYTEADJUST: { // get original byte from script and adjust it if (patchValue >= orgDataSize) error("Script-Patcher: can not get requested original byte from script"); @@ -2052,13 +2500,13 @@ void Script::patcherApplyPatch(const SciScriptPatcherEntry *patchEntry, byte *sc offset++; break; } - case PATCH_UINT16: - case PATCH_SELECTOR16: { + case PATCH_CODE_UINT16: + case PATCH_CODE_SELECTOR16: { byte byte1; byte byte2; - + switch (patchCommand) { - case PATCH_UINT16: { + case PATCH_CODE_UINT16: { byte1 = patchValue & PATCH_BYTEMASK; patchData++; patchWord = *patchData; if (patchWord & PATCH_COMMANDMASK) @@ -2066,8 +2514,8 @@ void Script::patcherApplyPatch(const SciScriptPatcherEntry *patchEntry, byte *sc byte2 = patchWord & PATCH_BYTEMASK; break; } - case PATCH_SELECTOR16: { - patchSelector = selectorTable[patchValue].id; + case PATCH_CODE_SELECTOR16: { + patchSelector = _selectorIdTable[patchValue]; byte1 = patchSelector & 0xFF; byte2 = patchSelector >> 8; break; @@ -2085,15 +2533,15 @@ void Script::patcherApplyPatch(const SciScriptPatcherEntry *patchEntry, byte *sc } break; } - case PATCH_SELECTOR8: { - patchSelector = selectorTable[patchValue].id; + case PATCH_CODE_SELECTOR8: { + patchSelector = _selectorIdTable[patchValue]; if (patchSelector & 0xFF00) error("Script-Patcher: 8 bit selector required, game uses 16 bit selector"); scriptData[offset] = patchSelector & 0xFF; offset++; break; } - case PATCH_BYTE: + case PATCH_CODE_BYTE: scriptData[offset] = patchValue & PATCH_BYTEMASK; offset++; } @@ -2103,18 +2551,18 @@ void Script::patcherApplyPatch(const SciScriptPatcherEntry *patchEntry, byte *sc } // will return -1 if no match was found, otherwise an offset to the start of the signature match -int32 Script::patcherFindSignature(const SciScriptPatcherEntry *patchEntry, const byte *scriptData, const uint32 scriptSize, const bool isMacSci11) { +int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize, const bool isMacSci11) { if (scriptSize < 4) // we need to find a DWORD, so less than 4 bytes is not okay return -1; - const uint32 magicDWord = patchEntry->magicDWord; // is platform-specific BE/LE form, so that the later match will work + const uint32 magicDWord = runtimeEntry->magicDWord; // is platform-specific BE/LE form, so that the later match will work const uint32 searchLimit = scriptSize - 3; uint32 DWordOffset = 0; // first search for the magic DWORD while (DWordOffset < searchLimit) { if (magicDWord == READ_UINT32(scriptData + DWordOffset)) { // magic DWORD found, check if actual signature matches - uint32 offset = DWordOffset + patchEntry->magicOffset; + uint32 offset = DWordOffset + runtimeEntry->magicOffset; uint32 byteOffset = offset; const uint16 *signatureData = patchEntry->signatureData; uint16 sigSelector = 0; @@ -2124,19 +2572,19 @@ int32 Script::patcherFindSignature(const SciScriptPatcherEntry *patchEntry, cons uint16 sigCommand = sigWord & SIG_COMMANDMASK; uint16 sigValue = sigWord & SIG_VALUEMASK; switch (sigCommand) { - case SIG_ADDTOOFFSET: { + case SIG_CODE_ADDTOOFFSET: { // add value to offset byteOffset += sigValue; break; } - case SIG_UINT16: - case SIG_SELECTOR16: { + case SIG_CODE_UINT16: + case SIG_CODE_SELECTOR16: { if ((byteOffset + 1) < scriptSize) { byte byte1; byte byte2; switch (sigCommand) { - case SIG_UINT16: { + case SIG_CODE_UINT16: { byte1 = sigValue & SIG_BYTEMASK; signatureData++; sigWord = *signatureData; if (sigWord & SIG_COMMANDMASK) @@ -2144,8 +2592,8 @@ int32 Script::patcherFindSignature(const SciScriptPatcherEntry *patchEntry, cons byte2 = sigWord & SIG_BYTEMASK; break; } - case SIG_SELECTOR16: { - sigSelector = selectorTable[sigValue].id; + case SIG_CODE_SELECTOR16: { + sigSelector = _selectorIdTable[sigValue]; byte1 = sigSelector & 0xFF; byte2 = sigSelector >> 8; break; @@ -2167,9 +2615,9 @@ int32 Script::patcherFindSignature(const SciScriptPatcherEntry *patchEntry, cons } break; } - case SIG_SELECTOR8: { + case SIG_CODE_SELECTOR8: { if (byteOffset < scriptSize) { - sigSelector = selectorTable[sigValue].id; + sigSelector = _selectorIdTable[sigValue]; if (sigSelector & 0xFF00) error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty patch: '%s'", patchEntry->description); if (scriptData[byteOffset] != (sigSelector & 0xFF)) @@ -2180,7 +2628,7 @@ int32 Script::patcherFindSignature(const SciScriptPatcherEntry *patchEntry, cons } break; } - case SIG_BYTE: + case SIG_CODE_BYTE: if (byteOffset < scriptSize) { if (scriptData[byteOffset] != sigWord) sigWord = SIG_MISMATCH; @@ -2189,14 +2637,14 @@ int32 Script::patcherFindSignature(const SciScriptPatcherEntry *patchEntry, cons sigWord = SIG_MISMATCH; // out of bounds } } - + if (sigWord == SIG_MISMATCH) break; - + signatureData++; sigWord = *signatureData; } - + if (sigWord == SIG_END) // signature fully matched? return offset; } @@ -2208,30 +2656,45 @@ int32 Script::patcherFindSignature(const SciScriptPatcherEntry *patchEntry, cons // This method calculates the magic DWORD for each entry in the signature table // and it also initializes the selector table for selectors used in the signatures/patches of the current game -void Script::patcherInitSignature(SciScriptPatcherEntry *patchTable, bool isMacSci11) { - SciScriptPatcherEntry *curEntry = patchTable; - SciScriptPatcherSelector *curSelector = NULL; +void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable, bool isMacSci11) { + const SciScriptPatcherEntry *curEntry = patchTable; + SciScriptPatcherRuntimeEntry *curRuntimeEntry; + Selector curSelector = -1; int step; int magicOffset; byte magicDWord[4]; int magicDWordLeft = 0; - const uint16 *curData; - uint16 curWord; - uint16 curCommand; - uint32 curValue; - byte byte1; - byte byte2; - - while (curEntry->signatureData) { + const uint16 *curData; + uint16 curWord; + uint16 curCommand; + uint32 curValue; + byte byte1; + byte byte2; + int patchEntryCount = 0; + + // Count entries and allocate runtime data + while (curEntry->signatureData) { + patchEntryCount++; curEntry++; + } + _runtimeTable = new SciScriptPatcherRuntimeEntry[patchEntryCount]; + memset(_runtimeTable, 0, sizeof(SciScriptPatcherRuntimeEntry) * patchEntryCount); + + curEntry = patchTable; + curRuntimeEntry = _runtimeTable; + while (curEntry->signatureData) { // process signature memset(magicDWord, 0, sizeof(magicDWord)); + curRuntimeEntry->active = curEntry->defaultActive; + curRuntimeEntry->magicDWord = 0; + curRuntimeEntry->magicOffset = 0; + for (step = 0; step < 2; step++) { switch (step) { case 0: curData = curEntry->signatureData; break; case 1: curData = curEntry->patchData; break; } - + curWord = *curData; magicOffset = 0; while (curWord != SIG_END) { @@ -2240,24 +2703,24 @@ void Script::patcherInitSignature(SciScriptPatcherEntry *patchTable, bool isMacS switch (curCommand) { case SIG_MAGICDWORD: { if (step == 0) { - if ((curEntry->magicDWord) || (magicDWordLeft)) + if ((curRuntimeEntry->magicDWord) || (magicDWordLeft)) error("Script-Patcher: Magic-DWORD specified multiple times in signature\nFaulty patch: '%s'", curEntry->description); magicDWordLeft = 4; - curEntry->magicOffset = magicOffset; + curRuntimeEntry->magicOffset = magicOffset; } break; } - case SIG_ADDTOOFFSET: { + case SIG_CODE_ADDTOOFFSET: { magicOffset -= curValue; if (magicDWordLeft) error("Script-Patcher: Magic-DWORD contains AddToOffset command\nFaulty patch: '%s'", curEntry->description); break; } - case SIG_UINT16: - case SIG_SELECTOR16: { + case SIG_CODE_UINT16: + case SIG_CODE_SELECTOR16: { // UINT16 or 1 switch (curCommand) { - case SIG_UINT16: { + case SIG_CODE_UINT16: { curData++; curWord = *curData; if (curWord & SIG_COMMANDMASK) error("Script-Patcher: signature entry inconsistent\nFaulty patch: '%s'", curEntry->description); @@ -2270,16 +2733,18 @@ void Script::patcherInitSignature(SciScriptPatcherEntry *patchTable, bool isMacS } break; } - case SIG_SELECTOR16: { - curSelector = &selectorTable[curValue]; - if (curSelector->id == -1) - curSelector->id = g_sci->getKernel()->findSelector(curSelector->name); + case SIG_CODE_SELECTOR16: { + curSelector = _selectorIdTable[curValue]; + if (curSelector == -1) { + curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]); + _selectorIdTable[curValue] = curSelector; + } if (!isMacSci11) { - byte1 = curSelector->id & 0x00FF; - byte2 = curSelector->id >> 8; + byte1 = curSelector & 0x00FF; + byte2 = curSelector >> 8; } else { - byte1 = curSelector->id >> 8; - byte2 = curSelector->id & 0x00FF; + byte1 = curSelector >> 8; + byte2 = curSelector & 0x00FF; } break; } @@ -2294,23 +2759,24 @@ void Script::patcherInitSignature(SciScriptPatcherEntry *patchTable, bool isMacS magicDWordLeft--; } if (!magicDWordLeft) { - curEntry->magicDWord = READ_LE_UINT32(magicDWord); + curRuntimeEntry->magicDWord = READ_LE_UINT32(magicDWord); } } break; } - case SIG_BYTE: - case SIG_SELECTOR8: { - if (curCommand == SIG_SELECTOR8) { - curSelector = &selectorTable[curValue]; - if (curSelector->id == -1) { - curSelector->id = g_sci->getKernel()->findSelector(curSelector->name); - if (curSelector->id != -1) { - if (curSelector->id & 0xFF00) + case SIG_CODE_BYTE: + case SIG_CODE_SELECTOR8: { + if (curCommand == SIG_CODE_SELECTOR8) { + curSelector = _selectorIdTable[curValue]; + if (curSelector == -1) { + curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]); + _selectorIdTable[curValue] = curSelector; + if (curSelector != -1) { + if (curSelector & 0xFF00) error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty patch: '%s'", curEntry->description); } } - curValue = curSelector->id; + curValue = curSelector; } magicOffset--; if (magicDWordLeft) { @@ -2318,7 +2784,7 @@ void Script::patcherInitSignature(SciScriptPatcherEntry *patchTable, bool isMacS magicDWord[4 - magicDWordLeft] = (byte)curValue; magicDWordLeft--; if (!magicDWordLeft) { - curEntry->magicDWord = READ_LE_UINT32(magicDWord); + curRuntimeEntry->magicDWord = READ_LE_UINT32(magicDWord); } } } @@ -2329,35 +2795,38 @@ void Script::patcherInitSignature(SciScriptPatcherEntry *patchTable, bool isMacS } if (magicDWordLeft) error("Script-Patcher: Magic-DWORD beyond End-Of-Signature\nFaulty patch: '%s'", curEntry->description); - if (!curEntry->magicDWord) + if (!curRuntimeEntry->magicDWord) error("Script-Patcher: Magic-DWORD not specified in signature\nFaulty patch: '%s'", curEntry->description); - - curEntry++; - } + + curEntry++; curRuntimeEntry++; + } } // This method enables certain patches // It's used for patches, which are not meant to get applied all the time -void Script::patcherEnablePatch(SciScriptPatcherEntry *patchTable, const char *searchDescription) { - SciScriptPatcherEntry *curEntry = patchTable; - int searchDescriptionLen = strlen( searchDescription ); +void ScriptPatcher::enablePatch(const SciScriptPatcherEntry *patchTable, const char *searchDescription) { + const SciScriptPatcherEntry *curEntry = patchTable; + SciScriptPatcherRuntimeEntry *runtimeEntry = _runtimeTable; + int searchDescriptionLen = strlen(searchDescription); int matchCount = 0; - - while (curEntry->signatureData) { + + while (curEntry->signatureData) { if (strncmp(curEntry->description, searchDescription, searchDescriptionLen) == 0) { // match found, enable patch - curEntry->active = true; + runtimeEntry->active = true; matchCount++; } - curEntry++; - } - - if (!matchCount) + curEntry++; runtimeEntry++; + } + + if (!matchCount) error("Script-Patcher: no patch found to enable"); } -void Script::patcherProcessScript(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) { - SciScriptPatcherEntry *signatureTable = NULL; +void ScriptPatcher::processScript(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) { + const SciScriptPatcherEntry *signatureTable = NULL; + const SciScriptPatcherEntry *curEntry = NULL; + SciScriptPatcherRuntimeEntry *curRuntimeEntry = NULL; const Sci::SciGameId gameId = g_sci->getGameId(); switch (gameId) { @@ -2431,48 +2900,57 @@ void Script::patcherProcessScript(uint16 scriptNr, byte *scriptData, const uint3 if (signatureTable) { bool isMacSci11 = (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1); - if (!signatureTable->magicDWord) { + if (!_runtimeTable) { // Abort, in case selectors are not yet initialized (happens for games w/o selector-dictionary) if (!g_sci->getKernel()->selectorNamesAvailable()) return; - + // signature table needs to get initialized (Magic DWORD set, selector table set) - patcherInitSignature(signatureTable, isMacSci11); - + initSignature(signatureTable, isMacSci11); + // Do additional game-specific initialization switch (gameId) { case GID_KQ5: if (g_sci->_features->useAltWinGMSound()) { // See the explanation in the kq5SignatureWinGMSignals comment - patcherEnablePatch(signatureTable, "Win: GM Music signal checks"); + enablePatch(signatureTable, "Win: GM Music signal checks"); + } + break; + case GID_KQ6: + if (g_sci->isCD()) { + // Enables Dual mode patches (audio + subtitles at the same time) for King's Quest 6 + enablePatch(signatureTable, "CD: audio + text support"); } break; case GID_LAURABOW2: - if (g_sci->speechAndSubtitlesEnabled()) { - // Enables Audio + subtitles patches for Laura Bow 2, when "Text and Speech: Both" is selected - patcherEnablePatch(signatureTable, "CD: audio + text support"); + if (g_sci->isCD()) { + // Enables Dual mode patches (audio + subtitles at the same time) for Laura Bow 2 + enablePatch(signatureTable, "CD: audio + text support"); } break; default: break; } } - - while (signatureTable->signatureData) { - if ( (scriptNr == signatureTable->scriptNr) && (signatureTable->active) ) { + + curEntry = signatureTable; + curRuntimeEntry = _runtimeTable; + + while (curEntry->signatureData) { + if ((scriptNr == curEntry->scriptNr) && (curRuntimeEntry->active)) { int32 foundOffset = 0; - int16 applyCount = signatureTable->applyCount; + int16 applyCount = curEntry->applyCount; do { - foundOffset = patcherFindSignature(signatureTable, scriptData, scriptSize, isMacSci11); + foundOffset = findSignature(curEntry, curRuntimeEntry, scriptData, scriptSize, isMacSci11); if (foundOffset != -1) { // found, so apply the patch - debugC(kDebugLevelScriptPatcher, "Script-Patcher: '%s' on script %d offset %d", signatureTable->description, scriptNr, foundOffset); - patcherApplyPatch(signatureTable, scriptData, scriptSize, foundOffset, isMacSci11); + debugC(kDebugLevelScriptPatcher, "Script-Patcher: '%s' on script %d offset %d", curEntry->description, scriptNr, foundOffset); + applyPatch(curEntry, scriptData, scriptSize, foundOffset, isMacSci11); } applyCount--; } while ((foundOffset != -1) && (applyCount)); } - signatureTable++; + curEntry++; curRuntimeEntry++; } } } |