aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorFilippos Karapetis2010-08-06 22:36:46 +0000
committerFilippos Karapetis2010-08-06 22:36:46 +0000
commit57fd5883277b258eba73bfec98a27503223569ff (patch)
tree20ac126b84b802720a627a77b5e850f4e67c943d /engines
parentdfe4c8d9a079c01d4a6cfdf5290da2a0af941c8a (diff)
downloadscummvm-rg350-57fd5883277b258eba73bfec98a27503223569ff.tar.gz
scummvm-rg350-57fd5883277b258eba73bfec98a27503223569ff.tar.bz2
scummvm-rg350-57fd5883277b258eba73bfec98a27503223569ff.zip
SCI: Split the new script patch code in a separate file
svn-id: r51810
Diffstat (limited to 'engines')
-rw-r--r--engines/sci/engine/script.cpp205
-rw-r--r--engines/sci/engine/script.h10
-rw-r--r--engines/sci/engine/script_patches.cpp247
-rw-r--r--engines/sci/module.mk1
4 files changed, 249 insertions, 214 deletions
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 07e0982076..3ba550adf9 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -113,211 +113,6 @@ void Script::init(int script_nr, ResourceManager *resMan) {
}
}
-// 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
-
-
-// this here gets called on entry and when going out of game windows
-// uEvt::port will not get changed after kDisposeWindow but a bit later, so
-// we would get an invalid port handle to a kSetPort call. We just patch in
-// resetting of the port selector. We destroy the stop/fade code in there,
-// it seems it isn't used at all in the game.
-const byte hoyle4SignaturePortFix[] = {
- 28,
- 0x39, 0x09, // pushi 09
- 0x89, 0x0b, // lsg 0b
- 0x39, 0x64, // pushi 64
- 0x38, 0xc8, 0x00, // pushi 00c8
- 0x38, 0x2c, 0x01, // pushi 012c
- 0x38, 0x90, 0x01, // pushi 0190
- 0x38, 0xf4, 0x01, // pushi 01f4
- 0x38, 0x58, 0x02, // pushi 0258
- 0x38, 0xbc, 0x02, // pushi 02bc
- 0x38, 0x20, 0x03, // pushi 0320
- 0x46, // calle [xxxx] [xxxx] [xx]
- +5, 43, // [skip 5 bytes]
- 0x30, 0x27, 0x00, // bnt 0027 -> end of routine
- 0x87, 0x00, // lap 00
- 0x30, 0x19, 0x00, // bnt 0019 -> fade out
- 0x87, 0x01, // lap 01
- 0x30, 0x14, 0x00, // bnt 0014 -> fade out
- 0x38, 0xa7, 0x00, // pushi 00a7
- 0x76, // push0
- 0x80, 0x29, 0x01, // lag 0129
- 0x4a, 0x04, // send 04 (song::stop)
- 0x39, 0x27, // pushi 27
- 0x78, // push1
- 0x8f, 0x01, // lsp 01
- 0x51, 0x54, // class 54
- 0x4a, 0x06, // send 06 (PlaySong::play)
- 0x33, 0x09, // jmp 09 -> end of routine
- 0x38, 0xaa, 0x00, // pushi 00aa
- 0x76, // push0
- 0x80, 0x29, 0x01, // lag 0129
- 0x4a, 0x04, // send 04
- 0x48, // ret
- 0
-};
-
-#define PATCH_END 0xFFFF
-#define PATCH_ADDTOOFFSET 0x8000
-#define PATCH_GETORIGINALBYTE 0x4000
-
-const uint16 hoyle4PatchPortFix[] = {
- PATCH_ADDTOOFFSET | +33,
- 0x38, 0x31, 0x01, // pushi 0131 (selector curEvent)
- 0x76, // push0
- 0x80, 0x50, 0x00, // lag 0050 (global var 80h, "User")
- 0x4a, 0x04, // send 04 (read User::curEvent)
-
- 0x38, 0x93, 0x00, // pushi 0093 (selector port)
- 0x78, // push1
- 0x76, // push0
- 0x4a, 0x06, // send 06 (write 0 to that object::port)
- 0x48, // ret
- PATCH_END
-};
-
-// script, description, magic DWORD, adjust
-const SciScriptSignature hoyle4Signatures[] = {
- { 0, "port fix when disposing windows", CONSTANT_LE_32(0x00C83864), -5, hoyle4SignaturePortFix, hoyle4PatchPortFix },
- { 0, NULL, 0, 0, NULL, NULL }
-};
-
-
-// this is called on every death dialog. Problem is at least the german
-// version of lsl6 gets title text that is far too long for the
-// available temp space resulting in temp space corruption
-// This patch moves the title text around, so this overflow
-// doesn't happen anymore. We would otherwise get a crash
-// calling for invalid views (this happens of course also
-// in sierra sci)
-const byte larry6SignatureDeathDialog[] = {
- 7,
- 0x3e, 0x33, 0x01, // link 0133 (offset 0x20)
- 0x35, 0xff, // ldi ff
- 0xa3, 0x00, // sal 00
- +255, 0,
- +255, 0,
- +170, 12, // [skip 680 bytes]
- 0x8f, 0x01, // lsp 01 (offset 0x2cf)
- 0x7a, // push2
- 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e
- 0x36, // push
- 0x43, 0x7c, 0x0e, // kMessage[7c] 0e
- +90, 10, // [skip 90 bytes]
- 0x38, 0xd6, 0x00, // pushi 00d6 (offset 0x335)
- 0x78, // push1
- 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e
- 0x36, // push
- +76, 11, // [skip 76 bytes]
- 0x38, 0xcd, 0x00, // pushi 00cd (offset 0x38b)
- 0x39, 0x03, // pushi 03
- 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e
- 0x36,
- 0
-};
-
-const uint16 larry6PatchDeathDialog[] = {
- 0x3e, 0x00, 0x02, // link 0200
- PATCH_ADDTOOFFSET | +687,
- 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140
- PATCH_ADDTOOFFSET | +98,
- 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140
- PATCH_ADDTOOFFSET | +82,
- 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140
- PATCH_END
-};
-
-// script, description, magic DWORD, adjust
-const SciScriptSignature larry6Signatures[] = {
- { 82, "death dialog memory corruption", CONSTANT_LE_32(0x3501333e), 0, larry6SignatureDeathDialog, larry6PatchDeathDialog },
- { 0, NULL, 0, 0, NULL, NULL }
-};
-
-// will actually patch previously found signature area
-void Script::applyPatch(const uint16 *patch, byte *scriptData, const uint32 scriptSize, int32 signatureOffset) {
- int32 offset = signatureOffset;
- uint16 patchWord = *patch;
-
- while (patchWord != PATCH_END) {
- if (patchWord & PATCH_ADDTOOFFSET) {
- offset += patchWord & ~PATCH_ADDTOOFFSET;
- } else if (patchWord & PATCH_GETORIGINALBYTE) {
- // TODO: implement this
- } else {
- scriptData[offset] = patchWord & 0xFF;
- offset++;
- }
- patch++;
- patchWord = *patch;
- }
-}
-
-// 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) {
- 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 searchLimit = scriptSize - 3;
- uint32 DWordOffset = 0;
- // first search for the magic DWORD
- while (DWordOffset < searchLimit) {
- if (magicDWord == *(const uint32 *)(scriptData + DWordOffset)) {
- // magic DWORD found, check if actual signature matches
- uint32 offset = DWordOffset + signature->magicOffset;
- uint32 byteOffset = offset;
- const byte *signatureData = signature->data;
- byte matchAdjust = 1;
- while (matchAdjust) {
- byte matchBytesCount = *signatureData++;
- if ((byteOffset + matchBytesCount) > scriptSize) // Out-Of-Bounds?
- break;
- if (memcmp(signatureData, &scriptData[byteOffset], matchBytesCount)) // Byte-Mismatch?
- break;
- // those bytes matched, adjust offsets accordingly
- signatureData += matchBytesCount;
- byteOffset += matchBytesCount;
- // get offset...
- matchAdjust = *signatureData++;
- byteOffset += matchAdjust;
- }
- if (!matchAdjust) // all matches worked?
- return offset;
- }
- DWordOffset++;
- }
- // nothing found
- return -1;
-}
-
-void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
- const SciScriptSignature *signatureTable = NULL;
- if (g_sci->getGameId() == GID_HOYLE4)
- signatureTable = hoyle4Signatures;
- if (g_sci->getGameId() == GID_LSL6)
- signatureTable = larry6Signatures;
-
- if (signatureTable) {
- while (signatureTable->data) {
- if (scriptNr == signatureTable->scriptNr) {
- int32 foundOffset = findSignature(signatureTable, scriptData, scriptSize);
- if (foundOffset != -1) {
- // found, so apply the patch
- warning("matched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset);
- applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset);
- }
- }
- signatureTable++;
- }
- }
-}
-
void Script::load(ResourceManager *resMan) {
Resource *script = resMan->findResource(ResourceId(kResourceTypeScript, _nr), 0);
assert(script != 0);
diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h
index 35daf20191..c60cc4b19f 100644
--- a/engines/sci/engine/script.h
+++ b/engines/sci/engine/script.h
@@ -31,17 +31,9 @@
namespace Sci {
-struct SciScriptSignature {
- uint16 scriptNr;
- const char *description;
- uint32 magicDWord;
- int magicOffset;
- const byte *data;
- const uint16 *patch;
-};
-
struct EngineState;
class ResourceManager;
+struct SciScriptSignature;
enum ScriptObjectTypes {
SCI_OBJ_TERMINATOR,
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
new file mode 100644
index 0000000000..228bf39e7d
--- /dev/null
+++ b/engines/sci/engine/script_patches.cpp
@@ -0,0 +1,247 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "sci/sci.h"
+#include "sci/engine/script.h"
+
+#include "common/util.h"
+
+namespace Sci {
+
+struct SciScriptSignature {
+ uint16 scriptNr;
+ const char *description;
+ uint32 magicDWord;
+ int magicOffset;
+ const byte *data;
+ const uint16 *patch;
+};
+
+// 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
+
+
+// this here gets called on entry and when going out of game windows
+// uEvt::port will not get changed after kDisposeWindow but a bit later, so
+// we would get an invalid port handle to a kSetPort call. We just patch in
+// resetting of the port selector. We destroy the stop/fade code in there,
+// it seems it isn't used at all in the game.
+const byte hoyle4SignaturePortFix[] = {
+ 28,
+ 0x39, 0x09, // pushi 09
+ 0x89, 0x0b, // lsg 0b
+ 0x39, 0x64, // pushi 64
+ 0x38, 0xc8, 0x00, // pushi 00c8
+ 0x38, 0x2c, 0x01, // pushi 012c
+ 0x38, 0x90, 0x01, // pushi 0190
+ 0x38, 0xf4, 0x01, // pushi 01f4
+ 0x38, 0x58, 0x02, // pushi 0258
+ 0x38, 0xbc, 0x02, // pushi 02bc
+ 0x38, 0x20, 0x03, // pushi 0320
+ 0x46, // calle [xxxx] [xxxx] [xx]
+ +5, 43, // [skip 5 bytes]
+ 0x30, 0x27, 0x00, // bnt 0027 -> end of routine
+ 0x87, 0x00, // lap 00
+ 0x30, 0x19, 0x00, // bnt 0019 -> fade out
+ 0x87, 0x01, // lap 01
+ 0x30, 0x14, 0x00, // bnt 0014 -> fade out
+ 0x38, 0xa7, 0x00, // pushi 00a7
+ 0x76, // push0
+ 0x80, 0x29, 0x01, // lag 0129
+ 0x4a, 0x04, // send 04 (song::stop)
+ 0x39, 0x27, // pushi 27
+ 0x78, // push1
+ 0x8f, 0x01, // lsp 01
+ 0x51, 0x54, // class 54
+ 0x4a, 0x06, // send 06 (PlaySong::play)
+ 0x33, 0x09, // jmp 09 -> end of routine
+ 0x38, 0xaa, 0x00, // pushi 00aa
+ 0x76, // push0
+ 0x80, 0x29, 0x01, // lag 0129
+ 0x4a, 0x04, // send 04
+ 0x48, // ret
+ 0
+};
+
+#define PATCH_END 0xFFFF
+#define PATCH_ADDTOOFFSET 0x8000
+#define PATCH_GETORIGINALBYTE 0x4000
+
+const uint16 hoyle4PatchPortFix[] = {
+ PATCH_ADDTOOFFSET | +33,
+ 0x38, 0x31, 0x01, // pushi 0131 (selector curEvent)
+ 0x76, // push0
+ 0x80, 0x50, 0x00, // lag 0050 (global var 80h, "User")
+ 0x4a, 0x04, // send 04 (read User::curEvent)
+
+ 0x38, 0x93, 0x00, // pushi 0093 (selector port)
+ 0x78, // push1
+ 0x76, // push0
+ 0x4a, 0x06, // send 06 (write 0 to that object::port)
+ 0x48, // ret
+ PATCH_END
+};
+
+// script, description, magic DWORD, adjust
+const SciScriptSignature hoyle4Signatures[] = {
+ { 0, "port fix when disposing windows", CONSTANT_LE_32(0x00C83864), -5, hoyle4SignaturePortFix, hoyle4PatchPortFix },
+ { 0, NULL, 0, 0, NULL, NULL }
+};
+
+
+// this is called on every death dialog. Problem is at least the german
+// version of lsl6 gets title text that is far too long for the
+// available temp space resulting in temp space corruption
+// This patch moves the title text around, so this overflow
+// doesn't happen anymore. We would otherwise get a crash
+// calling for invalid views (this happens of course also
+// in sierra sci)
+const byte larry6SignatureDeathDialog[] = {
+ 7,
+ 0x3e, 0x33, 0x01, // link 0133 (offset 0x20)
+ 0x35, 0xff, // ldi ff
+ 0xa3, 0x00, // sal 00
+ +255, 0,
+ +255, 0,
+ +170, 12, // [skip 680 bytes]
+ 0x8f, 0x01, // lsp 01 (offset 0x2cf)
+ 0x7a, // push2
+ 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e
+ 0x36, // push
+ 0x43, 0x7c, 0x0e, // kMessage[7c] 0e
+ +90, 10, // [skip 90 bytes]
+ 0x38, 0xd6, 0x00, // pushi 00d6 (offset 0x335)
+ 0x78, // push1
+ 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e
+ 0x36, // push
+ +76, 11, // [skip 76 bytes]
+ 0x38, 0xcd, 0x00, // pushi 00cd (offset 0x38b)
+ 0x39, 0x03, // pushi 03
+ 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e
+ 0x36,
+ 0
+};
+
+const uint16 larry6PatchDeathDialog[] = {
+ 0x3e, 0x00, 0x02, // link 0200
+ PATCH_ADDTOOFFSET | +687,
+ 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140
+ PATCH_ADDTOOFFSET | +98,
+ 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140
+ PATCH_ADDTOOFFSET | +82,
+ 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140
+ PATCH_END
+};
+
+// script, description, magic DWORD, adjust
+const SciScriptSignature larry6Signatures[] = {
+ { 82, "death dialog memory corruption", CONSTANT_LE_32(0x3501333e), 0, larry6SignatureDeathDialog, larry6PatchDeathDialog },
+ { 0, NULL, 0, 0, NULL, NULL }
+};
+
+// will actually patch previously found signature area
+void Script::applyPatch(const uint16 *patch, byte *scriptData, const uint32 scriptSize, int32 signatureOffset) {
+ int32 offset = signatureOffset;
+ uint16 patchWord = *patch;
+
+ while (patchWord != PATCH_END) {
+ if (patchWord & PATCH_ADDTOOFFSET) {
+ offset += patchWord & ~PATCH_ADDTOOFFSET;
+ } else if (patchWord & PATCH_GETORIGINALBYTE) {
+ // TODO: implement this
+ } else {
+ scriptData[offset] = patchWord & 0xFF;
+ offset++;
+ }
+ patch++;
+ patchWord = *patch;
+ }
+}
+
+// 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) {
+ 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 searchLimit = scriptSize - 3;
+ uint32 DWordOffset = 0;
+ // first search for the magic DWORD
+ while (DWordOffset < searchLimit) {
+ if (magicDWord == *(const uint32 *)(scriptData + DWordOffset)) {
+ // magic DWORD found, check if actual signature matches
+ uint32 offset = DWordOffset + signature->magicOffset;
+ uint32 byteOffset = offset;
+ const byte *signatureData = signature->data;
+ byte matchAdjust = 1;
+ while (matchAdjust) {
+ byte matchBytesCount = *signatureData++;
+ if ((byteOffset + matchBytesCount) > scriptSize) // Out-Of-Bounds?
+ break;
+ if (memcmp(signatureData, &scriptData[byteOffset], matchBytesCount)) // Byte-Mismatch?
+ break;
+ // those bytes matched, adjust offsets accordingly
+ signatureData += matchBytesCount;
+ byteOffset += matchBytesCount;
+ // get offset...
+ matchAdjust = *signatureData++;
+ byteOffset += matchAdjust;
+ }
+ if (!matchAdjust) // all matches worked?
+ return offset;
+ }
+ DWordOffset++;
+ }
+ // nothing found
+ return -1;
+}
+
+void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
+ const SciScriptSignature *signatureTable = NULL;
+ if (g_sci->getGameId() == GID_HOYLE4)
+ signatureTable = hoyle4Signatures;
+ if (g_sci->getGameId() == GID_LSL6)
+ signatureTable = larry6Signatures;
+
+ if (signatureTable) {
+ while (signatureTable->data) {
+ if (scriptNr == signatureTable->scriptNr) {
+ int32 foundOffset = findSignature(signatureTable, scriptData, scriptSize);
+ if (foundOffset != -1) {
+ // found, so apply the patch
+ warning("matched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset);
+ applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset);
+ }
+ }
+ signatureTable++;
+ }
+ }
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index dae2807cc2..7107b722f9 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -30,6 +30,7 @@ MODULE_OBJS := \
engine/savegame.o \
engine/script.o \
engine/scriptdebug.o \
+ engine/script_patches.o \
engine/selector.o \
engine/seg_manager.o \
engine/segment.o \