aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/script_patches.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/script_patches.cpp')
-rw-r--r--engines/sci/engine/script_patches.cpp2228
1 files changed, 1297 insertions, 931 deletions
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index d2c3356d54..ac42764e5b 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -21,6 +21,7 @@
*/
#include "sci/sci.h"
+#include "sci/engine/kernel.h"
#include "sci/engine/script.h"
#include "sci/engine/state.h"
#include "sci/engine/features.h"
@@ -29,34 +30,88 @@
namespace Sci {
-#define PATCH_END 0xFFFF
-#define PATCH_COMMANDMASK 0xF000
-#define PATCH_VALUEMASK 0x0FFF
-#define PATCH_ADDTOOFFSET 0xE000
-#define PATCH_GETORIGINALBYTE 0xD000
-#define PATCH_ADJUSTWORD 0xC000
-#define PATCH_ADJUSTWORD_NEG 0xB000
-#define PATCH_MAGICDWORD(a, b, c, d) CONSTANT_LE_32(a | (b << 8) | (c << 16) | (d << 24))
+#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 SciScriptSignature {
+struct SciScriptPatcherEntry {
uint16 scriptNr;
const char *description;
int16 applyCount;
uint32 magicDWord;
int magicOffset;
- const byte *data;
- const uint16 *patch;
+ const uint16 *signatureData;
+ const uint16 *patchData;
};
#define SCI_SIGNATUREENTRY_TERMINATOR { 0, NULL, 0, 0, 0, NULL, NULL }
-// signatures are built like this:
-// - first a counter of the bytes that follow
-// - then the actual bytes that need to get matched
-// - then another counter of bytes (0 for EOS)
-// - if not EOS, an adjust offset and the actual bytes
-// - rinse and repeat
+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
+ NULL, -1
+};
+
+enum ScriptPatcherSelectors {
+ SELECTOR_cycles = 0,
+ SELECTOR_seconds,
+ SELECTOR_init,
+ SELECTOR_dispose,
+ SELECTOR_new,
+ SELECTOR_curEvent,
+ SELECTOR_disable,
+ SELECTOR_show,
+ SELECTOR_x,
+ SELECTOR_cel,
+ SELECTOR_setMotion,
+ SELECTOR_deskSarg,
+ SELECTOR_localize,
+ SELECTOR_put,
+ SELECTOR_solvePuzzle,
+ SELECTOR_timesShownID
+};
// ===========================================================================
// Conquests of Camelot
@@ -78,35 +133,32 @@ struct SciScriptSignature {
// We fix the script by patching in a jump to the proper code inside fawaz::doit.
// Responsible method: fawaz::handleEvent
// Fixes bug #3614969
-const byte camelotSignaturePeepingTom[] = {
- 5,
- 0x72, 0x7e, 0x07, // lofsa fawaz <-- start of proper initializion code
- 0xa1, 0xb9, // sag b9h
- +255, 0,
- +255, 0,
- +61, 19, // skip 571 bytes
- 0x39, 0x7a, // pushi 7a <-- initialization code when walking automatically
- 0x78, // push1
- 0x7a, // push2
- 0x38, 0xa9, 0x00, // pushi 00a9 - script 169
- 0x78, // push1
- 0x43, 0x02, 0x04, // call kScriptID
- 0x36, // push
- 0x81, 0x00, // lag 00
- 0x4a, 0x06, // send 06
- 0x32, 0x20, 0x05, // jmp [end of fawaz::handleEvent]
- 0
+const uint16 camelotSignaturePeepingTom[] = {
+ 0x72, SIG_MAGICDWORD, SIG_UINT16 + 0x7e, 0x07, // lofsa fawaz <-- start of proper initializion code
+ 0xa1, 0xb9, // sag b9h
+ 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
+ 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]
+ SIG_END
};
const uint16 camelotPatchPeepingTom[] = {
- PATCH_ADDTOOFFSET | +576,
- 0x32, 0xbd, 0xfd, // jmp to fawaz::doit / properly init peepingTom code
+ PATCH_ADDTOOFFSET +576,
+ 0x32, PATCH_UINT16 + 0xbd, 0xfd, // jmp to fawaz::doit / properly init peepingTom code
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature camelotSignatures[] = {
- { 62, "fix peepingTom Sierra bug", 1, PATCH_MAGICDWORD(0x7e, 0x07, 0xa1, 0xb9), -1, camelotSignaturePeepingTom, camelotPatchPeepingTom },
+// script, description, signature patch
+SciScriptPatcherEntry camelotSignatures[] = {
+ { 62, "fix peepingTom Sierra bug", 1, 0, 0, camelotSignaturePeepingTom, camelotPatchPeepingTom },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -115,64 +167,67 @@ const SciScriptSignature camelotSignatures[] = {
// boundaries of room 660. Normally a textbox is supposed to get on screen
// but the call is wrong, so not only do we get an error message the script
// is also hanging because the cue won't get sent out
-// This also happens in sierra sci - refer to bug #3038387
-const byte ecoquest1SignatureStayAndHelp[] = {
- 40,
- 0x3f, 0x01, // link 01
- 0x87, 0x01, // lap param[1]
- 0x65, 0x14, // aTop state
- 0x36, // push
- 0x3c, // dup
- 0x35, 0x00, // ldi 00
- 0x1a, // eq?
- 0x31, 0x1c, // bnt [next state]
- 0x76, // push0
- 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off)
- 0x38, 0x22, 0x01, // pushi 0122
- 0x78, // push1
- 0x76, // push0
- 0x81, 0x00, // lag global[0]
- 0x4a, 0x06, // send 06 - call ego::setMotion(0)
- 0x39, 0x6e, // pushi 6e (selector init)
- 0x39, 0x04, // pushi 04
- 0x76, // push0
- 0x76, // push0
- 0x39, 0x17, // pushi 17
- 0x7c, // pushSelf
- 0x51, 0x82, // class EcoNarrator
- 0x4a, 0x0c, // send 0c - call EcoNarrator::init(0, 0, 23, self) (BADLY BROKEN!)
- 0x33, // jmp [end]
- 0
+// This also happens in sierra sci
+// Applies to at least: PC-CD
+// Responsible method: stayAndHelp::changeState
+// Fixes bug: #3038387
+const uint16 ecoquest1SignatureStayAndHelp[] = {
+ 0x3f, 0x01, // link 01
+ 0x87, 0x01, // lap param[1]
+ 0x65, 0x14, // aTop state
+ 0x36, // push
+ 0x3c, // dup
+ 0x35, 0x00, // ldi 00
+ 0x1a, // eq?
+ 0x31, 0x1c, // bnt [next state]
+ 0x76, // push0
+ 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off)
+ SIG_MAGICDWORD,
+ 0x38, SIG_UINT16 + 0x22, 0x01, // 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, 0x04, // pushi 04
+ 0x76, // push0
+ 0x76, // push0
+ 0x39, 0x17, // pushi 17
+ 0x7c, // pushSelf
+ 0x51, 0x82, // class EcoNarrator
+ 0x4a, 0x0c, // send 0c - call EcoNarrator::init(0, 0, 23, self) (BADLY BROKEN!)
+ 0x33, // jmp [end]
+ SIG_END
};
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, 0x22, 0x01, // pushi 0122
- 0x78, // push1
- 0x76, // push0
- 0x81, 0x00, // lag global[0]
- 0x4a, 0x06, // send 06 - call ego::setMotion(0)
- 0x39, 0x6e, // pushi 6e (selector init)
- 0x39, 0x06, // pushi 06
- 0x39, 0x02, // pushi 02 (additional 2 bytes)
- 0x76, // push0
- 0x76, // push0
- 0x39, 0x17, // pushi 17
- 0x7c, // pushSelf
- 0x38, 0x80, 0x02, // pushi 280 (additional 3 bytes)
- 0x51, 0x82, // class EcoNarrator
- 0x4a, 0x10, // send 10 - call EcoNarrator::init(2, 0, 0, 23, self, 640)
+ 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
+ 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, 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)
+ 0x51, 0x82, // class EcoNarrator
+ 0x4a, 0x10, // send 10 - call EcoNarrator::init(2, 0, 0, 23, self, 640)
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature ecoquest1Signatures[] = {
- { 660, "CD: bad messagebox and freeze", 1, PATCH_MAGICDWORD(0x38, 0x22, 0x01, 0x78), -17, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp },
+// script, description, signature patch
+SciScriptPatcherEntry ecoquest1Signatures[] = {
+ { 660, "CD: bad messagebox and freeze", 1, 0, 0, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -182,53 +237,53 @@ const SciScriptSignature ecoquest1Signatures[] = {
// this worked in sierra sci just by accident. In our sci, the temp space
// is resetted every time, which means the previous text isn't available
// anymore. We have to patch the code because of that - bug #3035386
-const byte ecoquest2SignatureEcorder[] = {
- 35,
- 0x31, 0x22, // bnt [next state]
- 0x39, 0x0a, // pushi 0a
- 0x5b, 0x04, 0x1e, // lea temp[1e]
- 0x36, // push
- 0x39, 0x64, // pushi 64
- 0x39, 0x7d, // pushi 7d
- 0x39, 0x32, // pushi 32
- 0x39, 0x66, // pushi 66
- 0x39, 0x17, // pushi 17
- 0x39, 0x69, // pushi 69
- 0x38, 0x31, 0x26, // 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]
- +1, 5, // [skip 1 byte]
- 0x3c, // dup
- 0x35, 0x03, // ldi 03
- 0x1a, // eq?
- 0x31, // bnt [end]
- 0
+const uint16 ecoquest2SignatureEcorder[] = {
+ 0x31, 0x22, // bnt [next state]
+ 0x39, 0x0a, // pushi 0a
+ 0x5b, 0x04, 0x1e, // lea temp[1e]
+ 0x36, // push
+ SIG_MAGICDWORD,
+ 0x39, 0x64, // pushi 64
+ 0x39, 0x7d, // pushi 7d
+ 0x39, 0x32, // pushi 32
+ 0x39, 0x66, // pushi 66
+ 0x39, 0x17, // pushi 17
+ 0x39, 0x69, // pushi 69
+ 0x38, PATCH_UINT16 + 0x31, 0x26, // 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]
+ 0x3c, // dup
+ 0x35, 0x03, // ldi 03
+ 0x1a, // eq?
+ 0x31, // bnt [end]
+ SIG_END
};
const uint16 ecoquest2PatchEcorder[] = {
- 0x2f, 0x02, // bt [to pushi 07]
- 0x3a, // toss
- 0x48, // ret
- 0x38, 0x07, 0x00, // pushi 07 (parameter count) (waste 1 byte)
- 0x39, 0x0b, // push (FillBoxAny)
- 0x39, 0x1d, // pushi 29d
- 0x39, 0x73, // pushi 115d
- 0x39, 0x5e, // pushi 94d
- 0x38, 0xd7, 0x00, // pushi 215d
- 0x78, // push1 (visual screen)
- 0x38, 0x17, 0x00, // pushi 17 (color) (waste 1 byte)
- 0x43, 0x6c, 0x0e, // call kGraph
- 0x38, 0x05, 0x00, // 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, 0xd7, 0x00, // pushi 215d
- 0x43, 0x6c, 0x0a, // call kGraph
+ 0x2f, 0x02, // bt [to pushi 07]
+ 0x3a, // toss
+ 0x48, // ret
+ 0x38, PATCH_UINT16 + 0x07, 0x00, // 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
+ 0x78, // push1 (visual screen)
+ 0x38, PATCH_UINT16 + 0x17, 0x00, // pushi 17 (color) (waste 1 byte)
+ 0x43, 0x6c, 0x0e, // call kGraph
+ 0x38, PATCH_UINT16 + 0x05, 0x00, // 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
+ 0x43, 0x6c, 0x0a, // call kGraph
PATCH_END
};
@@ -237,66 +292,66 @@ const uint16 ecoquest2PatchEcorder[] = {
// Two workarounds are needed for this patch in workarounds.cpp (when calling
// kGraphFillBoxAny and kGraphUpdateBox), as there isn't enough space to patch
// the function otherwise.
-const byte ecoquest2SignatureEcorderTutorial[] = {
- 36,
- 0x30, 0x23, 0x00, // bnt [next state]
- 0x39, 0x0a, // pushi 0a
- 0x5b, 0x04, 0x1f, // lea temp[1f]
- 0x36, // push
- 0x39, 0x64, // pushi 64
- 0x39, 0x7d, // pushi 7d
- 0x39, 0x32, // pushi 32
- 0x39, 0x66, // pushi 66
- 0x39, 0x17, // pushi 17
- 0x39, 0x69, // pushi 69
- 0x38, 0x31, 0x26, // pushi 2631
- 0x39, 0x6a, // pushi 6a
- 0x39, 0x64, // pushi 64
- 0x43, 0x1b, 0x14, // call kDisplay
- 0x35, 0x1e, // ldi 1e
- 0x65, 0x20, // aTop ticks
- 0x32, // jmp [end]
+const uint16 ecoquest2SignatureEcorderTutorial[] = {
+ 0x30, SIG_UINT16 + 0x23, 0x00, // bnt [next state]
+ 0x39, 0x0a, // pushi 0a
+ 0x5b, 0x04, 0x1f, // lea temp[1f]
+ 0x36, // push
+ SIG_MAGICDWORD,
+ 0x39, 0x64, // pushi 64
+ 0x39, 0x7d, // pushi 7d
+ 0x39, 0x32, // pushi 32
+ 0x39, 0x66, // pushi 66
+ 0x39, 0x17, // pushi 17
+ 0x39, 0x69, // pushi 69
+ 0x38, SIG_UINT16 + 0x31, 0x26, // pushi 2631
+ 0x39, 0x6a, // pushi 6a
+ 0x39, 0x64, // pushi 64
+ 0x43, 0x1b, 0x14, // call kDisplay
+ 0x35, 0x1e, // ldi 1e
+ 0x65, 0x20, // aTop ticks
+ 0x32, // jmp [end]
// 2 extra bytes, jmp offset
- 0
+ SIG_END
};
const uint16 ecoquest2PatchEcorderTutorial[] = {
- 0x31, 0x23, // bnt [next state] (save 1 byte)
+ 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
- 0x78, // push1 (parameter count)
- //0x39, 0x07, // pushi 07 (parameter count)
- 0x39, 0x0b, // push (FillBoxAny)
- 0x39, 0x1d, // pushi 29d
- 0x39, 0x73, // pushi 115d
- 0x39, 0x5e, // pushi 94d
- 0x38, 0xd7, 0x00, // pushi 215d
- 0x78, // push1 (visual screen)
- 0x39, 0x17, // pushi 17 (color)
- 0x43, 0x6c, 0x0e, // call kGraph
+ 0x78, // push1 (parameter count)
+ //0x39, 0x07, // pushi 07 (parameter count)
+ 0x39, 0x0b, // push (FillBoxAny)
+ 0x39, 0x1d, // pushi 29d
+ 0x39, 0x73, // pushi 115d
+ 0x39, 0x5e, // pushi 94d
+ 0x38, PATCH_UINT16 + 0xd7, 0x00, // pushi 215d
+ 0x78, // push1 (visual screen)
+ 0x39, 0x17, // pushi 17 (color)
+ 0x43, 0x6c, 0x0e, // call kGraph
// The parameter count below should be 5, but we're out of bytes
// to patch! A workaround has been added because of this
- 0x78, // push1 (parameter count)
- //0x39, 0x05, // pushi 05 (parameter count)
- 0x39, 0x0c, // pushi 12d (UpdateBox)
- 0x39, 0x1d, // pushi 29d
- 0x39, 0x73, // pushi 115d
- 0x39, 0x5e, // pushi 94d
- 0x38, 0xd7, 0x00, // pushi 215d
- 0x43, 0x6c, 0x0a, // call kGraph
+ 0x78, // push1 (parameter count)
+ //0x39, 0x05, // pushi 05 (parameter count)
+ 0x39, 0x0c, // pushi 12d (UpdateBox)
+ 0x39, 0x1d, // pushi 29d
+ 0x39, 0x73, // pushi 115d
+ 0x39, 0x5e, // pushi 94d
+ 0x38, PATCH_UINT16 + 0xd7, 0x00, // 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, 0xee, 0x01, // skip 494 (0x1EE) bytes
+ 0x32, PATCH_UINT16 + 0xee, 0x01, // skip 494 (0x1EE) bytes
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature ecoquest2Signatures[] = {
- { 50, "initial text not removed on ecorder", 1, PATCH_MAGICDWORD(0x39, 0x64, 0x39, 0x7d), -8, ecoquest2SignatureEcorder, ecoquest2PatchEcorder },
- { 333, "initial text not removed on ecorder tutorial",1, PATCH_MAGICDWORD(0x39, 0x64, 0x39, 0x7d), -9, ecoquest2SignatureEcorderTutorial, ecoquest2PatchEcorderTutorial },
+// script, description, signature patch
+SciScriptPatcherEntry ecoquest2Signatures[] = {
+ { 50, "initial text not removed on ecorder", 1, 0, 0, ecoquest2SignatureEcorder, ecoquest2PatchEcorder },
+ { 333, "initial text not removed on ecorder tutorial",1, 0, 0, ecoquest2SignatureEcorderTutorial, ecoquest2PatchEcorderTutorial },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -306,26 +361,26 @@ const SciScriptSignature 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 #3038870.
-const byte fanmadeSignatureInfiniteLoop[] = {
- 13,
- 0x38, 0x4c, 0x00, // pushi 004c
- 0x39, 0x00, // pushi 00
- 0x87, 0x01, // lap 01
- 0x4b, 0x04, // send 04
- 0x18, // not
- 0x30, 0x2f, 0x00, // bnt 002f [06a5] --> jmp ffbc [0664] --> BUG! infinite loop
- 0
+const uint16 fanmadeSignatureInfiniteLoop[] = {
+ 0x38, SIG_UINT16 + 0x4c, 0x00, // 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
+ SIG_END
};
const uint16 fanmadePatchInfiniteLoop[] = {
PATCH_ADDTOOFFSET | +10,
- 0x30, 0x32, 0x00, // bnt 0032 [06a8] --> pushi 004c
+ 0x30, SIG_UINT16 + 0x32, 0x00, // bnt 0032 [06a8] --> pushi 004c
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature fanmadeSignatures[] = {
- { 999, "infinite loop on typo", 1, PATCH_MAGICDWORD(0x18, 0x30, 0x2f, 0x00), -9, fanmadeSignatureInfiniteLoop, fanmadePatchInfiniteLoop },
+// script, description, signature patch
+SciScriptPatcherEntry fanmadeSignatures[] = {
+ { 999, "infinite loop on typo", 1, 0, 0, fanmadeSignatureInfiniteLoop, fanmadePatchInfiniteLoop },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -337,21 +392,23 @@ const SciScriptSignature fanmadeSignatures[] = {
// was already playing in the sound driver. In our case we would also stop
// the sample from playing, so we patch it out
// The "score" code is already buggy and sets volume to 0 when playing
-const byte freddypharkasSignatureScoreDisposal[] = {
- 10,
- 0x67, 0x32, // pTos 32 (selector theAudCount)
- 0x78, // push1
- 0x39, 0x0d, // pushi 0d
- 0x43, 0x75, 0x02, // call kDoAudio
- 0x1c, // ne?
- 0x31, // bnt (-> to skip disposal)
- 0
+// Applies to at least: English PC-CD
+// Responsible method: unknown
+const uint16 freddypharkasSignatureScoreDisposal[] = {
+ 0x67, 0x32, // pTos 32 (selector theAudCount)
+ 0x78, // push1
+ SIG_MAGICDWORD,
+ 0x39, 0x0d, // pushi 0d
+ 0x43, 0x75, 0x02, // call kDoAudio
+ 0x1c, // ne?
+ 0x31, // bnt (-> to skip disposal)
+ SIG_END
};
const uint16 freddypharkasPatchScoreDisposal[] = {
- 0x34, 0x00, 0x00, // ldi 0000
- 0x34, 0x00, 0x00, // ldi 0000
- 0x34, 0x00, 0x00, // ldi 0000
+ 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0000
+ 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0000
+ 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0000
PATCH_END
};
@@ -361,24 +418,26 @@ const uint16 freddypharkasPatchScoreDisposal[] = {
// in IconBar::disable doing endless loops even in sierra sci, because there
// is no enabled icon left. We remove disabling of icon 8 (which is help),
// this fixes the issue.
-const byte freddypharkasSignatureCanisterHang[] = {
- 12,
- 0x38, 0xf1, 0x00, // pushi f1 (selector disable)
- 0x7a, // push2
- 0x39, 0x07, // pushi 07
- 0x39, 0x08, // pushi 08
- 0x81, 0x45, // lag 45
- 0x4a, 0x08, // send 08 - call IconBar::disable(7, 8)
- 0
+// Applies to at least: English PC-CD
+// Responsible method: rm235::init and sEnterFrom500::changeState
+const uint16 freddypharkasSignatureCanisterHang[] = {
+ 0x38, SIG_SELECTOR16 + SELECTOR_disable, // pushi disable
+ 0x7a, // push2
+ SIG_MAGICDWORD,
+ 0x39, 0x07, // pushi 07
+ 0x39, 0x08, // pushi 08
+ 0x81, 0x45, // lag 45
+ 0x4a, 0x08, // send 08 - call IconBar::disable(7, 8)
+ SIG_END
};
const uint16 freddypharkasPatchCanisterHang[] = {
PATCH_ADDTOOFFSET | +3,
- 0x78, // push1
+ 0x78, // push1
PATCH_ADDTOOFFSET | +2,
- 0x33, 0x00, // ldi 00 (waste 2 bytes)
+ 0x33, 0x00, // ldi 00 (waste 2 bytes)
PATCH_ADDTOOFFSET | +3,
- 0x06, // send 06 - call IconBar::disable(7)
+ 0x06, // send 06 - call IconBar::disable(7)
PATCH_END
};
@@ -390,135 +449,132 @@ const uint16 freddypharkasPatchCanisterHang[] = {
// ego, sometimes clicks also won't get registered. Strangely it's not nearly
// as bad as in our sci, but these differences may be caused by timing.
// We just reuse the active event, thus removing the duplicate kGetEvent call.
-const byte freddypharkasSignatureLadderEvent[] = {
- 21,
- 0x39, 0x6d, // pushi 6d (selector new)
- 0x76, // push0
- 0x38, 0xf5, 0x00, // pushi f5 (selector 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, 0x94, 0x00, // pushi 94 (selector localize)
- 0x76, // push0
- 0x4a, 0x04, // send 04 - call curEvent::localize
- 0
+// Applies to at least: English PC-CD, German Floppy, English Mac
+// Responsible method: lowerLadder::doit and highLadder::doit
+const uint16 freddypharkasSignatureLadderEvent[] = {
+ 0x39, SIG_MAGICDWORD,
+ SIG_SELECTOR8 + SELECTOR_new, // pushi new
+ 0x76, // push0
+ 0x38, SIG_SELECTOR16 + SELECTOR_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,
+ 0x76, // push0
+ 0x4a, 0x04, // send 04 - call curEvent::localize
+ SIG_END
};
const uint16 freddypharkasPatchLadderEvent[] = {
- 0x34, 0x00, 0x00, // ldi 0000 (waste 3 bytes, overwrites first 2 pushes)
+ 0x34, 0x00, 0x00, // ldi 0000 (waste 3 bytes, overwrites first 2 pushes)
PATCH_ADDTOOFFSET | +8,
- 0xa5, 0x00, // sat temp[0] (waste 2 bytes, overwrites 2nd send)
+ 0xa5, 0x00, // sat temp[0] (waste 2 bytes, overwrites 2nd send)
PATCH_ADDTOOFFSET | +2,
- 0x34, 0x00, 0x00, // ldi 0000
- 0x34, 0x00, 0x00, // ldi 0000 (waste 6 bytes, overwrites last 3 opcodes)
+ 0x34, 0x00, 0x00, // ldi 0000
+ 0x34, 0x00, 0x00, // ldi 0000 (waste 6 bytes, overwrites last 3 opcodes)
PATCH_END
};
// In the Macintosh version of Freddy Pharkas, kRespondsTo is broken for
// property selectors. They hacked the script to work around the issue,
// so we revert the script back to using the values of the DOS script.
-const byte freddypharkasSignatureMacInventory[] = {
- 10,
- 0x39, 0x23, // pushi 23
- 0x39, 0x74, // pushi 74
- 0x78, // push1
- 0x38, 0x01, 0x74, // pushi 0174
- 0x85, 0x15, // lat 15
- 0
+// Applies to at least: English Mac
+// Responsible method: unknown
+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)
+ 0x85, 0x15, // lat 15
+ SIG_END
};
const uint16 freddypharkasPatchMacInventory[] = {
- 0x39, 0x02, // pushi 02 (now matches the DOS version)
- 0x39, 0x74, // pushi 74
- 0x78, // push1
- 0x38, 0x01, 0x74, // pushi 0174
- 0x85, 0x15, // lat 15
- 0x4a, 0x06, // send 06
- 0x31, 0x08, // bnt 08
- 0x38, 0x01, 0x74, // pushi 0174
- 0x76, // push0
- 0x85, 0x15, // lat 15
- 0x4a, 0x04, // send 04
- 0x02, // add
- 0xa5, 0x12, // sat 12
- 0x39, 0x04, // pushi 04 (now matches the DOS version)
+ 0x39, 0x02, // pushi 02 (now matches the DOS version)
+ PATCH_ADDTOOFFSET +23,
+ 0x39, 0x04, // pushi 04 (now matches the DOS version)
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature freddypharkasSignatures[] = {
- { 0, "CD: score early disposal", 1, PATCH_MAGICDWORD(0x39, 0x0d, 0x43, 0x75), -3, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal },
- { 15, "Mac: broken inventory", 1, PATCH_MAGICDWORD(0x39, 0x23, 0x39, 0x74), 0, freddypharkasSignatureMacInventory, freddypharkasPatchMacInventory },
- { 235, "CD: canister pickup hang", 3, PATCH_MAGICDWORD(0x39, 0x07, 0x39, 0x08), -4, freddypharkasSignatureCanisterHang, freddypharkasPatchCanisterHang },
- { 320, "ladder event issue", 2, PATCH_MAGICDWORD(0x6d, 0x76, 0x38, 0xf5), -1, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent },
+// script, description, signature patch
+SciScriptPatcherEntry freddypharkasSignatures[] = {
+ { 0, "CD: score early disposal", 1, 0, 0, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal },
+ { 15, "Mac: broken inventory", 1, 0, 0, freddypharkasSignatureMacInventory, freddypharkasPatchMacInventory },
+ { 235, "CD: canister pickup hang", 3, 0, 0, freddypharkasSignatureCanisterHang, freddypharkasPatchCanisterHang },
+ { 320, "ladder event issue", 2, 0, 0, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent },
SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
// daySixBeignet::changeState (4) is called when the cop goes out and sets cycles to 220.
// this is not enough time to get to the door, so we patch that to 23 seconds
-const byte gk1SignatureDay6PoliceBeignet[] = {
- 4,
- 0x35, 0x04, // ldi 04
- 0x1a, // eq?
- 0x30, // bnt [next state check]
- +2, 5, // [skip 2 bytes, offset of bnt]
- 0x38, 0x93, 0x00, // pushi 93 (selector dispose)
- 0x76, // push0
- 0x72, // lofsa deskSarg
- +2, 9, // [skip 2 bytes, offset of lofsa]
- 0x4a, 0x04, 0x00, // send 04
- 0x34, 0xdc, 0x00, // ldi 220
- 0x65, 0x1a, // aTop cycles
- 0x32, // jmp [end]
- 0
+// Applies to at least: English PC-CD, German PC-CD, English Mac
+// Responsible method: daySixBeignet::changeState
+const uint16 gk1SignatureDay6PoliceBeignet[] = {
+ 0x35, 0x04, // ldi 04
+ 0x1a, // eq?
+ 0x30, SIG_ADDTOOFFSET +2, // bnt [next state check]
+ 0x38, SIG_SELECTOR16 + SELECTOR_dispose, // pushi dispose
+ 0x76, // push0
+ 0x72, SIG_ADDTOOFFSET +2, // lofsa deskSarg
+ 0x4a, SIG_UINT16 + 0x04, 0x00, // send 04
+ SIG_MAGICDWORD,
+ 0x34, SIG_UINT16 + 0xdc, 0x00, // 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, 0x17, 0x00, // ldi 23
- 0x65, 0x1c, // aTop seconds
+ PATCH_ADDTOOFFSET +16,
+ 0x34, PATCH_UINT16 + 0x17, 0x00, // ldi 23
+ 0x65, PATCH_GETORIGINALBYTEADJUST +20, +2, // aTop seconds (1c for PC, 1e for Mac)
PATCH_END
};
// sargSleeping::changeState (8) is called when the cop falls asleep and sets cycles to 220.
// this is not enough time to get to the door, so we patch it to 42 seconds
-const byte gk1SignatureDay6PoliceSleep[] = {
- 4,
- 0x35, 0x08, // ldi 08
- 0x1a, // eq?
- 0x31, // bnt [next state check]
- +1, 6, // [skip 1 byte, offset of bnt]
- 0x34, 0xdc, 0x00, // ldi 220
- 0x65, 0x1a, // aTop cycles
- 0x32, // jmp [end]
+// Applies to at least: English PC-CD, German PC-CD, English Mac
+// Responsible method: sargSleeping::changeState
+const uint16 gk1SignatureDay6PoliceSleep[] = {
+ 0x35, 0x08, // ldi 08
+ 0x1a, // eq?
+ 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)
+ 0x32, // jmp [end]
0
};
const uint16 gk1PatchDay6PoliceSleep[] = {
- PATCH_ADDTOOFFSET | +5,
- 0x34, 0x2a, 0x00, // ldi 42
- 0x65, 0x1c, // aTop seconds
+ PATCH_ADDTOOFFSET +5,
+ 0x34, SIG_UINT16 + 0x2a, 0x00, // 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
-const byte gk1SignatureDay5PhoneFreeze[] = {
- 5,
- 0x35, 0x03, // ldi 03
- 0x65, 0x1a, // aTop cycles
- 0x32, // jmp [end]
- +2, 3, // [skip 2 bytes, offset of jmp]
- 0x3c, // dup
- 0x35, 0x21, // ldi 21
- 0
+// Applies to at least: English PC-CD, German PC-CD, English Mac
+// Responsible method: startOfDay5::changeState
+const uint16 gk1SignatureDay5PhoneFreeze[] = {
+ 0x4a,
+ SIG_MAGICDWORD, SIG_UINT16 + 0x0c, 0x00, // send 0c
+ 0x35, 0x03, // ldi 03
+ 0x65, SIG_ADDTOOFFSET +1, // aTop cycles
+ 0x32, SIG_ADDTOOFFSET +2, // jmp [end]
+ 0x3c, // dup
+ 0x35, 0x21, // ldi 21
+ SIG_END
};
const uint16 gk1PatchDay5PhoneFreeze[] = {
- 0x35, 0x06, // ldi 06
- 0x65, 0x20, // aTop ticks
+ PATCH_ADDTOOFFSET +3,
+ 0x35, 0x06, // ldi 01
+ 0x65, PATCH_GETORIGINALBYTEADJUST +6, +6, // aTop ticks
PATCH_END
};
@@ -530,63 +586,66 @@ const uint16 gk1PatchDay5PhoneFreeze[] = {
// comparison between a number an an object. In the CD version, the checks are
// in the correct order, thus the comparison is correct, thus we use the code
// from the CD version in the floppy one.
-const byte gk1SignatureInterrogationBug[] = {
- 43,
- 0x65, 0x4c, // aTop 4c
- 0x67, 0x50, // pTos 50
- 0x34, 0x10, 0x27, // ldi 2710
- 0x1e, // gt?
- 0x31, 0x08, // bnt 08 [05a0]
- 0x67, 0x50, // pTos 50
- 0x34, 0x10, 0x27, // ldi 2710
- 0x04, // sub
- 0x65, 0x50, // aTop 50
- 0x63, 0x50, // pToa 50
- 0x31, 0x15, // bnt 15 [05b9]
- 0x39, 0x0e, // pushi 0e
- 0x76, // push0
- 0x4a, 0x04, 0x00, // send 0004
- 0xa5, 0x00, // sat 00
- 0x38, 0x93, 0x00, // pushi 0093
- 0x76, // push0
- 0x63, 0x50, // pToa 50
- 0x4a, 0x04, 0x00, // send 0004
- 0x85, 0x00, // lat 00
- 0x65, 0x50, // aTop 50
- 0
+// 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[] = {
+ SIG_MAGICDWORD,
+ 0x65, 0x4c, // aTop 4c
+ 0x67, 0x50, // pTos 50
+ 0x34, SIG_UINT16 + 0x10, 0x27, // ldi 2710
+ 0x1e, // gt?
+ 0x31, 0x08, // bnt 08 [05a0]
+ 0x67, 0x50, // pTos 50
+ 0x34, SIG_UINT16 + 0x10, 0x27, // 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
+ 0xa5, 0x00, // sat 00
+ 0x38, SIG_SELECTOR16 + SELECTOR_dispose, // pushi dispose
+ 0x76, // push0
+ 0x63, 0x50, // pToa 50
+ 0x4a, SIG_UINT16 + 0x04, 0x00, // send 0004
+ 0x85, 0x00, // lat 00
+ 0x65, 0x50, // aTop 50
+ SIG_END
};
const uint16 gk1PatchInterrogationBug[] = {
- 0x65, 0x4c, // aTop 4c
- 0x63, 0x50, // pToa 50
- 0x31, 0x15, // bnt 15 [05b9]
- 0x39, 0x0e, // pushi 0e
- 0x76, // push0
- 0x4a, 0x04, 0x00, // send 0004
- 0xa5, 0x00, // sat 00
- 0x38, 0x93, 0x00, // pushi 0093
- 0x76, // push0
- 0x63, 0x50, // pToa 50
- 0x4a, 0x04, 0x00, // send 0004
- 0x85, 0x00, // lat 00
- 0x65, 0x50, // aTop 50
- 0x67, 0x50, // pTos 50
- 0x34, 0x10, 0x27, // ldi 2710
- 0x1e, // gt?
- 0x31, 0x08, // bnt 08 [05b9]
- 0x67, 0x50, // pTos 50
- 0x34, 0x10, 0x27, // ldi 2710
- 0x04, // sub
- 0x65, 0x50, // aTop 50
+ 0x65, 0x4c, // aTop 4c
+ 0x63, 0x50, // pToa 50
+ 0x31, 0x15, // bnt 15 [05b9]
+ 0x39, 0x0e, // pushi 0e
+ 0x76, // push0
+ 0x4a, 0x04, 0x00, // send 0004
+ 0xa5, 0x00, // sat 00
+ 0x38, SIG_SELECTOR16 + SELECTOR_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
+ 0x1e, // gt?
+ 0x31, 0x08, // bnt 08 [05b9]
+ 0x67, 0x50, // pTos 50
+ 0x34, PATCH_UINT16 + 0x10, 0x27, // ldi 2710
+ 0x04, // sub
+ 0x65, 0x50, // aTop 50
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature gk1Signatures[] = {
- { 51, "interrogation bug", 1, PATCH_MAGICDWORD(0x65, 0x4c, 0x67, 0x50), 0, gk1SignatureInterrogationBug, gk1PatchInterrogationBug },
- { 212, "day 5 phone freeze", 1, PATCH_MAGICDWORD(0x35, 0x03, 0x65, 0x1a), 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze },
- { 230, "day 6 police beignet timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -16, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet },
- { 230, "day 6 police sleep timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -5, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep },
+// script, description, signature patch
+SciScriptPatcherEntry gk1Signatures[] = {
+ { 51, "interrogation bug", 1, 0, 0, gk1SignatureInterrogationBug, gk1PatchInterrogationBug },
+ { 212, "day 5 phone freeze", 1, 0, 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze },
+ { 230, "day 6 police beignet timer issue", 1, 0, 0, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet },
+ { 230, "day 6 police sleep timer issue", 1, 0, 0, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -596,47 +655,47 @@ const SciScriptSignature 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 byte kq5SignatureCdHarpyVolume[] = {
- 34,
- 0x80, 0x91, 0x01, // lag global[191h]
- 0x18, // not
- 0x30, 0x2c, 0x00, // bnt [jump further] (jumping, if global 191h is 1)
- 0x35, 0x01, // ldi 01
- 0xa0, 0x91, 0x01, // sag global[191h] (setting global 191h to 1)
- 0x38, 0x7b, 0x01, // 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, 0x7b, 0x01, // pushi 017b
- 0x76, // push0
- 0x81, 0x01, // lag global[1]
- 0x4a, 0x04, // send 04 - read KQ5::masterVolume
- 0x36, // push
- 0x35, 0x04, // ldi 04
- 0x20, // ge? (followed by bnt)
- 0
+const uint16 kq5SignatureCdHarpyVolume[] = {
+ SIG_MAGICDWORD,
+ 0x80, SIG_UINT16 + 0x91, 0x01, // lag global[191h]
+ 0x18, // not
+ 0x30, SIG_UINT16 + 0x2c, 0x00, // 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
+ 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
+ 0x76, // push0
+ 0x81, 0x01, // lag global[1]
+ 0x4a, 0x04, // send 04 - read KQ5::masterVolume
+ 0x36, // push
+ 0x35, 0x04, // ldi 04
+ 0x20, // ge? (followed by bnt)
+ SIG_END
};
const uint16 kq5PatchCdHarpyVolume[] = {
- 0x38, 0x2f, 0x02, // 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, 0x91, 0x01, // lag global[191h]
+ 0x38, PATCH_UINT16 + 0x2f, 0x02, // 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]
// saving 1 byte due optimization
- 0x2e, 0x23, 0x00, // bt [jump further] (jumping, if global 191h is 1)
- 0x35, 0x01, // ldi 01
- 0xa0, 0x91, 0x01, // sag global[191h] (setting global 191h to 1)
- 0x38, 0x7b, 0x01, // 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)
+ 0x2e, PATCH_UINT16 + 0x23, 0x00, // 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
+ 0x76, // push0
+ 0x81, 0x01, // lag global[1]
+ 0x4a, 0x04, // send 04 - read KQ5::masterVolume
+ 0xa5, 0x03, // sat temp[3] (store volume in temp 3)
// saving 8 bytes due removing of duplicate code
- 0x39, 0x04, // pushi 04 (saving 1 byte due swapping)
- 0x22, // lt? (because we switched values)
+ 0x39, 0x04, // pushi 04 (saving 1 byte due swapping)
+ 0x22, // lt? (because we switched values)
PATCH_END
};
@@ -654,24 +713,24 @@ const uint16 kq5PatchCdHarpyVolume[] = {
// of variables effectively hides witchCage::doit, causing this position check
// to be bypassed entirely.
// See also the warning+comment in Object::initBaseObject
-const byte kq5SignatureWitchCageInit[] = {
- 16,
- 0x00, 0x00, // top
- 0x00, 0x00, // left
- 0x00, 0x00, // bottom
- 0x00, 0x00, // right
- 0x00, 0x00, // extra property #1
- 0x7a, 0x00, // extra property #2
- 0xc8, 0x00, // extra property #3
- 0xa3, 0x00, // extra property #4
- 0
+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
+ SIG_MAGICDWORD,
+ SIG_UINT16 + 0x7a, 0x00, // extra property #2
+ SIG_UINT16 + 0xc8, 0x00, // extra property #3
+ SIG_UINT16 + 0xa3, 0x00, // extra property #4
+ SIG_END
};
const uint16 kq5PatchWitchCageInit[] = {
- 0x00, 0x00, // top
- 0x7a, 0x00, // left
- 0xc8, 0x00, // bottom
- 0xa3, 0x00, // right
+ PATCH_UINT16 + 0x00, 0x00, // top
+ PATCH_UINT16 + 0x7a, 0x00, // left
+ PATCH_UINT16 + 0xc8, 0x00, // bottom
+ PATCH_UINT16 + 0xa3, 0x00, // right
PATCH_END
};
@@ -689,31 +748,31 @@ 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 byte kq5SignatureWinGMSignals[] = {
- 9,
- 0x80, 0x90, 0x01, // lag 0x190
- 0x18, // not
- 0x30, 0x1b, 0x00, // bnt +0x001B
- 0x89, 0x57, // lsg 0x57
- 0
+const uint16 kq5SignatureWinGMSignals[] = {
+ SIG_MAGICDWORD,
+ 0x80, SIG_UINT16 + 0x90, 0x01, // lag 0x190
+ 0x18, // not
+ 0x30, SIG_UINT16 + 0x1b, 0x00, // bnt +0x001B
+ 0x89, 0x57, // lsg 0x57
+ SIG_END
};
const uint16 kq5PatchWinGMSignals[] = {
- 0x34, 0x01, 0x00, // ldi 0x0001
+ 0x34, PATCH_UINT16 + 0x01, 0x00, // ldi 0x0001
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature kq5Signatures[] = {
- { 0, "CD: harpy volume change", 1, PATCH_MAGICDWORD(0x80, 0x91, 0x01, 0x18), 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
- { 200, "CD: witch cage init", 1, PATCH_MAGICDWORD(0x7a, 0x00, 0xc8, 0x00), -10, kq5SignatureWitchCageInit, kq5PatchWitchCageInit },
+// script, description, signature patch
+SciScriptPatcherEntry kq5Signatures[] = {
+ { 0, "CD: harpy volume change", 1, 0, 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
+ { 200, "CD: witch cage init", 1, 0, 0, kq5SignatureWitchCageInit, kq5PatchWitchCageInit },
SCI_SIGNATUREENTRY_TERMINATOR
};
-const SciScriptSignature kq5WinGMSignatures[] = {
- { 0, "CD: harpy volume change", 1, PATCH_MAGICDWORD(0x80, 0x91, 0x01, 0x18), 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
- { 200, "CD: witch cage init", 1, PATCH_MAGICDWORD(0x7a, 0x00, 0xc8, 0x00), -10, kq5SignatureWitchCageInit, kq5PatchWitchCageInit },
- { 124, "Win: GM Music signal checks", 4, PATCH_MAGICDWORD(0x80, 0x90, 0x01, 0x18), 0, kq5SignatureWinGMSignals, kq5PatchWinGMSignals },
+SciScriptPatcherEntry kq5WinGMSignatures[] = {
+ { 0, "CD: harpy volume change", 1, 0, 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
+ { 200, "CD: witch cage init", 1, 0, 0, kq5SignatureWitchCageInit, kq5PatchWitchCageInit },
+ { 124, "Win: GM Music signal checks", 4, 0, 0, kq5SignatureWinGMSignals, kq5PatchWinGMSignals },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -726,24 +785,95 @@ const SciScriptSignature kq5WinGMSignatures[] = {
// unnecessary cryMusic::check method out, thereby stopping the sound from
// constantly restarting (since it's being looped anyway), thus the normal
// game speech can work while the baby cry sound is heard. Fixes bug #3034579.
-const byte kq6SignatureDuplicateBabyCry[] = {
- 10,
- 0x83, 0x00, // lal 00
- 0x31, 0x1e, // bnt 1e [07f4]
- 0x78, // push1
- 0x39, 0x04, // pushi 04
- 0x43, 0x75, 0x02, // callk DoAudio[75] 02
- 0
+const uint16 kq6SignatureDuplicateBabyCry[] = {
+ SIG_MAGICDWORD,
+ 0x83, 0x00, // lal 00
+ 0x31, 0x1e, // bnt 1e [07f4]
+ 0x78, // push1
+ 0x39, 0x04, // pushi 04
+ 0x43, 0x75, 0x02, // callk DoAudio[75] 02
+ SIG_END
};
const uint16 kq6PatchDuplicateBabyCry[] = {
- 0x48, // ret
+ 0x48, // ret
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature kq6Signatures[] = {
- { 481, "duplicate baby cry", 1, PATCH_MAGICDWORD(0x83, 0x00, 0x31, 0x1e), 0, kq6SignatureDuplicateBabyCry, kq6PatchDuplicateBabyCry },
+// The inventory of King's Quest 6 is buggy. When it grows too large,
+// it will get split into 2 pages. Switching between those pages will
+// grow the stack, because it's calling itself per switch.
+// Which means after a while ScummVM will bomb out because the stack frame
+// will be too large. This patch fixes the buggy script.
+// Applies to at least: PC-CD, English PC floppy, German PC floppy, English Mac
+// Responsible method: KqInv::showSelf
+// Fixes bug: #3293954
+const uint16 kq6SignatureInventoryStackFix[] = {
+ 0x67, 0x30, // pTos state
+ 0x34, SIG_UINT16 + 0x00, 0x20, // ldi 2000
+ 0x12, // and
+ 0x18, // not
+ 0x31, 0x04, // bnt [not first refresh]
+ 0x35, 0x00, // ldi 00
+ SIG_MAGICDWORD,
+ 0x65, 0x1e, // aTop curIcon
+ 0x67, 0x30, // pTos state
+ 0x34, SIG_UINT16 + 0xff, 0xdf, // ldi dfff
+ 0x12, // and
+ 0x65, 0x30, // aTop state
+ 0x38, SIG_SELECTOR16 + SELECTOR_show, // pushi "show" ("show" is e1h for KQ6CD)
+ 0x78, // push1
+ 0x87, 0x00, // lap param[0]
+ 0x31, 0x04, // bnt [use global for show]
+ 0x87, 0x01, // lap param[1]
+ 0x33, 0x02, // jmp [use param for show]
+ 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)
+ 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[] = {
+ 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
+ 0x12, // and
+ 0x2f, 0x02, // bt [not first refresh] - saves 3 bytes in total
+ 0x65, 0x1e, // aTop curIcon
+ 0x00, // neg (either 2000 or 0000 in acc, this will create dfff or ffff) - saves 2 bytes
+ 0x12, // and
+ 0x65, 0x30, // aTop state
+ 0x38, // pushi "show"
+ PATCH_GETORIGINALBYTE +22,
+ PATCH_GETORIGINALBYTE +23,
+ 0x78, // push1
+ 0x87, 0x00, // lap param[0]
+ 0x31, 0x04, // bnt [call show using global 0]
+ 0x8f, 0x01, // lsp param[1], save 1 byte total with lsg global[0] combined
+ 0x33, 0x02, // jmp [call show using param 1]
+ 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
+ 0x12, // and
+ 0x2f, 0x05, // bt [to return]
+ 0x39, 0x39, // pushi 39
+ 0x76, // push0
+ 0x54, 0x04, // self 04 (self::doit)
+ 0x48, // ret (saves 2 bytes for PC, 1 byte for mac)
+ PATCH_END
+};
+
+// script, description, signature patch
+SciScriptPatcherEntry kq6Signatures[] = {
+ { 481, "duplicate baby cry", 1, 0, 0, kq6SignatureDuplicateBabyCry, kq6PatchDuplicateBabyCry },
+ { 907, "inventory stack fix", 1, 0, 0, kq6SignatureInventoryStackFix, kq6PatchInventoryStackFix },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -756,40 +886,40 @@ const SciScriptSignature kq6Signatures[] = {
// the function is undefined, thus kStrCat() that is called inside the function
// reads a random pointer and crashes. We patch all of the 5 function calls
// (one for each letter typed from "R", "O", "B", "I", "N") so that they are
-// the same as the English version. Fixes bug #3048054.
-const byte longbowSignatureShowHandCode[] = {
- 3,
- 0x78, // push1
- 0x78, // push1
- 0x72, // lofsa
- +2, 2, // skip 2 bytes, offset of lofsa (the letter typed)
- 0x36, // push
- 0x40, // call
- +2, 3, // skip 2 bytes, offset of call
- 0x02, // perform the call above with 2 parameters
- 0x36, // push
- 0x40, // call
- +2, 8, // skip 2 bytes, offset of call
- 0x02, // perform the call above with 2 parameters
- 0x38, 0x1c, 0x01, // pushi 011c (setMotion)
- 0x39, 0x04, // pushi 04 (x)
- 0x51, 0x1e, // class MoveTo
- 0
+// the same as the English version.
+// Applies to at least: German floppy
+// Responsible method: unknown
+// Fixes bug: #3048054
+const uint16 longbowSignatureShowHandCode[] = {
+ 0x78, // push1
+ 0x78, // push1
+ 0x72, SIG_ADDTOOFFSET +2, // lofsa (letter, that was typed)
+ 0x36, // push
+ 0x40, SIG_ADDTOOFFSET +2, // call
+ 0x02, // perform the call above with 2 parameters
+ 0x36, // push
+ 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)
+ 0x51, 0x1e, // class MoveTo
+ SIG_END
};
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
+ 0x39, 0x01, // pushi 1 (combine the two push1's in one, like in the English version)
+ PATCH_ADDTOOFFSET +3, // leave the lofsa call untouched
// The following will remove the duplicate call
- 0x32, 0x02, 0x00, // 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)
+ 0x32, PATCH_UINT16 + 0x02, 0x00, // 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, magic DWORD, adjust
-const SciScriptSignature longbowSignatures[] = {
- { 210, "hand code crash", 5, PATCH_MAGICDWORD(0x02, 0x38, 0x1c, 0x01), -14, longbowSignatureShowHandCode, longbowPatchShowHandCode },
+// script, description, signature patch
+SciScriptPatcherEntry longbowSignatures[] = {
+ { 210, "hand code crash", 5, 0, 0, longbowSignatureShowHandCode, longbowPatchShowHandCode },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -807,31 +937,31 @@ const SciScriptSignature longbowSignatures[] = {
// "worked" in SSCI, but ScummVM/SCI doesn't allow that.
// That's why those points weren't granted here at all.
// We patch the script to use global 90, which seems to be unused in the whole game.
+// Applies to at least: English floppy
// Responsible method: rm63Script::handleEvent
-// Fixes bug #3614419
-const byte larry2SignatureWearParachutePoints[] = {
- 16,
- 0x35, 0x01, // ldi 01
- 0xa1, 0x8e, // sag 8e
- 0x80, 0xe0, 0x01, // lag 1e0
- 0x18, // not
- 0x30, 0x0f, 0x00, // bnt [don't give points]
- 0x35, 0x01, // ldi 01
- 0xa0, 0xe0, 0x01, // sag 1e0
- 0
+// Fixes bug: #3614419
+const uint16 larry2SignatureWearParachutePoints[] = {
+ 0x35, 0x01, // ldi 01
+ 0xa1, SIG_MAGICDWORD, 0x8e, // sag 8e
+ 0x80, SIG_UINT16 + 0xe0, 0x01, // lag 1e0
+ 0x18, // not
+ 0x30, SIG_UINT16 + 0x0f, 0x00, // bnt [don't give points]
+ 0x35, 0x01, // ldi 01
+ 0xa0, 0xe0, 0x01, // sag 1e0
+ SIG_END
};
const uint16 larry2PatchWearParachutePoints[] = {
- PATCH_ADDTOOFFSET | +4,
- 0x80, 0x5a, 0x00, // lag 5a (global 90)
- PATCH_ADDTOOFFSET | +6,
- 0xa0, 0x5a, 0x00, // sag 5a (global 90)
+ PATCH_ADDTOOFFSET +4,
+ 0x80, PATCH_UINT16 + 0x5a, 0x00, // lag 5a (global 90)
+ PATCH_ADDTOOFFSET +6,
+ 0xa0, PATCH_UINT16 + 0x5a, 0x00, // sag 5a (global 90)
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature larry2Signatures[] = {
- { 63, "plane: no points for wearing plane", 1, PATCH_MAGICDWORD(0x8e, 0x80, 0xe0, 0x01), -3, larry2SignatureWearParachutePoints, larry2PatchWearParachutePoints },
+// script, description, signature patch
+SciScriptPatcherEntry larry2Signatures[] = {
+ { 63, "plane: no points for wearing plane", 1, 0, 0, larry2SignatureWearParachutePoints, larry2PatchWearParachutePoints },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -843,77 +973,79 @@ const SciScriptSignature larry2Signatures[] = {
// doesn't happen anymore. We would otherwise get a crash
// calling for invalid views (this happens of course also
// in sierra sci)
-const byte larry6SignatureDeathDialog[] = {
- 7,
- 0x3e, 0x33, 0x01, // link 0133 (offset 0x20)
- 0x35, 0xff, // ldi ff
- 0xa3, 0x00, // sal 00
- +255, 0,
- +255, 0,
- +170, 12, // [skip 680 bytes]
- 0x8f, 0x01, // lsp 01 (offset 0x2cf)
- 0x7a, // push2
- 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e
- 0x36, // push
- 0x43, 0x7c, 0x0e, // kMessage[7c] 0e
- +90, 10, // [skip 90 bytes]
- 0x38, 0xd6, 0x00, // pushi 00d6 (offset 0x335)
- 0x78, // push1
- 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e
- 0x36, // push
- +76, 11, // [skip 76 bytes]
- 0x38, 0xcd, 0x00, // pushi 00cd (offset 0x38b)
- 0x39, 0x03, // pushi 03
- 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e
+// Applies to at least: German PC-CD
+// Responsible method: unknown
+const uint16 larry6SignatureDeathDialog[] = {
+ SIG_MAGICDWORD,
+ 0x3e, SIG_UINT16 + 0x33, 0x01, // link 0133 (offset 0x20)
+ 0x35, 0xff, // ldi ff
+ 0xa3, 0x00, // sal 00
+ 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
+ 0x36, // push
+ 0x43, 0x7c, 0x0e, // kMessage[7c] 0e
+ SIG_ADDTOOFFSET +90, // [skip 90 bytes]
+ 0x38, SIG_UINT16 + 0xd6, 0x00, // pushi 00d6 (offset 0x335)
+ 0x78, // push1
+ 0x5a, SIG_UINT16 + 0x04, 0x00, SIG_UINT16 + 0x0e, 0x01, // lea 0004 010e
+ 0x36, // push
+ SIG_ADDTOOFFSET +76, // [skip 76 bytes]
+ 0x38, SIG_UINT16 + 0xcd, 0x00, // pushi 00cd (offset 0x38b)
+ 0x39, 0x03, // pushi 03
+ 0x5a, SIG_UINT16 + 0x04, 0x00, SIG_UINT16 + 0x0e, 0x01, // lea 0004 010e
0x36,
- 0
+ SIG_END
};
const uint16 larry6PatchDeathDialog[] = {
- 0x3e, 0x00, 0x02, // link 0200
- PATCH_ADDTOOFFSET | +687,
- 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140
- PATCH_ADDTOOFFSET | +98,
- 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140
- PATCH_ADDTOOFFSET | +82,
- 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140
+ 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_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature larry6Signatures[] = {
- { 82, "death dialog memory corruption", 1, PATCH_MAGICDWORD(0x3e, 0x33, 0x01, 0x35), 0, larry6SignatureDeathDialog, larry6PatchDeathDialog },
+// script, description, signature patch
+SciScriptPatcherEntry larry6Signatures[] = {
+ { 82, "death dialog memory corruption", 1, 0, 0, larry6SignatureDeathDialog, larry6PatchDeathDialog },
SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
// rm560::doit was supposed to close the painting, when Heimlich enters the
-// room. The code is buggy, so it actually closes the painting, when heimlich
+// room. The code is buggy. It actually closes the painting, when heimlich
// is not in the room. We fix that.
-const byte laurabow2SignaturePaintingClosing[] = {
- 17,
- 0x4a, 0x04, // send 04 - read aHeimlich::room
- 0x36, // push
- 0x81, 0x0b, // lag global[11d] -> current room
- 0x1c, // ne?
- 0x31, 0x0e, // bnt [don't close]
- 0x35, 0x00, // ldi 00
- 0xa3, 0x00, // sal local[0]
- 0x38, 0x92, 0x00, // pushi 0092
- 0x78, // push1
- 0x72, // lofsa sDumpSafe
- 0
+// Applies to at least: English floppy
+// Responsible method: rm560::doit
+const uint16 laurabow2SignaturePaintingClosing[] = {
+ 0x4a, 0x04, // send 04 - read aHeimlich::room
+ SIG_MAGICDWORD,
+ 0x36, // push
+ 0x81, 0x0b, // lag global[11d] -> current room
+ 0x1c, // ne?
+ 0x31, 0x0e, // bnt [don't close]
+ 0x35, 0x00, // ldi 00
+ 0xa3, 0x00, // sal local[0]
+ 0x38, SIG_UINT16 + 0x92, 0x00, // pushi 0092
+ 0x78, // push1
+ 0x72, // lofsa sDumpSafe
+ SIG_END
};
const uint16 laurabow2PatchPaintingClosing[] = {
- PATCH_ADDTOOFFSET | +6,
+ PATCH_ADDTOOFFSET +6,
0x2f, 0x0e, // bt [don't close]
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature laurabow2Signatures[] = {
- { 560, "painting closing immediately", 1, PATCH_MAGICDWORD(0x36, 0x81, 0x0b, 0x1c), -2, laurabow2SignaturePaintingClosing, laurabow2PatchPaintingClosing },
+// script, description, signature patch
+SciScriptPatcherEntry laurabow2Signatures[] = {
+ { 560, "painting closing immediately", 1, 0, 0, laurabow2SignaturePaintingClosing, laurabow2PatchPaintingClosing },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -922,29 +1054,27 @@ const SciScriptSignature 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 byte mothergoose256SignatureReplay[] = {
- 6,
- 0x36, // push
- 0x35, 0x20, // ldi 20
- 0x04, // sub
- 0xa1, 0xb3, // sag global[b3]
- 0
+const uint16 mothergoose256SignatureReplay[] = {
+ 0x36, // push
+ 0x35, SIG_MAGICDWORD, 0x20, // ldi 20
+ 0x04, // sub
+ 0xa1, 0xb3, // sag global[b3]
+ SIG_END
};
const uint16 mothergoose256PatchReplay[] = {
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
- 0x34, 0x00, 0x00, // ldi 0000 (dummy)
+ 0x34, PATCH_UINT16 + 0x00, 0x00, // ldi 0000 (dummy)
+ 0x34, PATCH_UINT16 + 0x00, 0x00, // 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 byte mothergoose256SignatureSaveLimit[] = {
- 5,
- 0x89, 0xb3, // lsg global[b3]
- 0x35, 0x0d, // ldi 0d
- 0x20, // ge?
- 0
+const uint16 mothergoose256SignatureSaveLimit[] = {
+ 0x89, SIG_MAGICDWORD, 0xb3, // lsg global[b3]
+ 0x35, 0x0d, // ldi 0d
+ 0x20, // ge?
+ SIG_END
};
const uint16 mothergoose256PatchSaveLimit[] = {
@@ -953,11 +1083,11 @@ const uint16 mothergoose256PatchSaveLimit[] = {
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature mothergoose256Signatures[] = {
- { 0, "replay save issue", 1, PATCH_MAGICDWORD(0x20, 0x04, 0xa1, 0xb3), -2, mothergoose256SignatureReplay, mothergoose256PatchReplay },
- { 0, "save limit dialog (SCI1.1)", 1, PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit },
- { 994, "save limit dialog (SCI1)", 1, PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit },
+// script, description, signature patch
+SciScriptPatcherEntry mothergoose256Signatures[] = {
+ { 0, "replay save issue", 1, 0, 0, mothergoose256SignatureReplay, mothergoose256PatchReplay },
+ { 0, "save limit dialog (SCI1.1)", 1, 0, 0, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit },
+ { 994, "save limit dialog (SCI1)", 1, 0, 0, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -971,55 +1101,56 @@ const SciScriptSignature mothergoose256Signatures[] = {
// SSCI.
// This patch changes the code, so that the gun is actually given away
// when the 2 seconds have passed and the locker got closed.
+// Applies to at least: English floppy
// Responsible method: putGun::changeState (script 341)
-// Fixes bug #3036933 / #3303802
-const byte pq1vgaSignaturePutGunInLockerBug[] = {
- 5,
- 0x35, 0x00, // ldi 00
- 0x1a, // eq?
- 0x31, 0x25, // bnt [next state check]
- +22, 29, // [skip 22 bytes]
- 0x38, 0x5f, 0x01, // pushi 15fh
- 0x78, // push1
- 0x76, // push0
- 0x81, 0x00, // lag 00
- 0x4a, 0x06, // send 06 - ego::put(0)
- 0x35, 0x02, // ldi 02
- 0x65, 0x1c, // aTop 1c (set timer to 2 seconds)
- 0x33, 0x0e, // jmp [end of method]
- 0x3c, // dup --- next state check target
- 0x35, 0x01, // ldi 01
- 0x1a, // eq?
- 0x31, 0x08, // bnt [end of method]
- 0x39, 0x6f, // pushi 6fh
- 0x76, // push0
- 0x72, 0x88, 0x00, // lofsa 0088
- 0x4a, 0x04, // send 04 - locker::dispose
- 0
+// Fixes bug: #3036933 / #3303802
+const uint16 pq1vgaSignaturePutGunInLockerBug[] = {
+ 0x35, 0x00, // ldi 00
+ 0x1a, // eq?
+ 0x31, 0x25, // bnt [next state check]
+ SIG_ADDTOOFFSET +22, // [skip 22 bytes]
+ SIG_MAGICDWORD,
+ 0x38, SIG_SELECTOR16 + SELECTOR_put, // pushi "put"
+ 0x78, // push1
+ 0x76, // push0
+ 0x81, 0x00, // lag 00
+ 0x4a, 0x06, // send 06 - ego::put(0)
+ 0x35, 0x02, // ldi 02
+ 0x65, 0x1c, // aTop 1c (set timer to 2 seconds)
+ 0x33, 0x0e, // jmp [end of method]
+ 0x3c, // dup --- next state check target
+ 0x35, 0x01, // ldi 01
+ 0x1a, // eq?
+ 0x31, 0x08, // bnt [end of method]
+ 0x39, SIG_SELECTOR8 + SELECTOR_dispose, // pushi "dispose"
+ 0x76, // push0
+ 0x72, SIG_UINT16 + 0x88, 0x00, // lofsa 0088
+ 0x4a, 0x04, // send 04 - locker::dispose
+ SIG_END
};
const uint16 pq1vgaPatchPutGunInLockerBug[] = {
- PATCH_ADDTOOFFSET | +3,
- 0x31, 0x1c, // bnt [next state check]
- PATCH_ADDTOOFFSET | +22,
- 0x35, 0x02, // ldi 02
- 0x65, 0x1c, // aTop 1c (set timer to 2 seconds)
- 0x33, 0x17, // jmp [end of method]
- 0x3c, // dup --- next state check target
- 0x35, 0x01, // ldi 01
- 0x1a, // eq?
- 0x31, 0x11, // bnt [end of method]
- 0x38, 0x5f, 0x01, // pushi 15fh
- 0x78, // push1
- 0x76, // push0
- 0x81, 0x00, // lag 00
- 0x4a, 0x06, // send 06 - ego::put(0)
+ PATCH_ADDTOOFFSET +3,
+ 0x31, 0x1c, // bnt [next state check]
+ PATCH_ADDTOOFFSET +22,
+ 0x35, 0x02, // ldi 02
+ 0x65, 0x1c, // aTop 1c (set timer to 2 seconds)
+ 0x33, 0x17, // jmp [end of method]
+ 0x3c, // dup --- next state check target
+ 0x35, 0x01, // ldi 01
+ 0x1a, // eq?
+ 0x31, 0x11, // bnt [end of method]
+ 0x38, PATCH_SELECTOR16 + SELECTOR_put, // pushi "put"
+ 0x78, // push1
+ 0x76, // push0
+ 0x81, 0x00, // lag 00
+ 0x4a, 0x06, // send 06 - ego::put(0)
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature pq1vgaSignatures[] = {
- { 341, "put gun in locker bug", 1, PATCH_MAGICDWORD(0x38, 0x5f, 0x01, 0x78), -27, pq1vgaSignaturePutGunInLockerBug, pq1vgaPatchPutGunInLockerBug },
+// script, description, signature patch
+SciScriptPatcherEntry pq1vgaSignatures[] = {
+ { 341, "put gun in locker bug", 1, 0, 0, pq1vgaSignaturePutGunInLockerBug, pq1vgaPatchPutGunInLockerBug },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -1032,43 +1163,45 @@ const SciScriptSignature pq1vgaSignatures[] = {
// not nearly as bad as in our sci, but these differences may be caused by
// timing.
// We just reuse the active event, thus removing the duplicate kGetEvent call.
-const byte qfg1vgaSignatureFightEvents[] = {
- 25,
- 0x39, 0x6d, // pushi 6d (selector new)
- 0x76, // push0
- 0x51, 0x07, // class Event
- 0x4a, 0x04, // send 04 - call Event::new
- 0xa5, 0x00, // sat temp[0]
- 0x78, // push1
- 0x76, // push0
- 0x4a, 0x04, // send 04 - read Event::x
- 0xa5, 0x03, // sat temp[3]
- 0x76, // push0 (selector y)
- 0x76, // push0
- 0x85, 0x00, // lat temp[0]
- 0x4a, 0x04, // send 04 - read Event::y
- 0x36, // push
- 0x35, 0x0a, // ldi 0a
- 0x04, // sub (poor mans localization) ;-)
- 0
+// Applies to at least: English floppy
+// Responsible method: pointBox::doit
+const uint16 qfg1vgaSignatureFightEvents[] = {
+ 0x39, SIG_MAGICDWORD,
+ SIG_SELECTOR8 + SELECTOR_new, // pushi "new"
+ 0x76, // push0
+ 0x51, 0x07, // class Event
+ 0x4a, 0x04, // send 04 - call Event::new
+ 0xa5, 0x00, // sat temp[0]
+ 0x78, // push1
+ 0x76, // push0
+ 0x4a, 0x04, // send 04 - read Event::x
+ 0xa5, 0x03, // sat temp[3]
+ 0x76, // push0 (selector y)
+ 0x76, // push0
+ 0x85, 0x00, // lat temp[0]
+ 0x4a, 0x04, // send 04 - read Event::y
+ 0x36, // push
+ 0x35, 0x0a, // ldi 0a
+ 0x04, // sub (poor mans localization) ;-)
+ SIG_END
};
const uint16 qfg1vgaPatchFightEvents[] = {
- 0x38, 0x5a, 0x01, // 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
- 0xa5, 0x00, // sat temp[0]
- 0x78, // push1
- 0x76, // push0
- 0x4a, 0x04, // send 04 - read Event::x
- 0xa5, 0x03, // sat temp[3]
- 0x76, // push0 (selector y)
- 0x76, // push0
- 0x85, 0x00, // lat temp[0]
- 0x4a, 0x04, // send 04 - read Event::y
- 0x39, 0x00, // pushi 00
- 0x02, // add (waste 3 bytes) - we don't need localization, User::doit has already done it
+ 0x38, PATCH_SELECTOR16 + SELECTOR_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
+ 0xa5, 0x00, // sat temp[0]
+ 0x78, // push1
+ 0x76, // push0
+ 0x4a, 0x04, // send 04 - read Event::x
+ 0xa5, 0x03, // sat temp[3]
+ 0x76, // push0 (selector y)
+ 0x76, // push0
+ 0x85, 0x00, // lat temp[0]
+ 0x4a, 0x04, // send 04 - read Event::y
+ 0x39, 0x00, // pushi 00
+ 0x02, // add (waste 3 bytes) - we don't need localization, User::doit has already done it
PATCH_END
};
@@ -1082,28 +1215,28 @@ const uint16 qfg1vgaPatchFightEvents[] = {
// Fixes bug #3568431.
// Patch 1: Increase temp space
-const byte qfg1vgaSignatureTempSpace[] = {
- 4,
- 0x3f, 0xba, // link 0xba
- 0x87, 0x00, // lap 0
- 0
+const uint16 qfg1vgaSignatureTempSpace[] = {
+ SIG_MAGICDWORD,
+ 0x3f, 0xba, // link 0xba
+ 0x87, 0x00, // lap 0
+ SIG_END
};
const uint16 qfg1vgaPatchTempSpace[] = {
- 0x3f, 0xca, // link 0xca
+ 0x3f, 0xca, // link 0xca
PATCH_END
};
// Patch 2: Move the pointer used for the window header a little bit
-const byte qfg1vgaSignatureDialogHeader[] = {
- 4,
- 0x5b, 0x04, 0x80, // lea temp[0x80]
- 0x36, // push
- 0
+const uint16 qfg1vgaSignatureDialogHeader[] = {
+ SIG_MAGICDWORD,
+ 0x5b, 0x04, 0x80, // lea temp[0x80]
+ 0x36, // push
+ SIG_END
};
const uint16 qfg1vgaPatchDialogHeader[] = {
- 0x5b, 0x04, 0x90, // lea temp[0x90]
+ 0x5b, 0x04, 0x90, // lea temp[0x90]
PATCH_END
};
@@ -1116,62 +1249,63 @@ 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 #3585189.
-const byte qfg1vgaSignatureMoveToCrusher[] = {
- 9,
- 0x51, 0x1f, // class Motion
- 0x36, // push
- 0x39, 0x4f, // pushi 4f (79 - x)
- 0x38, 0xa5, 0x00, // pushi 00a5 (165 - y)
- 0x7c, // pushSelf
- 0
+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)
+ 0x7c, // pushSelf
+ SIG_END
};
const uint16 qfg1vgaPatchMoveToCrusher[] = {
- PATCH_ADDTOOFFSET | +3,
- 0x39, 0x55, // pushi 55 (85 - x)
+ PATCH_ADDTOOFFSET +3,
+ 0x39, 0x55, // pushi 55 (85 - x)
PATCH_END
};
// Same pathfinding bug as above, where Ego is set to move to an impossible
// spot when sneaking. In GuardsTrumpet::changeState, we change the final
// location where Ego is moved from 111, 111 to 114, 114. Fixes bug #3604939.
-const byte qfg1vgaSignatureMoveToCastleGate[] = {
- 7,
- 0x51, 0x1f, // class MoveTo
- 0x36, // push
- 0x39, 0x6f, // pushi 6f (111 - x)
- 0x3c, // dup (111 - y)
- 0x7c, // pushSelf
- 0
+const uint16 qfg1vgaSignatureMoveToCastleGate[] = {
+ SIG_MAGICDWORD,
+ 0x51, 0x1f, // class MoveTo
+ 0x36, // push
+ 0x39, 0x6f, // pushi 6f (111 - x)
+ 0x3c, // dup (111 - y)
+ 0x7c, // pushSelf
+ SIG_END
};
const uint16 qfg1vgaPatchMoveToCastleGate[] = {
- PATCH_ADDTOOFFSET | +3,
- 0x39, 0x72, // pushi 72 (114 - x)
+ PATCH_ADDTOOFFSET +3,
+ 0x39, 0x72, // pushi 72 (114 - x)
PATCH_END
};
// Typo in the original Sierra scripts
// Looking at a cheetaur resulted in a text about a Saurus Rex
// The code treats both monster types the same.
+// Applies to at least: English floppy
// Responsible method: smallMonster::doVerb
// Fixes bug #3604943.
-const byte qfg1vgaSignatureCheetaurDescription[] = {
- 16,
- 0x34, 0xb8, 0x01, // ldi 01b8
- 0x1a, // eq?
- 0x31, 0x16, // bnt 16
- 0x38, 0x27, 0x01, // pushi 0127
- 0x39, 0x06, // pushi 06
- 0x39, 0x03, // pushi 03
- 0x78, // push1
- 0x39, 0x12, // pushi 12 -> monster type Saurus Rex
- 0
+const uint16 qfg1vgaSignatureCheetaurDescription[] = {
+ SIG_MAGICDWORD,
+ 0x34, SIG_UINT16 + 0xb8, 0x01, // ldi 01b8
+ 0x1a, // eq?
+ 0x31, 0x16, // bnt 16
+ 0x38, SIG_UINT16 + 0x27, 0x01, // pushi 0127
+ 0x39, 0x06, // pushi 06
+ 0x39, 0x03, // pushi 03
+ 0x78, // push1
+ 0x39, 0x12, // pushi 12 -> monster type Saurus Rex
+ SIG_END
};
const uint16 qfg1vgaPatchCheetaurDescription[] = {
- PATCH_ADDTOOFFSET | +14,
- 0x39, 0x11, // pushi 11 -> monster type cheetaur
+ PATCH_ADDTOOFFSET +14,
+ 0x39, 0x11, // pushi 11 -> monster type cheetaur
PATCH_END
};
@@ -1185,41 +1319,42 @@ const uint16 qfg1vgaPatchCheetaurDescription[] = {
// Local 5 of that room is a timer, that closes the door (object door11).
// Setting it to 1 during happyFace::changeState(0) stops door11::doit from
// calling goTo6::init, so the whole issue is stopped from happening.
+// Applies to at least: English floppy
// Responsible method: happyFace::changeState, door11::doit
// Fixes bug #3585793
-const byte qfg1vgaSignatureFunnyRoomFix[] = {
- 14,
- 0x65, 0x14, // aTop 14 (state)
- 0x36, // push
- 0x3c, // dup
- 0x35, 0x00, // ldi 00
- 0x1a, // eq?
- 0x30, 0x25, 0x00, // bnt 0025 [-> next state]
- 0x35, 0x01, // ldi 01
- 0xa3, 0x4e, // sal 4e
- 0
+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]
+ SIG_MAGICDWORD,
+ 0x35, 0x01, // ldi 01
+ 0xa3, 0x4e, // sal 4e
+ SIG_END
};
const uint16 qfg1vgaPatchFunnyRoomFix[] = {
- PATCH_ADDTOOFFSET | +3,
- 0x2e, 0x29, 0x00, // bt 0029 [-> next state] - saves 4 bytes
- 0x35, 0x01, // ldi 01
- 0xa3, 0x4e, // sal 4e
- 0xa3, 0x05, // sal 05 (sets local 5 to 1)
- 0xa3, 0x05, // and again to make absolutely sure (actually to waste 2 bytes)
+ PATCH_ADDTOOFFSET +3,
+ 0x2e, PATCH_UINT16 + 0x29, 0x00, // bt 0029 [-> next state] - saves 4 bytes
+ 0x35, 0x01, // ldi 01
+ 0xa3, 0x4e, // sal 4e
+ 0xa3, 0x05, // sal 05 (sets local 5 to 1)
+ 0xa3, 0x05, // and again to make absolutely sure (actually to waste 2 bytes)
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature qfg1vgaSignatures[] = {
- { 215, "fight event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
- { 216, "weapon master event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
- { 814, "window text temp space", 1, PATCH_MAGICDWORD(0x3f, 0xba, 0x87, 0x00), 0, qfg1vgaSignatureTempSpace, qfg1vgaPatchTempSpace },
- { 814, "dialog header offset", 3, PATCH_MAGICDWORD(0x5b, 0x04, 0x80, 0x36), 0, qfg1vgaSignatureDialogHeader, qfg1vgaPatchDialogHeader },
- { 331, "moving to crusher", 1, PATCH_MAGICDWORD(0x51, 0x1f, 0x36, 0x39), 0, qfg1vgaSignatureMoveToCrusher, qfg1vgaPatchMoveToCrusher },
- { 41, "moving to castle gate", 1, PATCH_MAGICDWORD(0x51, 0x1f, 0x36, 0x39), 0, qfg1vgaSignatureMoveToCastleGate, qfg1vgaPatchMoveToCastleGate },
- { 210, "cheetaur description fixed", 1, PATCH_MAGICDWORD(0x34, 0xb8, 0x01, 0x1a), 0, qfg1vgaSignatureCheetaurDescription, qfg1vgaPatchCheetaurDescription },
- { 96, "funny room script bug fixed", 1, PATCH_MAGICDWORD(0x35, 0x01, 0xa3, 0x4e), -10, qfg1vgaSignatureFunnyRoomFix, qfg1vgaPatchFunnyRoomFix },
+// script, description, signature patch
+SciScriptPatcherEntry qfg1vgaSignatures[] = {
+ { 215, "fight event issue", 1, 0, 0, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
+ { 216, "weapon master event issue", 1, 0, 0, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
+ { 814, "window text temp space", 1, 0, 0, qfg1vgaSignatureTempSpace, qfg1vgaPatchTempSpace },
+ { 814, "dialog header offset", 3, 0, 0, qfg1vgaSignatureDialogHeader, qfg1vgaPatchDialogHeader },
+ { 331, "moving to crusher", 1, 0, 0, qfg1vgaSignatureMoveToCrusher, qfg1vgaPatchMoveToCrusher },
+ { 41, "moving to castle gate", 1, 0, 0, qfg1vgaSignatureMoveToCastleGate, qfg1vgaPatchMoveToCastleGate },
+ { 210, "cheetaur description fixed", 1, 0, 0, qfg1vgaSignatureCheetaurDescription, qfg1vgaPatchCheetaurDescription },
+ { 96, "funny room script bug fixed", 1, 0, 0, qfg1vgaSignatureFunnyRoomFix, qfg1vgaPatchFunnyRoomFix },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -1237,49 +1372,47 @@ const SciScriptSignature qfg1vgaSignatures[] = {
// and text entry refreshes whenever a button is pressed, and prevent possible
// crashes because of these constant quick object reallocations. Fixes bug
// #3037996.
-const byte qfg2SignatureImportDialog[] = {
- 16,
- 0x63, 0x20, // pToa text
- 0x30, 0x0b, 0x00, // bnt [next state]
- 0x7a, // push2
- 0x39, 0x03, // pushi 03
- 0x36, // push
- 0x43, 0x72, 0x04, // callk Memory 4
- 0x35, 0x00, // ldi 00
- 0x65, 0x20, // aTop text
- 0
+const uint16 qfg2SignatureImportDialog[] = {
+ 0x63, SIG_MAGICDWORD, 0x20, // pToa text
+ 0x30, SIG_UINT16 + 0x0b, 0x00, // bnt [next state]
+ 0x7a, // push2
+ 0x39, 0x03, // pushi 03
+ 0x36, // push
+ 0x43, 0x72, 0x04, // callk Memory 4
+ 0x35, 0x00, // ldi 00
+ 0x65, 0x20, // aTop text
+ SIG_END
};
const uint16 qfg2PatchImportDialog[] = {
- PATCH_ADDTOOFFSET | +5,
- 0x48, // ret
+ PATCH_ADDTOOFFSET +5,
+ 0x48, // ret
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature qfg2Signatures[] = {
- { 944, "import dialog continuous calls", 1, PATCH_MAGICDWORD(0x20, 0x30, 0x0b, 0x00), -1, qfg2SignatureImportDialog, qfg2PatchImportDialog },
+// script, description, signature patch
+SciScriptPatcherEntry qfg2Signatures[] = {
+ { 944, "import dialog continuous calls", 1, 0, 0, qfg2SignatureImportDialog, qfg2PatchImportDialog },
SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
// Patch for the import screen in QFG3, same as the one for QFG2 above
-const byte qfg3SignatureImportDialog[] = {
- 15,
- 0x63, 0x2a, // pToa text
- 0x31, 0x0b, // bnt [next state]
- 0x7a, // push2
- 0x39, 0x03, // pushi 03
- 0x36, // push
- 0x43, 0x72, 0x04, // callk Memory 4
- 0x35, 0x00, // ldi 00
- 0x65, 0x2a, // aTop text
- 0
+const uint16 qfg3SignatureImportDialog[] = {
+ 0x63, SIG_MAGICDWORD, 0x2a, // pToa text
+ 0x31, 0x0b, // bnt [next state]
+ 0x7a, // push2
+ 0x39, 0x03, // pushi 03
+ 0x36, // push
+ 0x43, 0x72, 0x04, // callk Memory 4
+ 0x35, 0x00, // ldi 00
+ 0x65, 0x2a, // aTop text
+ SIG_END
};
const uint16 qfg3PatchImportDialog[] = {
- PATCH_ADDTOOFFSET | +4,
- 0x48, // ret
+ PATCH_ADDTOOFFSET +4,
+ 0x48, // ret
PATCH_END
};
@@ -1298,38 +1431,39 @@ const uint16 qfg3PatchImportDialog[] = {
// hero::solvePuzzle (0xfffc) which does a ret afterwards without going to
// Teller::doChild. We jump to this call of hero::solvePuzzle to get that same
// behaviour.
-
-const byte qfg3SignatureWooDialog[] = {
- 30,
- 0x67, 0x12, // pTos 12 (query)
- 0x35, 0xb6, // ldi b6
- 0x1a, // eq?
- 0x2f, 0x05, // bt 05
- 0x67, 0x12, // pTos 12 (query)
- 0x35, 0x9b, // ldi 9b
- 0x1a, // eq?
- 0x31, 0x0c, // bnt 0c
- 0x38, 0x97, 0x02, // pushi 0297
- 0x7a, // push2
- 0x38, 0x0c, 0x01, // pushi 010c
- 0x7a, // push2
- 0x81, 0x00, // lag 00
- 0x4a, 0x08, // send 08
- 0x67, 0x12, // pTos 12 (query)
- 0x35, 0xb5, // ldi b5
- 0
+// Applies to at least: English, German, Italian, French, Spanish Floppy
+// Responsible method: unknown
+const uint16 qfg3SignatureWooDialog[] = {
+ SIG_MAGICDWORD,
+ 0x67, 0x12, // pTos 12 (query)
+ 0x35, 0xb6, // ldi b6
+ 0x1a, // eq?
+ 0x2f, 0x05, // bt 05
+ 0x67, 0x12, // pTos 12 (query)
+ 0x35, 0x9b, // ldi 9b
+ 0x1a, // eq?
+ 0x31, 0x0c, // bnt 0c
+ 0x38, SIG_SELECTOR16 + SELECTOR_solvePuzzle, // pushi 0297
+ 0x7a, // push2
+ 0x38, SIG_UINT16 + 0x0c, 0x01, // pushi 010c
+ 0x7a, // push2
+ 0x81, 0x00, // lag 00
+ 0x4a, 0x08, // send 08
+ 0x67, 0x12, // pTos 12 (query)
+ 0x35, 0xb5, // ldi b5
+ SIG_END
};
const uint16 qfg3PatchWooDialog[] = {
- PATCH_ADDTOOFFSET | +0x29,
- 0x33, 0x11, // jmp to 0x6a2, the call to hero::solvePuzzle for 0xFFFC
+ PATCH_ADDTOOFFSET +0x29,
+ 0x33, 0x11, // jmp to 0x6a2, the call to hero::solvePuzzle for 0xFFFC
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature qfg3Signatures[] = {
- { 944, "import dialog continuous calls", 1, PATCH_MAGICDWORD(0x2a, 0x31, 0x0b, 0x7a), -1, qfg3SignatureImportDialog, qfg3PatchImportDialog },
- { 440, "dialog crash when asking about Woo", 1, PATCH_MAGICDWORD(0x67, 0x12, 0x35, 0xb5), -26, qfg3SignatureWooDialog, qfg3PatchWooDialog },
+// script, description, signature patch
+SciScriptPatcherEntry qfg3Signatures[] = {
+ { 944, "import dialog continuous calls", 1, 0, 0, qfg3SignatureImportDialog, qfg3PatchImportDialog },
+ { 440, "dialog crash when asking about Woo", 1, 0, 0, qfg3SignatureWooDialog, qfg3PatchWooDialog },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -1340,30 +1474,19 @@ const SciScriptSignature qfg3Signatures[] = {
// we never reach that of course, so the pterodactyl-flight will go endlessly
// we could either calculate property count differently somehow fixing this
// but I think just patching it out is cleaner (bug #3037938)
-const byte sq4FloppySignatureEndlessFlight[] = {
- 8,
- 0x39, 0x04, // pushi 04 (selector x)
- 0x78, // push1
- 0x67, 0x08, // pTos 08 (property x)
- 0x63, 0x44, // pToa 44 (invalid property)
- 0x02, // add
- 0
-};
-
-// Similar to the above, for the German version (bug #3110215)
-const byte sq4FloppySignatureEndlessFlightGerman[] = {
- 8,
- 0x39, 0x04, // pushi 04 (selector x)
- 0x78, // push1
- 0x67, 0x08, // pTos 08 (property x)
- 0x63, 0x4c, // pToa 4c (invalid property)
- 0x02, // add
- 0
+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
+ 0x02, // add
+ SIG_END
};
const uint16 sq4FloppyPatchEndlessFlight[] = {
- PATCH_ADDTOOFFSET | +5,
- 0x35, 0x03, // ldi 03 (which would be the content of the property)
+ PATCH_ADDTOOFFSET +5,
+ 0x35, 0x03, // ldi 03 (which would be the content of the property)
PATCH_END
};
@@ -1373,40 +1496,40 @@ const uint16 sq4FloppyPatchEndlessFlight[] = {
// 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 byte sq4CdSignatureTextOptionsButton[] = {
- 11,
- 0x35, 0x01, // ldi 0x01
- 0xa1, 0x53, // sag 0x53
- 0x39, 0x03, // pushi 0x03
- 0x78, // push1
- 0x39, 0x09, // pushi 0x09
- 0x54, 0x06, // self 0x06
- 0
+const uint16 sq4CdSignatureTextOptionsButton[] = {
+ SIG_MAGICDWORD,
+ 0x35, 0x01, // ldi 0x01
+ 0xa1, 0x53, // sag 0x53
+ 0x39, 0x03, // pushi 0x03
+ 0x78, // push1
+ 0x39, 0x09, // pushi 0x09
+ 0x54, 0x06, // self 0x06
+ SIG_END
};
const uint16 sq4CdPatchTextOptionsButton[] = {
- PATCH_ADDTOOFFSET | +7,
- 0x39, 0x0b, // pushi 0x0b
+ PATCH_ADDTOOFFSET +7,
+ 0x39, 0x0b, // pushi 0x0b
PATCH_END
};
// 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 #3538418.
-const byte sq4CdSignatureBabbleIcon[] = {
- 7,
- 0x89, 0x5a, // lsg 5a
- 0x35, 0x02, // ldi 02
- 0x1a, // eq?
- 0x31, 0x26, // bnt 26 [02a7]
- 0
+const uint16 sq4CdSignatureBabbleIcon[] = {
+ SIG_MAGICDWORD,
+ 0x89, 0x5a, // lsg 5a
+ 0x35, 0x02, // ldi 02
+ 0x1a, // eq?
+ 0x31, 0x26, // bnt 26 [02a7]
+ SIG_END
};
const uint16 sq4CdPatchBabbleIcon[] = {
- 0x89, 0x5a, // lsg 5a
- 0x35, 0x01, // ldi 01
- 0x1a, // eq?
- 0x2f, 0x26, // bt 26 [02a7]
+ 0x89, 0x5a, // lsg 5a
+ 0x35, 0x01, // ldi 01
+ 0x1a, // eq?
+ 0x2f, 0x26, // bt 26 [02a7]
PATCH_END
};
@@ -1414,56 +1537,55 @@ 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 byte sq4CdSignatureTextOptions[] = {
- 32,
- 0x89, 0x5a, // lsg 0x5a (load global 90 to stack)
- 0x3c, // dup
- 0x35, 0x01, // ldi 0x01
- 0x1a, // eq? (global 90 == 1)
- 0x31, 0x06, // bnt 0x06 (0x0691)
- 0x35, 0x02, // ldi 0x02
- 0xa1, 0x5a, // sag 0x5a (save acc to global 90)
- 0x33, 0x0a, // jmp 0x0a (0x69b)
- 0x3c, // dup
- 0x35, 0x02, // ldi 0x02
- 0x1a, // eq? (global 90 == 2)
- 0x31, 0x04, // bnt 0x04 (0x069b)
- 0x35, 0x01, // ldi 0x01
- 0xa1, 0x5a, // sag 0x5a (save acc to global 90)
- 0x3a, // toss
- 0x38, 0xd9, 0x00, // pushi 0x00d9
- 0x76, // push0
- 0x54, 0x04, // self 0x04
- 0x48, // ret
- 0
+const uint16 sq4CdSignatureTextOptions[] = {
+ SIG_MAGICDWORD,
+ 0x89, 0x5a, // lsg 0x5a (load global 90 to stack)
+ 0x3c, // dup
+ 0x35, 0x01, // ldi 0x01
+ 0x1a, // eq? (global 90 == 1)
+ 0x31, 0x06, // bnt 0x06 (0x0691)
+ 0x35, 0x02, // ldi 0x02
+ 0xa1, 0x5a, // sag 0x5a (save acc to global 90)
+ 0x33, 0x0a, // jmp 0x0a (0x69b)
+ 0x3c, // dup
+ 0x35, 0x02, // ldi 0x02
+ 0x1a, // eq? (global 90 == 2)
+ 0x31, 0x04, // bnt 0x04 (0x069b)
+ 0x35, 0x01, // ldi 0x01
+ 0xa1, 0x5a, // sag 0x5a (save acc to global 90)
+ 0x3a, // toss
+ 0x38, SIG_SELECTOR16 + SELECTOR_show, // pushi 0x00d9
+ 0x76, // push0
+ 0x54, 0x04, // self 0x04
+ 0x48, // ret
+ SIG_END
};
const uint16 sq4CdPatchTextOptions[] = {
- 0x89, 0x5a, // lsg 0x5a (load global 90 to stack)
- 0x3c, // dup
- 0x35, 0x03, // ldi 0x03 (acc = 3)
- 0x1a, // eq? (global 90 == 3)
- 0x2f, 0x07, // bt 0x07
- 0x89, 0x5a, // lsg 0x5a (load global 90 to stack again)
- 0x35, 0x01, // ldi 0x01 (acc = 1)
- 0x02, // add: acc = global 90 (on stack) + 1 (previous acc value)
- 0x33, 0x02, // jmp 0x02
- 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, 0x00, 0x00, // ldi 0x0000 (waste 3 bytes)
- 0x3a, // toss
+ 0x89, 0x5a, // lsg 0x5a (load global 90 to stack)
+ 0x3c, // dup
+ 0x35, 0x03, // ldi 0x03 (acc = 3)
+ 0x1a, // eq? (global 90 == 3)
+ 0x2f, 0x07, // bt 0x07
+ 0x89, 0x5a, // lsg 0x5a (load global 90 to stack again)
+ 0x35, 0x01, // ldi 0x01 (acc = 1)
+ 0x02, // add: acc = global 90 (on stack) + 1 (previous acc value)
+ 0x33, 0x02, // jmp 0x02
+ 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)
+ 0x3a, // toss
// (the rest of the code is the same)
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature sq4Signatures[] = {
- { 298, "Floppy: endless flight", 1, PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x44), -3, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight },
- { 298, "Floppy (German): endless flight", 1, PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x4c), -3, sq4FloppySignatureEndlessFlightGerman, sq4FloppyPatchEndlessFlight },
- { 818, "CD: Speech and subtitles option", 1, PATCH_MAGICDWORD(0x89, 0x5a, 0x3c, 0x35), 0, sq4CdSignatureTextOptions, sq4CdPatchTextOptions },
- { 0, "CD: Babble icon speech and subtitles fix", 1, PATCH_MAGICDWORD(0x89, 0x5a, 0x35, 0x02), 0, sq4CdSignatureBabbleIcon, sq4CdPatchBabbleIcon },
- { 818, "CD: Speech and subtitles option button", 1, PATCH_MAGICDWORD(0x35, 0x01, 0xa1, 0x53), 0, sq4CdSignatureTextOptionsButton, sq4CdPatchTextOptionsButton },
+// script, description, signature patch
+SciScriptPatcherEntry sq4Signatures[] = {
+ { 298, "Floppy: endless flight", 1, 0, 0, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight },
+ { 818, "CD: Speech and subtitles option", 1, 0, 0, sq4CdSignatureTextOptions, sq4CdPatchTextOptions },
+ { 0, "CD: Babble icon speech and subtitles fix", 1, 0, 0, sq4CdSignatureBabbleIcon, sq4CdPatchBabbleIcon },
+ { 818, "CD: Speech and subtitles option button", 1, 0, 0, sq4CdSignatureTextOptionsButton, sq4CdPatchTextOptionsButton },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -1478,75 +1600,76 @@ const SciScriptSignature 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 byte sq1vgaSignatureUlenceFlatsTimepodGfxGlitch[] = {
- 8,
- 0x39, 0x07, // pushi 07 (ship::cel)
- 0x78, // push1
- 0x39, 0x0a, // pushi 0x0a (set ship::cel to 10)
- 0x38, 0xa0, 0x00, // pushi 0x00a0 (ship::setLoop)
- 0
+const uint16 sq1vgaSignatureUlenceFlatsTimepodGfxGlitch[] = {
+ 0x39,
+ SIG_MAGICDWORD, SIG_SELECTOR8 + SELECTOR_cel, // pushi "cel"
+ 0x78, // push1
+ 0x39, 0x0a, // pushi 0x0a (set ship::cel to 10)
+ 0x38, SIG_UINT16 + 0xa0, 0x00, // pushi 0x00a0 (ship::setLoop)
+ SIG_END
};
const uint16 sq1vgaPatchUlenceFlatsTimepodGfxGlitch[] = {
- PATCH_ADDTOOFFSET | +3,
- 0x39, 0x09, // pushi 0x09 (set ship::cel to 9)
+ PATCH_ADDTOOFFSET +3,
+ 0x39, 0x09, // pushi 0x09 (set ship::cel to 9)
PATCH_END
};
-const byte sq1vgaSignatureEgoShowsCard[] = {
- 25,
- 0x38, 0x46, 0x02, // push 0x246 (set up send frame to set timesShownID)
- 0x78, // push1
- 0x38, 0x46, 0x02, // push 0x246 (set up send frame to get timesShownID)
- 0x76, // push0
- 0x51, 0x7c, // class DeltaurRegion
- 0x4a, 0x04, // send 0x04 (get timesShownID)
- 0x36, // push
- 0x35, 0x01, // ldi 1
- 0x02, // add
- 0x36, // push
- 0x51, 0x7c, // class DeltaurRegion
- 0x4a, 0x06, // send 0x06 (set timesShownID)
- 0x36, // push (wrong, acc clobbered by class, above)
- 0x35, 0x03, // ldi 0x03
- 0x22, // lt?
- 0
+const uint16 sq1vgaSignatureEgoShowsCard[] = {
+ SIG_MAGICDWORD,
+ 0x38, SIG_SELECTOR16 + SELECTOR_timesShownID, // push "timesShownID"
+ 0x78, // push1
+ 0x38, SIG_SELECTOR16 + SELECTOR_timesShownID, // push "timesShownID"
+ 0x76, // push0
+ 0x51, 0x7c, // class DeltaurRegion
+ 0x4a, 0x04, // send 0x04 (get timesShownID)
+ 0x36, // push
+ 0x35, 0x01, // ldi 1
+ 0x02, // add
+ 0x36, // push
+ 0x51, 0x7c, // class DeltaurRegion
+ 0x4a, 0x06, // send 0x06 (set timesShownID)
+ 0x36, // push (wrong, acc clobbered by class, above)
+ 0x35, 0x03, // ldi 0x03
+ 0x22, // lt?
+ SIG_END
};
// Note that this script patch is merely a reordering of the
// instructions in the original script.
const uint16 sq1vgaPatchEgoShowsCard[] = {
- 0x38, 0x46, 0x02, // push 0x246 (set up send frame to get timesShownID)
- 0x76, // push0
- 0x51, 0x7c, // class DeltaurRegion
- 0x4a, 0x04, // send 0x04 (get timesShownID)
- 0x36, // push
- 0x35, 0x01, // ldi 1
- 0x02, // add
- 0x36, // push (this push corresponds to the wrong one above)
- 0x38, 0x46, 0x02, // push 0x246 (set up send frame to set timesShownID)
- 0x78, // push1
- 0x36, // push
- 0x51, 0x7c, // class DeltaurRegion
- 0x4a, 0x06, // send 0x06 (set timesShownID)
- 0x35, 0x03, // ldi 0x03
- 0x22, // lt?
+ 0x38, PATCH_SELECTOR16 + SELECTOR_timesShownID, // push "timesShownID"
+ 0x76, // push0
+ 0x51, 0x7c, // class DeltaurRegion
+ 0x4a, 0x04, // send 0x04 (get timesShownID)
+ 0x36, // push
+ 0x35, 0x01, // ldi 1
+ 0x02, // add
+ 0x36, // push (this push corresponds to the wrong one above)
+ 0x38, PATCH_SELECTOR16 + SELECTOR_timesShownID, // push "timesShownID"
+ 0x78, // push1
+ 0x36, // push
+ 0x51, 0x7c, // class DeltaurRegion
+ 0x4a, 0x06, // send 0x06 (set timesShownID)
+ 0x35, 0x03, // ldi 0x03
+ 0x22, // lt?
PATCH_END
};
-// script, description, magic DWORD, adjust
-const SciScriptSignature sq1vgaSignatures[] = {
- { 45, "Ulence Flats: timepod graphic glitch", 1, PATCH_MAGICDWORD( 0x07, 0x78, 0x39, 0x0a ), -1, sq1vgaSignatureUlenceFlatsTimepodGfxGlitch, sq1vgaPatchUlenceFlatsTimepodGfxGlitch },
- { 58, "Sarien armory droid zapping ego first time", 1, PATCH_MAGICDWORD( 0x72, 0x88, 0x15, 0x36 ), -70, sq1vgaSignatureEgoShowsCard, sq1vgaPatchEgoShowsCard },
-
+// script, description, signature patch
+SciScriptPatcherEntry sq1vgaSignatures[] = {
+ { 45, "Ulence Flats: timepod graphic glitch", 1, 0, 0, sq1vgaSignatureUlenceFlatsTimepodGfxGlitch, sq1vgaPatchUlenceFlatsTimepodGfxGlitch },
+ { 58, "Sarien armory droid zapping ego first time", 1, 0, 0, sq1vgaSignatureEgoShowsCard, sq1vgaPatchEgoShowsCard },
SCI_SIGNATUREENTRY_TERMINATOR};
// will actually patch previously found signature area
-void Script::applyPatch(const uint16 *patch, byte *scriptData, const uint32 scriptSize, int32 signatureOffset) {
+void Script::patcherApplyPatch(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;
- uint16 patchWord = *patch;
+ uint16 patchWord = *patchEntry->patchData;
+ uint16 patchSelector = 0;
// Copy over original bytes from script
uint32 orgDataSize = scriptSize - offset;
@@ -1555,74 +1678,179 @@ void Script::applyPatch(const uint16 *patch, byte *scriptData, const uint32 scri
memcpy(&orgData, &scriptData[offset], orgDataSize);
while (patchWord != PATCH_END) {
+ uint16 patchCommand = patchWord & PATCH_COMMANDMASK;
uint16 patchValue = patchWord & PATCH_VALUEMASK;
- switch (patchWord & PATCH_COMMANDMASK) {
- case PATCH_ADDTOOFFSET:
+ switch (patchCommand) {
+ case PATCH_ADDTOOFFSET: {
// add value to offset
- offset += patchValue & ~PATCH_ADDTOOFFSET;
+ offset += patchValue;
break;
- case PATCH_GETORIGINALBYTE:
+ }
+ case PATCH_GETORIGINALBYTE: {
// get original byte from script
if (patchValue >= orgDataSize)
- error("patching: can not get requested original byte from script");
+ error("Script-Patcher: can not get requested original byte from script");
scriptData[offset] = orgData[patchValue];
offset++;
break;
- case PATCH_ADJUSTWORD: {
- // Adjust word right before current position
- byte *adjustPtr = &scriptData[offset - 2];
- uint16 adjustWord = READ_LE_UINT16(adjustPtr);
- adjustWord += patchValue;
- WRITE_LE_UINT16(adjustPtr, adjustWord);
+ }
+ case PATCH_GETORIGINALBYTEADJUST: {
+ // get original byte from script and adjust it
+ if (patchValue >= orgDataSize)
+ error("Script-Patcher: can not get requested original byte from script");
+ byte orgByte = orgData[patchValue];
+ int16 adjustValue;
+ patchData++; adjustValue = (int16)(*patchData);
+ scriptData[offset] = orgByte + adjustValue;
+ offset++;
+ break;
+ }
+ case PATCH_UINT16:
+ case PATCH_SELECTOR16: {
+ byte byte1;
+ byte byte2;
+
+ switch (patchCommand) {
+ case PATCH_UINT16: {
+ byte1 = patchValue & PATCH_BYTEMASK;
+ patchData++; patchWord = *patchData;
+ if (patchWord & PATCH_COMMANDMASK)
+ error("Script-Patcher: Patch inconsistent");
+ byte2 = patchWord & PATCH_BYTEMASK;
+ break;
+ }
+ case PATCH_SELECTOR16: {
+ patchSelector = selectorTable[patchValue].id;
+ byte1 = patchSelector & 0xFF;
+ byte2 = patchSelector >> 8;
+ break;
+ }
+ default:
+ byte1 = 0; byte2 = 0;
+ }
+ if (!isMacSci11) {
+ scriptData[offset++] = byte1;
+ scriptData[offset++] = byte2;
+ } else {
+ // SCI1.1+ on macintosh had uint16s in script in BE-order
+ scriptData[offset++] = byte2;
+ scriptData[offset++] = byte1;
+ }
break;
}
- case PATCH_ADJUSTWORD_NEG: {
- // Adjust word right before current position (negative way)
- byte *adjustPtr = &scriptData[offset - 2];
- uint16 adjustWord = READ_LE_UINT16(adjustPtr);
- adjustWord -= patchValue;
- WRITE_LE_UINT16(adjustPtr, adjustWord);
+ case PATCH_SELECTOR8: {
+ patchSelector = selectorTable[patchValue].id;
+ if (patchSelector & 0xFF00)
+ error("Script-Patcher: 8 bit selector required, game uses 16 bit selector");
+ scriptData[offset] = patchSelector & 0xFF;
+ offset++;
break;
}
- default:
- scriptData[offset] = patchValue & 0xFF;
+ case PATCH_BYTE:
+ scriptData[offset] = patchValue & PATCH_BYTEMASK;
offset++;
}
- patch++;
- patchWord = *patch;
+ patchData++;
+ patchWord = *patchData;
}
}
// will return -1 if no match was found, otherwise an offset to the start of the signature match
-int32 Script::findSignature(const SciScriptSignature *signature, const byte *scriptData, const uint32 scriptSize) {
+int32 Script::patcherFindSignature(const SciScriptPatcherEntry *patchEntry, 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 = signature->magicDWord; // is platform-specific BE/LE form, so that the later match will work
+ const uint32 magicDWord = patchEntry->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 + signature->magicOffset;
+ uint32 offset = DWordOffset + patchEntry->magicOffset;
uint32 byteOffset = offset;
- const byte *signatureData = signature->data;
- byte matchAdjust = 1;
- while (matchAdjust) {
- byte matchBytesCount = *signatureData++;
- if ((byteOffset + matchBytesCount) > scriptSize) // Out-Of-Bounds?
+ const uint16 *signatureData = patchEntry->signatureData;
+ uint16 sigSelector = 0;
+
+ uint16 sigWord = *signatureData;
+ while (sigWord != SIG_END) {
+ uint16 sigCommand = sigWord & SIG_COMMANDMASK;
+ uint16 sigValue = sigWord & SIG_VALUEMASK;
+ switch (sigCommand) {
+ case SIG_ADDTOOFFSET: {
+ // add value to offset
+ byteOffset += sigValue;
+ break;
+ }
+ case SIG_UINT16:
+ case SIG_SELECTOR16: {
+ if ((byteOffset + 1) < scriptSize) {
+ byte byte1;
+ byte byte2;
+
+ switch (sigCommand) {
+ case SIG_UINT16: {
+ byte1 = sigValue & SIG_BYTEMASK;
+ signatureData++; sigWord = *signatureData;
+ if (sigWord & SIG_COMMANDMASK)
+ error("Script-Patcher: signature inconsistent\nFaulty patch: '%s'", patchEntry->description);
+ byte2 = sigWord & SIG_BYTEMASK;
+ break;
+ }
+ case SIG_SELECTOR16: {
+ sigSelector = selectorTable[sigValue].id;
+ byte1 = sigSelector & 0xFF;
+ byte2 = sigSelector >> 8;
+ break;
+ }
+ default:
+ byte1 = 0; byte2 = 0;
+ }
+ if (!isMacSci11) {
+ if ((scriptData[byteOffset] != byte1) || (scriptData[byteOffset + 1] != byte2))
+ sigWord = SIG_MISMATCH;
+ } else {
+ // SCI1.1+ on macintosh had uint16s in script in BE-order
+ if ((scriptData[byteOffset] != byte2) || (scriptData[byteOffset + 1] != byte1))
+ sigWord = SIG_MISMATCH;
+ }
+ byteOffset += 2;
+ } else {
+ sigWord = SIG_MISMATCH;
+ }
break;
- if (memcmp(signatureData, &scriptData[byteOffset], matchBytesCount)) // Byte-Mismatch?
+ }
+ case SIG_SELECTOR8: {
+ if (byteOffset < scriptSize) {
+ sigSelector = selectorTable[sigValue].id;
+ 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))
+ sigWord = SIG_MISMATCH;
+ byteOffset++;
+ } else {
+ sigWord = SIG_MISMATCH; // out of bounds
+ }
+ break;
+ }
+ case SIG_BYTE:
+ if (byteOffset < scriptSize) {
+ if (scriptData[byteOffset] != sigWord)
+ sigWord = SIG_MISMATCH;
+ byteOffset++;
+ } else {
+ sigWord = SIG_MISMATCH; // out of bounds
+ }
+ }
+
+ if (sigWord == SIG_MISMATCH)
break;
- // those bytes matched, adjust offsets accordingly
- signatureData += matchBytesCount;
- byteOffset += matchBytesCount;
- // get offset...
- matchAdjust = *signatureData++;
- byteOffset += matchAdjust;
+
+ signatureData++;
+ sigWord = *signatureData;
}
- if (!matchAdjust) // all matches worked?
+
+ if (sigWord == SIG_END) // signature fully matched?
return offset;
}
DWordOffset++;
@@ -1631,8 +1859,139 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr
return -1;
}
-void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
- const SciScriptSignature *signatureTable = NULL;
+// 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;
+ 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) {
+ // process signature
+ memset(magicDWord, 0, sizeof(magicDWord));
+
+ 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) {
+ curCommand = curWord & SIG_COMMANDMASK;
+ curValue = curWord & SIG_VALUEMASK;
+ switch (curCommand) {
+ case SIG_MAGICDWORD: {
+ if (step == 0) {
+ if ((curEntry->magicDWord) || (magicDWordLeft))
+ error("Script-Patcher: Magic-DWORD specified multiple times in signature\nFaulty patch: '%s'", curEntry->description);
+ magicDWordLeft = 4;
+ curEntry->magicOffset = magicOffset;
+ }
+ break;
+ }
+ case SIG_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: {
+ // UINT16 or 1
+ switch (curCommand) {
+ case SIG_UINT16: {
+ curData++; curWord = *curData;
+ if (curWord & SIG_COMMANDMASK)
+ error("Script-Patcher: signature entry inconsistent\nFaulty patch: '%s'", curEntry->description);
+ if (!isMacSci11) {
+ byte1 = curValue;
+ byte2 = curWord & SIG_BYTEMASK;
+ } else {
+ byte1 = curWord & SIG_BYTEMASK;
+ byte2 = curValue;
+ }
+ break;
+ }
+ case SIG_SELECTOR16: {
+ curSelector = &selectorTable[curValue];
+ if (curSelector->id == -1)
+ curSelector->id = g_sci->getKernel()->findSelector(curSelector->name);
+ if (!isMacSci11) {
+ byte1 = curSelector->id & 0x00FF;
+ byte2 = curSelector->id >> 8;
+ } else {
+ byte1 = curSelector->id >> 8;
+ byte2 = curSelector->id & 0x00FF;
+ }
+ break;
+ }
+ }
+ magicOffset -= 2;
+ if (magicDWordLeft) {
+ // Remember current word for Magic DWORD
+ magicDWord[4 - magicDWordLeft] = byte1;
+ magicDWordLeft--;
+ if (magicDWordLeft) {
+ magicDWord[4 - magicDWordLeft] = byte2;
+ magicDWordLeft--;
+ }
+ if (!magicDWordLeft) {
+ curEntry->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)
+ error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty patch: '%s'", curEntry->description);
+ }
+ }
+ curValue = curSelector->id;
+ }
+ magicOffset--;
+ if (magicDWordLeft) {
+ // Remember current byte for Magic DWORD
+ magicDWord[4 - magicDWordLeft] = (byte)curValue;
+ magicDWordLeft--;
+ if (!magicDWordLeft) {
+ curEntry->magicDWord = READ_LE_UINT32(magicDWord);
+ }
+ }
+ }
+ }
+ curData++;
+ curWord = *curData;
+ }
+ }
+ if (magicDWordLeft)
+ error("Script-Patcher: Magic-DWORD beyond End-Of-Signature\nFaulty patch: '%s'", curEntry->description);
+ if (!curEntry->magicDWord)
+ error("Script-Patcher: Magic-DWORD not specified in signature\nFaulty patch: '%s'", curEntry->description);
+
+ curEntry++;
+ }
+}
+
+void Script::patcherProcessScript(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
+ SciScriptPatcherEntry *signatureTable = NULL;
+
switch (g_sci->getGameId()) {
case GID_CAMELOT:
signatureTable = camelotSignatures;
@@ -1700,16 +2059,23 @@ void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uin
}
if (signatureTable) {
- while (signatureTable->data) {
+ bool isMacSci11 = (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1);
+
+ if (!signatureTable->magicDWord) {
+ // signature table needs to get initialized (Magic DWORD set, selector table set)
+ patcherInitSignature(signatureTable, isMacSci11);
+ }
+
+ while (signatureTable->signatureData) {
if (scriptNr == signatureTable->scriptNr) {
int32 foundOffset = 0;
int16 applyCount = signatureTable->applyCount;
do {
- foundOffset = findSignature(signatureTable, scriptData, scriptSize);
+ foundOffset = patcherFindSignature(signatureTable, scriptData, scriptSize, isMacSci11);
if (foundOffset != -1) {
// found, so apply the patch
- debugC(kDebugLevelScripts, "matched and patched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset);
- applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset);
+ debugC(kDebugLevelScriptPatcher, "Script-Patcher: '%s' on script %d offset %d", signatureTable->description, scriptNr, foundOffset);
+ patcherApplyPatch(signatureTable, scriptData, scriptSize, foundOffset, isMacSci11);
}
applyCount--;
} while ((foundOffset != -1) && (applyCount));