Permalink
Browse files

SCI32: Fix QFG4 talking to absent innkeeper (#1395)

Fixes inn dialogue after Igor's rescue, bug #10753
  • Loading branch information...
Vhati authored and bluegr committed Nov 28, 2018
1 parent c58d619 commit 4fd1da70a48829f37d10ce7e858320ad4ae3e5d4
Showing with 102 additions and 0 deletions.
  1. +102 −0 engines/sci/engine/script_patches.cpp
@@ -7762,6 +7762,107 @@ static const uint16 qfg4MoonrisePatch[] = {
PATCH_END
};

// Visiting the inn after rescuing Igor sets a plot flag. Such flags are tested
// on subsequent visits to decide the dialogue options when clicking MOUTH on
// hero. That particular check neglects time of day, allowing hero to talk to
// an empty room after midnight... and get responses from the absent innkeeper.
//
// The inn's init() has a series of cond blocks to boil down all the checks
// into values for local[2], representing discrete situations. Then there's a
// switch block in sInitShit() that acts on those values, making arrival
// announcements and setting new flags.
//
// "So Dmitri says the gypsy didn't really kill Igor after all." sets flag 132.
// "I must thank you for saving our Tanya." sets flag 134.
//
// There are two bugged situations. When you have flag 132 and haven't gotten
// 134 yet, local[2] = 11. When you get flag 134, local[2] = 12. Neither
// of them consider the time of day, talking as if the innkeeper were always
// present.
//
// A day in QFG4 is broken up into 3-hour spans: 6,7,0,1,2,3,4,5. Where 6 is
// midnight. The sun rises in 0 and sets in 4. Current span is global[123]. The
// innkeeper sprite is not around from midnight to morning.
//
// To make room, we optimize block 10's time check:
// "t <= 3 || t is in [4, 5]" becomes "t <= 5". No need for a lengthy call
// to do a simple comparison. Conceptually it meant, "daytime and evening".
//
// That gap is used to insert similar pre-midnight checks before block 11 and
// block 12. This will sync them with the sprite's schedule. Ideally, the
// sprite never would've been scheduled separately in the first place.
//
// Applies to at least: English CD, English floppy, German floppy
// Responsible method: rm320::init()
// Fixes bug: #10753
static const uint16 qfg4AbsentInnkeeperSignature[] = {
SIG_MAGICDWORD, // (Block 10, partway through.)
0x31, 0x1c, // bnt 28d [block 11]
0x89, 0x7b, // lsg global[123]
0x35, 0x03, // ldi 3d
0x24, // le?
// (~~ Junk begins ~~)
0x2f, 0x0f, // bt 15d [after the calle]
0x39, 0x03, // pushi 3d
0x89, 0x7b, // lsg global[123]
0x39, 0x04, // pushi 4d
0x39, 0x05, // pushi 5d
0x46, SIG_UINT16(0xfde7), SIG_UINT16(0x0005), SIG_UINT16(0x0006), // calle proc64999_5(global[123], 4, 5) 06
// (~~ Junk ends ~~)
0x31, 0x04, // bnt 4d [block 11]
0x35, 0x0a, // ldi 10d
0x33, 0x29, // jmp 41d (done, local[2]=acc)
//
SIG_ADDTOOFFSET(+25), // (...Block 11...) (Patch ends after this.)
SIG_ADDTOOFFSET(+14), // (...Block 12...)
SIG_ADDTOOFFSET(+2), // (...Else 0...)
0xa3, 0x02, // sal local[2] (all blocks set acc and jmp here)
PATCH_END
};

static const uint16 qfg4AbsentInnkeeperPatch[] = {
0x31, 0x0e, // bnt 14d [block 11]
0x89, 0x7b, // lsg global[123]
0x35, 0x05, // ldi 5d (make it t <= 5)
0x24, // le?
// (*snip*)
0x31, 0x07, // bnt 7d [block 11]
0x35, 0x0a, // ldi 10d
0x33, 0x3a, // jmp 58d (done, local[2]=acc)
//
0x34, PATCH_UINT16(0x0000), // ldi 0 (waste 3 bytes)
// (14 freed bytes remain.)
// (Use 7 freed bytes to prepend block 11.)
// (And shift all of block 11 up by 7 bytes.)
// (Use that new gap below to prepend block 12.)
//
// (Block 11. Prepend a time check.)
0x89, 0x7b, // lsg global[123]
0x35, 0x05, // ldi 5d
0x24, // le?
0x31, 0x19, // bnt 25d [block 12]
// (Block 11 original ops shift up.)
0x78, // push1
0x38, PATCH_UINT16(0x0084), // pushi 132
0x45, 0x04, PATCH_UINT16(0x0002), // callb proc0_4(132) 02
0x31, 0x0f, // bnt 15d [next block]
0x78, // push1
0x38, PATCH_UINT16(0x0086), // pushi 134
0x45, 0x04, PATCH_UINT16(0x0002), // callb proc0_4(134) 02
0x18, // not
0x31, 0x04, // bnt 4d [block 12]
0x35, 0x0b, // ldi 11d
0x33, 0x17, // jmp 23d (done, local[2]=acc)
//
// (Block 12. Prepend a time check.)
0x89, 0x7b, // lsg global[123]
0x35, 0x05, // ldi 5d
0x24, // le?
0x31, 0x0e, // bnt 14d [else block]
// (Block 12 original ops continue here.)
PATCH_END
};

// When entering flipped stairways from the upper door, hero is initially
// placed outside the walkable area. As a result, hero will float around
// inappropriately in stairways leading to Tanya's room (620) and to the iron
@@ -7892,6 +7993,7 @@ static const SciScriptPatcherEntry qfg4Signatures[] = {
{ true, 83, "fix incorrect array type", 1, qfg4TrapArrayTypeSignature, qfg4TrapArrayTypePatch },
{ true, 83, "fix incorrect array type (floppy)", 1, qfg4TrapArrayTypeFloppySignature, qfg4TrapArrayTypeFloppyPatch },
{ true, 320, "fix pathfinding at the inn", 1, qg4InnPathfindingSignature, qg4InnPathfindingPatch },
{ true, 320, "fix talking to absent innkeeper", 1, qfg4AbsentInnkeeperSignature, qfg4AbsentInnkeeperPatch },
{ true, 440, "fix setLooper calls (1/2)", 1, qg4SetLooperSignature1, qg4SetLooperPatch1 },
{ true, 530, "fix setLooper calls (1/2)", 4, qg4SetLooperSignature1, qg4SetLooperPatch1 },
{ true, 535, "fix setLooper calls (1/2)", 4, qg4SetLooperSignature1, qg4SetLooperPatch1 },

0 comments on commit 4fd1da7

Please sign in to comment.