aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorsluicebox2019-07-11 20:19:53 -0700
committerFilippos Karapetis2019-07-12 21:33:46 +0300
commit4dc9752d2ae8761c74cc5e68d5796e0975431a82 (patch)
tree15b9cdb636b56522f40bfecc16acc3fcc41ee377 /engines/sci
parent3094dd693135c369c797b6b0a409efb2f4acec48 (diff)
downloadscummvm-rg350-4dc9752d2ae8761c74cc5e68d5796e0975431a82.tar.gz
scummvm-rg350-4dc9752d2ae8761c74cc5e68d5796e0975431a82.tar.bz2
scummvm-rg350-4dc9752d2ae8761c74cc5e68d5796e0975431a82.zip
SCI: Fix ICEMAN destroyer timer, bug #11017
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/engine/script_patches.cpp127
1 files changed, 127 insertions, 0 deletions
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 617f8fc56a..0b328d5d97 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -105,6 +105,7 @@ static const char *const selectorNameTable[] = {
"handsOff", // system selector
"handsOn", // system selector
"localize", // Freddy Pharkas
+ "roomFlags", // Iceman
"put", // Police Quest 1 VGA
"changeState", // Quest For Glory 1 VGA, QFG4
"hide", // Quest For Glory 1 VGA, QFG4
@@ -215,6 +216,7 @@ enum ScriptPatcherSelectors {
SELECTOR_handsOff,
SELECTOR_handsOn,
SELECTOR_localize,
+ SELECTOR_roomFlags,
SELECTOR_put,
SELECTOR_changeState,
SELECTOR_hide,
@@ -2694,6 +2696,128 @@ static const SciScriptPatcherEntry gk2Signatures[] = {
#endif
+// When spotting the destroyer, timing problems prevent completing the bridge
+// scene at fast game speeds.
+//
+// In the control room, room 25, ego and the captain go to the bridge, room 28,
+// where they spot ships in an effectively automatic scene. When this completes
+// they return to the control room, the captain falls, and the player regains
+// control of ego and has to walk to the control panel. This entire sequence
+// has to be completed within 400 game cycles or the destroyer kills the sub,
+// but the bridge timing is in wall time and has at least 25 seconds of delays,
+// which at faster speeds is longer than 400 cycles. The bridge also animates
+// during messages, causing the timer to run while reading, so even at slower
+// speeds the game can illogically end before the ships are revealed.
+//
+// There are several problems here but the real bug is that the timer starts
+// before the player has control. We fix this by disabling the timer during the
+// bridge and resetting it to 120 game cycles when the player regains control.
+// This preserves the original timer duration in the control room, where the
+// real timed action is, and is compatible with existing saved games. When the
+// timer expires, subMarineScript:changeState(9) no longer ends the game if
+// subMarine:roomFlags flag 2 isn't set, which captainfallsScript sets at the
+// same time that it now calls subMarineScript:changeState(8).
+//
+// Applies to: All versions
+// Responsible methods: subMarineScript:changeState, captainfallsScript:changeState
+// Fixes bug #11017
+static const uint16 icemanDestroyerTimer1Signature[] = {
+ 0x30, SIG_UINT16(0x0022), // bnt 0022 [ state 8 ]
+ SIG_ADDTOOFFSET(+0x1f),
+ SIG_MAGICDWORD,
+ 0x32, SIG_UINT16(0x0074), // jmp 0074 [ end of method ]
+ 0x3c, // dup
+ 0x35, 0x08, // ldi 08
+ 0x1a, // eq?
+ 0x30, SIG_UINT16(0x0008), // bnt 0008 [ state 9 ]
+ 0x34, SIG_UINT16(0x0190), // ldi 0190
+ 0x65, 0x10, // aTop cycles [ cycles = 400 ]
+ 0x32, SIG_UINT16(0x0065), // jmp 0065 [ end of method ]
+ 0x3c, // dup
+ 0x35, 0x09, // ldi 09
+ 0x1a, // eq?
+ 0x30, SIG_UINT16(0x0023), // bnt 0023 [ state 15 ]
+ 0x8f, 0x00, // lsp 00
+ 0x35, 0x02, // ldi 02
+ 0x22, // lt? [ didn't reach control panel? ]
+ 0x30, SIG_UINT16(0x0014), // bnt 0014 [ skip death if reached control panel ]
+ SIG_END
+};
+
+static const uint16 icemanDestroyerTimer1Patch[] = {
+ 0x30, PATCH_UINT16(0x001f), // bnt 001f [ state 8 ]
+ PATCH_ADDTOOFFSET(+0x1f),
+ 0x3c, // dup
+ 0x35, 0x08, // ldi 08
+ 0x1a, // eq?
+ 0x31, 0x04, // bnt 04 [ state 9 ]
+ 0x35, 0x78, // ldi 78
+ 0x65, 0x10, // aTop cycles [ cycles = 120 ]
+ 0x3c, // dup
+ 0x35, 0x09, // ldi 09
+ 0x1a, // eq?
+ 0x31, 0x2c, // bnt 2c [ state 15 ]
+ 0x38, PATCH_SELECTOR16(roomFlags), // pushi roomFlags
+ 0x76, // push0
+ 0x63, 0x08, // pToa client
+ 0x4a, 0x04, // send 04 [ subMarine roomFlags? ]
+ 0x7a, // push2 [ flag 2 set when captain falls ]
+ 0x12, // and [ has captain fallen? ]
+ 0x31, 0x19, // bnt 19 [ skip death if captain hasn't fallen ]
+ 0x8f, 0x00, // lsp 00
+ 0x22, // lt? [ didn't reach control panel? ]
+ 0x31, 0x14, // bnt 14 [ skip death if reached control panel ]
+ PATCH_END
+};
+
+static const uint16 icemanDestroyerTimer2Signature[] = {
+ // print four messages
+ 0x7a, // push2
+ 0x38, SIG_UINT16(0x0187), // pushi 0187
+ SIG_MAGICDWORD,
+ 0x7a, // push2
+ 0x47, 0xff, 0x00, 0x04, // calle proc255_0 [ print 391 2 ]
+ SIG_ADDTOOFFSET(+20), // [ print 391 3, print 391 4 ]
+ 0x7a, // push2
+ 0x38, SIG_UINT16(0x0187), // pushi 0187
+ 0x39, 0x05, // pushi 05
+ 0x47, 0xff, 0x00, 0x04, // calle proc255_0 [ print 391 5 ]
+ SIG_END,
+};
+
+static const uint16 icemanDestroyerTimer2Patch[] = {
+ // print four messages using a loop
+ 0x35, 0x02, // ldi 02
+ 0xa7, 0x01, // sap 01
+ 0x8f, 0x01, // lsp 01
+ 0x35, 0x05, // ldi 05
+ 0x24, // le? [ loop while 2 <= param1 <= 5 ]
+ 0x31, 0x0e, // bnt 0e [ exit loop ]
+ 0x7a, // push2
+ 0x38, PATCH_UINT16(0x0187), // pushi 0187
+ 0x8f, 0x01, // lsp 01
+ 0x47, 0xff, 0x00, 0x04, // calle proc255_0 [ print 391 param1 ]
+ 0xcf, 0x01, // +sp 01 [ increment and push param1 ]
+ 0x33, 0xed, // jmp ed [ continue loop ]
+ // reset subMarineScript timer
+ 0x39, PATCH_SELECTOR8(script), // pushi script
+ 0x76, // push0
+ 0x51, 0x5c, // class subMarine
+ 0x4a, 0x04, // send 04 [ subMarine script? ]
+ 0x39, PATCH_SELECTOR8(changeState), // pushi changeState
+ 0x78, // push1
+ 0x39, 0x08, // pushi 08
+ 0x4a, 0x06, // send 06 [ subMarineScript changeState: 8 ]
+ PATCH_END
+};
+
+// script, description, signature patch
+static const SciScriptPatcherEntry icemanSignatures[] = {
+ { true, 314, "destroyer timer (1/2)", 1, icemanDestroyerTimer1Signature, icemanDestroyerTimer1Patch },
+ { true, 391, "destroyer timer (2/2)", 1, icemanDestroyerTimer2Signature, icemanDestroyerTimer2Patch },
+ SCI_SIGNATUREENTRY_TERMINATOR
+};
+
// ===========================================================================
// At least during the harpy scene, export 29 of script 0 is called and has an
// issue where temp[3] won't get inititialized, but is later used to set
@@ -14987,6 +15111,9 @@ void ScriptPatcher::processScript(uint16 scriptNr, SciSpan<byte> scriptData) {
signatureTable = gk2Signatures;
break;
#endif
+ case GID_ICEMAN:
+ signatureTable = icemanSignatures;
+ break;
case GID_KQ5:
signatureTable = kq5Signatures;
break;