aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Snover2017-01-10 12:33:21 -0600
committerColin Snover2017-01-16 12:16:12 -0600
commit0744dc4109acd6ca433d3da492b9a1f02bd38a81 (patch)
treebe6672e5a2ebbf5ec920d463ceca7369ebe9cc09
parent60867811ccc6d0b7d0e5dbb4ad92883a9a59657c (diff)
downloadscummvm-rg350-0744dc4109acd6ca433d3da492b9a1f02bd38a81.tar.gz
scummvm-rg350-0744dc4109acd6ca433d3da492b9a1f02bd38a81.tar.bz2
scummvm-rg350-0744dc4109acd6ca433d3da492b9a1f02bd38a81.zip
SCI32: Fix spinloop in Hoyle5
Hoyle5 will spin on kGetTime between 15 and 300 ticks in multiple game scripts in order to delay execution (for example, after choosing opponents and clicking "okay"). This causes ScummVM to be unresponsive and wastes CPU time. This commit patches the spin subroutines to instead call a kernel function (kWait) that waits without a spin loop. This kernel function was removed in SCI2, and has been added back in ScummVM specifically for Hoyle5, so this patch will not work with the original interpreter.
-rw-r--r--engines/sci/engine/kernel.cpp5
-rw-r--r--engines/sci/engine/kernel_tables.h2
-rw-r--r--engines/sci/engine/script_patches.cpp40
3 files changed, 46 insertions, 1 deletions
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 1845ecaac5..c7732c6b15 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -905,6 +905,11 @@ void Kernel::loadKernelNames(GameFeatures *features) {
} else {
// Normal SCI2.1 kernel table
_kernelNames = Common::StringArray(sci21_default_knames, kKernelEntriesSci21);
+
+ // Used by script patcher to remove CPU spinning on kGetTime
+ if (g_sci->getGameId() == GID_HOYLE5) {
+ _kernelNames[0x4f] = "Wait";
+ }
}
break;
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index ac4987e603..741f46e02c 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -1408,7 +1408,7 @@ static const char *const sci21_default_knames[] = {
/*0x4c*/ "ScrollWindow", // Dummy in SCI3
/*0x4d*/ "Dummy",
/*0x4e*/ "Dummy",
- /*0x4f*/ "Dummy",
+ /*0x4f*/ "Dummy", // Replaced with kWait for Hoyle5 in ScummVM
/*0x50*/ "GetEvent",
/*0x51*/ "GlobalToLocal",
/*0x52*/ "LocalToGlobal",
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index b2d66d0170..968d72747a 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -699,6 +699,43 @@ static const SciScriptPatcherEntry freddypharkasSignatures[] = {
#ifdef ENABLE_SCI32
#pragma mark -
+#pragma mark Hoyle 5
+
+// Several scripts in Hoyle5 contain a subroutine which spins on kGetTime until
+// a certain number of ticks elapse. Since this wastes CPU and makes ScummVM
+// unresponsive, the kWait kernel function (which was removed in SCI2) is
+// reintroduced at 0x4f in kernel.cpp only for Hoyle5, and the spin subroutines
+// are patched here to call that function instead.
+// Applies to at least: English Demo
+static const uint16 hoyle5SignatureSpinLoop[] = {
+ SIG_MAGICDWORD,
+ 0x76, // push0
+ 0x43, 0x79, SIG_UINT16(0x00), // callk GetTime, $0
+ 0x36, // push
+ 0x87, 0x01, // lap param[1]
+ 0x02, // add
+ 0xa5, 0x00, // sat temp[0]
+ SIG_END
+};
+
+static const uint16 hoyle5PatchSpinLoop[] = {
+ 0x78, // push1
+ 0x8f, 0x01, // lsp param[1]
+ 0x43, 0x4f, PATCH_UINT16(0x02), // callk Wait, $2
+ 0x48, // ret
+ PATCH_END
+};
+
+// script, description, signature patch
+static const SciScriptPatcherEntry hoyle5Signatures[] = {
+ { true, 3, "remove kGetTime spin", 1, hoyle5SignatureSpinLoop, hoyle5PatchSpinLoop },
+ { true, 23, "remove kGetTime spin", 1, hoyle5SignatureSpinLoop, hoyle5PatchSpinLoop },
+ { true, 500, "remove kGetTime spin", 1, hoyle5SignatureSpinLoop, hoyle5PatchSpinLoop },
+ { true, 64937, "remove kGetTime spin", 1, hoyle5SignatureSpinLoop, hoyle5PatchSpinLoop },
+ SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#pragma mark -
#pragma mark Gabriel Knight 1
// ===========================================================================
@@ -5170,6 +5207,9 @@ void ScriptPatcher::processScript(uint16 scriptNr, byte *scriptData, const uint3
signatureTable = freddypharkasSignatures;
break;
#ifdef ENABLE_SCI32
+ case GID_HOYLE5:
+ signatureTable = hoyle5Signatures;
+ break;
case GID_GK1:
signatureTable = gk1Signatures;
break;