[Scummvm-git-logs] scummvm master -> 3e953e42c0a0c156818c8a4e16f34dfc24cf818b

bluegr noreply at scummvm.org
Tue Nov 1 15:09:34 UTC 2022


This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
ffdf9f85ca NEWS.md: Correct spelling mistake
b82f3cc4a8 SUPERNOVA: Correct spelling mistakes
7900f40730 ICB: Correct spelling mistake
c187b2ff58 GLK: Correct spelling mistakes
8e2c7715fa SCI: Correct spelling mistake
c483a688e4 SCI: Correct spelling mistake
3e953e42c0 ULTIMA: Remove superflous space


Commit: ffdf9f85ca06eb9f86af3e4f43befeabbf81ddfe
    https://github.com/scummvm/scummvm/commit/ffdf9f85ca06eb9f86af3e4f43befeabbf81ddfe
Author: Hubert Maier (raziel- at users.noreply.github.com)
Date: 2022-11-01T17:09:25+02:00

Commit Message:
NEWS.md: Correct spelling mistake

accomodate -> accommodate

Changed paths:
    NEWS.md


diff --git a/NEWS.md b/NEWS.md
index 99f50440073..7b687467f3b 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -2804,7 +2804,7 @@ For a more comprehensive changelog of the latest experimental code, see:
 
  Simon:
    - Improved Hebrew support.
-   - Lots of long-overdue cleanups and re-structuring were made to accomodate
+   - Lots of long-overdue cleanups and re-structuring were made to accommodate
      for The Feeble Files.
    - Fixed a rare MIDI bug that would cause a channel to change volume without
      adjusting it to the master volume.


Commit: b82f3cc4a8c4ccd266c3b2ce81bd63df821a2990
    https://github.com/scummvm/scummvm/commit/b82f3cc4a8c4ccd266c3b2ce81bd63df821a2990
Author: Hubert Maier (raziel- at users.noreply.github.com)
Date: 2022-11-01T17:09:25+02:00

Commit Message:
SUPERNOVA: Correct spelling mistakes

begining -> beginning

Changed paths:
    devtools/create_supernova/create_image/README


diff --git a/devtools/create_supernova/create_image/README b/devtools/create_supernova/create_image/README
index d4d756e3ee1..51556cfcc28 100644
--- a/devtools/create_supernova/create_image/README
+++ b/devtools/create_supernova/create_image/README
@@ -6,7 +6,7 @@ so it could easily generate nonsense without any warning if for example command
 arguments aren't as expected.
 
 To use this tool create a folder named as the number of the datafile you want to
-create, it should be 3 characters long, add required numbers of zeros to the begining
+create, it should be 3 characters long, add required numbers of zeros to the beginning
 of the name (015 for ms2_data.015).
 
 Inside this folder should be:
@@ -77,7 +77,7 @@ The tool needs 3 comand line arguments when running it:
 -- Prefix of the file to be created (use "ms2_data" to create "ms2_data.###")
 -- Number of the file to be created and also the number of a folder to read all the
 files from (use "15" to create prefix.015)
--- Number of bytes to skip in each .bmp file. At the begining of each .bmp file is
+-- Number of bytes to skip in each .bmp file. At the beginning of each .bmp file is
 a header with information about the file and after that is stored the palette. This
 tool doesn't need these, so this number says how many bytes to skip to get to the pixel
 data. For example: use 1146 to generate ms2_data.015 from the files included.


Commit: 7900f407308ff11b8224cfbc685d34b275664f0f
    https://github.com/scummvm/scummvm/commit/7900f407308ff11b8224cfbc685d34b275664f0f
Author: Hubert Maier (raziel- at users.noreply.github.com)
Date: 2022-11-01T17:09:25+02:00

Commit Message:
ICB: Correct spelling mistake

belive -> believe

Changed paths:
    engines/icb/player_interaction.cpp


diff --git a/engines/icb/player_interaction.cpp b/engines/icb/player_interaction.cpp
index 9b96b59dbd4..d8b62eef722 100644
--- a/engines/icb/player_interaction.cpp
+++ b/engines/icb/player_interaction.cpp
@@ -187,7 +187,7 @@ void _player::Find_current_player_interact_object() {
 								mega_id = j + 1;
 								dead_mega = TRUE8; // chosen a dead mega
 							}
-						} else if (!MS->logic_structs[j]->mega->dead) { // must belive if we're stood
+						} else if (!MS->logic_structs[j]->mega->dead) { // must believe if we're stood
 							evil_chosen = MS->logic_structs[j]->mega->is_evil;
 							nearest_mega = len;
 							mega_id = j + 1;


Commit: c187b2ff5854a35a3bd6336072759b76044c3642
    https://github.com/scummvm/scummvm/commit/c187b2ff5854a35a3bd6336072759b76044c3642
Author: Hubert Maier (raziel- at users.noreply.github.com)
Date: 2022-11-01T17:09:25+02:00

Commit Message:
GLK: Correct spelling mistakes

apparantly -> apparently

Changed paths:
    engines/glk/agt/gamedata.cpp


diff --git a/engines/glk/agt/gamedata.cpp b/engines/glk/agt/gamedata.cpp
index d8f4b8af9b0..acda28ff63c 100644
--- a/engines/glk/agt/gamedata.cpp
+++ b/engines/glk/agt/gamedata.cpp
@@ -323,8 +323,8 @@ const opdef illegal_def = a(ILLEGAL);
    The last table entry is now marked by a new value of -1.*/
 
 /* Versions of the command set:
-	v1.21 apparantly has a compatible command set w/ 1.7 (!)
-	  [except that their maxcmd is apparantly 22, not 30]
+	v1.21 apparently has a compatible command set w/ 1.7 (!)
+	  [except that their maxcmd is apparently 22, not 30]
 	1.0 doesn't; it seems to have an EOC code of 154, as opposed to
 	165 or so.
 	1.18 seems to be slightly different from 1.7, but seemingly only


Commit: 8e2c7715fa601d6eb8ad4e131d340181b07a4279
    https://github.com/scummvm/scummvm/commit/8e2c7715fa601d6eb8ad4e131d340181b07a4279
Author: Hubert Maier (raziel- at users.noreply.github.com)
Date: 2022-11-01T17:09:25+02:00

Commit Message:
SCI: Correct spelling mistake

I had to delete and reupload the file, because it's too big to edit from the website

Changed paths:
  R engines/sci/engine/script_patches.cpp


diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
deleted file mode 100644
index c6fbe3194d6..00000000000
--- a/engines/sci/engine/script_patches.cpp
+++ /dev/null
@@ -1,24480 +0,0 @@
-/* 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "sci/sci.h"
-#include "sci/engine/kernel.h"
-#include "sci/engine/script.h"
-#include "sci/engine/state.h"
-#include "sci/engine/features.h"
-#include "sci/engine/script_patches.h"
-#ifdef ENABLE_SCI32
-#include "sci/engine/guest_additions.h"
-#endif
-
-#include "common/util.h"
-
-namespace Sci {
-
-// IMPORTANT:
-// every patch entry needs the following:
-//  - script number (pretty obvious)
-//
-//  - apply count
-//     specifies the number of times a patch is supposed to get applied.
-//     Most of the time, it should be 1.
-//
-//  - magicDWORD + magicOffset
-//     please ALWAYS put 0 for those two. Both will get filled out at runtime by the patcher.
-//
-//  - signature data (is used to identify certain script code, that needs patching)
-//     every signature needs to contain SIG_MAGICDWORD once.
-//      The following 4 bytes after SIG_MAGICDWORD - which don't have to be fixed, you may for example
-//      use SIG_SELECTOR16, will get used to quickly search for a partly match before verifying that
-//      the whole signature actually matches. If it's not included, the script patcher will error() out
-//      right when loading up the game.
-//     If selector-IDs are included, please use SIG_SELECTOR16 + SIG_SELECTOR8 [1]. Simply
-//      specify the selector that way, so that the patcher will search for the specific
-//      selector instead of looking for a hardcoded value. Selectors may not be the same
-//      between game versions.
-//     For UINT16s either use SIG_UINT16 or SIG_SELECTOR16.
-//      Macintosh versions of SCI games are using BE ordering instead of LE since SCI1.1 for UINT16s in scripts
-//      By using those 2 commands, it's possible to make patches work for PC and Mac versions of the same game.
-//     You may also skip bytes by using the SIG_ADDTOOFFSET command
-//     Every signature data needs to get terminated using SIGNATURE_END
-//
-//  - patch data (is used for actually patching scripts)
-//     When a match is found, the patch data will get applied.
-//     Patch data is similar to signature data. Just use PATCH_SELECTOR16 + PATCH_SELECTOR8 [1]
-//      for patching in selectors.
-//     There are also patch specific commands.
-//     Those are PATCH_GETORIGINALBYTE, which fetches a byte from the original script
-//      and PATCH_GETORIGINALBYTEADJUST, which does the same but gets a second value
-//      from the uint16 array and uses that value to adjust the original byte.
-//     Every patch data needs to get terminated using PATCH_END
-//
-//  - and please always add a comment about why the patch was done and what's causing issues.
-//     If possible make sure, that the patch works on localized (or just different) game versions
-//      as well in case those need patching too.
-//
-// [1] - selectors need to get specified in selectorTable[] and ScriptPatcherSelectors-enum
-//        before they can get used using the SIG_SELECTORx and PATCH_SELECTORx commands.
-//        You have to use the exact same order in both the table and the enum, otherwise
-//        it won't work.
-//        ATTENTION: selectors will only work here, when they are also in SelectorCache (selector.h)
-
-static const char *const selectorNameTable[] = {
-	"cycles",       // system selector
-	"seconds",      // system selector
-	"init",         // system selector
-	"dispose",      // system selector
-	"new",          // system selector
-	"curEvent",     // system selector
-	"disable",      // system selector
-	"doit",         // system selector
-	"show",         // system selector
-	"x",            // system selector
-	"cel",          // system selector
-	"setMotion",    // system selector
-	"overlay",      // system selector
-	"setPri",       // system selector - for setting priority
-	"play",         // system selector
-	"number",       // system selector
-	"setScript",    // system selector
-	"setCycle",     // system selector
-	"setStep",      // system selector
-	"cycleSpeed",   // system selector
-	"handsOff",     // system selector
-	"handsOn",      // system selector
-	"type",         // system selector
-	"client",       // system selector
-	"state",        // system selector
-	"localize",     // Freddy Pharkas
-	"roomFlags",    // Iceman
-	"put",          // Police Quest 1 VGA
-	"approachVerbs", // Police Quest 1 VGA, QFG4
-	"newRoom",      // Police Quest 3, GK1
-	"register",     // Quest For Glory 1 EGA, QFG4
-	"changeState",  // Quest For Glory 1 VGA, QFG4
-	"hide",         // Quest For Glory 1 VGA, QFG4
-	"say",          // Quest For Glory 1 VGA, QFG4
-	"script",       // Quest For Glory 1 VGA
-	"isEmpty",      // Quest For Glory 3
-	"solvePuzzle",  // Quest For Glory 3
-	"curIcon",      // Quest For Glory 3, QFG4
-	"curInvIcon",   // Quest For Glory 3, QFG4
-	"startText",    // King's Quest 6 CD / Laura Bow 2 CD for audio+text support
-	"startAudio",   // King's Quest 6 CD / Laura Bow 2 CD for audio+text support
-	"modNum",       // King's Quest 6 CD / Laura Bow 2 CD for audio+text support
-	"handle",       // King's Quest 6 / Laura Bow 2 / RAMA
-	"add",          // King's Quest 6
-	"givePoints",   // King's Quest 6
-	"has",          // King's Quest 6, GK1
-	"modeless",     // King's Quest 6 CD
-	"message",      // King's Quest 6
-	"forceUpd",     // Police Quest 3
-	"cycler",       // Space Quest 4 / system selector
-	"setCel",       // Space Quest 4, Phant2, GK1
-	"addToPic",     // Space Quest 4
-	"stop",         // Space Quest 4
-	"canControl",   // Space Quest 4
-	"looper",       // Space Quest 4
-	"nMsgType",     // Space Quest 4
-	"doVerb",       // Space Quest 4
-	"setRegions",   // Space Quest 4
-	"cursor",       // Space Quest 5
-	"showSelf",     // Space Quest 5
-	"claimed",      // Space Quest 5, QFG4
-	"setCursor",    // Space Quest 5, QFG4
-	"setSpeed",     // Space Quest 5, QFG4
-	"loop",         // Laura Bow 1 Colonel's Bequest, QFG4
-	"setLoop",      // Laura Bow 1 Colonel's Bequest, QFG4
-	"ignoreActors", // Laura Bow 1 Colonel's Bequest
-	"setVol",       // Laura Bow 2 CD
-	"at",           // Longbow, QFG4
-	"owner",        // Longbow, QFG4
-	"fade",         // Longbow, Shivers
-	"enable",       // Longbow, SQ6
-	"delete",       // EcoQuest 1
-	"size",         // EcoQuest 1
-	"signal",       // EcoQuest 1, GK1
-	"obstacles",    // EcoQuest 1, QFG4
-	"handleEvent",  // EcoQuest 2, Shivers
-	"view",         // King's Quest 4, RAMA benchmarking, GK1, QFG4
-#ifdef ENABLE_SCI32
-	"newWith",      // SCI2 array script
-	"posn",         // GK1, Phant2, QFG4
-	"printLang",    // GK2
-	"test",         // Torin
-	"get",          // Torin, GK1
-	"normalize",    // GK1
-	"setReal",      // GK1
-	"set",          // Torin
-	"clear",        // Torin
-	"masterVolume", // SCI2 master volume reset
-	"data",         // Phant2, QFG4
-	"format",       // Phant2
-	"mouseMoved",   // Phant2
-	"setSize",      // Phant2
-	"iconV",        // Phant2
-	"track",        // Phant2
-	"update",       // Phant2
-	"xOff",         // Phant2
-	"addRespondVerb",// KQ7
-	"eachElementDo",// KQ7
-	"fore",         // KQ7
-	"back",         // KQ7
-	"font",         // KQ7
-	"setHeading",   // KQ7
-	"newPic",       // Lighthouse
-	"start",        // Lighthouse
-	"setScale",     // LSL6hires, QFG4
-	"setScaler",    // LSL6hires, QFG4
-	"showTitle",    // LSL6hires
-	"name",         // LSL6hires
-	"oSpecialSync", // LSL7
-	"readWord",     // LSL7, Phant1, Torin
-	"points",       // PQ4
-	"select",       // PQ4
-	"addObstacle",  // QFG4
-	"saveFilePtr",  // RAMA
-	"priority",     // RAMA
-	"plane",        // RAMA
-	"getSubscriberObj", // RAMA
-	"advance",      // QFG4
-	"advanceCurIcon", // QFG4
-	"amount",       // QFG4
-	"cue",          // QFG4
-	"drop",         // QFG4
-	"getCursor",    // QFG4
-	"heading",      // QFG4
-	"moveSpeed",    // QFG4
-	"retreat",      // QFG4
-	"sayMessage",   // QFG4
-	"setLooper",    // QFG4
-	"use",          // QFG4
-	"useStamina",   // QFG4
-	"value",        // QFG4
-	"setupExit",    // SQ6
-	"vol",          // SQ6
-	"walkIconItem", // SQ6
-#endif
-	nullptr
-};
-
-enum ScriptPatcherSelectors {
-	SELECTOR_cycles = 0,
-	SELECTOR_seconds,
-	SELECTOR_init,
-	SELECTOR_dispose,
-	SELECTOR_new,
-	SELECTOR_curEvent,
-	SELECTOR_disable,
-	SELECTOR_doit,
-	SELECTOR_show,
-	SELECTOR_x,
-	SELECTOR_cel,
-	SELECTOR_setMotion,
-	SELECTOR_overlay,
-	SELECTOR_setPri,
-	SELECTOR_play,
-	SELECTOR_number,
-	SELECTOR_setScript,
-	SELECTOR_setCycle,
-	SELECTOR_setStep,
-	SELECTOR_cycleSpeed,
-	SELECTOR_handsOff,
-	SELECTOR_handsOn,
-	SELECTOR_type,
-	SELECTOR_client,
-	SELECTOR_state,
-	SELECTOR_localize,
-	SELECTOR_roomFlags,
-	SELECTOR_put,
-	SELECTOR_approachVerbs,
-	SELECTOR_newRoom,
-	SELECTOR_register,
-	SELECTOR_changeState,
-	SELECTOR_hide,
-	SELECTOR_say,
-	SELECTOR_script,
-	SELECTOR_isEmpty,
-	SELECTOR_solvePuzzle,
-	SELECTOR_curIcon,
-	SELECTOR_curInvIcon,
-	SELECTOR_startText,
-	SELECTOR_startAudio,
-	SELECTOR_modNum,
-	SELECTOR_handle,
-	SELECTOR_add,
-	SELECTOR_givePoints,
-	SELECTOR_has,
-	SELECTOR_modeless,
-	SELECTOR_message,
-	SELECTOR_forceUpd,
-	SELECTOR_cycler,
-	SELECTOR_setCel,
-	SELECTOR_addToPic,
-	SELECTOR_stop,
-	SELECTOR_canControl,
-	SELECTOR_looper,
-	SELECTOR_nMsgType,
-	SELECTOR_doVerb,
-	SELECTOR_setRegions,
-	SELECTOR_cursor,
-	SELECTOR_showSelf,
-	SELECTOR_claimed,
-	SELECTOR_setCursor,
-	SELECTOR_setSpeed,
-	SELECTOR_loop,
-	SELECTOR_setLoop,
-	SELECTOR_ignoreActors,
-	SELECTOR_setVol,
-	SELECTOR_at,
-	SELECTOR_owner,
-	SELECTOR_fade,
-	SELECTOR_enable,
-	SELECTOR_delete,
-	SELECTOR_size,
-	SELECTOR_signal,
-	SELECTOR_obstacles,
-	SELECTOR_handleEvent,
-	SELECTOR_view
-#ifdef ENABLE_SCI32
-	,
-	SELECTOR_newWith,
-	SELECTOR_posn,
-	SELECTOR_printLang,
-	SELECTOR_test,
-	SELECTOR_get,
-	SELECTOR_normalize,
-	SELECTOR_setReal,
-	SELECTOR_set,
-	SELECTOR_clear,
-	SELECTOR_masterVolume,
-	SELECTOR_data,
-	SELECTOR_format,
-	SELECTOR_mouseMoved,
-	SELECTOR_setSize,
-	SELECTOR_iconV,
-	SELECTOR_track,
-	SELECTOR_update,
-	SELECTOR_xOff,
-	SELECTOR_addRespondVerb,
-	SELECTOR_eachElementDo,
-	SELECTOR_fore,
-	SELECTOR_back,
-	SELECTOR_font,
-	SELECTOR_setHeading,
-	SELECTOR_newPic,
-	SELECTOR_start,
-	SELECTOR_setScale,
-	SELECTOR_setScaler,
-	SELECTOR_showTitle,
-	SELECTOR_name,
-	SELECTOR_oSpecialSync,
-	SELECTOR_readWord,
-	SELECTOR_points,
-	SELECTOR_select,
-	SELECTOR_addObstacle,
-	SELECTOR_saveFilePtr,
-	SELECTOR_priority,
-	SELECTOR_plane,
-	SELECTOR_getSubscriberObj,
-	SELECTOR_advance,
-	SELECTOR_advanceCurIcon,
-	SELECTOR_amount,
-	SELECTOR_cue,
-	SELECTOR_drop,
-	SELECTOR_getCursor,
-	SELECTOR_heading,
-	SELECTOR_moveSpeed,
-	SELECTOR_retreat,
-	SELECTOR_sayMessage,
-	SELECTOR_setLooper,
-	SELECTOR_use,
-	SELECTOR_useStamina,
-	SELECTOR_value,
-	SELECTOR_setupExit,
-	SELECTOR_vol,
-	SELECTOR_walkIconItem
-#endif
-};
-
-#ifdef ENABLE_SCI32
-// It is not possible to change the directory for ScummVM save games, so disable
-// the "change directory" button in the standard save dialogue
-static const uint16 sci2ChangeDirSignature[] = {
-	0x72, SIG_ADDTOOFFSET(+2), // lofsa changeDirI
-	0x4a, SIG_UINT16(0x0004),  // send 4
-	SIG_MAGICDWORD,
-	0x36,                      // push
-	0x35, 0xf7,                // ldi $f7
-	0x12,                      // and
-	0x36,                      // push
-	SIG_END
-};
-
-static const uint16 sci2ChangeDirPatch[] = {
-	PATCH_ADDTOOFFSET(+3),    // lofsa changeDirI
-	PATCH_ADDTOOFFSET(+3),    // send 4
-	PATCH_ADDTOOFFSET(+1),    // push
-	0x35, 0x00,               // ldi 0
-	PATCH_END
-};
-
-// Save game script hardcodes the maximum number of save games to 20, but
-// this is an artificial constraint that does not apply to ScummVM
-static const uint16 sci2NumSavesSignature1[] = {
-	SIG_MAGICDWORD,
-	0x8b, 0x02,                    // lsl local[2]
-	0x35, 0x14,                    // ldi 20
-	0x22,                          // lt?
-	SIG_END
-};
-
-static const uint16 sci2NumSavesPatch1[] = {
-	PATCH_ADDTOOFFSET(+2),         // lsl local[2]
-	0x35, 0x63,                    // ldi 99
-	PATCH_END
-};
-
-static const uint16 sci2NumSavesSignature2[] = {
-	SIG_MAGICDWORD,
-	0x8b, 0x02,                    // lsl local[2]
-	0x35, 0x14,                    // ldi 20
-	0x1a,                          // eq?
-	SIG_END
-};
-
-static const uint16 sci2NumSavesPatch2[] = {
-	PATCH_ADDTOOFFSET(+2),         // lsl local[2]
-	0x35, 0x63,                    // ldi 99
-	PATCH_END
-};
-
-// Phantasmagoria & SQ6 try to initialize the first entry of an int16 array
-// using an empty string, which is not valid (it should be a number)
-static const uint16 sci21IntArraySignature[] = {
-	0x38, SIG_SELECTOR16(newWith), // pushi newWith
-	0x7a,                          // push2
-	0x39, 0x04,                    // pushi $4
-	0x72, SIG_ADDTOOFFSET(+2),     // lofsa string ""
-	SIG_MAGICDWORD,
-	0x36,                          // push
-	0x51, 0x0b,                    // class IntArray
-	0x4a, 0x08,                    // send $8
-	SIG_END
-};
-
-static const uint16 sci21IntArrayPatch[] = {
-	PATCH_ADDTOOFFSET(+6),      // push $b9; push2; pushi $4
-	0x76,                       // push0
-	0x34, PATCH_UINT16(0x0001), // ldi 0001 (waste bytes)
-	PATCH_END
-};
-
-// Most SCI32 games have a video performance benchmarking loop at the
-// beginning of the game. Running this benchmark with calls to
-// `OSystem::updateScreen` will often cause the benchmark to return a low value,
-// which causes games to disable some visual effects. Running without calls to
-// `OSystem::updateScreen` on any reasonably modern CPU will cause the benchmark
-// to overflow, leading to randomly disabled effects. This patch changes the
-// benchmarking code to always return the game's maximum speed value.
-//
-// The speed test function in script 64908 changes between games and is compiled
-//  differently between versions of the same game, so to generically patch this
-//  we replace the call-sites with zero, which is the fastest result. RAMA's
-//  speed test function reverses this and returns a high value for fast machines
-//  so it requires a different patch.
-//
-// Applies to: GK1, PQ4, LSL6hires, Phant1, Shivers, SQ6, RAMA
-static const uint16 sci2BenchmarkSignature[] = {
-	SIG_MAGICDWORD,
-	0x76,                       // push0
-	0x46, SIG_UINT16(0xfd8c),   // calle proc64908_0 [ speed test function ]
-	      SIG_UINT16(0x0000),
-	      SIG_UINT16(0x0000),
-	SIG_END
-};
-
-static const uint16 sci2BenchmarkPatch[] = {
-	0x35, 0x00,                 // ldi 00 [ fastest speed test result ]
-	0x33, 0x04,                 // jmp 04
-	PATCH_END
-};
-
-static const uint16 sci2BenchmarkReversePatch[] = {
-	0x34, PATCH_UINT16(0x2710), // ldi 10000 [ fastest speed test result for RAMA ]
-	0x33, 0x03,                 // jmp 03
-	PATCH_END
-};
-
-// The init code that runs in many SCI32 games unconditionally resets the music
-// volume, but the game should always use the volume stored in ScummVM.
-// Applies to at least: LSL6hires, MGDX, PQ:SWAT, QFG4
-static const uint16 sci2VolumeResetSignature[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(masterVolume), // pushi masterVolume
-	0x78,                               // push1
-	0x39, SIG_ADDTOOFFSET(+1),          // pushi [default volume]
-	0x81, 0x01,                         // lag global[1]
-	0x4a, SIG_UINT16(0x0006),           // send 6
-	SIG_END
-};
-
-static const uint16 sci2VolumeResetPatch[] = {
-	0x32, PATCH_UINT16(0x0008),         // jmp 8 [past volume reset]
-	PATCH_END
-};
-
-// At least Gabriel Knight 1 and Police Quest 4 floppy have a broken Str::strip inside script 64918.
-// The code never passes over the actual string to kStringTrim, so that would not work and also trigger
-// a signature mismatch.
-// Localized version of Police Quest 4 were also affected.
-// Gabriel Knight although affected doesn't seem to ever call the code, so there is no reason to patch it.
-// Police Quest 4 CD got this fixed.
-static const uint16 sci2BrokenStrStripSignature[] = {
-	SIG_MAGICDWORD,
-	0x85, 0x06,                         // lat temp[6]
-	0x31, 0x10,                         // bnt [jump to code that passes 2 parameters]
-	0x38, SIG_UINT16(0x00c2),           // pushi 00c2 (callKernel)
-	0x38, SIG_UINT16(0x0003),           // pushi 03
-	0x39, 0x0e,                         // pushi 0e
-	0x8d, 0x0b,                         // lst temp[0b]
-	0x36,                               // push
-	0x54, SIG_UINT16(0x000a),           // self 0a
-	0x33, 0x0b,                         // jmp [ret]
-	// 2 parameter code
-	0x38, SIG_UINT16(0x00c2),           // pushi 00c2
-	0x7a,                               // push2
-	0x39, 0x0e,                         // pushi 0e
-	0x8d, 0x0b,                         // lst temp[0b]
-	0x54, SIG_UINT16(0x0008),           // self 08
-	SIG_END
-};
-
-static const uint16 sci2BrokenStrStripPatch[] = {
-	PATCH_ADDTOOFFSET(+2),
-	0x85, 0x06,                         // lat temp[6] (once more]
-	PATCH_ADDTOOFFSET(+3),              // jump over pushi callKernel
-	0x39, 0x04,                         // pushi 04
-	0x39, 0x0e,                         // pushi 0e
-	// Attention: data is 0x14 in PQ4 CD, in floppy it's 0x12
-	0x67, 0x12,                         // pTos data (pass actual data)
-	0x8d, 0x0b,                         // lst temp[0b]
-	0x36,                               // push
-	0x54, PATCH_UINT16(0x000c),         // self 0c
-	0x48,                               // ret
-	PATCH_END
-};
-
-// Torin/LSL7-specific version of sci2NumSavesSignature1/2
-// Applies to at least: English CD
-static const uint16 torinLarry7NumSavesSignature[] = {
-	SIG_MAGICDWORD,
-	0x36,       // push
-	0x35, 0x14, // ldi 20
-	0x20,       // ge?
-	SIG_END
-};
-
-static const uint16 torinLarry7NumSavesPatch[] = {
-	PATCH_ADDTOOFFSET(+1), // push
-	0x35, 0x63,            // ldi 99
-	PATCH_END
-};
-
-#endif
-
-// Most SCI games run an initial speed test. The results are used to enable
-//  animations and other details but some games go further. For example, LSL3
-//  calculates how many times the player has to do a task using machine speed.
-//
-// We disable speed tests by patching them to return fixed results so that all
-//  graphics are enabled and games behave consistently. This also fixes the bug
-//  where tests fail on fast CPUs because their scores overflow. (bug #13529)
-//  We still have a heuristic in GfxAnimate::throttleSpeed() that attempts to
-//  detect tests and unthrottle the engine so that they score well. That should
-//  reasonably handle any games or versions that haven't been patched yet.
-//
-// Note that these patches are only for SCI16 games; the test was rewritten for
-//  SCI32 and we have separate patches for those.
-//
-// The first generation of speed tests measured how many game cycles occurred
-//  within a fixed amount of time and stored it in a global. Initialize this
-//  to a value that always passes and skip the real initialization so that the
-//  test immediately completes. This also removes a 1-2 second startup delay.
-static const uint16 sci0EarlySpeedTestSignature[] = {
-	0xc9, SIG_ADDTOOFFSET(+1),          // +sg machine-speed
-	SIG_MAGICDWORD,
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	0x30,                               // bnt [ skip initialization ]
-	SIG_END
-};
-
-static const uint16 sci0EarlySpeedTestPatch[] = {
-	0x34, PATCH_UINT16(0x00ff),         // ldi 00ff
-	0xa1, PATCH_GETORIGINALBYTE(+1),    // sag [ machine-speed = 255 ]
-	0x32,                               // jmp [ always skip initialization ]
-	PATCH_END
-};
-
-// Same as previous but the +sg instruction became +ag/push
-static const uint16 sci01SpeedTestGlobalSignature[] = {
-	0xc1, SIG_ADDTOOFFSET(+1),          // +ag machine-speed
-	SIG_MAGICDWORD,
-	0x36,                               // push
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	SIG_END                             // bnt [ skip initialization ]
-};
-
-static const uint16 sci01SpeedTestGlobalPatch[] = {
-	0x34, PATCH_UINT16(0x00ff),         // ldi 00ff
-	0xa1, PATCH_GETORIGINALBYTE(+1),    // sag [ machine-speed = 255 ]
-	0x18,                               // not [ always skip initialization ]
-	PATCH_END
-};
-
-// Same as previous but a local variable is used instead of a global
-static const uint16 sci01SpeedTestLocalSignature[] = {
-	0xc3, SIG_ADDTOOFFSET(+1),          // +al machine-speed
-	SIG_MAGICDWORD,
-	0x36,                               // push
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	SIG_END                             // bnt [ skip initialization ]
-};
-
-static const uint16 sci01SpeedTestLocalPatch[] = {
-	0x34, PATCH_UINT16(0x00ff),         // ldi 00ff
-	0xa3, PATCH_GETORIGINALBYTE(+1),    // sal [ machine-speed = 255 ]
-	0x18,                               // not [ always skip initialization ]
-	PATCH_END
-};
-
-// The second generation of speed tests measured how much time it takes to do a
-//  fixed amount of work. Patch the duration calculation to always be zero.
-static const uint16 sci11SpeedTestSignature[] = {
-	0x76,                               // push0
-	0x43, 0x42, 0x00,                   // callk GetTime 00
-	0x36,                               // push
-	SIG_MAGICDWORD,
-	0x83, 0x01,                         // lal 01
-	0x04,                               // sub    [ GetTime() - start-time ]
-	0xa3, 0x00,                         // sal 00 [ local0 = test-duration ]
-	SIG_END
-};
-
-static const uint16 sci11SpeedTestPatch[] = {
-	0x35, 0x00,                         // ldi 00
-	0x33, 0x04,                         // jmp 04 [ local0 = 0, best result ]
-	PATCH_END
-};
-
-// The Narrator class contains a bug that's responsible for rare random lockups
-//  in almost every Messager SCI game from 1992 to 1996. The later first-person
-//  and FMV games have structures that tend to survive this bug. It was finally,
-//  and only, fixed in LSL7.
-//
-// When a message is said, either through text or audio, Narrator:say calculates
-//  the game time when the message will end and stores this in Narrator:ticks.
-//  Narrator:doit disposes of itself once ticks is reached unless the user has
-//  already dismissed the message. When Narrator isn't saying a message it sets
-//  ticks to the sentinel value -1 which prevents doit and handleEvent from
-//  doing anything. The one rule of a sentinel value is that it can't appear in
-//  normal data, but game time is unsigned and there's nothing preventing
-//  Narrator:say from correctly calculating ticks as 65535 (-1). At 60 ticks per
-//  second, game time rolls over every 18 minutes and 12 seconds, and as each
-//  rollover approaches it's an opportunity for lockup. If a message is said
-//  when game time is high and Narrator:say calculates ticks as 65535 then the
-//  message never ends because handleEvent ignores user input and doit won't
-//  dispose of the message.
-//
-// We fix this by preventing Narrator:say from setting ticks to 65535 (-1). When
-//  it attempts this we use 0 instead, avoiding lockup by adding 1/60th of a
-//  second to the expiration time. Narrator:say changes over time but most
-//  versions can be handled by a generic patch, plus another for SCI32 versions
-//  that were compiled with debug instructions. A few games customized or cloned
-//  Narrator and require specific patches. Others use versions that predate the
-//  problem or don't use their Narrator class at all, but otherwise we patch all
-//  buggy versions.
-//
-// Applies to: Most games that use Messager/Narrator
-// Responsible method: Narrator:say
-static const uint16 sciNarratorLockupSignature[] = {
-	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
-	SIG_MAGICDWORD,
-	0x35, 0x3c,                         // ldi 3c
-	0x02,                               // add
-	0x36,                               // push
-	0x81, 0x58,                         // lag 58 [ game time ]
-	0x02,                               // add
-	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time ]
-	0x35, 0x01,                         // ldi 01 [ true ]
-	0x48,                               // ret
-	SIG_END
-};
-
-static const uint16 sciNarratorLockupPatch[] = {
-	PATCH_ADDTOOFFSET(+5),
-	0x89, 0x58,                         // lsg 58 [ game time ]
-	0x02,                               // add
-	0x65, PATCH_GETORIGINALBYTE(+1),    // aTop ticks [ ticks += 60 + game time ]
-	0x00,                               // bnot
-	0x31, 0xfb,                         // bnt fb [ set ticks to 0 if ticks == -1 ]
-	PATCH_END
-};
-
-#ifdef ENABLE_SCI32
-// Same signature/patch as above but for SCI32 games with debug line instructions.
-//  Some games use both because different versions were compiled differently.
-static const uint16 sciNarratorLockupLineSignature[] = {
-	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
-	SIG_MAGICDWORD,
-	0x35, 0x3c,                         // ldi 3c
-	0x02,                               // add
-	0x36,                               // push
-	0x81, 0x58,                         // lag 58 [ game time ]
-	0x02,                               // add
-	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time ]
-	0x7e, SIG_ADDTOOFFSET(+2),          // line
-	SIG_END
-};
-
-static const uint16 sciNarratorLockupLinePatch[] = {
-	PATCH_ADDTOOFFSET(+11),
-	0x00,                               // bnot
-	0x31, 0xfb,                         // bnt fb [ set ticks to 0 if ticks == -1 ]
-	PATCH_END
-};
-#endif
-
-// ECO1 CD and SQ4 CD share an early Narrator:say variant
-static const uint16 ecoquest1Sq4CdNarratorLockupSignature[] = {
-	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
-	SIG_MAGICDWORD,
-	0x35, 0x3c,                         // ldi 3c
-	0x02,                               // add
-	0x36,                               // push
-	0x81, 0x58,                         // lag 58 [ game time ]
-	0x02,                               // add
-	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time ]
-	0x63, SIG_ADDTOOFFSET(+1),          // pToa modeless
-	0x18,                               // not
-	0x31, SIG_ADDTOOFFSET(+1),          // bnt [ skip fastCast event handling ]
-	0x81, 0x54,                         // lag 54
-	0x31, SIG_ADDTOOFFSET(+1),          // bnt [ skip fastCast event handling ]
-	0x81, 0x54,                         // lag 54
-	0x31, SIG_ADDTOOFFSET(+1),          // bnt [ skip fastCast event handling ]
-	SIG_END
-};
-
-static const uint16 ecoquest1Sq4CdNarratorLockupPatch[] = {
-	PATCH_ADDTOOFFSET(+11),
-	0x00,                               // bnot
-	0x30, PATCH_UINT16(0xfffa),         // bnt fffa [ set ticks to 0 if ticks == -1 ]
-	0x63, PATCH_GETORIGINALBYTE(+12),   // pToa modeless
-	0x18,                               // not
-	PATCH_END
-};
-
-// Several SCI Version 1 games use a Timer class that doesn't handle kGetTime
-//  rollover correctly. When Timer:set60ths is called with a tick value that
-//  elapses after kGetTime rolls over from 65535 to 0, the timer instantly cues.
-//  The CD versions of KQ5 and Mixed Up Mother Goose set a timer this way when
-//  playing speech that can't be skipped. As rollover approaches every 18
-//  minutes and 12 seconds, these messages can instantly complete and cause
-//  entire scenes to randomly skip. For example, this can happen in KQ5CD's
-//  Harpy and Hermit cutscenes.
-//
-// We fix this by replacing the Timer's tick calculation with the correct logic
-//  that appears in later versions when set60ths was renamed to setTicks.
-//
-// Applies to: Games that use Timer:set60ths
-// Responsible methods: Timer:doit, SpeakTimer:doit in KQ5CD
-static const uint16 sciSignatureTimerRollover[] = {
-	0x67, SIG_ADDTOOFFSET(+1),       // pTos ticksToDo
-	0x63, SIG_ADDTOOFFSET(+1),       // pToa lastTime
-	0x02,                            // add
-	0x36,                            // push
-	0x76,                            // push0
-	SIG_MAGICDWORD,
-	0x43, 0x42, 0x00,                // callk GetTime 00
-	0x2a,                            // ult? [ ticksToDo + lastTime u< kGetTime ]
-	0x2e, SIG_UINT16(0x0013),        // bt 0013
-	0x67, SIG_ADDTOOFFSET(+1),       // pTos lastTime
-	0x76,                            // push0
-	SIG_ADDTOOFFSET(+16),
-	0x30,                            // bnt [ cue client if acc == true ]
-	SIG_END
-};
-
-static const uint16 sciPatchTimerRollover[] = {
-	0x76,                            // push0
-	0x43, 0x42, 0x00,                // callk GetTime 00
-	0x36,                            // push
-	0x67, PATCH_GETORIGINALBYTE(+1), // pTos ticksToDo
-	0x63, PATCH_GETORIGINALBYTE(+3), // pToa lastTime
-	0x02,                            // add
-	0x04,                            // sub
-	0x36,                            // push
-	0x35, 0x00,                      // ldi 00
-	0x1e,                            // gt? [ kGetTime - (ticksToDo + lastTime) > 0 ]
-	0x33, 0x10,                      // jmp 10 [ cue client if acc == true ]
-	PATCH_END
-};
-
-// ===========================================================================
-// Conquests of Camelot
-// At the bazaar in Jerusalem, it's possible to see a girl taking a shower.
-//  If you get too close, you get warned by the father - if you don't get away,
-//  he will kill you.
-// Instead of walking there manually, it's also possible to enter "look window"
-//  and ego will automatically walk to the window. It seems that this is something
-//  that wasn't properly implemented, because instead of getting killed, you will
-//  get an "Oops" message in Sierra SCI.
-//
-// This is caused by peepingTom in script 169 not getting properly initialized.
-// peepingTom calls the object behind global[b9h]. This global variable is
-//  properly initialized when walking there manually (method fawaz::doit).
-// When you instead walk there automatically (method fawaz::handleEvent), that
-//  global isn't initialized, which then results in the Oops-message in Sierra SCI
-//  and an error message in ScummVM/SCI.
-//
-// We fix the script by patching in a jump to the proper code inside fawaz::doit.
-// Responsible method: fawaz::handleEvent
-// Fixes bug: #6402
-static const uint16 camelotSignaturePeepingTom[] = {
-	0x72, SIG_MAGICDWORD, SIG_UINT16(0x077e), // lofsa fawaz <-- start of proper initializion code
-	0xa1, 0xb9,                      // sag global[b9h]
-	SIG_ADDTOOFFSET(+571),           // ...
-	0x39, 0x7a,                      // pushi 7a <-- initialization code when walking automatically
-	0x78,                            // push1
-	0x7a,                            // push2
-	0x38, SIG_UINT16(0x00a9),        // pushi 00a9 - script 169
-	0x78,                            // push1
-	0x43, 0x02, 0x04,                // callk ScriptID
-	0x36,                            // push
-	0x81, 0x00,                      // lag global[0]
-	0x4a, 0x06,                      // send 06
-	0x32, SIG_UINT16(0x0520),        // jmp [end of fawaz::handleEvent]
-	SIG_END
-};
-
-static const uint16 camelotPatchPeepingTom[] = {
-	PATCH_ADDTOOFFSET(+576),
-	0x32, PATCH_UINT16(0xfdbd),      // jmp [to fawaz::doit] (properly init peepingTom code)
-	PATCH_END
-};
-
-// If the butcher's daughter in room 62 closes her window while Arthur interacts
-//  with the relic merchant then the game locks up. The script daughterAppears
-//  attempts to dispose the script peepingTom, but it does so by clearing ego's
-//  script no matter what it is, which breaks the game if the script is buyRelic
-//  or one of the other handsOff merchant scripts.
-//
-// We fix this by calling peepingTom:dispose instead of clearing ego's script.
-//  As this is an earlier SCI game prior to Script:dispose clearing the client
-//  property, we need to do that ourselves in peepingTom:doit when Arthur turns
-//  away from the window, or else peepingTom:client will still point to ego
-//  after disposal, and the subsequent peepingTom:dispose will end ego's script.
-//
-// Applies to: All versions
-// Responsible methods: daughterAppears:changeState(6), peepingTom:doit
-// Fixes bug: #11025
-static const uint16 camelotSignatureRelicMerchantLockup1[] = {
-	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
-	0x78,                               // push1
-	0x76,                               // push0
-	0x81, SIG_MAGICDWORD, 0x00,         // lag 00
-	0x4a, 0x06,                         // send 06 [ ego setScript: 0 ]
-	0x3a,                               // toss
-	SIG_END
-};
-
-static const uint16 camelotPatchRelicMerchantLockup1[] = {
-	0x39, PATCH_SELECTOR8(dispose),     // pushi dispose
-	0x76,                               // push0
-	0x72, PATCH_UINT16(0x01f3),         // lofsa peepingTom
-	0x4a, 0x04,                         // send 04 [ peepingTom dispose: ]
-	PATCH_END
-};
-
-static const uint16 camelotSignatureRelicMerchantLockup2[] = {
-	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
-	0x78,                               // push1
-	0x76,                               // push0
-	0x81, SIG_MAGICDWORD, 0x00,         // lag 00
-	0x4a, 0x06,                         // send 06 [ ego setScript: 0 ]
-	0x48,                               // ret
-	SIG_END
-};
-
-static const uint16 camelotPatchRelicMerchantLockup2[] = {
-	0x39, PATCH_SELECTOR8(dispose),     // pushi dispose
-	0x76,                               // push0
-	0x54, 0x04,                         // self 04 [ self dispose: ]
-	0x76,                               // push0
-	0x69, 0x08,                         // sTop client [ client = 0 ]
-	PATCH_END
-};
-
-// The hunter in room 11 doesn't award soul points if you buy his furs with the
-//  "buy furs" command first and "pay" second. Two points are awarded if these
-//  commands are entered in the opposite order.
-//
-// We fix this by adding the missing function call to award the soul points as
-//  Sierra did in later versions. Fortunately, the GiveMoney script contains
-//  redundant code that can be replaced as it is occurs later in the method.
-//
-// Applies to: PC only
-// Responsible method: GiveMoney:changeState(3)
-// Fixes bug: #11027
-static const uint16 camelotSignatureHunterMissingPoints[] = {
-	SIG_MAGICDWORD,
-	0x30, SIG_UINT16(0x0020),           // bnt 0020 [ matches PC only ]
-	0x35, 0x00,                         // ldi 00
-	0xa3, 0x00,                         // sal 00 [ local0 = 0 ]
-	// unnecessary code which is repeated later in the method
-	0x89, 0xdd,                         // lsg dd
-	0x81, 0x84,                         // lag 84
-	0x02,                               // add
-	0xa1, 0xdd,                         // sag dd [ global221 += global132 ]
-	0x35, 0x00,                         // ldi 00
-	0xa1, 0x84,                         // sag 84 [ global132 = 0 ]
-	SIG_END
-};
-
-static const uint16 camelotPatchHunterMissingPoints[] = {
-	PATCH_ADDTOOFFSET(+7),
-	0x38, PATCH_UINT16(0x0003),         // pushi 0003
-	0x38, PATCH_UINT16(0x00f5),         // pushi 00f5 [ point flag 245 ]
-	0x7a,                               // push2 [ soul points ]
-	0x7a,                               // push2 [ +2 points ]
-	0x45, 0x0a, 0x06,                   // callb proc0_10 06 [ +2 soul points ]
-	PATCH_END
-};
-
-// When giving away the mule in room 56, the merchant's first long message is
-//  immediately replaced by the next. mo:handleEvent displays the first and
-//  starts the script getMule, which proceeds to display its own messages
-//  without waiting.
-//
-// We fix this by adding code to getMule to wait for the merchant's message to
-//  complete if you gave away the mule and a message is on screen.
-//
-// Applies to: All versions
-// Responsible method: getMule:changeState(4)
-// Fixes bug: #11026
-static const uint16 camelotSignatureGiveMuleMessage[] = {
-	0x30, SIG_UINT16(0x0023),           // bnt 0023 [ state 4 ]
-	SIG_ADDTOOFFSET(+0x20),
-	SIG_MAGICDWORD,
-	0x32, SIG_UINT16(0x0239),           // jmp 0239 [ end of method ]
-	0x3c,                               // dup
-	0x35, 0x04,                         // ldi 04
-	0x1a,                               // eq?
-	0x30, SIG_UINT16(0x0016),           // bnt 0016 [ state 5 ]
-	0x83, 0x02,                         // lal 02   [ gave away mule? ]
-	0x30, SIG_UINT16(0x000a),           // bnt 000a [ skip state 14 if mule was sold ]
-	0x39, SIG_SELECTOR8(changeState),   // pushi changeState
-	0x78,                               // push1
-	0x39, 0x0e,                         // pushi 0e
-	0x54, 0x06,                         // self 06 [ self changeState: 14 ]
-	0x32, SIG_UINT16(0x0223),           // jmp 0223 [ end of method ]
-	0x35, 0x01,                         // ldi 01
-	0x65, 0x10,                         // aTop cycles [ cycles = 1 ]
-	0x32, SIG_UINT16(0x021c),           // jmp 021c [ end of method ]
-	SIG_END
-};
-
-static const uint16 camelotPatchGiveMuleMessage[] = {
-	0x30, PATCH_UINT16(0x0020),         // bnt 0020 [ state 4 ]
-	PATCH_ADDTOOFFSET(+0x20),
-	0x3c,                               // dup
-	0x35, 0x04,                         // ldi 04
-	0x1a,                               // eq?
-	0x31, 0x1a,                         // bnt 1a [ state 5 ]
-	0x83, 0x02,                         // lal 02 [ gave away mule? ]
-	0x31, 0x13,                         // bnt 13 [ skip state 14 if mule was sold ]
-	0x35, 0x0d,                         // ldi 0d
-	0x65, 0x0a,                         // aTop state [ state = 13 ]
-	0x38, PATCH_UINT16(0x0121),         // pushi talkCue [ same value in all versions ]
-	0x78,                               // push1
-	0x7c,                               // pushSelf
-	0x38, PATCH_UINT16(0x0122),         // pushi tS1 [ same value in all versions ]
-	0x76,                               // push0
-	0x81, 0x6f,                         // lag 6f
-	0x4a, 0x0a,                         // send 0a [ tObj talkCue: self tS1? ]
-	0x2f, 0x03,                         // bt 03   [ don't set cycles if message on screen ]
-	0x78,                               // push1
-	0x69, 0x10,                         // sTop cycles [ cycles = 1 ]
-	PATCH_END
-};
-
-// In Fatima's house in room 64, "look room" and "look trap" respond with the
-//  wrong messages due to testing the wrong flag. Flag 162 is set when falling
-//  through the trap door and alters responses the next time in the room, but
-//  the script tests flag 137 instead, which is set when entering the room.
-//
-// Sierra fixed the first flag test in Amiga and Atari ST but not the second, so
-//  this patch is applied only once to those versions and twice to PC.
-//
-// Applies to: All versions
-// Responsible method: Rm64:handleEvent
-// Fixes bug: #11028
-static const uint16 camelotSignatureFatimaRoomMessages[] = {
-	0x78,                               // push1
-	0x38, SIG_MAGICDWORD,               // pushi 0089 [ flag 137, always true ]
-	      SIG_UINT16(0x0089),
-	0x45, 0x09, 0x02,                   // callb proc0_9 02 [ is flag 137 set? ]
-	SIG_END
-};
-
-static const uint16 camelotPatchFatimaRoomMessages[] = {
-	PATCH_ADDTOOFFSET(+1),
-	0x38, PATCH_UINT16(0x00a2),         // pushi 00a2 [ flag 162, set by trap ]
-	PATCH_END
-};
-
-// Sheathing the sword by pressing F8 while entering or exiting a room breaks
-//  the game by placing ego in an invalid state that allows walking through
-//  obstacles and prevents room changes. This affects rooms that subclass eRoom
-//  in areas that allow walking with sword drawn such as the monk's ruins and
-//  the desert. This is most likely to occur while battling the monk.
-//
-// eRoom walks ego in and out of rooms in handsOff mode. It sets ego:illegalBits
-//  to 0, enables ignoreActors, and sets a motion that cues when complete to
-//  restore ego's properties. Sheathing the sword interrupts the motion, which
-//  prevents eRoom:cue, and prematurely restores control to the user with ego in
-//  the temporary state. There are almost no restrictions on sheathing because
-//  it's used when input is disabled and during several handsOff scenes.
-//
-// We fix this by preventing sword scripts from starting when an eRoom is in the
-//  middle of controlling ego. eRoom tracks this with the comingIn and goingOut
-//  properties and we require that both be cleared to execute a sword command.
-//
-// Applies to: All versions
-// Responsible method: ARTHUR:doit
-// Fixes bug: #11042
-static const uint16 camelotSignatureSwordSheathing[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x7d,                         // lsg 7d [ sword-command ]
-	0x3c,                               // dup
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq? [ sword-command == 1 (draw) ]
-	0x30, SIG_UINT16(0x0013),           // bnt 0013
-	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
-	0x78,                               // push1
-	0x7a,                               // push2
-	0x38, SIG_UINT16(0x038e),           // pushi 910d
-	0x76,                               // push0
-	0x43, 0x02, 0x04,                   // callk ScriptID 04 [ ScriptID 910 0 (DrawSword) ]
-	0x36,                               // push
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x06,                         // send 06 [ ego setScript: DrawSword ]
-	0x32, SIG_UINT16(0x0085),           // jmp 0085 [ end of switch ]
-	0x3c,                               // dup
-	0x35, 0x02,                         // ldi 02
-	0x1a,                               // eq? [ sword-command == 2 (sheathe) ]
-	0x30, SIG_UINT16(0x0013),           // bnt 0013
-	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
-	0x78,                               // push1
-	0x7a,                               // push2
-	0x38, SIG_UINT16(0x038e),           // pushi 910d
-	0x78,                               // push1
-	0x43, 0x02, 0x04,                   // callk ScriptID 04 [ ScriptID 910 1 (SheatheSword) ]
-	0x36,                               // push
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x06,                         // send 06 [ ego setScript: SheatheSword ]
-	0x32, SIG_UINT16(0x006b),           // jmp 006b [ end of switch ]
-	0x3c,                               // dup
-	0x35, 0x03,                         // ldi 03
-	0x1a,                               // eq? [ sword-command == 3 (parry) ]
-	0x30, SIG_UINT16(0x0013),           // bnt 0013
-	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
-	0x78,                               // push1
-	0x7a,                               // push2
-	0x38, SIG_UINT16(0x0390),           // pushi 912d
-	0x78,                               // push1
-	0x43, 0x02, 0x04,                   // callk ScriptID 04 [ ScriptID 912 1 (DoParry) ]
-	SIG_ADDTOOFFSET(+15),
-	0x81, 0x7c,                         // lag 7c [ start of sword-command == 0 handler ]
-	SIG_ADDTOOFFSET(+72),
-	0x3a,                               // toss [ end of switch ]
-	SIG_END
-};
-
-static const uint16 camelotPatchSwordSheathing[] = {
-	0x81, 0x7d,                         // lag 7d [ sword-command ]
-	0x31, 0x53,                         // bnt 53 [ sword-command == 0 handler ]
-	0x39, 0x03,                         // pushi 03
-	0x20,                               // ge? [ 3 >= sword-command ]
-	0x31, 0x3e,                         // bnt 3e [ exit if sword-command > 3 ]
-	0x7a,                               // push2
-	0x89, 0x02,                         // lsg 02
-	0x38, PATCH_UINT16(0x014b),         // pushi comingIn [ same value in all versions ]
-	0x43, 0x07, 0x04,                   // callk RespondsTo 04 [ RespondsTo currentRoom comingIn ]
-	0x31, 0x14,                         // bnt 14 [ skip eRoom checks if room isn't an eRoom ]
-	0x38, PATCH_UINT16(0x014b),         // pushi comingIn
-	0x76,                               // push0
-	0x81, 0x02,                         // lag 02
-	0x4a, 0x04,                         // send 04 [ currentRoom comingIn? ]
-	0x2f, 0x29,                         // bt 29   [ skip sword scripts if entering room ]
-	0x38, PATCH_UINT16(0x014c),         // pushi goingOut [ same value in all versions ]
-	0x76,                               // push0
-	0x81, 0x02,                         // lag 02
-	0x4a, 0x04,                         // send 04 [ currentRoom goingOut? ]
-	0x2f, 0x1f,                         // bt 1f   [ skip sword scripts if exiting room ]
-	0x39, PATCH_SELECTOR8(setScript),   // pushi setScript
-	0x78,                               // push1
-	0x7a,                               // push2
-	0x81, 0x7d,                         // lag 7d
-	0x7a,                               // push2
-	0x20,                               // ge? [ 2 >= sword-command ]
-	0x31, 0x05,                         // bnt 05
-	0x38, PATCH_UINT16(0x038e),         // pushi 910d
-	0x33, 0x03,                         // jmp 03
-	0x38, PATCH_UINT16(0x0390),         // pushi 912d
-	0x81, 0x7d,                         // lag 7d
-	0x78,                               // push1
-	0x1c,                               // ne? [ sword-command != 1 ]
-	0x36,                               // push
-	0x43, 0x02, 0x04,                   // callk ScriptID 04 [ ScriptID (sword-command <= 2) ? 910 : 912, (sword-command != 1) ]
-	0x36,                               // push
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x06,                         // send 06 [ ego setScript: sword-script ]
-	0x48,                               // ret
-	PATCH_ADDTOOFFSET(+89),
-	0x48,                               // ret [ remove toss since dup instructions were removed ]
-	PATCH_END
-};
-
-// When Arthur's sword is drawn, ARTHUR:doit calls kGetEvent a second time on
-//  each cycle to test if a shift key is pressed, causing input events to be
-//  frequently dropped. This is similar to Freddy Pharkas and QFG1VGA where this
-//  technique just happened to usually work in Sierra's interpreter. We fix this
-//  in the same way by using the current event instead of consuming a new one.
-//
-// Applies to: All versions
-// Responsible method: ARTHUR:doit
-// Fixes bug: #11269
-static const uint16 camelotSignatureSwordEvents[] = {
-	0x30, SIG_MAGICDWORD,               // bnt 0045
-	      SIG_UINT16(0x0045),
-	0x39, SIG_SELECTOR8(new),           // pushi new
-	0x76,                               // push0
-	0x51, 0x07,                         // class Event
-	0x4a, 0x04,                         // send 04 [ Event new: ]
-	0xa5, 0x01,                         // sat 01 [ temp1 = Event new: ]
-	SIG_ADDTOOFFSET(+53),
-	0x39, SIG_SELECTOR8(dispose),       // pushi dispose
-	0x76,                               // push0
-	0x85, 0x01,                         // lat 01
-	0x4a, 0x04,                         // send 04 [ temp1 dispose: ]
-	SIG_END
-};
-
-static const uint16 camelotPatchSwordEvents[] = {
-	0x31, 0x46,                         // bnt 46
-	0x38, PATCH_SELECTOR16(curEvent),   // pushi curEvent
-	0x76,                               // push0
-	0x51, 0x30,                         // class User [ User: curEvent ]
-	PATCH_ADDTOOFFSET(+57),
-	0x33, 0x05,                         // jmp 05 [ don't dispose event ]
-	PATCH_END
-};
-
-//         script, description,                                       signature                             patch
-static const SciScriptPatcherEntry camelotSignatures[] = {
-	{ true,     0, "fix sword sheathing",                          1, camelotSignatureSwordSheathing,       camelotPatchSwordSheathing },
-	{ true,     0, "fix sword events",                             1, camelotSignatureSwordEvents,          camelotPatchSwordEvents },
-	{ true,    11, "fix hunter missing points",                    1, camelotSignatureHunterMissingPoints,  camelotPatchHunterMissingPoints },
-	{ true,    62, "fix peepingTom Sierra bug",                    1, camelotSignaturePeepingTom,           camelotPatchPeepingTom },
-	{ true,    64, "fix Fatima room messages",                     2, camelotSignatureFatimaRoomMessages,   camelotPatchFatimaRoomMessages },
-	{ true,   112, "disable speed test",                           1, sci01SpeedTestLocalSignature,         sci01SpeedTestLocalPatch },
-	{ true,   158, "fix give mule message",                        1, camelotSignatureGiveMuleMessage,      camelotPatchGiveMuleMessage },
-	{ true,   169, "fix relic merchant lockup (1/2)",              1, camelotSignatureRelicMerchantLockup1, camelotPatchRelicMerchantLockup1 },
-	{ true,   169, "fix relic merchant lockup (2/2)",              1, camelotSignatureRelicMerchantLockup2, camelotPatchRelicMerchantLockup2 },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// Castle of Dr. Brain
-
-//          script, description,                                      signature                                 patch
-static const SciScriptPatcherEntry castleBrainSignatures[] = {
-	{  true,   802, "disable speed test",                          1, sci01SpeedTestGlobalSignature,            sci01SpeedTestGlobalPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// stayAndHelp::changeState (0) is called when ego swims to the left or right
-//  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
-// Applies to at least: PC-CD
-// Responsible method: stayAndHelp::changeState
-// Fixes bug: #5107
-static 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 [export 1 of script 0], 00 (switching control off)
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x0122),        // pushi 0122
-	0x78,                            // push1
-	0x76,                            // push0
-	0x81, 0x00,                      // lag global[0]
-	0x4a, 0x06,                      // send 06 - call ego::setMotion(0)
-	0x39, SIG_SELECTOR8(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
-};
-
-static 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 [export 1 of script 0], 00 (switching control off)
-	0x38, PATCH_UINT16(0x0122),      // pushi 0122
-	0x78,                            // push1
-	0x76,                            // push0
-	0x81, 0x00,                      // lag global[0]
-	0x4a, 0x06,                      // send 06 - call ego::setMotion(0)
-	0x39, PATCH_SELECTOR8(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(0x0280),      // pushi 280 (additional 3 bytes)
-	0x51, 0x82,                      // class EcoNarrator
-	0x4a, 0x10,                      // send 10 - call EcoNarrator::init(2, 0, 0, 23, self, 640)
-	PATCH_END
-};
-
-// Giving the oily shell to Superfluous when he's out of the mask runs the
-//  wrong animation and skips messages in the CD version. Sierra modified
-//  getInOilyShell for the CD version by adding a new state to the beginning
-//  but forgot to increment the state numbers passed to self:changeState to
-//  their new values, causing the script to change to the wrong states.
-//
-// We fix this by incrementing the state numbers passed to self:changeState.
-//
-// Applies to: PC CD
-// Responsible method: getInOilyShell:changeState
-// Fixes bug #10881
-static const uint16 ecoquest1SignatureGiveOilyShell[] = {
-	0x30, SIG_UINT16(0x000a),       // bnt 000a
-	0x38, SIG_UINT16(0x0090),       // pushi changeState [ hard coded for CD ]
-	0x78,                           // push1
-	0x7a,                           // push2 [ state 2 ]
-	0x54, SIG_MAGICDWORD, 0x06,     // self 06
-	0x32, SIG_UINT16(0x0195),       // jmp 0195
-	SIG_ADDTOOFFSET(+209),
-	0x39, 0x08,                     // pushi 08 [ state 8 ]
-	SIG_ADDTOOFFSET(+16),
-	0x39, 0x0b,                     // pushi 0b [ state 11 ]
-	SIG_END
-};
-
-static const uint16 ecoquest1PatchGiveOilyShell[] = {
-	0x31, 0x0b,                     // bnt 0b
-	0x38, PATCH_UINT16(0x0090),     // pushi changeState [ hard coded for CD ]
-	0x78,                           // push1
-	0x39, 0x03,                     // pushi 03 [ state 3 ]
-	PATCH_ADDTOOFFSET(+214),
-	0x39, 0x09,                     // pushi 09 [ state 9 ]
-	PATCH_ADDTOOFFSET(+16),
-	0x39, 0x0c,                     // pushi 0c [ state 12 ]
-	PATCH_END
-};
-
-// Reading the prophecy scroll in the CD version breaks messages in at least
-//  rooms 100 and 120. scrollScript:init overwrites the global that holds the
-//  noun for the room's message tuples. This global was added in the CD version
-//  and is set by most rooms during initialization. This pattern was mistakenly
-//  applied to scrollScript which isn't a room and doesn't depend on the global.
-//
-// We fix this by skipping the problematic code which overwrites the global.
-//
-// Applies to: PC CD
-// Responsible method: scrollScript:init
-// Fixes bug #10883
-static const uint16 ecoquest1SignatureProphecyScroll[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x01,                     // ldi 01
-	0xa1, 0xfa,                     // sag fa [ global250 = 1 ]
-	SIG_END
-};
-
-static const uint16 ecoquest1PatchProphecyScroll[] = {
-	0x33, 0x02,                     // jmp 02 [ don't set global250 ]
-	PATCH_END
-};
-
-// The empty apartments have several broken messages in the CD version due to
-//  not setting the global that holds the current room's noun, so we set it.
-//
-// Applies to: PC CD
-// Responsible method: rm220:init
-// Fixes bug #10903
-static const uint16 ecoquest1SignatureEmptyApartmentMessages[] = {
-	SIG_MAGICDWORD,
-	0x54, 0x0c,                     // self 0c [ self setRegions: 51, addObstacle: ... ]
-	0x39, SIG_SELECTOR8(init),      // pushi init
-	0x76,                           // push0
-	0x59, 0x01,                     // &rest 01 [ unused by ApartmentRoom:init ]
-	0x57, 0x96, 0x04,               // super ApartmentRoom 04 [ super init: &rest ]
-	SIG_END
-};
-
-static const uint16 ecoquest1PatchEmptyApartmentMessages[] = {
-	0x35, 0x01,                     // ldi 01 [ the room's noun ]
-	PATCH_ADDTOOFFSET(+3),
-	0xa1, 0xfa,                     // sag fa [ global250 = 1 ]
-	0x57, 0x96, 0x10,               // super ApartmentRoom 10 [ combine self and super ]
-	PATCH_END
-};
-
-// The temple has a complex script bug in the CD version which can crash the
-//  interpreter when solving the mosaic puzzle after loading a game that was
-//  saved during the puzzle. The bug causes invalid memory access which locks up
-//  Sierra's interpreter and can cause ours to fail an assertion.
-//
-// Room 140 has three insets and a conch shell in the middle. This room's script
-//  was significantly changed in the CD version and transition animations were
-//  added. Due to these changes the shell no longer renders beneath the insets
-//  and so Sierra added code to hide the shell while they're displayed.
-//  Unfortunately this code is incorrect and leaves the game in a state that's
-//  unsafe to save. The shell is removed from the cast when showing an inset and
-//  then shell:init is called when hiding. This leaves shell:underBits pointing
-//  to hunk memory while temporarily not a member of the cast. Hunk memory isn't
-//  persisted in saved games but underBits' values are. SCI games handle this in
-//  Game:replay by clearing the underBits of cast members when restoring. Saving
-//  while the puzzle is displayed causes shell:underBits' stale hunk value to
-//  survive restoring. Solving the puzzle adds the shell back to the cast via
-//  init followed by a call to kAnimate that accesses the potentially stale
-//  shell:underBits. If the hunk segment id upon restoring in ScummVM is the
-//  same as when saved then this out of bounds access will fail an assertion.
-//
-// We fix this by fully disposing the shell when showing an inset so that its
-//  resources are cleaned up and it's safe to save the game. In order to do this
-//  without changing the animation effect we set shell's disposal flag and then
-//  immediately call shell:delete. This is equivalent to shell:dispose but
-//  prevents hiding the shell before the transition animation takes place.
-//
-// Applies to: PC CD
-// Responsible methods: MosaicWall:doVerb, localproc_2ab6 in script 140
-// Fixes bug #10884
-static const uint16 ecoquest1SignatureMosaicPuzzleFix[] = {
-	0x36,                           // push     [ conchShell:owner ]
-	0x34, SIG_UINT16(0x008c),       // ldi 008c [ room number ]
-	0x1a,                           // eq?      [ is conchShell owned by room 140? ]
-	0x30, SIG_UINT16(0x000b),       // bnt 000b [ no shell to hide ]
-	SIG_MAGICDWORD,
-	0x39, SIG_SELECTOR8(delete),    // pushi delete
-	0x78,                           // push1
-	0x72, SIG_UINT16(0x056a),       // lofsa shell
-	0x36,                           // push
-	0x81, 0x05,                     // lag 05
-	0x4a, 0x06,                     // send 06 [ cast delete: shell ]
-	SIG_END
-};
-
-static const uint16 ecoquest1PatchMosaicPuzzleFix[] = {
-	0x89, 0x0b,                     // lsg 0b [ current room number, saves 2 bytes ]
-	0x1a,                           // eq?    [ is conchShell owned by room 140? ]
-	0x31, 0x0e,                     // bnt 0e [ no shell to hide, save a byte ]
-	0x39, PATCH_SELECTOR8(signal),  // pushi signal
-	0x78,                           // push1
-	0x38, PATCH_UINT16(0xc014),     // pushi c014 [ kSignalDisposeMe | shell:signal ]
-	0x39, PATCH_SELECTOR8(delete),  // pushi delete
-	0x76,                           // push0
-	0x72, PATCH_UINT16(0x056a),     // lofsa shell
-	0x4a, 0x0a,                     // send 0a [ shell signal: c014, delete ]
-	PATCH_END
-};
-
-// The column puzzle in room 160 can be put in a state that can't be completed.
-//  This is a bug in the original that affects all versions.
-//
-// The puzzle consists of nine columns that must be rotated to their correct
-//  positions in the correct order. As each column is solved it is locked. When
-//  leaving the room the puzzle state is saved to globals but this state is
-//  insufficient to recreate the puzzle. The game saves column positions but not
-//  lock states. Instead it infers lock states from positions when restoring but
-//  this is inaccurate because columns can be put in their correct positions out
-//  of order. If the player leaves the room while all columns are in their
-//  correct positions but before the puzzle is solved then all columns will be
-//  locked when returning and the game can't be completed.
-//
-// The proper solution would be to save and restore lock states but it would be
-//  impractical to patch in that functionality while retaining save game
-//  compatibility. Instead we patch the loop that reinitializes lock states to
-//  skip the last column so that it's always unlocked and the player can't get
-//  stuck. This code only runs when the puzzle isn't solved and should never
-//  have been able to lock the last column.
-//
-// Applies to: All Floppy and CD versions
-// Responsible method: Local procedure 5 in script 160
-// Fixes bug #10885
-static const uint16 ecoquest1SignatureColumnPuzzleFix[] = {
-	0x39, SIG_SELECTOR8(size),      // pushi size
-	0x76,                           // push0
-	0x72, SIG_ADDTOOFFSET(+2),      // lofsa columnList [ columns in solution order ]
-	0x4a, 0x04,                     // send 04 [ columnList:size ]
-	0x22,                           // lt? [ temp0 < columnList:size (9) ]
-	0x30, SIG_ADDTOOFFSET(+2),      // bnt [ end of method ]
-	0x39, SIG_MAGICDWORD,           // pushi cel
-	      SIG_SELECTOR8(cel),
-	0x76,                           // push0
-	0x39, SIG_SELECTOR8(at),        // pushi at
-	SIG_END
-};
-
-static const uint16 ecoquest1PatchColumnPuzzleFix[] = {
-	0x34, PATCH_UINT16(0x0008),     // ldi 0008 [ only initialize 8 of 9 columns ]
-	0x32, PATCH_UINT16(0x0002),     // jmp 0002
-	PATCH_END
-};
-
-// The ocean cliffs that border rooms 320 and 321 aren't displayed in the CD
-//  version. Instead they are drawn above the visible area and on more screens
-//  than they should. This also occurs in the original.
-//
-// Cliff views 325 and 326 have y displacements greater than 127 in the floppy
-//  versions. In the CD version these offsets were changed to zero. Sierra
-//  attempted to compensate for this by adding rows of empty pixels to the views
-//  but it appears that someone mistook the unsigned offsets for negative values
-//  and added the wrong number of rows to the wrong side of the views, causing
-//  the cliffs to be drawn 256 pixels higher than normal.
-//
-// The ocean scripts were changed to use different techniques for adding and
-//  removing the cliffs but this introduced more errors. Room 321 reinitializes
-//  the cliffs instead of disposing them, causing them to be redrawn on the
-//  wrong screens, and room 320 disposes the eastern cliffs instead of western.
-//
-// We fix the cliffs by adjusting their positions by 256 and disposing of them
-//  in room 321. We leave room 320's incorrect cliff disposal in place since
-//  both are automatically disposed of when that room's pic changes.
-//
-// Applies to: PC CD
-// Responsible methods: Heap in scripts 320 and 321, toEast:changeState, toWest:changeState
-// Fixes bug #10893
-static const uint16 ecoquest1SignatureSouthCliffsPosition[] = {
-	SIG_MAGICDWORD,
-	SIG_UINT16(0x0095),             // easternCliffs:x = 149
-	SIG_UINT16(0x0033),             // easternCliffs:y = 51
-	SIG_ADDTOOFFSET(+88),
-	SIG_UINT16(0x0004),             // westernCliffs:x = 4
-	SIG_UINT16(0x0014),             // westernCliffs:y = 20
-	SIG_END
-};
-
-static const uint16 ecoquest1PatchSouthCliffsPosition[] = {
-	PATCH_ADDTOOFFSET(+2),
-	PATCH_UINT16(0x0133),           // easternCliffs:y = 307
-	PATCH_ADDTOOFFSET(+90),
-	PATCH_UINT16(0x0114),           // westernCliffs:y = 276
-	PATCH_END
-};
-
-static const uint16 ecoquest1SignatureNorthCliffsPosition[] = {
-	SIG_MAGICDWORD,
-	SIG_UINT16(0x00eb),             // easternCliffs:x = 236
-	SIG_UINT16(0x0038),             // easternCliffs:y = 56
-	SIG_ADDTOOFFSET(+88),
-	SIG_UINT16(0x0000),             // westernCliffs:x = 0
-	SIG_UINT16(0x0032),             // westernCliffs:y = 50
-	SIG_END
-};
-
-static const uint16 ecoquest1PatchNorthCliffsPosition[] = {
-	PATCH_ADDTOOFFSET(+2),
-	PATCH_UINT16(0x0138),           // easternCliffs:y = 312
-	PATCH_ADDTOOFFSET(+90),
-	PATCH_UINT16(0x0132),           // westernCliffs:y = 306
-	PATCH_END
-};
-
-static const uint16 ecoquest1SignatureNorthCliffsDisposal[] = {
-	0x39, SIG_SELECTOR8(init),          // pushi init
-	0x76,                               // push0
-	0x72, SIG_ADDTOOFFSET(+2),          // lofsa easternCliffs or westernCliffs
-	0x4a, SIG_MAGICDWORD, 0x04,         // send 04 [ cliffs init: ]
-	0x38, SIG_SELECTOR16(obstacles),    // pushi obstacles
-	SIG_END
-};
-
-static const uint16 ecoquest1PatchNorthCliffsDisposal[] = {
-	0x39, PATCH_SELECTOR8(dispose),     // pushi dispose
-	PATCH_END
-};
-
-// The Spanish version of EcoQuest accidentally shipped with temporary test code
-//  that breaks the game when entering Olympia's apartment. (room 226)
-//
-// A message box's position was localized in the Spanish version. This message
-//  occurs after saving Olympia by pumping bleach out of the window. To test
-//  this change, a developer added code to forcibly run the usePump script upon
-//  entering the room, but then forgot to remove it. This breaks the puzzle and
-//  locks up the game upon re-entering the room.
-//
-// We fix this by disabling the test code that should not have been shipped.
-//
-// Applies to: Spanish PC Floppy
-// Responsible method: rm226:init
-// Fixes bug #10900
-static const uint16 ecoquest1SignatureBleachPumpTest[] = {
-	SIG_MAGICDWORD,
-	0x78,                               // push1
-	0x39, 0x35,                         // pushi 35
-	0x46, SIG_UINT16(0x0333),           // calle proc819_3 [ set recycled-bleach flag ]
-	      SIG_UINT16(0x0003), 0x02,
-	0x38, SIG_SELECTOR16(setScript),    // pushi setScript
-	0x78,                               // push1
-	0x72, SIG_UINT16(0x0a44),           // lofsa usePump
-	0x36,                               // push
-	0x54, 0x06,                         // self 06 [ self setScript: usePump ]
-	SIG_END
-};
-
-static const uint16 ecoquest1PatchBleachPumpTest[] = {
-	0x32, PATCH_UINT16(0x0010),         // jmp 0010 [ skip test code ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                                 patch
-static const SciScriptPatcherEntry ecoquest1Signatures[] = {
-	{  true,   140, "CD: mosaic puzzle fix",                       2, ecoquest1SignatureMosaicPuzzleFix,        ecoquest1PatchMosaicPuzzleFix },
-	{  true,   160, "CD: give superfluous oily shell",             1, ecoquest1SignatureGiveOilyShell,          ecoquest1PatchGiveOilyShell },
-	{  true,   160, "CD/Floppy: column puzzle fix",                1, ecoquest1SignatureColumnPuzzleFix,        ecoquest1PatchColumnPuzzleFix },
-	{  true,   220, "CD: empty apartment messages",                1, ecoquest1SignatureEmptyApartmentMessages, ecoquest1PatchEmptyApartmentMessages },
-	{  true,   226, "Spanish: disable bleach pump test",           1, ecoquest1SignatureBleachPumpTest,         ecoquest1PatchBleachPumpTest },
-	{  true,   320, "CD: south cliffs position",                   1, ecoquest1SignatureSouthCliffsPosition,    ecoquest1PatchSouthCliffsPosition },
-	{  true,   321, "CD: north cliffs position",                   1, ecoquest1SignatureNorthCliffsPosition,    ecoquest1PatchNorthCliffsPosition },
-	{  true,   321, "CD: north cliffs disposal",                   2, ecoquest1SignatureNorthCliffsDisposal,    ecoquest1PatchNorthCliffsDisposal },
-	{  true,   660, "CD: bad messagebox and freeze",               1, ecoquest1SignatureStayAndHelp,            ecoquest1PatchStayAndHelp },
-	{  true,   803, "disable speed test",                          1, sci01SpeedTestGlobalSignature,            sci01SpeedTestGlobalPatch },
-	{  true,   816, "CD: prophecy scroll",                         1, ecoquest1SignatureProphecyScroll,         ecoquest1PatchProphecyScroll },
-	{  true,   928, "CD: EcoTalker lockup fix",                    1, ecoquest1Sq4CdNarratorLockupSignature,    ecoquest1Sq4CdNarratorLockupPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// When the Ecorder is turned on and displays its initial welcome text, the
-//  doMyThing script stores the string in temporary space in one state and then
-//  accesses it in a later state. This worked in Sierra's interpreter by
-//  accident. We reset temporary space every time.
-//
-// We fix this by storing the string in local space instead of temporary space.
-//  Script 50 has 200 bytes of local space reserved for a local procedure to
-//  use as temporary string space so we use that.
-//
-// Applies to: All versions
-// Responsible method: doMyThing:changeState
-// Fixes bug: #4993
-static const uint16 ecoquest2SignatureEcorder[] = {
-	SIG_MAGICDWORD,
-	0x5b, 0x04, 0x1e,                // lea 04 1e [ @temp30 ]
-	0x36,                            // push
-	SIG_END
-};
-
-static const uint16 ecoquest2PatchEcorder[] = {
-	0x5b, 0x02, 0x10,                // lea 02 10 [ @local16 ]
-	PATCH_END
-};
-
-// This is the same Ecorder patch as above, but it's for the introduction when
-//  you're given the Ecorder. The showEcorder script has the same bug and we
-//  fix it the same way by using local space instead of temporary space.
-//
-// Applies to: All versions
-// Responsible method: showEcorder:changeState
-// Fixes bug: #5467
-static const uint16 ecoquest2SignatureEcorderTutorial[] = {
-	SIG_MAGICDWORD,
-	0x5b, 0x04, 0x1f,                // lea 04 1f [ @temp31 ]
-	0x36,                            // push
-	SIG_END
-};
-
-static const uint16 ecoquest2PatchEcorderTutorial[] = {
-	0x5b, 0x02, 0x02,                // lea 02 02 [ @local2 ]
-	PATCH_END
-};
-
-// Clicking an icon during the icon bar tutorial in room 100 sends messages to
-//  an uninitialized temporary variable. This is supposed to be the dispatched
-//  Event object that's passed around earlier in the call stack. In Sierra's
-//  interpreter that's what happened to be at this location and it worked.
-//
-// We fix this by using the global variable that stores the current Event object
-//  instead of the uninitialized temp variable that accidentally points to it.
-//  User:handleEvent sets this global before dispatching an event.
-//
-// Applies to: All versions
-// Responsible methods: iconWalk:select, iconLook:select, ...
-// Fixes bug: #11081
-static const uint16 ecoquest2SignatureIconBarTutorial[] = {
-	0x7a,                               // push2
-	0x38, SIG_SELECTOR16(handleEvent),  // pushi handleEvent
-	SIG_MAGICDWORD,
-	0x8d, 0x01,                         // lst 01  [ uninitialized ]
-	0x4a, 0x08,                         // send 08 [ EventHandler firstTrue: handleEvent temp1 ]
-	SIG_END
-};
-
-static const uint16 ecoquest2PatchIconBarTutorial[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x89, 0x18,                         // lsg 18 [ current event ]
-	PATCH_END
-};
-
-// The electronic organizer and password paper reappear in room 500 after they
-//  fall into the water when entering the canoe. rm500:init only tests if these
-//  items are in inventory. It should have also tested the canoe flag like room
-//  530 does to prevent the vacuum from reappearing.
-//
-// We fix this by only adding an item to the room if its InvI:owner is zero.
-//  This is initially zero, then set to ego when getting an item, and finally
-//  set to negative one when the item is removed from inventory.
-//
-// Applies to: All versions
-// Responsible method: rm500:init
-// Fixes bug: #11135
-static const uint16 ecoquest2SignatureRoom500Items[] = {
-	0x38, SIG_ADDTOOFFSET(+2),          // pushi test
-	0x78,                               // push1
-	SIG_MAGICDWORD,
-	0x39, 0x0b,                         // pushi 0b
-	0x81, 0x96,                         // lag 96
-	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 11 ]
-	0xa5, 0x00,                         // sat 00
-	0x38, SIG_ADDTOOFFSET(+2),          // pushi test
-	0x78,                               // push1
-	0x39, 0x04,                         // pushi 04
-	0x81, 0x96,                         // lag 96
-	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 4 ]
-	0xa5, 0x01,                         // sat 01
-	0x38, SIG_ADDTOOFFSET(+2),          // pushi test
-	0x78,                               // push1
-	0x39, 0x17,                         // pushi 17
-	0x81, 0x96,                         // lag 96
-	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 23 ]
-	0xa5, 0x02,                         // sat 02
-	0x38, SIG_ADDTOOFFSET(+2),          // pushi test
-	SIG_ADDTOOFFSET(+636),
-	0x38, SIG_SELECTOR16(has),          // pushi has
-	0x78,                               // push1
-	0x39, 0x15,                         // pushi 15
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x06,                         // send 06 [ ego has: 21 ]
-	0x18,                               // not
-	0x31, 0x13,                         // bnt 13 [ don't initialize theOrganizer ]
-	SIG_ADDTOOFFSET(+236),
-	0x38, SIG_SELECTOR16(has),          // pushi has
-	0x78,                               // push1
-	0x39, 0x0b,                         // pushi 0b
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x06,                         // send 06 [ ego has: 11 ]
-	0x18,                               // not
-	0x30, SIG_UINT16(0x0058),           // bnt 0058 [ don't initialize paper ]
-	SIG_END
-};
-
-static const uint16 ecoquest2PatchRoom500Items[] = {
-	0x39, PATCH_SELECTOR8(at),          // pushi at
-	0x3c,                               // dup [ push at, saves 1 byte ]
-	0x78,                               // push1
-	0x39, 0x15,                         // pushi 15
-	0x38, PATCH_GETORIGINALUINT16(+1),  // pushi test
-	0x3c,                               // dup [ push test, saves 2 bytes ]
-	0x3c,                               // dup [ push test, saves 2 bytes ]
-	0x3c,                               // dup [ push test, saves 2 bytes ]
-	0x78,                               // push1
-	0x39, 0x0b,                         // pushi 0b
-	0x81, 0x96,                         // lag 96
-	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 11 ]
-	0xa5, 0x00,                         // sat 00
-	0x78,                               // push1
-	0x39, 0x04,                         // pushi 04
-	0x81, 0x96,                         // lag 96
-	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 4 ]
-	0xa5, 0x01,                         // sat 01
-	0x78,                               // push1
-	0x39, 0x17,                         // pushi 17
-	0x81, 0x96,                         // lag 96
-	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 23 ]
-	0xa5, 0x02,                         // sat 02
-	PATCH_ADDTOOFFSET(+636),
-	0x81, 0x09,                         // lag 09
-	0x4a, 0x06,                         // send 06 [ Inv at: 21 ]
-	0x38, PATCH_SELECTOR16(owner),      // pushi owner
-	0x76,                               // push0
-	0x4a, 0x04,                         // send 04 [ organizer owner? ]
-	0x78,                               // push1
-	0x2f, 0x13,                         // bt 13 [ don't initialize theOrganizer ]
-	PATCH_ADDTOOFFSET(+236),
-	0x39, 0x0b,                         // pushi 0b
-	0x81, 0x09,                         // lag 09
-	0x4a, 0x06,                         // send 06 [ Inv at: 11 ]
-	0x38, PATCH_SELECTOR16(owner),      // pushi owner
-	0x76,                               // push0
-	0x4a, 0x04,                         // send 04 [ password owner? ]
-	0x2f, 0x58,                         // bt 58 [ don't initialize paper ]
-	PATCH_END
-};
-
-// The Ecorder cursor only highlights over one of the four Victoria lilies, even
-//  though they all respond to Ecorder clicks. Each lily has a doit method that
-//  highlights the cursor but three of them never execute because they are
-//  added to the room pic. This removes them from the cast and prevents doit.
-//
-// We fix this by removing the addToPic calls so the lilies remain in the cast.
-//
-// Applies to: All versions
-// Responsible methods: lilly1:init, lilly2:init, lilly3:init
-// Fixes bug: #5552
-static const uint16 ecoquest2SignatureEcorderLily[] = {
-	0x38, SIG_MAGICDWORD,               // pushi addToPic
-	      SIG_SELECTOR16(addToPic),
-	0x76,                               // push0
-	0x54, 0x04,                         // self 04 [ self addToPic: ]
-	SIG_END
-};
-
-static const uint16 ecoquest2PatchEcorderLily[] = {
-	0x32, PATCH_UINT16(0x0003),         // jmp 0003
-	PATCH_END
-};
-
-// Objects that you can hide behind in rooms 530 and 560 all have messages that
-//  are supposed to display when clicking Do after Gonzales leaves camp, but
-//  their doVerb methods are missing a call to super:doVerb. We fix this by
-//  patching the doVerb methods to call super:doVerb instead of doing nothing.
-//
-// Applies to: All versions
-// Responsible methods: crates:doVerb, barrel1-4:doVerb, refuse:doVerb in 530,
-//  bullldozer:doVerb, barrel1-5:doVerb, crates:doVerb in 560
-static const uint16 ecoquest2SignatureCampMessages1[] = {
-	0x30, SIG_UINT16(0x0033),           // bnt 0033 [ end of method ]
-	SIG_ADDTOOFFSET(+10),
-	0x30, SIG_UINT16(0x0026),           // bnt 0026 [ end of method ]
-	SIG_ADDTOOFFSET(+8),
-	0x30, SIG_UINT16(0x001b),           // bnt 001b [ end of method ]
-	0x38, SIG_SELECTOR16(setScript),    // pushi setScript
-	0x39, SIG_MAGICDWORD, 0x03,         // pushi 03
-	0x72, SIG_UINT16(0x00cc),           // lofsa sRunHide
-	SIG_ADDTOOFFSET(+10),
-	0x38, SIG_SELECTOR16(doVerb),       // pushi doVerb
-	SIG_END
-};
-
-static const uint16 ecoquest2PatchCampMessages1[] = {
-	0x30, PATCH_UINT16(0x002a),         // bnt 002a [ super doVerb: verb ]
-	PATCH_ADDTOOFFSET(+10),
-	0x30, PATCH_UINT16(0x001d),         // bnt 001d [ super doVerb: verb ]
-	PATCH_ADDTOOFFSET(+8),
-	0x30, PATCH_UINT16(0x0012),         // bnt 0012 [ super doVerb: verb ]
-	PATCH_END
-};
-
-static const uint16 ecoquest2SignatureCampMessages2[] = {
-	0x30, SIG_UINT16(0x001b),           // bnt 001b [ end of method ]
-	0x38, SIG_SELECTOR16(setScript),    // pushi setScript
-	0x39, SIG_MAGICDWORD, 0x03,         // pushi 03
-	0x72, SIG_UINT16(0x0154),           // lofsa sRunHide
-	SIG_ADDTOOFFSET(+10),
-	0x38, SIG_SELECTOR16(doVerb),       // pushi doVerb
-	SIG_END
-};
-
-static const uint16 ecoquest2PatchCampMessages2[] = {
-	0x30, PATCH_UINT16(0x0012),         // bnt 0012 [ super doVerb: verb ]
-	PATCH_END
-};
-
-//          script, description,                                        signature                          patch
-static const SciScriptPatcherEntry ecoquest2Signatures[] = {
-	{  true,     0, "icon bar tutorial",                            10, ecoquest2SignatureIconBarTutorial, ecoquest2PatchIconBarTutorial },
-	{  true,    10, "disable speed test",                            1, sci11SpeedTestSignature,           sci11SpeedTestPatch},
-	{  true,    50, "initial text not removed on ecorder",           3, ecoquest2SignatureEcorder,         ecoquest2PatchEcorder },
-	{  true,   333, "initial text not removed on ecorder tutorial",  3, ecoquest2SignatureEcorderTutorial, ecoquest2PatchEcorderTutorial },
-	{  true,   500, "room 500 items reappear",                       1, ecoquest2SignatureRoom500Items,    ecoquest2PatchRoom500Items },
-	{  true,   530, "missing camp messages",                         6, ecoquest2SignatureCampMessages1,   ecoquest2PatchCampMessages1 },
-	{  true,   560, "missing camp messages",                         7, ecoquest2SignatureCampMessages2,   ecoquest2PatchCampMessages2 },
-	{  true,   702, "ecorder not highlighting lilies",               3, ecoquest2SignatureEcorderLily,     ecoquest2PatchEcorderLily },
-	{  true,   928, "Narrator lockup fix",                           1, sciNarratorLockupSignature,        sciNarratorLockupPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// Fan-made games
-// Attention: Try to make script patches as specific as possible
-
-// CascadeQuest::autosave in script 994 is called various times to auto-save.
-//  It uses a fixed slot (999) for this purpose. This doesn't work in ScummVM,
-//  because we do not let scripts save directly into specific slots, but
-//  instead use virtual slots / detect scripts wanting to create a new slot.
-// We patch the code to use slot 99 instead. kSaveGame also checks for Cascade
-//  Quest, and if slot 99 is asked for, it will then use the actual slot 0,
-//  which is the official ScummVM auto-save slot.
-//
-// Responsible method: CascadeQuest::autosave
-// Fixes bug: #7007
-static const uint16 fanmadeSignatureCascadeQuestFixAutoSaving[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x03e7),        // pushi 3E7 (999d) -> save game slot 999
-	0x74, SIG_UINT16(0x06f8),        // lofss "AutoSave"
-	0x89, 0x1e,                      // lsg global[1e]
-	0x43, 0x2d, 0x08,                // callk SaveGame
-	SIG_END
-};
-
-static const uint16 fanmadePatchCascadeQuestFixAutoSaving[] = {
-	0x38, PATCH_UINT16((SAVEGAMEID_OFFICIALRANGE_START - 1)), // fix slot
-	PATCH_END
-};
-
-// EventHandler::handleEvent in Demo Quest has a bug, and it jumps to the
-// wrong address when an incorrect word is typed, therefore leading to an
-// 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: #5120
-static const uint16 fanmadeSignatureDemoQuestInfiniteLoop[] = {
-	0x38, SIG_UINT16(0x004c),        // pushi 004c
-	0x39, 0x00,                      // pushi 00
-	0x87, 0x01,                      // lap param[1]
-	0x4b, 0x04,                      // send 04
-	SIG_MAGICDWORD,
-	0x18,                            // not
-	0x30, SIG_UINT16(0x002f),        // bnt 002f  [06a5]    --> jmp ffbc  [0664] --> BUG! infinite loop
-	SIG_END
-};
-
-static const uint16 fanmadePatchDemoQuestInfiniteLoop[] = {
-	PATCH_ADDTOOFFSET(+10),
-	0x30, PATCH_UINT16(0x0032),      // bnt 0032  [06a8] --> pushi 004c
-	PATCH_END
-};
-
-// This patch is for a bug that first appeared in the LSL3 volume dialog and was
-//  then copied into the templates included with SCI Studio and SCI Companion,
-//  causing it to appear in fan games. See larry3SignatureVolumeSlider.
-//
-// Applies to: Fan games built with the SCI Studio / SCI Companion SCI0 template
-// Responsible method: TheMenuBar:handleEvent
-static const uint16 fangameSignatureVolumeSlider1[] = {
-	0x39, SIG_SELECTOR8(doit),       // pushi doit
-	SIG_ADDTOOFFSET(+1),             // push1 [ opcode 79 instead of 78 in some games ]
-	SIG_ADDTOOFFSET(+1),             // push2 [ opcode 7b instead of 7a in some games ]
-	SIG_MAGICDWORD,
-	0x39, 0x08,                      // pushi 08 [ volume ]
-	0x8d, 0x03,                      // lst 03   [ uninitialized variable ]
-	0x43, 0x31, 0x04,                // callk DoSound 04 [ set volume and return previous ]
-	SIG_END
-};
-
-static const uint16 fangamePatchVolumeSlider1[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x39, 0x01,                      // pushi 01
-	0x38, PATCH_UINT16(0x0008),      // pushi 0008 [ volume ]
-	0x43, 0x31, 0x02,                // callk DoSound 02 [ return volume ]
-	PATCH_END
-};
-
-static const uint16 fangameSignatureVolumeSlider2[] = {
-	0x38, SIG_SELECTOR16(doit),      // pushi doit
-	0x39, 0x01,                      // pushi 01
-	0x39, 0x02,                      // pushi 02
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x0008),        // pushi 0808 [ volume ]
-	0x8d, 0x03,                      // lst 03     [ uninitialized variable ]
-	0x43, 0x31, 0x04,                // callk DoSound 04 [ set volume and return previous ]
-	SIG_END
-};
-
-static const uint16 fangamePatchVolumeSlider2[] = {
-	PATCH_ADDTOOFFSET(+5),
-	0x39, 0x01,                      // pushi 01
-	PATCH_ADDTOOFFSET(+3),
-	0x33, 0x00,                      // jmp 00
-	0x43, 0x31, 0x02,                // callk DoSound 02 [ return volume ]
-	PATCH_END
-};
-
-// Fan games based on the SCI Studio template reset their volume to 15 (max) in
-//  the init method of their game object in script 0. As with most SCI32 games,
-//  we patch this out so that the volume stored in ScummVM is used.
-// 
-// Applies to: Fan games built with the SCI Studio / SCI Companion SCI0 template
-// Responsible method: Template:init (the Game object in script 0)
-// Fixes bug: #13795
-static const uint16 fangameSignatureVolumeReset1[] = {
-	0x35, 0x0f,                      // ldi 0f
-	SIG_ADDTOOFFSET(+1), 0x1d,       // sag 1d   [ sag or sal depending on compiler ] 
-	SIG_ADDTOOFFSET(+1),             // push2    [ opcode 7b instead of 7a in some games ]
-	0x39, 0x08,                      // pushi 08 [ volume ]
-	SIG_ADDTOOFFSET(+1),             // lsg 1d   [ lsg or lsl depending on compiler ]
-	SIG_MAGICDWORD, 0x1d,      
-	0x43, 0x31, 0x04,                // callk DoSound 04
-	SIG_END
-};
-
-static const uint16 fangamePatchVolumeReset1[] = {
-	0x33, 0x0a,                      // jmp 0a
-	PATCH_END
-};
-
-static const uint16 fangameSignatureVolumeReset2[] = {
-	0x34, SIG_UINT16(0x000f),        // ldi 0f
-	0xa1, 0x1d,                      // sag 1d
-	0x39, 0x02,                      // pushi 02
-	0x38, SIG_UINT16(0x0008),        // pushi 0008 [ volume ]
-	0x89, SIG_MAGICDWORD, 0x1d,      // lsg 1d
-	0x43, 0x31, 0x04,                // callk DoSound 04
-	SIG_END
-};
-
-static const uint16 fangamePatchVolumeReset2[] = {
-	0x33, 0x0d,                      // jmp 0d
-	PATCH_END
-};
-
-//          script, description,                                      signature                                  patch
-static const SciScriptPatcherEntry fanmadeSignatures[] = {
-	{  true,     0, "SCI Template: disable volume reset",          1, fangameSignatureVolumeReset1,              fangamePatchVolumeReset1 },
-	{  true,     0, "SCI Template: disable volume reset",          1, fangameSignatureVolumeReset2,              fangamePatchVolumeReset2 },
-	{  true,   994, "Cascade Quest: fix auto-saving",              1, fanmadeSignatureCascadeQuestFixAutoSaving, fanmadePatchCascadeQuestFixAutoSaving },
-	{  true,   997, "SCI Template: fix volume slider",             1, fangameSignatureVolumeSlider1,             fangamePatchVolumeSlider1 },
-	{  true,   997, "SCI Template: fix volume slider",             1, fangameSignatureVolumeSlider2,             fangamePatchVolumeSlider2 },
-	{  true,   999, "Demo Quest: infinite loop on typo",           1, fanmadeSignatureDemoQuestInfiniteLoop,     fanmadePatchDemoQuestInfiniteLoop },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-
-// WORKAROUND
-// Freddy Pharkas intro screen
-// Sierra used inner loops for the scaling of the 2 title views.
-// Those inner loops don't call kGameIsRestarting, which is why
-// we do not update the screen and we also do not throttle.
-//
-// This patch fixes this and makes it work.
-// Applies to at least: English PC-CD
-// Responsible method: sTownScript::changeState(1), sTownScript::changeState(3) (script 110)
-static const uint16 freddypharkasSignatureIntroScaling[] = {
-	0x38, SIG_ADDTOOFFSET(+2),       // pushi (setLoop) (009b for PC CD)
-	0x78,                            // push1
-	SIG_ADDTOOFFSET(+1),             // push0 for first code, push1 for second code
-	0x38, SIG_ADDTOOFFSET(+2),       // pushi (setStep) (0143 for PC CD)
-	0x7a,                            // push2
-	0x39, 0x05,                      // pushi 05
-	0x3c,                            // dup
-	0x72, SIG_ADDTOOFFSET(+2),       // lofsa (view)
-	SIG_MAGICDWORD,
-	0x4a, 0x1e,                      // send 1e
-	0x35, 0x0a,                      // ldi 0a
-	0xa3, 0x02,                      // sal local[2]
-	// start of inner loop
-	0x8b, 0x02,                      // lsl local[2]
-	SIG_ADDTOOFFSET(+43),            // skip almost all of inner loop
-	0xa3, 0x02,                      // sal local[2]
-	0x33, 0xcf,                      // jmp [inner loop start]
-	SIG_END
-};
-
-static const uint16 freddypharkasPatchIntroScaling[] = {
-	// remove setLoop(), objects in heap are already prepared, saves 5 bytes
-	0x38,
-	PATCH_GETORIGINALUINT16(+6),     // pushi (setStep)
-	0x7a,                            // push2
-	0x39, 0x05,                      // pushi 05
-	0x3c,                            // dup
-	0x72,
-	PATCH_GETORIGINALUINT16(+13),    // lofsa (view)
-	0x4a, 0x18,                      // send 18 - adjusted
-	0x35, 0x0a,                      // ldi 0a
-	0xa3, 0x02,                      // sal local[2]
-	// start of new inner loop
-	0x78,                            // push1
-	0x76,                            // push0
-	0x43, 0x2c, 0x02,                // callk GameIsRestarting 02 (add this to trigger our speed throttler)
-	PATCH_ADDTOOFFSET(+47),          // skip almost all of inner loop
-	0x33, 0xca,                      // jmp [inner loop start]
-	PATCH_END
-};
-
-// In script 235, rm235::init and sEnterFrom500 disable icon 7+8 of iconbar (CD
-//  only). When picking up the canister after placing it down, the scripts will
-//  disable all the other icons. This results in IconBar::disable doing endless
-//  loops even in sierra sci because there is no enabled icon left. We remove
-//  the disabling of icon 8 (which is help). This fixes the issue.
-// Applies to at least: English PC-CD
-// Responsible method: rm235::init and sEnterFrom500::changeState
-// Fixes bug: #5245
-static const uint16 freddypharkasSignatureCanisterHang[] = {
-	0x38, SIG_SELECTOR16(disable),   // pushi disable
-	0x7a,                            // push2
-	SIG_MAGICDWORD,
-	0x39, 0x07,                      // pushi 07
-	0x39, 0x08,                      // pushi 08
-	0x81, 0x45,                      // lag global[45]
-	0x4a, 0x08,                      // send 08 (call IconBar::disable(7, 8))
-	SIG_END
-};
-
-static const uint16 freddypharkasPatchCanisterHang[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x78,                            // push1
-	PATCH_ADDTOOFFSET(+2),
-	0x33, 0x00,                      // jmp 0 (waste 2 bytes)
-	PATCH_ADDTOOFFSET(+3),
-	0x06,                            // send 06 (call IconBar::disable(7))
-	PATCH_END
-};
-
-// In script 215, lowerLadder::doit and highLadder::doit actually process
-//   keyboard presses when the ladder is on the screen in that room. They
-//   strangely also call kGetEvent. Because the main User::doit also calls
-//   kGetEvent, it's pure luck, where the event will hit. It's the same issue
-//   as in QfG1VGA. If you turn DOSBox to max cycles and click around for 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.
-// Applies to at least: English PC-CD, German Floppy, English Mac
-// Responsible method: lowerLadder::doit and highLadder::doit
-// Fixes bug: #5060
-static const uint16 freddypharkasSignatureLadderEvent[] = {
-	0x39, SIG_MAGICDWORD,
-	SIG_SELECTOR8(new),              // pushi new
-	0x76,                            // push0
-	0x38, SIG_SELECTOR16(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(localize),  // pushi localize
-	0x76,                            // push0
-	0x4a, 0x04,                      // send 04 (call curEvent::localize)
-	SIG_END
-};
-
-static const uint16 freddypharkasPatchLadderEvent[] = {
-	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)
-	PATCH_ADDTOOFFSET(+2),
-	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.
-// Applies to at least: English Mac
-// Responsible method: publicfpInv::drawInvWindow in script 15
-static const uint16 freddypharkasSignatureMacInventory[] = {
-	SIG_MAGICDWORD,
-	0x39, 0x23,                      // pushi 23
-	0x39, 0x74,                      // pushi 74
-	0x78,                            // push1
-	0x38, SIG_UINT16(0x0174),        // pushi 0174 (on mac it's actually 0x01, 0x74)
-	0x85, 0x15,                      // lat temp[15]
-	SIG_END
-};
-
-static const uint16 freddypharkasPatchMacInventory[] = {
-	0x39, 0x02,                      // pushi 02 (now matches the DOS version)
-	PATCH_ADDTOOFFSET(+23),
-	0x39, 0x04,                      // pushi 04 (now matches the DOS version)
-	PATCH_END
-};
-
-// WORKAROUND
-// FPFP Mac has an easter egg with a script bug that accidentally works in
-//  Sierra's interpreter. Clicking Talk on a small part of the mine in room 270
-//  triggers it. The script macThing plays macSound and waits for it to finish,
-//  but macSound:loop is set to -1, indicating that it should loop forever.
-//  ScummVM loops the sound and so macThing never advances to the next state and
-//  the user never regains control. Sierra's interpreter cues the script after
-//  the first play and doesn't loop the sound, despite macSound:loop.
-//
-// We work around this by setting macSound:loop correctly on the heap so that it
-//  only plays once and macThing proceeds.
-//
-// This buggy script didn't break in the original because the Mac interpreter
-//  didn't support looping sounds. It always played sounds just once and then
-//  signaled when they were complete and ignored the value of the loop property.
-//  This was most apparent in the KQ6 Mac port. All the room music, which was
-//  designed to loop, stopped abruptly after a minute in a room and then
-//  jarringly returned when changing rooms.
-//
-// Applies to: Mac Floppy
-// Responsible method: Heap in script 270
-// Fixes bug #7065
-static const uint16 freddypharkasSignatureMacEasterEggHang[] = {
-	SIG_MAGICDWORD,                 // macSound
-	SIG_UINT16(0x0b89),             // number = 2953
-	SIG_UINT16(0x007f),             // vol = 127
-	SIG_UINT16(0x0000),             // priority = 0
-	SIG_UINT16(0xffff),             // loop = -1 [ loop sound forever ]
-	SIG_END
-};
-
-static const uint16 freddypharkasPatchMacEasterEggHang[] = {
-	PATCH_ADDTOOFFSET(+6),
-	PATCH_UINT16(0x0001),           // loop = 1 [ play sound once ]
-	PATCH_END
-};
-
-// WORKAROUND
-// FPFP Mac's easter egg has a view that relies on a bug in the Mac interpreter.
-//  Sierra's interpreter draws views one pixel higher than their y coordinate.
-//  KQ6 Mac has this bug too. Compared to their original PC versions, views
-//  appear higher relative to their background. This is a problem for views that
-//  require precise placement to blend in with those backgrounds.
-//
-// The Mac easter egg adds such a view. View 275 contains a hand in the lake
-//  holding a Macintosh computer. Because this feature was developed against the
-//  Mac interpreter, the y coordinate that achieved the water effect is really
-//  off by one. In our interpreter, which doesn't have this bug, the view
-//  appears one pixel lower than intended and doesn't match the background.
-//
-// We fix this by adjusting macView:y to compensate for Sierra's off-by-one bug
-//  so that view 275 matches the lake background as in the original.
-//
-// Applies to: Mac Floppy
-// Responsible method: Heap in script 270
-static const uint16 freddypharkasSignatureMacEasterEggView[] = {
-	SIG_MAGICDWORD,                 // macView
-	SIG_UINT16(0x061e),             // name = $061e [ macView ]
-	SIG_UINT16(0x00cd),             // x = 205
-	SIG_UINT16(0x0065),             // y = 101
-	SIG_END
-};
-
-static const uint16 freddypharkasPatchMacEasterEggView[] = {
-	PATCH_ADDTOOFFSET(+4),
-	PATCH_UINT16(0x0064),           // y = 100
-	PATCH_END
-};
-
-// FPFP Mac is missing view 844 of Hop Singh leaving town, breaking the scene.
-//  This occurs when going to the desert (room 200) after the restaurant closes
-//  but before act 3 ends. This would also crash the original so we just disable
-//  this minor optional scene.
-//
-// Applies to: Mac Floppy
-// Responsible method: rm200:init
-// Fixes bug #10954
-static const uint16 freddypharkasSignatureMacHopSingh[] = {
-	0x89, 0x77,                     // lsg 77
-	0x35, 0x13,                     // ldi 13
-	0x1a,                           // eq? [ did restaurant just close? ]
-	0x31, 0x46,                     // bnt 46 [ skip hop singh scene ]
-	SIG_ADDTOOFFSET(+0x41),
-	SIG_MAGICDWORD,
-	0x72, 0x01, 0xd0,               // lofsa hopSingh [ hard-coded big endian for mac ]
-	0x4a, 0x20,                     // send 20 [ hopSingh init: ... setScript: sLeaveTown ]
-	SIG_END
-};
-
-static const uint16 freddypharkasPatchMacHopSingh[] = {
-	0x33, 0x4b,                     // jmp 4b [ always skip hop singh scene ]
-	PATCH_END
-};
-
-// At the start of act 4 the church key is removed from inventory but reappears
-//  in the church door. The door script attempts to prevent this by not drawing
-//  the key in act 4 but the verb handler is missing this check. Looking at the
-//  door in act 4 still brings up the inset with the key. Sierra fixed this in
-//  Mac but forgot to include the fix in the CD version a year later.
-//
-// We fix this by replacing a duplicate inventory check with an act 4 check so
-//  that the key no longer appears in the inset and can't be picked up again.
-//
-// Applies to: PC Floppy, PC CD
-// Responsible method: inDoorInset:init
-// Fixes bug #10975
-static const uint16 freddypharkasSignatureChurchKey[] = {
-	SIG_MAGICDWORD,
-	0x76,                           // push0
-	0x59, 0x01,                     // &rest 01
-	0x57, SIG_ADDTOOFFSET(+1), 0x04,// super Inset 04 [ super: init &rest ]
-	0x38, SIG_SELECTOR16(has),      // pushi has
-	0x78,                           // push1
-	0x39, 0x06,                     // pushi 06
-	0x81, 0x00,                     // lag 00
-	0x4a, 0x06,                     // send 06 [ ego has: 6 (church key) ]
-	SIG_END
-};
-
-static const uint16 freddypharkasPatchChurchKey[] = {
-	PATCH_ADDTOOFFSET(+6),
-	0x89, 0x78,                     // lsg 78 [ act number ]
-	0x35, 0x04,                     // ldi 04
-	0x20,                           // ge?
-	0x33, 0x03,                     // jmp 03
-	PATCH_END
-};
-
-// After leaving the desk letter in the grave, the letter reappears in the desk.
-//  The desk script only checks if the letter is in inventory. Sierra started to
-//  fix this in the CD version by setting a new flag but forgot to check it.
-//
-// We fix this by testing Letter's owner, if -1 then it is in the grave.
-//
-// Applies to: All versions
-// Responsible method: deskDrawer:doVerb(1)
-// Fixes bug #10975
-static const uint16 freddypharkasSignatureDeskLetter[] = {
-	SIG_MAGICDWORD,
-	0x30, SIG_UINT16(0x0055),       // bnt 0055
-	0x38, SIG_SELECTOR16(has),      // pushi has
-	0x78,                           // push1
-	0x39, 0x1f,                     // pushi 1f
-	0x81, 0x00,                     // lag 00
-	0x4a, 0x06,                     // send 06 [ ego has: 31 (Letter) ]
-	0x18,                           // not
-	0x31, 0x1f,                     // bnt 1f
-	0x78,                           // push1
-	0x39, 0x31,                     // pushi 31
-	0x45, 0x02, 0x02,               // callb proc0_2 02 [ is flag 49 set? ]
-	0x31, 0x17,                     // bnt 17
-	0x38, SIG_ADDTOOFFSET(+2),      // pushi stopUpd
-	0x76,                           // push0
-	0x81, 0x00,                     // lag 00
-	0x4a, 0x04,                     // send 04 [ ego stopUpd: (optimization) ]
-	0x38, SIG_ADDTOOFFSET(+2),      // pushi setInset
-	0x78,                           // push1
-	0x72, SIG_UINT16(0x0522),       // lofsa inLetterInset
-	0x36,                           // push
-	0x81, 0x02,                     // lag 02
-	0x4a, 0x06,                     // send 06  [ rm610 setInset: inLetterInset ]
-	0x32, SIG_UINT16(0x008f),       // jmp 008f [ end of method ]
-	0x78,                           // push1
-	0x39, 0x31,                     // pushi 31
-	0x45, 0x02, 0x02,               // callb proc0_2 02 [ is flag 49 set? ]
-	0x31, 0x11,                     // bnt 11 [ drawer is closed ]
-	SIG_END
-};
-
-static const uint16 freddypharkasPatchDeskLetter[] = {
-	0x31, 0x56,                     // bnt 56
-	0x78,                           // push1
-	0x39, 0x31,                     // pushi 31
-	0x45, 0x02, 0x02,               // callb proc0_2 02 [ is flag 49 set? ]
-	0x31, 0x3e,                     // bnt 3e  [ drawer is closed ]
-	0x38, PATCH_SELECTOR16(has),    // pushi has
-	0x78,                           // push1
-	0x39, 0x1f,                     // pushi 1f
-	0x81, 0x00,                     // lag 00
-	0x4a, 0x06,                     // send 06 [ ego has: 31 (Letter) ]
-	0x2f, 0x21,                     // bt 21   [ drawer is open and empty ]
-	0x39, PATCH_SELECTOR8(at),      // pushi at
-	0x78,                           // push1
-	0x39, 0x1f,                     // pushi 1f
-	0x81, 0x09,                     // lag 09
-	0x4a, 0x06,                     // send 06 [ fpInv at: 31 (Letter) ]
-	0x38, PATCH_SELECTOR16(owner),  // pushi owner
-	0x76,                           // push0
-	0x4a, 0x04,                     // send 04 [ Letter owner? ]
-	0x39, 0xff,                     // pushi ff
-	0x1a,                           // eq?
-	0x2f, 0x0d,                     // bt 0d   [ drawer is open and empty ]
-	0x38, PATCH_GETORIGINALUINT16(+33), // pushi setInset
-	0x78,                           // push1
-	0x74, PATCH_UINT16(0x0522),     // lofss inLetterInset
-	0x81, 0x02,                     // lag 02
-	0x4a, 0x06,                     // send 06 [ rm610 setInset: inLetterInset ]
-	0x3a,                           // toss
-	0x48,                           // ret
-	PATCH_END
-};
-
-//          script, description,                                      signature                                patch
-static const SciScriptPatcherEntry freddypharkasSignatures[] = {
-	{  true,    15, "Mac: broken inventory",                       1, freddypharkasSignatureMacInventory,      freddypharkasPatchMacInventory },
-	{  true,    28, "disable speed test",                          1, sci11SpeedTestSignature,                 sci11SpeedTestPatch },
-	{  true,   110, "intro scaling workaround",                    2, freddypharkasSignatureIntroScaling,      freddypharkasPatchIntroScaling },
-	{  false,  200, "Mac: skip broken hop singh scene",            1, freddypharkasSignatureMacHopSingh,       freddypharkasPatchMacHopSingh },
-	{  true,   235, "CD: canister pickup hang",                    3, freddypharkasSignatureCanisterHang,      freddypharkasPatchCanisterHang },
-	{  true,   270, "Mac: easter egg hang",                        1, freddypharkasSignatureMacEasterEggHang,  freddypharkasPatchMacEasterEggHang },
-	{  true,   270, "Mac: easter egg view",                        1, freddypharkasSignatureMacEasterEggView,  freddypharkasPatchMacEasterEggView },
-	{  true,   310, "church key reappears",                        1, freddypharkasSignatureChurchKey,         freddypharkasPatchChurchKey },
-	{  true,   320, "ladder event issue",                          2, freddypharkasSignatureLadderEvent,       freddypharkasPatchLadderEvent },
-	{  true,   610, "desk letter reappears",                       1, freddypharkasSignatureDeskLetter,        freddypharkasPatchDeskLetter },
-	{  true,   928, "Narrator lockup fix",                         1, sciNarratorLockupSignature,              sciNarratorLockupPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-
-// During Bridge, Declarer_Second_NT:think performs a bitwise or against an
-//  object due to a script typo. This operation is supposed to be against
-//  (bridgeHand:highCard):rank but instead it's against bridgeHand:highCard.
-//  ThirdSeat_Trump:think has a correct version of this. Declarer_Second_NT must
-//  have just been missing the word "rank" in the original script.
-//
-// We fix this by inserting the missing rank code. To make room we remove the
-//  call to self:checkFinCard. It's called immediately before this patch and its
-//  result is stored in local1 so we just use that. Hoyle5 also has this bug.
-//
-// Applies to at least: English PC
-// Responsible method: Declarer_Second_NT:think
-// Fixes bug #11163
-static const uint16 hoyle4SignatureBridgeArithmetic[] = {
-	0x36,                               // push [ bridgeHand:highCard ]
-	0x34, SIG_UINT16(0x0f00),           // ldi 0f00
-	0x14,                               // or [ error: bridgeHand:highCard is an object ]
-	0x36,                               // push
-	0x63, 0x42,                         // pToa pard
-	0x4a, 0x08,                         // send 08 [ pard hasCard: theSuitLead (bridgeHand:highCard | 0f00) ]
-	SIG_MAGICDWORD,
-	0x2f, 0x1d,                         // bt 1d
-	0x83, 0x03,                         // lal 03
-	0x2f, 0x19,                         // bt 19
-	0x38, SIG_ADDTOOFFSET(+2),          // pushi rank
-	0x76,                               // push0
-	0x38, SIG_ADDTOOFFSET(+2),          // pushi checkFinCard
-	0x78,                               // push1
-	0x67, 0x48,                         // pTos theSuitLead
-	0x54, 0x06,                         // self 06 [ self checkFinCard: theSuitLead ]
-	SIG_END
-};
-
-static const uint16 hoyle4PatchBridgeArithmetic[] = {
-	0x38, PATCH_GETORIGINALUINT16(+17), // pushi rank
-	0x76,                               // push0
-	0x4a, 0x04,                         // send 04 [ bridgeHand:highCard rank? ]
-	0x36,                               // push
-	0x34, PATCH_UINT16(0x0f00),         // ldi 0f00
-	0x14,                               // or
-	0x36,                               // push
-	0x63, 0x42,                         // pToa pard
-	0x4a, 0x08,                         // send 08 [ pard hasCard: theSuitLead ((bridgeHand:highCard):rank | 0f00) ]
-	0x2f, 0x17,                         // bt 17
-	0x83, 0x03,                         // lal 03
-	0x2f, 0x13,                         // bt 13
-	0x38, PATCH_GETORIGINALUINT16(+17), // pushi rank
-	0x76,                               // push0
-	0x83, 0x01,                         // lal 01 [ set to "self checkFinCard: theSuitLead" earlier ]
-	PATCH_END
-};
-
-// In Crazy Eights, playing an eight plays a transition sound effect that's
-//  abruptly interrupted at modern CPU speeds. The timing only worked in the
-//  original on slow CPUs where the interpreter couldn't complete the transition
-//  animation and deal the next card fast enough.
-//
-// We fix this by waiting on the transition sound instead of the animation.
-//
-// Applies to at least: English PC
-// Responsible method: transition:init
-// Fixes bug #10790
-static const uint16 hoyle4SignatureCrazyEightsSound[] = {
-	0x80, SIG_UINT16(0x0129),           // lag 0129
-	0x4a, 0x06,                         // send 06 [ song setLoop: 1 ]
-	0x39, SIG_SELECTOR8(play),          // pushi play
-	0x78,                               // push1
-	0x39, SIG_MAGICDWORD, 0x6f,         // pushi 6f
-	0x80, SIG_UINT16(0x0129),           // lag 0129
-	0x4a, 0x06,                         // send 06 [ song play: 111 ]
-	SIG_ADDTOOFFSET(+57),
-	0x7c,                               // pushSelf [ animation caller ]
-	SIG_END
-};
-
-static const uint16 hoyle4PatchCrazyEightsSound[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x33, 0x00,                         // jmp 00
-	PATCH_ADDTOOFFSET(+2),
-	0x7a,                               // push2
-	PATCH_ADDTOOFFSET(+2),
-	0x7c,                               // pushSelf
-	0x4a, 0x0e,                         // send 0e [ song setLoop: 1 play: 111 self ]
-	0x33, 0x00,                         // jmp 00
-	PATCH_ADDTOOFFSET(+57),
-	0x76,                               // push0 [ no animation caller ]
-	PATCH_END
-};
-
-// In Gin Rummy, sound 404 plays when undercutting the computer but it gets
-//  interrupted. layEmOut:changeState sets a half-second delay, which is long
-//  enough for the undercut sound when the computer wins, but not this one.
-//
-// We fix this by increasing the delay to a full second when playing sound 404.
-//
-// Applies to: All versions
-// Responsible method: layEmOut:changeState(11)
-static const uint16 hoyle4SignatureGinUndercutSound[] = {
-	0x30, SIG_UINT16(0x0027),          // bnt 0027
-	SIG_ADDTOOFFSET(+11),
-	0x30, SIG_UINT16(0x000e),          // bnt 000e
-	SIG_ADDTOOFFSET(+11),
-	0x32, SIG_UINT16(0x000b),          // jmp 000b
-	0x39, SIG_SELECTOR8(play),         // pushi play
-	0x78,                              // push1
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x0194),          // pushi 0194
-	0x80, SIG_UINT16(0x012a),          // lag 012a
-	0x4a, 0x06,                        // send 06 [ sound play: 404 ]
-	0x35, 0x1e,                        // ldi 1e
-	0x65, 0x20,                        // aTop ticks [ ticks = 30 ]
-	0x32, SIG_UINT16(0x000c),          // jmp 000c [ toss, ret ]
-	SIG_END
-};
-
-static const uint16 hoyle4PatchGinUndercutSound[] = {
-	0x30, PATCH_UINT16(0x002a),        // bnt 002a
-	PATCH_ADDTOOFFSET(+11),
-	0x30, PATCH_UINT16(0x000d),        // bnt 000d
-	PATCH_ADDTOOFFSET(+11),
-	0x33, 0x0f,                        // jmp 0f
-	0x39, PATCH_SELECTOR8(play),       // pushi play
-	0x78,                              // push1
-	0x38, PATCH_UINT16(0x0194),        // pushi 0194
-	0x80, PATCH_UINT16(0x012a),        // lag 012a
-	0x4a, 0x06,                        // send 06 [ sound play: 404 ]
-	0x35, 0x3c,                        // ldi 3c
-	0x33, 0x02,                        // jmp 02 [ ticks = 60 ]
-	0x35, 0x1e,                        // ldi 1e
-	0x65, 0x20,                        // aTop ticks [ ticks = 30 ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                         patch
-static const SciScriptPatcherEntry hoyle4Signatures[] = {
-	{  true,   100, "crazy eights sound",                          1, hoyle4SignatureCrazyEightsSound,  hoyle4PatchCrazyEightsSound },
-	{  true,   400, "gin undercut sound",                          1, hoyle4SignatureGinUndercutSound,  hoyle4PatchGinUndercutSound },
-	{  true,   733, "bridge arithmetic against object",            1, hoyle4SignatureBridgeArithmetic,  hoyle4PatchBridgeArithmetic },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#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, we replace this with a call to kScummVMSleep for the requested
-// number of ticks.
-// Applies to at least: English Demo, English PC, English Mac
-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, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, $2
-	0x48,                                     // ret
-	PATCH_END
-};
-
-// While playing Old Maid (room 200), a repeated typo in the game script
-// means that `setScale` is called accidentally instead of `setScaler`.
-// In SSCI this did not do much because the first argument happened to be
-// smaller than the y-position of `ego`, but in ScummVM the first argument is
-// larger and so a debug message "y value less than vanishingY" is displayed.
-// This is the same issue as with LSL6 hires.
-static const uint16 hoyle5SetScaleSignature[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(setScale), // pushi setScale ($14b)
-	0x38, SIG_UINT16(0x05),         // pushi 5
-	0x51, 0x2c,                     // class Scaler
-	SIG_END
-};
-
-static const uint16 hoyle5PatchSetScale[] = {
-	0x38, PATCH_SELECTOR16(setScaler), // pushi setScaler ($14f)
-	PATCH_END
-};
-
-// There are two derived collections of Hoyle Classic Games:
-// 1) The Hoyle Children's Collection, which includes the following games:
-// - Crazy Eights (script 100)
-// - Old Maid (script 200)
-// - Checkers (script 1200)
-// 2) Hoyle Bridge, which includes the following games:
-// - Bridge (script 700)
-// In these two collections, the scripts for the other games have been removed.
-// Choosing any other game than the above results in a "No script found" error.
-// The original game did not show the game selection screen, as there were
-// direct shortcuts to each game.
-// We do show the game selection screen for Children's Collection, thus we
-// disable all the games which are not included in this version:
-// - Hearts (script 300)
-// - Gin Rummy (script 400)
-// - Cribbage (script 500)
-// - Klondike / Solitaire (script 600)
-// - Bridge (script 700)
-// - Poker (script 1100)
-// - Backgammon (script 1300)
-static const uint16 hoyle5SignatureHearts[] = {
-	SIG_MAGICDWORD,
-	0x38, 0x8e, 0x00,      // pushi 008e
-	0x76,                  // push0
-	0x38, 0xf0, 0x02,      // pushi 02f0
-	0x76,                  // push0
-	0x72, 0xdc, 0x03,      // lofsa chooseHearts
-	0x4a, 0x08, 0x00,      // send  0008
-	SIG_END
-};
-
-static const uint16 hoyle5SignatureGinRummy[] = {
-	SIG_MAGICDWORD,
-	0x38, 0x8e, 0x00,      // pushi 008e
-	0x76,                  // push0
-	0x38, 0xf0, 0x02,      // pushi 02f0
-	0x76,                  // push0
-	0x72, 0xbc, 0x02,      // lofsa chooseGinRummy
-	0x4a, 0x08, 0x00,      // send  0008
-	SIG_END
-};
-
-static const uint16 hoyle5SignatureCribbage[] = {
-	SIG_MAGICDWORD,
-	0x38, 0x8e, 0x00,      // pushi 008e
-	0x76,                  // push0
-	0x38, 0xf0, 0x02,      // pushi 02f0
-	0x76,                  // push0
-	0x72, 0x4c, 0x03,      // lofsa chooseCribbage
-	0x4a, 0x08, 0x00,      // send  0008
-	SIG_END
-};
-
-static const uint16 hoyle5SignatureKlondike[] = {
-	SIG_MAGICDWORD,
-	0x38, 0x8e, 0x00,      // pushi 008e
-	0x76,                  // push0
-	0x38, 0xf0, 0x02,      // pushi 02f0
-	0x76,                  // push0
-	0x72, 0xfc, 0x04,      // lofsa chooseKlondike
-	0x4a, 0x08, 0x00,      // send  0008
-	SIG_END
-};
-
-static const uint16 hoyle5SignatureBridge[] = {
-	SIG_MAGICDWORD,
-	0x38, 0x8e, 0x00,      // pushi 008e
-	0x76,                  // push0
-	0x38, 0xf0, 0x02,      // pushi 02f0
-	0x76,                  // push0
-	0x72, 0x6c, 0x04,      // lofsa chooseBridge
-	0x4a, 0x08, 0x00,      // send  0008
-	SIG_END
-};
-
-static const uint16 hoyle5SignaturePoker[] = {
-	SIG_MAGICDWORD,
-	0x38, 0x8e, 0x00,      // pushi 008e
-	0x76,                  // push0
-	0x38, 0xf0, 0x02,      // pushi 02f0
-	0x76,                  // push0
-	0x72, 0x8c, 0x05,      // lofsa choosePoker
-	0x4a, 0x08, 0x00,      // send  0008
-	SIG_END
-};
-
-static const uint16 hoyle5SignatureBackgammon[] = {
-	SIG_MAGICDWORD,
-	0x38, 0x8e, 0x00,      // pushi 008e
-	0x76,                  // push0
-	0x38, 0xf0, 0x02,      // pushi 02f0
-	0x76,                  // push0
-	0x72, 0xac, 0x06,      // lofsa chooseBackgammon
-	0x4a, 0x08, 0x00,      // send  0008
-	SIG_END
-};
-
-static const uint16 hoyle5PatchDisableGame[] = {
-	0x35, 0x00,                      // ldi 00
-	0x35, 0x00,                      // ldi 00
-	0x35, 0x00,                      // ldi 00
-	0x35, 0x00,                      // ldi 00
-	0x35, 0x00,                      // ldi 00
-	0x35, 0x00,                      // ldi 00
-	0x35, 0x00,                      // ldi 00
-	PATCH_END
-};
-
-// During Bridge, Declarer_Second_NT:think performs a bitwise or against an
-//  object due to a script typo. This script bug is also in Hoyle4, see its
-//  patch notes above for more detail.
-//
-// Applies to at least: English PC
-// Responsible method: Declarer_Second_NT:think
-// Fixes bug #11173
-static const uint16 hoyle5SignatureBridgeArithmetic[] = {
-	0x36,                               // push [ bridgeHand:highCard ]
-	0x34, SIG_UINT16(0x0f00),           // ldi 0f00
-	0x14,                               // or [ error: bridgeHand:highCard is an object ]
-	0x36,                               // push
-	0x63, 0x44,                         // pToa pard
-	0x4a, SIG_UINT16(0x0008),           // send 08 [ pard hasCard: theSuitLead (bridgeHand:highCard | 0f00) ]
-	0x2f, 0x26,                         // bt 26
-	0x7e, SIG_ADDTOOFFSET(+2),          // line
-	SIG_MAGICDWORD,
-	0x83, 0x03,                         // lal 03
-	0x2f, 0x1f,                         // bt 1f
-	0x7e, SIG_ADDTOOFFSET(+2),          // line
-	0x38,                               // pushi rank
-	SIG_END
-};
-
-static const uint16 hoyle5PatchBridgeArithmetic[] = {
-	0x38, PATCH_GETORIGINALUINT16(+24), // pushi rank
-	0x76,                               // push0
-	0x4a, PATCH_UINT16(0x0004),         // send 04 [ bridgeHand:highCard rank? ]
-	0x38, PATCH_UINT16(0x0f00),         // pushi 0f00
-	0x14,                               // or
-	0x36,                               // push
-	0x63, 0x44,                         // pToa pard
-	0x4a, PATCH_UINT16(0x0008),         // send 08 [ pard hasCard: theSuitLead ((bridgeHand:highCard):rank | 0f00) ]
-	0x2f, 0x20,                         // bt 20
-	0x83, 0x03,                         // lal 03
-	0x2f, 0x1c,                         // bt 1c
-	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,   200, "fix setScale calls",                         11, hoyle5SetScaleSignature,          hoyle5PatchSetScale },
-	{  true,   500, "remove kGetTime spin",                        1, hoyle5SignatureSpinLoop,          hoyle5PatchSpinLoop },
-	{  true, 64937, "remove kGetTime spin",                        1, hoyle5SignatureSpinLoop,          hoyle5PatchSpinLoop },
-	{  true,   733, "bridge arithmetic against object",            1, hoyle5SignatureBridgeArithmetic,  hoyle5PatchBridgeArithmetic },
-	{  true, 64990, "increase number of save games (1/2)",         1, sci2NumSavesSignature1,           sci2NumSavesPatch1 },
-	{  true, 64990, "increase number of save games (2/2)",         1, sci2NumSavesSignature2,           sci2NumSavesPatch2 },
-	{  true, 64990, "disable change directory button",             1, sci2ChangeDirSignature,           sci2ChangeDirPatch },
-	{ false,   975, "disable Gin Rummy",                           1, hoyle5SignatureGinRummy,          hoyle5PatchDisableGame },
-	{ false,   975, "disable Cribbage",                            1, hoyle5SignatureCribbage,          hoyle5PatchDisableGame },
-	{ false,   975, "disable Klondike",                            1, hoyle5SignatureKlondike,          hoyle5PatchDisableGame },
-	{ false,   975, "disable Bridge",                              1, hoyle5SignatureBridge,            hoyle5PatchDisableGame },
-	{ false,   975, "disable Poker",                               1, hoyle5SignaturePoker,             hoyle5PatchDisableGame },
-	{ false,   975, "disable Hearts",                              1, hoyle5SignatureHearts,            hoyle5PatchDisableGame },
-	{ false,   975, "disable Backgammon",                          1, hoyle5SignatureBackgammon,        hoyle5PatchDisableGame },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#pragma mark -
-#pragma mark Gabriel Knight 1
-
-// `daySixBeignet::changeState(4)` is called when the cop goes outside. It sets
-// cycles to 220. This is a CPU-speed dependent value and not usually enough
-// time to get to the door, so patch it to 22 seconds.
-//
-// Applies to at least: English PC-CD, German PC-CD, English Mac
-static const uint16 gk1Day6PoliceBeignetSignature1[] = {
-	0x35, 0x04,                    // ldi 4
-	0x1a,                          // eq?
-	0x30, SIG_ADDTOOFFSET(+2),     // bnt [next state check]
-	0x38, SIG_SELECTOR16(dispose), // pushi dispose
-	0x76,                          // push0
-	0x72, SIG_ADDTOOFFSET(+2),     // lofsa deskSarg
-	0x4a, SIG_UINT16(0x04),        // send 4
-	SIG_MAGICDWORD,
-	0x34, SIG_UINT16(0xdc),        // ldi 220
-	0x65, SIG_ADDTOOFFSET(+1),     // aTop cycles ($1a for PC, $1c for Mac)
-	0x32,                          // jmp [end]
-	SIG_END
-};
-
-static const uint16 gk1Day6PoliceBeignetPatch1[] = {
-	PATCH_ADDTOOFFSET(+16),
-	0x34, PATCH_UINT16(0x16),                   // ldi 22
-	0x65, PATCH_GETORIGINALBYTEADJUST(+20, +2), // aTop seconds ($1c for PC, $1e for Mac)
-	PATCH_END
-};
-
-// On day 6 when the cop is outside for the beignet, walking through the
-// swinging door will also reset the puzzle timer so the player has 200 cycles
-// to get through the area before the cop returns. This is a CPU-speed
-// dependent value and not usually enough time to get to the door, so we patch
-// it to 20 seconds instead.
-//
-// Applies to at least: English PC-CD, German PC-CD, English Mac
-// Responsible method: sInGateWithPermission::changeState(0)
-// Fixes bug: #9805
-static const uint16 gk1Day6PoliceBeignetSignature2[] = {
-	0x72, SIG_ADDTOOFFSET(+2),    // lofsa daySixBeignet
-	0x1a,                         // eq?
-	0x31, 0x0d,                   // bnt [skip set cycles]
-	0x38, SIG_SELECTOR16(cycles), // pushi cycles
-	0x78,                         // push1
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0xc8),       // pushi 200
-	0x72,                         // lofsa
-	SIG_END
-};
-
-static const uint16 gk1Day6PoliceBeignetPatch2[] = {
-	PATCH_ADDTOOFFSET(+6),
-	0x38, PATCH_SELECTOR16(seconds), // pushi seconds
-	0x78,                            // push1
-	0x38, PATCH_UINT16(0x14),        // pushi 20
-	PATCH_END
-};
-
-// `sargSleeping::changeState(8)` is called when the cop falls asleep and sets
-// the puzzle timer to 220 cycles. This is CPU-speed dependent and not usually
-// enough time to get to the door, so patch it to 22 seconds instead.
-//
-// Applies to at least: English PC-CD, German PC-CD, English Mac
-static const uint16 gk1Day6PoliceSleepSignature[] = {
-	0x35, 0x08,                // ldi 8
-	0x1a,                      // eq?
-	0x31, SIG_ADDTOOFFSET(+1), // bnt [next state check]
-	SIG_MAGICDWORD,
-	0x34, SIG_UINT16(0xdc),    // ldi 220
-	0x65, SIG_ADDTOOFFSET(+1), // aTop cycles ($1a for PC, $1c for Mac)
-	0x32,                      // jmp [end]
-	SIG_END
-};
-
-static const uint16 gk1Day6PoliceSleepPatch[] = {
-	PATCH_ADDTOOFFSET(+5),
-	0x34, PATCH_UINT16(0x16),                  // ldi 22
-	0x65, PATCH_GETORIGINALBYTEADJUST(+9, +2), // aTop seconds (1c for PC, 1e for Mac)
-	PATCH_END
-};
-
-// The beignet vendor's speed at the police station is CPU dependent, causing
-//  him to zoom to his position in room 230 on modern machines at an unintended
-//  high speed that's inconsistent with the room. Unlike the other actors,
-//  theVendor:moveSpeed is set to 0, which advances his motion on every game
-//  cycle instead of tethering his speed to ticks. On a machine from 1993 this
-//  was much slower which is why his movement sound effect is five seconds long.
-//
-// We fix this by setting theVendor:moveSpeed to a time-based speed that matches
-//  the room scene. This doesn't affect puzzle timing, it's just cosmetic.
-//
-// Applies to: All versions
-// Responsible method: heap in script 231
-// Fixes bug: #11892
-static const uint16 gk1BeignetVendorSpeedSignature[] = {
-	SIG_MAGICDWORD,             // theVendor
-	SIG_UINT16(0x0006),         // xStep = 6
-	SIG_UINT16(0x0302),         // origStep = 770
-	SIG_UINT16(0x0000),         // moveSpeed = 0
-	SIG_END
-};
-
-static const uint16 gk1BeignetVendorSpeedPatch[] = {
-	PATCH_ADDTOOFFSET(+4),
-	PATCH_UINT16(0x0006),       // moveSpeed = 6
-	PATCH_END
-};
-
-// At the start of day 5, when the player already has the veve but still needs
-// to get the drum book, the drum book dialogue with Grace is played twice in
-// a row, and then the veve dialogue gets played again even though it was
-// already played during day 4.
-//
-// The duplicate drum book dialogue happens because it is triggered once in
-// `GetTheVeve::changeState(0)` and then again in `GetTheVeve::changeState(11)`.
-// The re-run of the veve dialogue happens because the game gives the player
-// the drum book in `GetTheVeVe::changeState(1)`, then *after* doing so, checks
-// if the player has the drum book and runs the veve dialogue if so.
-//
-// We fix both of these issues by skipping the has-drum-book check if the player
-// just got the drum book in 'GetTheVeve::changeState(1)'.
-// Doing this causes the game to jump from state 1 to state 12, which bypasses
-// the duplicate drum book dialogue in state 11, as well as the veve dialogue
-// trigger in the has-drum-book check.
-//
-// More notes: The veve newspaper item is inventory 9. The drum book is
-//             inventory 14. The flag for veve research is 36, the flag for drum
-//             research is 73.
-//
-// Special thanks, credits and kudos to sluicebox on IRC, who did a ton of
-// research on this and even found this game bug originally.
-//
-// Applies to at least: English PC-CD, German PC-CD
-static const uint16 gk1Day5DrumBookDialogueSignature[] = {
-	0x31, 0x0b,                         // bnt [skip giving player drum book code]
-	0x38, SIG_SELECTOR16(get),          // pushi get ($200)
-	0x78,                               // push1
-	SIG_MAGICDWORD,
-	0x39, 0x0e,                         // pushi $e
-	0x81, 0x00,                         // lag global[0]
-	0x4a, SIG_UINT16(0x06),             // send 6 - GKEgo::get($e)
-	// end of giving player drum book code
-	0x38, SIG_SELECTOR16(has),          // pushi has ($202)
-	0x78,                               // push1
-	0x39, 0x0e,                         // pushi $e
-	0x81, 0x00,                         // lag global[0]
-	0x4a, SIG_UINT16(0x06),             // send 6 - GKEgo::has($e)
-	0x18,                               // not
-	0x30, SIG_UINT16(0x25),             // bnt [veve newspaper code]
-	SIG_END
-};
-
-static const uint16 gk1Day5DrumBookDialoguePatch[] = {
-	0x31, 0x0d,                         // bnt [skip giving player drum book code] adjusted
-	PATCH_ADDTOOFFSET(+11),             // skip give player drum book original code
-	0x33, 0x0d,                         // jmp [over the check inventory for drum book code]
-	// check inventory for drum book
-	0x38, PATCH_SELECTOR16(has),        // pushi has ($202)
-	0x78,                               // push1
-	0x39, 0x0e,                         // pushi $e
-	0x81, 0x00,                         // lag global[0]
-	0x4a, PATCH_UINT16(0x0006),         // send 6 - GKEgo::has($e)
-	0x2f, 0x23,                         // bt [veve newspaper code] (adjusted, saves 2 bytes)
-	PATCH_END
-};
-
-// When Gabriel goes to the phone, the script softlocks at
-// `startOfDay5::changeState(32)`.
-//
-// Applies to at least: English PC-CD, German PC-CD, English Mac
-static const uint16 gk1Day5PhoneFreezeSignature[] = {
-	0x4a,                             // send ...
-	SIG_MAGICDWORD, SIG_UINT16(0x0c), // ... $c
-	0x35, 0x03,                       // ldi 3
-	0x65, SIG_ADDTOOFFSET(+1),        // aTop cycles
-	0x32, SIG_ADDTOOFFSET(+2),        // jmp [end]
-	0x3c,                             // dup
-	0x35, 0x21,                       // ldi $21
-	SIG_END
-};
-
-static const uint16 gk1Day5PhoneFreezePatch[] = {
-	PATCH_ADDTOOFFSET(+3),                     // send $c
-	0x35, 0x06,                                // ldi 6
-	0x65, PATCH_GETORIGINALBYTEADJUST(+6, +6), // aTop ticks
-	PATCH_END
-};
-
-// When Gabriel is grabbing a vine, his saying "I can't believe I'm doing
-// this..." is cut off. We change it so the scripts wait for the audio.
-//
-// This is not supposed to be applied to the Floppy version.
-//
-// Applies to at least: English PC-CD, German PC-CD, Spanish PC-CD
-// Responsible method: vineSwing::changeState(1)
-// Fixes bug: #9820
-static const uint16 gk1Day9VineSwingSignature[] = {
-	0x38, SIG_UINT16(0x0004),         // pushi $4
-	0x51, 0x17,                       // class CT
-	0x36,                             // push
-	0x39, 0x0b,                       // pushi $b
-	0x78,                             // push1
-	0x7c,                             // pushSelf
-	0x81, 0x00,                       // lag global[$0]
-	0x4a, SIG_UINT16(0x0020),         // send $20
-	0x38, SIG_SELECTOR16(setMotion),  // pushi setMotion
-	0x78,                             // push1
-	0x76,                             // push0
-	0x72, SIG_UINT16(0x0412),         // lofsa guard1
-	0x4a, SIG_UINT16(0x0006),         // send $6
-	0x38, SIG_SELECTOR16(say),        // pushi say
-	0x38, SIG_UINT16(0x0004),         // pushi $4
-	SIG_MAGICDWORD,
-	0x39, 0x07,                       // pushi $7
-	0x39, 0x08,                       // pushi $8
-	0x39, 0x10,                       // pushi $10
-	0x78,                             // push1
-	0x81, 0x5b,                       // lag global[$5b]
-	0x4a, SIG_UINT16(0x000c),         // send $c
-	SIG_END
-};
-
-static const uint16 gk1Day9VineSwingPatch[] = {
-	0x38, PATCH_UINT16(0x0003),         // pushi $3
-	0x51, 0x17,                         // class CT
-	0x36,                               // push
-	0x39, 0x0b,                         // pushi $b
-	0x78,                               // push1
-	0x81, 0x00,                         // lag global[$0]
-	0x4a, PATCH_UINT16(0x001e),         // send $20
-	0x38, PATCH_SELECTOR16(setMotion),  // pushi setMotion
-	0x78,                               // push1
-	0x76,                               // push0
-	0x72, PATCH_UINT16(0x0412),         // lofsa guard1
-	0x4a, PATCH_UINT16(0x0006),         // send $6
-	0x38, PATCH_SELECTOR16(say),        // pushi say
-	0x38, PATCH_UINT16(0x0005),         // pushi $5
-	0x39, 0x07,                         // pushi $7
-	0x39, 0x08,                         // pushi $8
-	0x39, 0x10,                         // pushi $10
-	0x78,                               // push1
-	0x7c,                               // pushSelf
-	0x81, 0x5b,                         // lag global[$5b]
-	0x4a, PATCH_UINT16(0x000e),         // send $c
-	PATCH_END
-};
-
-// The mummies on day 9 move without animating if ego exits to the north before
-//  the first one finishes standing. This also occurs in Sierra's interpreter.
-//
-// The 12 outer rooms of the African mound all take place in room 710, which
-//  reinitializes its contents on each room change. Each room's mummy is guard1
-//  repositioned with a different view. When the mummies come to life,
-//  keyWorks:changeState(6) starts guard1's standing animation after which
-//  state 7 initializes guard1 for chasing ego. Ego however can leave before
-//  guard1 finishes standing, preventing state 7 from occurring. The script for
-//  exiting to the north assumes state 7 has run, otherwise guard1 remains on
-//  the wrong view with no cycler or looper in subsequent rooms.
-//
-// This bug is due to the script rightWay only partially initializing guard1 for
-//  chasing as opposed to wrongWay and backTrack which fully initialize. We fix
-//  this by replacing rightWay's partial initialization with the full version
-//  from keyWorks state 7. There are two versions of this patch due to
-//  significant differences between floppy and CD versions of this script.
-//
-// This patch is not applied to the NRS versions of this script, which address
-//  this bug by disabling control until guard1 finishes standing, giving the
-//  player less time to escape.
-//
-// Applies to: All PC Floppy and CD versions. TODO: Test Mac
-// Responsible method: rightWay:changeState(1)
-// Fixes bug: #10828
-static const uint16 gk1MummyAnimateFloppySignature[] = {
-	0x39, SIG_SELECTOR8(view),          // pushi view [ full guard1 init ]
-	SIG_MAGICDWORD,
-	0x78,                               // push1
-	0x38, SIG_UINT16(0x02c5),           // pushi 709d
-	SIG_ADDTOOFFSET(+674),
-	0x38, SIG_SELECTOR16(setMotion),    // pushi setMotion [ partial guard1 init ]
-	0x38, SIG_UINT16(0x0004),           // pushi 0004
-	0x51, 0x70,                         // class PChase
-	0x36,                               // push
-	0x89, 0x00,                         // lsg global[0]
-	0x39, 0x0f,                         // pushi 0f
-	SIG_END
-};
-
-static const uint16 gk1MummyAnimateFloppyPatch[] = {
-	PATCH_ADDTOOFFSET(+680),
-	0x39, PATCH_SELECTOR8(view),        // pushi view [ waste 6 stack items to be compatible with ]
-	0x76,                               // push0      [  the send instruction in full guard1 init ]
-	0x39, PATCH_SELECTOR8(view),        // pushi view
-	0x76,                               // push0
-	0x39, PATCH_SELECTOR8(view),        // pushi view
-	0x39, 0x00,                         // pushi 00
-	0x32, PATCH_UINT16(0xfd4b),         // jmp -693d [ continue full guard1 init in keyWorks state 7 ]
-	PATCH_END
-};
-
-static const uint16 gk1MummyAnimateCDSignature[] = {
-	0x39, SIG_SELECTOR8(view),          // pushi view [ full guard1 init ]
-	SIG_MAGICDWORD,
-	0x78,                               // push1
-	0x38, SIG_UINT16(0x02c5),           // pushi 709d
-	SIG_ADDTOOFFSET(+750),
-	0x38, SIG_SELECTOR16(setMotion),    // pushi setMotion [ partial guard1 init ]
-	0x38, SIG_UINT16(0x0004),           // pushi 0004
-	0x51, 0x70,                         // class PChase
-	0x36,                               // push
-	0x89, 0x00,                         // lsg global[0]
-	0x39, 0x0f,                         // pushi 0f
-	SIG_END
-};
-
-static const uint16 gk1MummyAnimateCDPatch[] = {
-	PATCH_ADDTOOFFSET(+756),
-	0x39, PATCH_SELECTOR8(view),        // pushi view [ waste 6 stack items to be compatible with ]
-	0x76,                               // push0      [  the send instruction in full guard1 init ]
-	0x39, PATCH_SELECTOR8(view),        // pushi view
-	0x76,                               // push0
-	0x39, PATCH_SELECTOR8(view),        // pushi view
-	0x39, 0x00,                         // pushi 00
-	0x32, PATCH_UINT16(0xfcff),         // jmp -769d [ continue full guard1 init in keyWorks state 7 ]
-	PATCH_END
-};
-
-// In GK1, the `view` selector is used to store view numbers in some cases and
-// object references to Views in other cases. `Interrogation::dispose` compares
-// an object stored in the `view` selector with a number (which is not valid)
-// because its checks are in the wrong order. The check order was fixed in the
-// CD version, so just do what the CD version does.
-//
-// TODO: Check if English Mac is affected too and if this patch applies
-// Applies to at least: English Floppy
-static const uint16 gk1InterrogationBugSignature[] = {
-	SIG_MAGICDWORD,
-	0x65, 0x4c,                      // aTop $4c
-	0x67, 0x50,                      // pTos $50
-	0x34, SIG_UINT16(0x2710),        // ldi $2710
-	0x1e,                            // gt?
-	0x31, 0x08,                      // bnt 8 [05a0]
-	0x67, 0x50,                      // pTos $50
-	0x34, SIG_UINT16(0x2710),        // ldi $2710
-	0x04,                            // sub
-	0x65, 0x50,                      // aTop $50
-	0x63, 0x50,                      // pToa $50
-	0x31, 0x15,                      // bnt $15 [05b9]
-	0x39, SIG_SELECTOR8(view),       // pushi view ($e)
-	0x76,                            // push0
-	0x4a, SIG_UINT16(0x04),          // send 4
-	0xa5, 0x00,                      // sat temp[0]
-	0x38, SIG_SELECTOR16(dispose),   // pushi dispose
-	0x76,                            // push0
-	0x63, 0x50,                      // pToa $50
-	0x4a, SIG_UINT16(0x04),          // send 4
-	0x85, 0x00,                      // lat temp[0]
-	0x65, 0x50,                      // aTop $50
-	SIG_END
-};
-
-static const uint16 gk1InterrogationBugPatch[] = {
-	0x65, 0x4c,                      // aTop $4c
-	0x63, 0x50,                      // pToa $50
-	0x31, 0x15,                      // bnt $15 [05b9]
-	0x39, PATCH_SELECTOR8(view),     // pushi view ($e)
-	0x76,                            // push0
-	0x4a, PATCH_UINT16(0x04),        // send 4
-	0xa5, 0x00,                      // sat temp[0]
-	0x38, PATCH_SELECTOR16(dispose), // pushi dispose
-	0x76,                            // push0
-	0x63, 0x50,                      // pToa $50
-	0x4a, PATCH_UINT16(0x04),        // send 4
-	0x85, 0x00,                      // lat temp[0]
-	0x65, 0x50,                      // aTop $50
-	0x67, 0x50,                      // pTos $50
-	0x34, PATCH_UINT16(0x2710),      // ldi $2710
-	0x1e,                            // gt?
-	0x31, 0x08,                      // bnt 8 [05b9]
-	0x67, 0x50,                      // pTos $50
-	0x34, PATCH_UINT16(0x2710),      // ldi $2710
-	0x04,                            // sub
-	0x65, 0x50,                      // aTop $50
-	PATCH_END
-};
-
-// WORKAROUND: Script needed, because of differences in our pathfinding
-// algorithm.
-// In Madame Cazanoux's house, when Gabriel is leaving, he is placed on
-// the edge of the walkable area initially. This leads to a failure in
-// the pathfinding algorithm, and the pathfinding area is then ignored,
-// so Gabriel goes straight to the door by walking through the wall.
-// This is an edge case, which was apparently acceptable in SSCI. We
-// change the upper border of the walk area slightly, so that Gabriel
-// can be placed inside, and the pathfinding algorithm works correctly.
-//
-// Responsible method: rm280:init
-// Fixes bug: #9770
-static const uint16 gk1CazanouxPathfindingSignature[] = {
-	SIG_MAGICDWORD,
-	0x78,                            // push1 x = 1
-	0x38, SIG_UINT16(0x0090),        // pushi y = 144
-	0x38, SIG_UINT16(0x00f6),        // pushi x = 246
-	0x38, SIG_UINT16(0x0092),        // pushi y = 146
-	0x38, SIG_UINT16(0x00f2),        // pushi x = 242
-	0x39, 0x69,                      // pushi y = 105
-	0x39, 0x7c,                      // pushi x = 124
-	0x39, 0x68,                      // pushi y = 104
-	0x39, 0x56,                      // pushi x = 86
-	0x39, 0x6f,                      // pushi y = 111
-	0x39, 0x45,                      // pushi x = 69
-	0x39, 0x7c,                      // pushi y = 124
-	0x39, 0x2e,                      // pushi x = 46
-	0x38, SIG_UINT16(0x0081),        // pushi y = 129
-	SIG_END
-};
-
-static const uint16 gk1CazanouxPathfindingPatch[] = {
-	PATCH_ADDTOOFFSET(+15),
-	0x39, 0x7c,                      // pushi x = 124
-	0x39, 0x67,                      // pushi y = 103 (was 104)
-	PATCH_END
-};
-
-// GK1 english pc floppy locks up on day 10 in the honfour (room 800) when
-//  using the keycard on an unlocked door's keypad. This is due to mistakenly
-//  calling handsOff instead of handsOn. Sierra fixed this in floppy patch 1.0a
-//  and all other versions.
-//
-// We fix this by changing handsOff to handsOn and passing 0 as the caller
-//  to gkMessager:say since the script disposes itself.
-//
-// Applies to: English PC Floppy only
-// Responsible method: sUnlockDoor:changeState(2)
-// Fixes bug: #10767
-static const uint16 gk1HonfourUnlockDoorSignature[] = {
-	0x7c,                           // pushSelf
-	0x81, 0x5b,                     // lag global[5b]
-	0x4a, SIG_MAGICDWORD,           // send e [ gkMessager:say ... self ]
-	SIG_UINT16(0x000e),
-	0x38, SIG_UINT16(0x0216),       // pushi 0216 [ handsOff ]
-	SIG_END
-};
-
-static const uint16 gk1HonfourUnlockDoorPatch[] = {
-	0x76,                           // push0
-	0x81, 0x5b,                     // lag global[5b]
-	0x4a, PATCH_UINT16(0x000e),     // send e [ gkMessager:say ... 0 ]
-	0x38, PATCH_UINT16(0x0217),     // pushi 0217 [ handsOn ]
-	PATCH_END
-};
-
-// GK1 english pc floppy locks up on day 2 when using the binoculars to view
-//  room 410 when the artist's drawing blows away. This is particularly bad
-//  because when using the binoculars you can't use the mouse to access the
-//  control panel to restore.
-//
-// We fix this as Sierra did in later versions by not allowing the drawing to
-//  blow away when viewing through binoculars. To make room for this patch
-//  we remove initializing juggler:cycleSpeed to 6 as this is redundant.
-//  juggler is a Prop and Prop:cycleSpeed's initial value is 6.
-//
-// Applies to: English PC Floppy
-// Responsible method: neJackson:init
-// Fixes bug: #10797
-static const uint16 gk1Day2BinocularsLockupSignature[] = {
-	SIG_MAGICDWORD,
-	0x30, SIG_UINT16(0x01d6),           // bnt 01d6 [ english pc floppy 1.0 only ]
-	0x38, SIG_SELECTOR16(init),         // pushi init
-	0x76,                               // push0
-	0x38, SIG_SELECTOR16(cycleSpeed),   // pushi cycleSpeed
-	0x78,                               // push1
-	0x39, 0x06,                         // pushi 06
-	0x38, SIG_SELECTOR16(setCycle),     // pushi setCycle
-	0x78,                               // push1
-	0x51, 0x15,                         // class Fwd
-	0x36,                               // push
-	0x72, SIG_UINT16(0x02b0),           // lofsa juggler
-	0x4a, SIG_UINT16(0x0010),           // send 10 [ juggler: init, cycleSpeed: 6, setCycle: Fwd ]
-	0x38, SIG_SELECTOR16(init),         // pushi init
-	0x76,                               // push0
-	0x72, SIG_UINT16(0x0538),           // lofsa easel
-	0x4a, SIG_UINT16(0x0004),           // send 4 [ easel: init ]
-	SIG_END
-};
-
-static const uint16 gk1Day2BinocularsLockupPatch[] = {
-	PATCH_ADDTOOFFSET(+6),
-	0x3c,                               // dup
-	0x76,                               // push0
-	0x38, PATCH_SELECTOR16(setCycle),   // pushi setCycle
-	0x78,                               // push1
-	0x51, 0x15,                         // class Fwd
-	0x36,                               // push
-	0x72, PATCH_UINT16(0x02b0),         // lofsa juggler
-	0x4a, PATCH_UINT16(0x000a),         // send a [ juggler: init, setCycle Fwd ]
-	0x76,                               // push0
-	0x72, PATCH_UINT16(0x0538),         // lofsa easel
-	0x4a, PATCH_UINT16(0x0004),         // send 4 [ easel: init ]
-
-	0x89, 0x0c,                         // lsg global[0c] [ previous room ]
-	0x34, PATCH_UINT16(0x0190),         // ldi 0190 [ overlook ]
-	0x1c,                               // ne?
-	0x31, 0x09,                         // bnt 09 [ drawing doesn't blow away ]
-	PATCH_END
-};
-
-// GK1 english pc floppy has a missing-points bug on day 5 in room 240.
-//  Showing Mosely the veve sketch and Hartridge's notes awards 2 points
-//  but not if you show the notes before the veve.
-//  Sierra fixed this in floppy patch 1.0b and all other versions.
-//
-// We fix this by awarding 2 points when showing the veve second.
-//
-// Applies to: English PC Floppy
-// Responsible method: showMoselyPaper:changeState(5)
-// Fixes bug: #10763
-static const uint16 gk1Day5MoselyVevePointsSignature[] = {
-	0x78,                                   // push1
-	0x39, 0x1b,                             // pushi 1b
-	0x47, 0x0d, 0x00, SIG_UINT16(0x0002),   // calle [export 0 of script 13], 02 [ is flag 1b set? ]
-	0x30, SIG_UINT16(0x001e),               // bnt 001e [ haven't shown notes yet ]
-	0x78,                                   // push1
-	0x39, 0x1a,                             // pushi 1a
-	0x47, 0x0d, 0x01, SIG_UINT16(0x0002),   // calle [export 1 of script 13], 02 [ set flag 1a ]
-	0x38, SIG_UINT16(0x00f2),               // pushi 00f2 [ say ]
-	0x38, SIG_UINT16(0x0005),               // pushi 0005
-	0x39, 0x11,                             // pushi 11 [ noun ]
-	SIG_MAGICDWORD,
-	0x39, 0x10,                             // pushi 10 [ verb ]
-	0x39, 0x38,                             // pushi 38 [ cond ]
-	0x76,                                   // push0
-	0x7c,                                   // pushSelf
-	0x81, 0x5b,                             // lag global[5b] [ GkMessager ]
-	0x4a, SIG_UINT16(0x000e),               // send 000e [ GkMessager:say ]
-	0x32, SIG_UINT16(0x0013),               // jmp 0013
-	0x38, SIG_UINT16(0x00f2),               // pushi 00f2 [ say ]
-	SIG_END
-};
-
-static const uint16 gk1Day5MoselyVevePointsPatch[] = {
-	0x38, PATCH_UINT16(0x00f2),             // pushi 00f2 [ say ]
-	0x39, 0x05,                             // pushi 05
-	0x39, 0x11,                             // pushi 11 [ noun ]
-	0x39, 0x10,                             // pushi 10 [ verb ]
-	0x78,                                   // push1
-	0x39, 0x1b,                             // pushi 1b
-	0x47, 0x0d, 0x00, PATCH_UINT16(0x0002), // calle [export 0 of script 13], 02 [ is flag 1b set? ]
-	0x31, 0x20,                             // bnt 20 [ pushi 37, continue GkMessager:say ]
-	0x38, PATCH_UINT16(0x02fa),             // pushi 02fa [ getPoints ]
-	0x7a,                                   // push2
-	0x38, PATCH_UINT16(0xfc19),             // pushi fc19 [ no flag ]
-	0x7a,                                   // push2 [ 2 points ]
-	0x81, 0x00,                             // lag global[0]
-	0x4a, PATCH_UINT16(0x0008),             // send 8 [ GKEgo:getPoints -999 2 ]
-	0x78,                                   // push1
-	0x39, 0x1a,                             // pushi 1a
-	0x47, 0x0d, 0x01, PATCH_UINT16(0x0002), // calle [export 1 of script 13], 02 [ set flag 1a ]
-	0x39, 0x38,                             // pushi 38 [ cond ]
-	0x33, 0x09,                             // jmp 9 [ continue GkMessager:say ]
-	PATCH_END
-};
-
-// When turning on the museum's air conditioner prior to day 5 in room 260, the
-//  timing is off and speech is interrupted. Some parts of the sequence run at
-//  game speed and others don't, which at high speeds eliminates pauses between
-//  dialogue. Dr. John's "We have air conditioning, you see" speech is cut off
-//  at all speeds.
-//
-// We fix this by setting ego's speed to its default (6) during this sequence
-//  and waiting for the messages to complete before proceeding. flipTheSwitch
-//  restores ego's speed at the end of the script, even though it never sets it.
-//
-// Applies to: All CD versions
-// Responsible method: flipTheSwitch:changeState
-// Fixes bug: #11219
-static const uint16 gk1AirConditionerSpeechSignature[] = {
-	0x30, SIG_UINT16(0x0020),               // bnt 0020 [ state 1 ]
-	SIG_ADDTOOFFSET(+26),
-	0x4a, SIG_UINT16(0x000c),               // send 0c
-	0x32, SIG_UINT16(0x0409),               // jmp 0409 [ end of method ]
-	0x3c,                                   // dup
-	0x35, SIG_MAGICDWORD, 0x01,             // ldi 01
-	0x1a,                                   // eq?
-	0x30, SIG_UINT16(0x0056),               // bnt 0056 [ state 2 ]
-	SIG_ADDTOOFFSET(+24),
-	0x4a, SIG_UINT16(0x001a),               // send 1a [ GKEgo view: 265 ... ]
-	SIG_ADDTOOFFSET(+33),
-	0x4a, SIG_UINT16(0x000c),               // send 0c
-	0x32, SIG_UINT16(0x03c0),               // jmp 03c0 [ end of method ]
-	SIG_ADDTOOFFSET(+620),
-	0x7a,                                   // push2
-	SIG_ADDTOOFFSET(+3),
-	0x7c,                                   // pushSelf
-	0x81, 0x00,                             // lag 00
-	0x4a, SIG_UINT16(0x0014),               // send 14 [ GKEgo ... setCycle: End self ]
-	SIG_ADDTOOFFSET(+8),
-	0x38, SIG_UINT16(0x0004),               // pushi 0004
-	SIG_ADDTOOFFSET(+10),
-	0x4a, SIG_UINT16(0x000c),               // send 0c  [ gkMessager say: 28 8 7 4 ]
-	0x32, SIG_UINT16(0x012f),               // jmp 012f [ end of method ]
-	SIG_ADDTOOFFSET(+3),
-	0x38, SIG_UINT16(0x0004),               // pushi 0004
-	SIG_ADDTOOFFSET(+9),
-	0x4a, SIG_UINT16(0x000c),               // send 0c  [ gkMessager say: 28 8 8 4 ]
-	0x32, SIG_UINT16(0x011a),               // jmp 011a [ end of method ]
-	SIG_ADDTOOFFSET(+6),
-	0x38, SIG_SELECTOR16(stop),             // pushi stop [ stop snake sound ]
-	SIG_END
-};
-
-static const uint16 gk1AirConditionerSpeechPatch[] = {
-	0x30, PATCH_UINT16(0x001c),             // bnt 001c [ state 1 ]
-	PATCH_ADDTOOFFSET(+26),
-	0x33, 0x47,                             // jmp 47 [ send 0c / end of method ]
-	0x3c,                                   // dup
-	0x18,                                   // not
-	0x1a,                                   // eq?
-	0x31, 0x5c,                             // bnt 5c [ state 2 ]
-	0x38, PATCH_SELECTOR16(cycleSpeed),     // pushi cycleSpeed
-	0x78,                                   // push1
-	0x39, 0x06,                             // pushi 06
-	PATCH_ADDTOOFFSET(+24),
-	0x4a, PATCH_UINT16(0x0020),             // send 20 [ GKEgo cycleSpeed: 6 view: 265 ... ]
-	PATCH_ADDTOOFFSET(+659),
-	0x78,                                   // push1
-	PATCH_ADDTOOFFSET(+3),
-	0x80, PATCH_UINT16(0x0000),             // lag 0000
-	0x4a, PATCH_UINT16(0x0012),             // send 12 [ GKEgo ... setCycle: End ]
-	PATCH_ADDTOOFFSET(+8),
-	0x38, PATCH_UINT16(0x0005),             // pushi 0005
-	PATCH_ADDTOOFFSET(+10),
-	0x7c,                                   // pushSelf
-	0x4a, PATCH_UINT16(0x000e),             // send 0e [ gkMessager say: 28 8 7 4 self ]
-	0x33, 0x1b,                             // jmp 1b  [ stop snake sound ]
-	PATCH_ADDTOOFFSET(+3),
-	0x38, PATCH_UINT16(0x0005),             // pushi 0005
-	PATCH_ADDTOOFFSET(+9),
-	0x7c,                                   // pushSelf
-	0x4a, PATCH_UINT16(0x000e),             // send 0e [ gkMessager say: 28 8 8 4 self ]
-	0x33, 0x06,                             // jmp 06  [ stop snake sound ]
-	PATCH_END
-};
-
-// The day 5 snake attack has speed, audio, and graphics problems.
-//  These occur in all versions and also in Sierra's interpreter.
-//
-// Gabriel automatically walks cautiously in the darkened museum while looking
-//  around and saying lines, then a snake drops on him. Depending on the game's
-//  speed setting, the audio for "Why is it so dark in here?" is interrupted as
-//  much as halfway through by the next line, "Dr. John, hello?". The cautious
-//  walk animation runs at game speed, which can be fast, then abruptly changes
-//  to 10 (33%) when the snake drops, which looks off. Ego doesn't even reach
-//  the snake and instead stops short and warps 17 pixels to the right when the
-//  drop animation starts.
-//
-// We fix all of this. Initializing ego's speed to 10 solves the interrupted
-//  speech and inconsistent speed. It feels like this was the intended pacing.
-//  The snake-warping isn't a speed issue, ego's animation frames for this
-//  scene simply fall short of the snake's location. To fix that we start ego
-//  a little farther in the room and increase ego's final position so that he
-//  ends up directly under the snake and transitions to the drop animation
-//  smoothly. Finally, we initialize ego on the room's first cycle instead of
-//  second so that ego doesn't materialize after the room is already displayed.
-//
-// This patch works with pc floppy and cd even though they have different
-//  snakeAttack scripts. Floppy doesn't have speech to interrupt but it
-//  has the same issues.
-//
-// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
-// Responsible method: snakeAttack:changeState
-// Fixes bug: #10793
-static const uint16 gk1Day5SnakeAttackSignature1[] = {
-	0x65, 0x1a,                         // aTop cycles
-	0x32, SIG_ADDTOOFFSET(+2),          // jmp [ end of method ]
-	0x3c,                               // dup
-	0x35, 0x01,                         // ldi 1
-	SIG_MAGICDWORD,
-	0x1a,                               // eq?
-	0x30, SIG_UINT16(0x0048),           // bnt 0048 [ state 2 ]
-	0x35, 0x01,                         // ldi 1 [ free bytes ]
-	0x39, SIG_SELECTOR8(view),          // pushi view
-	0x78,                               // push1
-	0x38, SIG_UINT16(0x0107),           // pushi 0107
-	0x38, SIG_SELECTOR16(setCel),       // pushi setCel
-	0x78,                               // push1
-	0x76,                               // push0
-	0x38, SIG_SELECTOR16(setLoop),      // pushi setLoop
-	0x78,                               // push1
-	0x76,                               // push0
-	0x39, SIG_SELECTOR8(signal),        // pushi signal
-	0x78,                               // push1
-	0x39, SIG_SELECTOR8(signal),        // pushi signal
-	0x76,                               // push0
-	0x81, 0x00,                         // lag global[0]
-	0x4a, SIG_UINT16(0x0004),           // send 4 [ GKEgo:signal? ]
-	SIG_ADDTOOFFSET(+18),
-	0x39, 0x64,                         // pushi 64 [ initial x ]
-	SIG_END
-};
-
-static const uint16 gk1Day5SnakeAttackPatch1[] = {
-	0x39, PATCH_SELECTOR8(view),        // pushi view [ begin initializing ego in state 0 ]
-	0x78,                               // push1
-	0x33, 0x07,                         // jmp 07 [ continue initializing ego in state 0 ]
-	0x3c,                               // dup
-	0x18,                               // not [ acc = 1 ]
-	0x1a,                               // eq?
-	0x65, 0x1a,                         // aTop cycles [ just set cycles to 1 in state 1 ]
-	0x33, 0x48,                         // jmp 47 [ state 2 ]
-	0x38, PATCH_UINT16(0x0107),         // pushi 0107
-	0x39, PATCH_SELECTOR8(cel),         // pushi cel
-	0x78,                               // push1
-	0x76,                               // push0
-	0x38, PATCH_SELECTOR16(setLoop),    // pushi setLoop
-	0x78,                               // push1
-	0x76,                               // push0
-	0x39, PATCH_SELECTOR8(signal),      // pushi signal
-	0x78,                               // push1
-	0x38, PATCH_SELECTOR16(cycleSpeed), // pushi cycleSpeed
-	0x78,                               // push1
-	0x39, 0x0a,                         // pushi 0a
-	PATCH_ADDTOOFFSET(+5),
-	0x4a, PATCH_UINT16(0x000a),         // send a [ GKEgo:signal?, cycleSpeed = a ]
-	PATCH_ADDTOOFFSET(+18),
-	0x39, 0x70,                         // pushi 70 [ new initial x ]
-	PATCH_END
-};
-
-// This just changes ego's second x coordinate but unfortunately that promotes it to 16 bits
-static const uint16 gk1Day5SnakeAttackSignature2[] = {
-	SIG_MAGICDWORD,
-	0x39, 0x7a,                         // pushi 7a [ x for second walking loop ]
-	0x39, 0x7c,                         // pushi 7c
-	0x38, SIG_SELECTOR16(setCycle),     // pushi setCycle
-	0x7a,                               // push2
-	0x51, 0x18,                         // class End
-	0x36,                               // push
-	0x7c,                               // pushSelf
-	0x81, 0x00,                         // lag global[0]
-	0x4a, SIG_UINT16(0x0022),           // send 22
-	0x32, SIG_ADDTOOFFSET(+2),          // jmp [ end of method ]
-	SIG_END
-};
-
-static const uint16 gk1Day5SnakeAttackPatch2[] = {
-	0x38, PATCH_UINT16(0x008b),         // pushi 008b [ new x for second walking loop ]
-	0x39, 0x7c,                         // pushi 7c
-	0x38, PATCH_SELECTOR16(setCycle),   // pushi setCycle
-	0x7a,                               // push2
-	0x51, 0x18,                         // class End
-	0x36,                               // push
-	0x7c,                               // pushSelf
-	0x81, 0x00,                         // lag global[0]
-	0x4a, PATCH_UINT16(0x0022),         // send 22
-	0x3a,                               // toss
-	0x48,                               // ret
-	PATCH_END
-};
-
-// When entering the police station (room 230) sGabeEnters sets ego speed
-//  to 4 for the door animation but fails to restore it to the game speed
-//  by calling GKEgo:normalize. This leaves ego at 75% speed until doing
-//  something that does call normalize.
-//
-// We fix this by calling GKEgo:normalize after Gabriel finishes walking
-//  through the door in sGabeEnters:changeState(4). This replaces setting
-//  GKEgo:ignoreActors to 0 but that's okay because normalize does that.
-//
-// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
-// Responsible method: sGabeEnters:changeState(4)
-// Fixes bug: #10780
-static const uint16 gk1PoliceEgoSpeedFixSignature[] = {
-	0x38, SIG_MAGICDWORD,               // pushi ignoreActors
-	      SIG_SELECTOR16(ignoreActors),
-	0x78,                               // push1
-	0x76,                               // push0
-	0x81, 0x00,                         // lag global[0]
-	0x4a, SIG_UINT16(0x000c),           // send c [ GKEgo: ..., ignoreActors: 0 ]
-	SIG_END
-};
-
-static const uint16 gk1PoliceEgoSpeedFixPatch[] = {
-	0x38, PATCH_SELECTOR16(normalize),  // pushi normalize
-	0x39, 0x00,                         // pushi 00
-	0x81, 0x00,                         // lag global[0]
-	0x4a, PATCH_UINT16(0x000a),         // send a [ GKEgo: ..., normalize ]
-	PATCH_END
-};
-
-// When exiting the drugstore (room 250) egoExits sets ego speed to 15
-//  (slowest) for the door animation but fails to restore it to game
-//  speed by calling GKEgo:normalize. This leaves ego slow until doing
-//  something that does call normalize.
-//
-// We fix this by calling GKEgo:normalize after the door animation.
-//
-// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
-// Responsible method: egoExits:changeState
-// Fixes bug: #10780
-static const uint16 gk1DrugStoreEgoSpeedFixSignature[] = {
-	0x30, SIG_UINT16(0x003f),           // bnt 003f [ state 1 ]
-	SIG_ADDTOOFFSET(+60),
-	SIG_MAGICDWORD,
-	0x32, SIG_UINT16(0x0012),           // jmp 12 [ end of method ]
-	0x3c,                               // dup
-	0x35, 0x01,                         // ldi 1
-	0x1a,                               // eq?
-	0x31, 0x0c,                         // bnt c [ end of method ]
-	0x38, SIG_SELECTOR16(newRoom),      // pushi newRoom
-	0x78,                               // push1
-	0x38, SIG_UINT16(0x00c8),           // pushi 00c8 [ map ]
-	0x81, 0x02,                         // lag global[2]
-	0x4a, SIG_UINT16(0x0006),           // send 6 [ rm250:newRoom = map ]
-	0x3a,                               // toss
-	SIG_END
-};
-
-static const uint16 gk1DrugStoreEgoSpeedFixPatch[] = {
-	0x3a,                               // toss
-	0x31, 0x3d,                         // bnt 3d [ state 1 ]
-	PATCH_ADDTOOFFSET(+60),
-	0x48,                               // ret
-	0x38, PATCH_SELECTOR16(normalize),  // pushi normalize
-	0x76,                               // push0
-	0x81, 0x00,                         // lag global[0]
-	0x4a, PATCH_UINT16(0x0004),         // send 4 [ GKEgo:normalize ]
-	0x38, PATCH_SELECTOR16(newRoom),    // pushi newRoom
-	0x78,                               // push1
-	0x38, PATCH_UINT16(0x00c8),         // pushi 00c8 [ map ]
-	0x81, 0x02,                         // lag global[2]
-	0x4a, PATCH_UINT16(0x0006),         // send 6 [ rm250:newRoom = map ]
-	PATCH_END
-};
-
-// GK1 CD version cuts off Grace's speech when hanging up the phone on day 1.
-//  This is a timing issue that also occurs in the original.
-//
-// startingCartoon:changeState(12) plays Grace's final phone message but doesn't
-//  synchronize it with the script. Instead ego goes through a series of movements
-//  that advance the state while Grace is speaking. Once the sequence is complete
-//  Grace hangs up the phone and starts her next message which interrupts the
-//  previous one. There is no mechanism to make sure that Grace's message has
-//  first completed and so it cut offs the last one or two words. The timing only
-//  worked in the original on slower machines that weren't able to run the
-//  sequence at full speed.
-//
-// We fix this by adding a delay to startingCartoon:changeState(18) so that
-//  Grace's speech has time to complete. This scene occurs before game speed
-//  can be set and it plays at a consistent speed on ScummVM.
-//
-// This patch is only applied to CD versions. Floppies have a different script.
-//
-// Applies to: All CD versions
-// Responsible method: startingCartoon:changeState(18)
-// Fixes bug: #10787
-static const uint16 gk1Day1GracePhoneSignature[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x12,                 // ldi 12
-	0x1a,                       // eq?
-	0x31, 0x2c,                 // bnt 2c
-	SIG_ADDTOOFFSET(+28),
-	0x38, SIG_UINT16(0x0003),   // pushi 0003
-	0x51, 0x69,                 // class Osc
-	0x36,                       // push
-	0x78,                       // push1
-	0x7c,                       // pushSelf
-	0x81, 0x00,                 // lag global[0]
-	0x4a, SIG_UINT16(0x0024),   // send 24 [ GKEgo: ... setCycle: Osc 1 self ]
-	0x32, SIG_ADDTOOFFSET(+2),  // jmp [ end of method ]
-	SIG_END
-};
-
-static const uint16 gk1Day1GracePhonePatch[] = {
-	PATCH_ADDTOOFFSET(+33),
-	0x7a,                       // push2
-	0x51, 0x69,                 // class Osc
-	0x36,                       // push
-	0x78,                       // push1
-	0x81, 0x00,                 // lag global[0]
-	0x4a, PATCH_UINT16(0x0022), // send 22 [ GKEgo: ... setCycle: Osc 1 ]
-
-	// advance to the next state in 6 seconds instead of when Gabriel finishes
-	//  taking a sip of coffee, which takes 2 seconds, giving Grace's speech
-	//  an extra 4 seconds to complete.
-	0x35, 0x06,                 // ldi 06
-	0x65, 0x1c,                 // aTop seconds
-
-	0x3a,                       // toss
-	0x48,                       // ret
-	PATCH_END
-};
-
-// French and Spanish CD versions contain an active debugging hotkey, ALT+N,
-//  which brings up a series of unskippable bug-reporting dialogs and
-//  eventually writes files to disk and crashes non-release builds due to
-//  an uninitialized read. This hotkey is always active and not hidden
-//  behind the game's debug mode flag so we just patch it out.
-//
-// Applies to: French and Spanish PC CD
-// Responsible method: GK:handleEvent
-// Fixes bug: #10781
-static const uint16 gk1SysLoggerHotKeySignature[] = {
-	SIG_MAGICDWORD,
-	0x34, SIG_UINT16(0x3100),       // ldi 3100 [ ALT+N ]
-	0x1a,                           // eq?
-	0x31,                           // bnt
-	SIG_END
-};
-
-static const uint16 gk1SysLoggerHotKeyPatch[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x33,                           // jmp
-	PATCH_END
-};
-
-// After interrogating Gran in room 380, the room is re-initialized incorrectly.
-//  Clicking on objects while seated causes Gabriel to briefly flicker into
-//  standing and other frames. After standing, the knitting basket can be walked
-//  through. These are script bugs which also occur in Sierra's interpreter.
-//
-// Ego is initialized incorrectly by rm380:init when returning from interrogation
-//  (room 50). Several properties are wrong and it's bad luck that it works as
-//  well as it does or Sierra would have noticed. For comparison, the scripts
-//  egoEnters and sitDown do it correctly. rm380:init first initializes ego for
-//  walking and then applies only some of the properties for sitting in the chair.
-//
-// This leaves ego in a walking/sitting state with several problems:
-//  - signal flag kSignalDoesntTurn isn't set
-//  - cycler is set to StopWalk instead of none
-//  - loop/cel is set to 2 0 instead of 0 5
-//
-// rm380:init sets ego's loop/cel to 0 5 (Gabriel sitting) but the unexpected
-//  StopWalk immediately changes this to 2 0 (Gabriel starts talking) which went
-//  unnoticed because those two frames are similar. This is why Gabriel's hand
-//  is slightly raised when returning from interrogation. The flickering is due
-//  to ego attempting to turn to face items while sitting due to kSignalDoesntTurn
-//  not being set.
-//
-// We fix the flickering by passing a second parameter to GKEgo:setLoop which
-//  causes kSignalDoesntTurn to be set, preventing ego from attempting to face
-//  objects being clicked, just as egoEnters and sitDown do. We fix the knitting
-//  basket by adding its obstacle polygon to the room even when returning from
-//  interrogation, which Sierra forgot to do.
-//
-// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
-// Responsible method: rm380:init
-// Fixes bug: #9760, #10707
-static const uint16 gk1GranRoomInitSignature[] = {
-	0x38, SIG_SELECTOR16(setCel),       // pushi setCel
-	0x78,                               // push1
-	0x39, 0x05,                         // pushi 05
-	0x38, SIG_SELECTOR16(setLoop),      // pushi setLoop
-	0x78,                               // push1
-	0x76,                               // push0 [ loop: 0 ]
-	0x38, SIG_SELECTOR16(init),         // pushi init
-	0x76,                               // push0
-	0x38, SIG_SELECTOR16(posn),         // pushi posn
-	SIG_MAGICDWORD,
-	0x7a,                               // push2
-	0x38, SIG_UINT16(0x00af),           // pushi 00af
-	0x39, 0x75,                         // pushi 75
-	0x81, 0x00,                         // lag global[0]
-	0x4a, SIG_UINT16(0x001e),           // send 1e [ GKEgo: ... setCel: 5, setLoop: 0 ... ]
-	0x35, 0x01,                         // ldi 1
-	0xa3, 0x00,                         // sal local[0] [ 1, a non-zero value indicates ego is sitting ]
-	SIG_END
-};
-
-static const uint16 gk1GranRoomInitPatch[] = {
-	0x39, PATCH_SELECTOR8(cel),         // pushi cel [ use cel instead of equivalent setCel to save a byte ]
-	0x78,                               // push1
-	0x39, 0x05,                         // pushi 05
-	0x38, PATCH_SELECTOR16(setLoop),    // pushi setLoop
-	0x7a,                               // push2
-	0x76,                               // push0 [ loop: 0 ]
-	0x78,                               // push1 [ 2nd param tells setLoop to set kSignalDoesntTurn ]
-	0x38, PATCH_SELECTOR16(init),       // pushi init
-	0x76,                               // push0
-	0x38, PATCH_SELECTOR16(posn),       // pushi posn
-	0x7a,                               // push2
-	0x38, PATCH_UINT16(0x00af),         // pushi 00af
-	0x39, 0x75,                         // pushi 75
-	0x81, 0x00,                         // lag global[0]
-	0xa3, 0x00,                         // sal local[0] [ setting a non-zero object instead of 1 saves 2 bytes ]
-	0x4a, PATCH_UINT16(0x0020),         // send 20 [ GKEgo: ... cel: 5, setLoop: 0 1 ... ]
-	0x33, 0x87,                         // jmp -79 [ add knitting basket obstacle to room ]
-	PATCH_END
-};
-
-// After phoning Wolfgang on day 7, Gabriel is placed beyond room 220's obstacle
-//  boundary and can walk through walls and behind the room. This also occurs in
-//  the original. The script inconsistently uses accessible and inaccessible
-//  positions for placing ego next to the phone. We patch all instances to use
-//  the accessible position.
-//
-// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
-// Responsible methods: rm220:init, useThePhone:changeState(0)
-// Fixes bug: #10853
-static const uint16 gk1EgoPhonePositionSignature[] = {
-	SIG_MAGICDWORD,
-	0x39, 0x68,                         // pushi 68 [ x: 104 ]
-	0x39, 0x7e,                         // pushi 7e [ y: 126 ]
-	SIG_END
-};
-
-static const uint16 gk1EgoPhonePositionPatch[] = {
-	0x39, 0x6b,                         // pushi 6b [ x: 107 ]
-	0x39, 0x7c,                         // pushi 7c [ y: 124 ]
-	PATCH_END
-};
-
-// Restarting the game doesn't reset the current inventory item in the icon bar.
-//  The previously selected item can then be used on day 1.
-//
-// Room 93 restarts the game and resets inventory by setting each item's owner
-//  to zero. It makes no attempt to reset the icon bar. We fix this by instead
-//  calling GKEgo:put on each item and passing zero for the new owner, as this
-//  handles updating the icon bar when dropping an item. The "state" property is
-//  no longer cleared for items but that's okay because it's never set or used.
-//
-// Applies to: All versions
-// Responsible method: doTheRestart:changeState(0)
-// Fixes bug: #11222
-static const uint16 gk1RestartInventorySignature[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(owner),            // pushi owner
-	0x78,                                   // push1
-	0x76,                                   // push0
-	0x39, SIG_SELECTOR8(state),             // pushi state
-	0x78,                                   // push1
-	0x76,                                   // push0
-	0x39, SIG_SELECTOR8(at),                // pushi at
-	0x78,                                   // push1
-	0x8b, 0x00,                             // lsl 00
-	0x81, 0x09,                             // lag 09
-	0x4a, SIG_UINT16(0x0006),               // send 06 [ GKInventory at: local0 ]
-	0x4a, SIG_UINT16(0x000c),               // send 0c [ item owner: 0 state: 0 ]
-	SIG_END
-};
-
-static const uint16 gk1RestartInventoryPatch[] = {
-	0x38, PATCH_SELECTOR16(put),            // pushi put
-	0x7a,                                   // push2
-	0x8b, 0x00,                             // lsl 00
-	0x76,                                   // push0
-	0x81, 0x00,                             // lag 00
-	0x4a, PATCH_UINT16(0x0008),             // send 08 [ GKEgo put: local0 0 ]
-	0x33, 0x08,                             // jmp 08
-	PATCH_END
-};
-
-// On day 6 in Jackson Square, if you never gave Madame Lorelei her veil on an
-//  earlier day, then looking at her empty booth says that she's sitting there.
-//  Clicking Operate also says the wrong message. The logic in the booth and
-//  chair doVerb methods doesn't consider that this optional action might not
-//  occur by day 6. We add the missing day check by overwriting a redundant
-//  local variable test.
-//
-// Applies to: All versions
-// Responsible methods: booth:doVerb, chair1:doVerb, chair2:doVerb
-static const uint16 gk1EmptyBoothMessageSignature[] = {
-	SIG_MAGICDWORD,
-	0x30, SIG_UINT16(0x001a),               // bnt 001a [ skip lorelei message ]
-	0x83, 0x01,                             // lal 01   [ always zero ]
-	0x18,                                   // not
-	0x30, SIG_UINT16(0x0014),               // bnt 0014 [ skip lorelei message ]
-	SIG_END
-};
-
-static const uint16 gk1EmptyBoothMessagePatch[] = {
-	0x31, 0x1b,                             // bnt 1b [ skip lorelei message ]
-	0x89, 0x7b,                             // lsg 7b
-	0x35, 0x05,                             // ldi 05
-	0x24,                                   // le?    [ day <= 5 ]
-	0x31, 0x14,                             // bnt 14 [ skip lorelei message ]
-	PATCH_END
-};
-
-// Madame Lorelei has an obscure timer bug that can cause events to repeat and
-//  award duplicate points. When exiting the conversation with her by selecting
-//  "Er...nothing.", fortuneTeller:cue resets the dance timer incorrectly.
-//  loreleiTimer's client is the room. When it fires, nwJackson:cue tests flags
-//  and room conditions before running the sLoreleiDance script, otherwise it
-//  resets the timer for 5 seconds. When fortuneTeller:cue resets the timer it
-//  changes the client to sLoreleiDance, bypassing the checks in nwJackson:cue.
-//  Madame Lorelei can then dance and drop her veil a second time while Gabriel
-//  already has it, among other edge cases.
-//
-// We fix this by setting the room as the client when resetting the timer. This
-//  requires calling dispose first since the timer is already running, which
-//  might have been what led to this script being written differently.
-//
-// Applies to: All versions
-// Responsible method: fortuneTeller:cue
-static const uint16 gk1LoreleiDanceTimerSignature[] = {
-	0x30, SIG_UINT16(0x0005),               // bnt 0005
-	0xc3, SIG_MAGICDWORD, 0x04,             // +al 04
-	0x32, SIG_UINT16(0x001f),               // jmp 001f
-	0x3c,                                   // dup
-	0x35, 0x10,                             // ldi 10 [ "Er...nothing." ]
-	0x1a,                                   // eq?
-	0x30, SIG_UINT16(0x0018),               // bnt 0018
-	0x38, SIG_SELECTOR16(setReal),          // pushi setReal
-	0x7a,                                   // push2
-	0x72, SIG_ADDTOOFFSET(+2),              // lofsa sLoreleiDance
-	0x36,                                   // push
-	SIG_ADDTOOFFSET(+13),
-	0x4a, SIG_UINT16(0x0008),               // send 08 [ loreleiTimer setReal: sLoreleiDance ... ]
-	SIG_END
-};
-
-static const uint16 gk1LoreleiDanceTimerPatch[] = {
-	0x30, PATCH_UINT16(0x0004),             // bnt 0004
-	PATCH_ADDTOOFFSET(+2),
-	0x33, 0x20,                             // jmp 20
-	0x3c,                                   // dup
-	0x35, 0x10,                             // ldi 10 [ "Er...nothing." ]
-	0x1a,                                   // eq?
-	0x31, 0x1a,                             // bnt 1a
-	0x38, PATCH_SELECTOR16(dispose),        // pushi dispose
-	0x76,                                   // push0
-	0x38, PATCH_SELECTOR16(setReal),        // pushi setReal
-	0x7a,                                   // push2
-	0x89, 0x02,                             // lsg 02
-	PATCH_ADDTOOFFSET(+13),
-	0x4a, PATCH_UINT16(0x000c),             // send 0c [ loreleiTimer dispose: setReal: nwJackson ... ]
-	PATCH_END
-};
-
-// When walking between rooms in Jackson Square, the cursor is often initialized
-//  to the wrong view, even though it's really the Walk cursor. This seemingly
-//  random event with many variations is due to a bug in the ExitFeature class.
-//
-// ExitFeature is responsible for swapping the cursor with an Exit cursor when
-//  the mouse is over it and then restoring afterwards. The previous cursor is
-//  stored in ExitFeature:lastCursor. The first problem is that ExitFeature:init
-//  initializes lastCursor to the current cursor even though the mouse hasn't
-//  touched it yet. The second problem is that ExitFeature:dispose restores the
-//  cursor to lastCursor if the current cursor is any Exit cursor, including
-//  ones it's not responsible for. Entering Jackson Square from the cathedral
-//  causes all three ExitFeatures in the room to initialize lastCursor to
-//  theWaitCursor (the shield). When exiting the room, the ExitFeatures are
-//  disposed in the order they were added, which means northExit disposes first.
-//  northExit:lastCursor is still theWaitCursor unless it was moused over.
-//  Exiting to another Jackson Square room will cause northExit:dispose to check
-//  if the cursor is globeCursor, which represents all Exit cursors, and if so
-//  then it will incorrectly restore the cursor to theWaitCursor, preventing
-//  the ExitFeature responsible for the room change from correctly restoring.
-//
-// We fix this by patching ExitFeature:dispose to only restore the cursor if
-//  its view matches the Exit cursor that it's responsible for.
-//
-// Applies to: All versions
-// Responsible method: ExitFeature:dispose
-static const uint16 gk1ExitFeatureCursorSignature[] = {
-	0x89, 0x13,                             // lsg 13 [ current-cursor ]
-	0x7a,                                   // push2
-	0x76,                                   // push0
-	0x78,                                   // push1
-	0x43, 0x02, SIG_UINT16(0x0004),         // callk ScriptID 0 1 [ globeCursor ]
-	0x1a,                                   // eq?
-	0x31, 0x0b,                             // bnt 0b [ skip if current-cursor isn't an exit cursor ]
-	0x38, SIG_SELECTOR16(setCursor),        // pushi setCursor
-	0x78,                                   // push1
-	0x67, SIG_ADDTOOFFSET(+1),              // pTos lastCursor
-	0x81, 0x01,                             // lag 01
-	0x4a, SIG_UINT16(0x0006),               // send 06 [ GK1 setCursor: lastCursor ]
-	SIG_MAGICDWORD,
-	0x39, SIG_SELECTOR8(delete),            // pushi delete
-	0x78,                                   // push1
-	0x7c,                                   // pushSelf
-	0x81, 0xce,                             // lag ce
-	0x4a, SIG_UINT16(0x0006),               // send 06 [ gk1Exits delete: self ]
-	0x48,                                   // ret
-	SIG_ADDTOOFFSET(+372),
-	0x38, SIG_SELECTOR16(setCursor),        // pushi setCursor
-	0x78,                                   // push1
-	0x67, SIG_ADDTOOFFSET(+1),              // pTos lastCursor
-	0x81, 0x01,                             // lag 01
-	0x4a, SIG_UINT16(0x0006),               // send 06 [ GK1 setCursor: lastCursor ]
-	0x35, 0x01,                             // ldi 01
-	0x65, SIG_ADDTOOFFSET(+1),              // aTop eCursor [ eCursor = 1 ]
-	0x48,                                   // ret
-	SIG_END
-};
-
-static const uint16 gk1ExitFeatureCursorPatch[] = {
-	0x39, PATCH_SELECTOR8(delete),          // pushi delete
-	0x78,                                   // push1
-	0x7c,                                   // pushSelf
-	0x81, 0xce,                             // lag ce
-	0x4a, PATCH_UINT16(0x0006),             // send 06 [ gk1Exits delete: self ]
-	0x39, PATCH_SELECTOR8(view),            // pushi view
-	0x76,                                   // push0
-	0x81, 0x13,                             // lag 13  [ current-cursor ]
-	0x4a, PATCH_UINT16(0x0004),             // send 04 [ current-cursor: view? ]
-	0x67, PATCH_GETORIGINALBYTEADJUST(+17, -2), // pTos cursor
-	0x1a,                                   // eq?     [ current-cursor:view == self:cursor ]
-	0x2e, PATCH_UINT16(0x017e),             // bt 017e [ GK1 setCursor: lastCursor ]
-	0x48,                                   // ret
-	PATCH_END
-};
-
-// The Windows CD version never plays its AVI videos during the bayou ritual,
-//  instead it runs the view-based slide shows for the floppy versions. The
-//  ritual script contains the normal code for playing its AVI and SEQ files
-//  depending on kPlatform, just like every video script in the game, except
-//  that the initial floppy flag test has been replaced with another kPlatform
-//  call which prevents the real platform test from executing.
-//
-// It's unclear if this is a script bug or why it would be intentional, but
-//  the end result is that selecting Windows as the platform excludes videos
-//  from this one scene whereas selecting DOS doesn't, so we patch the platform
-//  tests back to floppy tests like everywhere else and enable the AVI videos.
-//
-// Applies to: All CD versions, though only English versions support Windows
-// Responsible method: roomScript:changeState
-// Fixes bug: #9807
-static const uint16 gk1BayouRitualAviSignature[] = {
-	0x76,                                   // push0
-	0x43, 0x68, SIG_UINT16(0x0000),         // callk Platform
-	SIG_MAGICDWORD,
-	0x36,                                   // push
-	0x35, 0x01,                             // ldi 01 [ DOS ]
-	0x1c,                                   // ne?
-	SIG_END
-};
-
-static const uint16 gk1BayouRitualAviPatch[] = {
-	0x78,                                   // push1
-	0x38, PATCH_UINT16(0x01d6),             // pushi 01d6     [ flag 470 ]
-	0x47, 0x0d, 0x00, PATCH_UINT16(0x0002), // calle proc13_0 [ is floppy flag set? ]
-	PATCH_END
-};
-
-// The comic-book cartoon scenes have timing problems. Many delays are too fast,
-//  instantaneous, or random. As with other GK1 timing bugs, these scripts were
-//  written against CPUs that couldn't run the interpreter at full speed.
-//
-// Most cartoon delays are implemented by setting Script:seconds to one or two.
-//  At slower CPU speeds, Sierra's interpreter lagged enough that it appeared to
-//  deliver the requested durations. But without that lag, the real behavior is
-//  exposed. When Script:seconds is set, the first second is deducted on the
-//  next doit except in some cases when there are stale values from a previous
-//  delay. A one second delay is usually no delay at all. Subsequent seconds
-//  are deducted whenever the seconds value of the system clock changes. This
-//  means that the duration of the 2nd "second" depends on the system clock's
-//  subsecond value when the delay was requested. A script that requests a two
-//  second delay usually gets a random delay between zero and one second.
-//
-// We fix this by replacing all the one and two second cartoon delays with the
-//  equivalent in ticks. This makes the durations match the requested values and
-//  removes the inconsistencies due to subseconds. These correct timings expose
-//  broken animation in one of the bayou cartoon panels due to the script
-//  specifying the wrong view number, so we fix that too.
-//
-// There is still room for improvement in the bayou cartoons. Several delays are
-//  implemented by waiting on disabled messages that instantly cue. All fades
-//  are done by unthrottled inner loops and the scene timing implicitly depends
-//  on those going slowly. This is why several panels only appear for an instant
-//  before the entire screen changes.
-//
-// Applies to: All versions
-// Responsible methods: doTheCloseUp:changeState, roomScript:changeState (480),
-//                      cutToTheHeart:changeState, sCutPanel1:changeState,
-//                      sCutPanel2:changeState, sCutPanel4:changeState
-static const uint16 gk1CartoonTimingPcSignature1[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x01,                         // ldi 01
-	0x65, 0x1c,                         // aTop seconds [ seconds = 1 ]
-	SIG_END
-};
-
-static const uint16 gk1CartoonTimingMacSignature1[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x01,                         // ldi 01
-	0x65, 0x1e,                         // aTop seconds [ seconds = 1 ]
-	SIG_END
-};
-
-static const uint16 gk1CartoonTimingPatch1[] = {
-	0x35, 0x3c,                                // ldi 3c
-	0x65, PATCH_GETORIGINALBYTEADJUST(+3, +4), // aTop ticks [ ticks = 60 ]
-	PATCH_END
-};
-
-static const uint16 gk1CartoonTimingPcSignature2[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x02,                         // ldi 02
-	0x65, 0x1c,                         // aTop seconds [ seconds = 2 ]
-	SIG_END
-};
-
-static const uint16 gk1CartoonTimingMacSignature2[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x02,                         // ldi 02
-	0x65, 0x1e,                         // aTop seconds [ seconds = 2 ]
-	SIG_END
-};
-
-static const uint16 gk1CartoonTimingPatch2[] = {
-	0x35, 0x78,                                // ldi 78
-	0x65, PATCH_GETORIGINALBYTEADJUST(+3, +4), // aTop ticks [ ticks = 120 ]
-	PATCH_END
-};
-
-// During the bayou cartoon when Malia recognizes Gabriel, the third panel's
-//  animation is broken. The script attempts to animate Gabriel's face but it
-//  instead it specifies the wrong view and draws a fragment of Malia's face.
-//  This wasn't noticed because of the broken timing (see above patch notes)
-//  that immediately overwrote the wrong first view with the correct second.
-//  Now that we've fixed the timing, we fix this view as well so that the panel
-//  animates correctly. We know that 6142 is the correct view because the script
-//  attempts to unload it afterwards.
-//
-// Applies to: All versions
-// Responsible method: roomScript:changeState(64)
-static const uint16 gk1BayouCartoonViewSignature[] = {
-	0x39, SIG_SELECTOR8(view),          // pushi view
-	SIG_MAGICDWORD,
-	0x78,                               // push1
-	0x38, SIG_UINT16(0x17fd),           // pushi 17fd [ view 6141: Malia ]
-	SIG_END
-};
-
-static const uint16 gk1BayouCartoonViewPatch[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x38, PATCH_UINT16(0x17fe),         // pushi 17fe [ view 6142: Gabriel ]
-	PATCH_END
-};
-
-// On day 6, an envelope is dropped off in the bookstore after 20 seconds, but
-//  if the game is in the middle of a message sequence then it can lockup.
-//  When a timer expires, bookstore:cue tests a number of properties to make
-//  sure that it's not interrupting anything, but unlike other rooms such as
-//  nwJackson:cue it doesn't test if a message is being said. Looking at Grace
-//  triggers one of many message sequences which can prevent ego from completing
-//  his turn to face the door, leaving dropTheEnvelope stuck in handsOff mode.
-//
-// We fix this by adding a test to bookstore:cue to verify that a message isn't
-//  being said, just like nwJackson:cue. We make room for this by overwriting a
-//  redundant handsOff call. This also prevents the florist script from starting
-//  in the middle of a message, as this could have similar conflicts.
-//
-// Applies to: All versions
-// Responsible method: bookstore:cue
-static const uint16 gk1Day6EnvelopeSignature[] = {
-	SIG_MAGICDWORD,
-	0x39, SIG_SELECTOR8(state),             // pushi state
-	0x76,                                   // push0
-	0x51, SIG_ADDTOOFFSET(+1),              // class CueObj
-	0x4a, SIG_UINT16(0x0004),               // send 04 [ CueObj state? ]
-	0x18,                                   // not
-	0x31, SIG_ADDTOOFFSET(+1),              // bnt [ reset timer ]
-	0x38, SIG_SELECTOR16(handsOff),         // pushi handsOff
-	0x76,                                   // push0
-	0x81, 0x01,                             // lag 01
-	0x4a, SIG_UINT16(0x0004),               // send 04 [ GK1 handsOff: ]
-	SIG_END
-};
-
-static const uint16 gk1Day6EnvelopePatch[] = {
-	PATCH_ADDTOOFFSET(+8),
-	0x2f, PATCH_GETORIGINALBYTEADJUST(+10, +1), // bt [ reset timer ]
-	0x39, PATCH_SELECTOR8(size),                // pushi size
-	0x76,                                       // push0
-	0x81, 0x54,                                 // lag 54
-	0x4a, PATCH_UINT16(0x0004),                 // send 04 [ talkers size? ]
-	0x2f, PATCH_GETORIGINALBYTEADJUST(+10, -9), // bt [ reset timer ]
-	PATCH_END
-};
-
-// GK1 Mac is missing view 56, which is the close-up of the talisman. Clicking
-//  Look on the talisman from inventory is supposed to display an inset with
-//  view 56 and say a message, but instead this would crash the Mac interpreter.
-//
-// We fix this by skipping the talisman inset when view 56 isn't present in the
-//  Mac version. The default verb handler still says the talisman message.
-//
-// Applies to: Mac Floppy
-// Responsible method: talisman:doVerb
-static const uint16 gk1MacTalismanInsetSignature[] = {
-	0x31, 0x3e,                             // bnt 3e [ super doVerb: verb &rest ]
-	0x39, SIG_SELECTOR8(hide),              // pushi hide
-	0x78,                                   // push1
-	0x78,                                   // push1
-	0x81, 0x09,                             // lag 09
-	0x4a, SIG_UINT16(0x0006),               // send 06 [ GKInventory hide: 1 ]
-	0x39, SIG_SELECTOR8(doit),              // pushi doit
-	0x38, SIG_MAGICDWORD,                   // pushi 0008
-	      SIG_UINT16(0x0008),
-	0x39, 0x38,                             // pushi 38 [ talisman view ]
-	SIG_END
-};
-
-static const uint16 gk1MacTalismanInsetPatch[] = {
-	0x33,                                   // jmp [ super doVerb: verb &rest ]
-	PATCH_END
-};
-
-// In the final scene before the credits the wrong font is used and the 'a' with
-//  an umlaut in "Schattenjager" isn't displayed. endTalker:font is set to 999
-//  which doesn't include decorated characters. Font 40 has the same glyphs as
-//  999 plus the decorated characters, so we use that instead. This patch is
-//  only to be applied to English versions; localized ones have different fonts.
-//
-// Applies to: English CD versions
-// Responsible method: heap in script 670
-static const uint16 gk1EndGameFontSignature[] = {
-	SIG_MAGICDWORD,                     // endTalker
-	SIG_UINT16(0x0002),                 // modeless = 2
-	SIG_UINT16(0x03e7),                 // font = 999
-	SIG_END
-};
-
-static const uint16 gk1EndGameFontPatch[] = {
-	PATCH_ADDTOOFFSET(+2),
-	PATCH_UINT16(0x0028),               // font = 40
-	PATCH_END
-};
-
-// Narrator lockup fix for GK1 CD / Mac, see sciNarratorLockupSignature.
-//  The custom code in these versions overlaps with the generic patch signature
-//  so we enable the correct one based on game version and platform.
-static const uint16 gk1NarratorLockupSignature[] = {
-	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += game time ]
-	0x33, 0x0b,                         // jmp 0b
-	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
-	SIG_MAGICDWORD,
-	0x35, 0x3c,                         // ldi 3c
-	0x02,                               // add
-	0x36,                               // push
-	0x81, 0x58,                         // lag 58 [ game time ]
-	0x02,                               // add
-	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time ]
-	0x35, 0x01,                         // ldi 01 [ true ]
-	0x48,                               // ret
-	SIG_END
-};
-
-static const uint16 gk1NarratorLockupPatch[] = {
-	PATCH_ADDTOOFFSET(+2),
-	0x33, 0x0a,                         // jmp 0a
-	PATCH_ADDTOOFFSET(+5),
-	0x89, 0x58,                         // lsg 58 [ game time ]
-	0x02,                               // add
-	0x65, PATCH_GETORIGINALBYTE(+1),    // aTop ticks [ ticks += 60 + game time ]
-	0x00,                               // bnot
-	0x31, 0xfb,                         // bnt fb [ set ticks to 0 if ticks == -1 ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                         patch
-static const SciScriptPatcherEntry gk1Signatures[] = {
-	{  true,     0, "remove alt+n syslogger hotkey",               1, gk1SysLoggerHotKeySignature,      gk1SysLoggerHotKeyPatch },
-	{  true,    17, "disable video benchmarking",                  1, sci2BenchmarkSignature,           sci2BenchmarkPatch },
-	{  true,    21, "fix ExitFeature cursor restore",              1, gk1ExitFeatureCursorSignature,    gk1ExitFeatureCursorPatch },
-	{  false,   24, "mac: fix missing talisman view",              1, gk1MacTalismanInsetSignature,     gk1MacTalismanInsetPatch },
-	{  true,    51, "fix interrogation bug",                       1, gk1InterrogationBugSignature,     gk1InterrogationBugPatch },
-	{  true,    93, "fix inventory on restart",                    1, gk1RestartInventorySignature,     gk1RestartInventoryPatch },
-	{  true,   210, "fix day 6 envelope lockup",                   2, gk1Day6EnvelopeSignature,         gk1Day6EnvelopePatch },
-	{  true,   211, "fix day 1 grace phone speech timing",         1, gk1Day1GracePhoneSignature,       gk1Day1GracePhonePatch },
-	{  true,   212, "fix day 5 drum book dialogue error",          1, gk1Day5DrumBookDialogueSignature, gk1Day5DrumBookDialoguePatch },
-	{  true,   212, "fix day 5 phone softlock",                    1, gk1Day5PhoneFreezeSignature,      gk1Day5PhoneFreezePatch },
-	{  true,   220, "fix ego phone position",                      2, gk1EgoPhonePositionSignature,     gk1EgoPhonePositionPatch },
-	{  true,   230, "fix day 6 police beignet timer issue (1/2)",  1, gk1Day6PoliceBeignetSignature1,   gk1Day6PoliceBeignetPatch1 },
-	{  true,   230, "fix day 6 police beignet timer issue (2/2)",  1, gk1Day6PoliceBeignetSignature2,   gk1Day6PoliceBeignetPatch2 },
-	{  true,   230, "fix day 6 police sleep timer issue",          1, gk1Day6PoliceSleepSignature,      gk1Day6PoliceSleepPatch },
-	{  true,   230, "fix police station ego speed",                1, gk1PoliceEgoSpeedFixSignature,    gk1PoliceEgoSpeedFixPatch },
-	{  true,   231, "fix beignet vendor speed",                    1, gk1BeignetVendorSpeedSignature,   gk1BeignetVendorSpeedPatch },
-	{  true,   240, "fix day 5 mosely veve missing points",        1, gk1Day5MoselyVevePointsSignature, gk1Day5MoselyVevePointsPatch },
-	{  true,   250, "fix ego speed when exiting drug store",       1, gk1DrugStoreEgoSpeedFixSignature, gk1DrugStoreEgoSpeedFixPatch },
-	{  true,   260, "fix air conditioner speech timing",           1, gk1AirConditionerSpeechSignature, gk1AirConditionerSpeechPatch },
-	{  true,   260, "fix day 5 snake attack (1/2)",                1, gk1Day5SnakeAttackSignature1,     gk1Day5SnakeAttackPatch1 },
-	{  true,   260, "fix day 5 snake attack (2/2)",                1, gk1Day5SnakeAttackSignature2,     gk1Day5SnakeAttackPatch2 },
-	{  true,   280, "fix pathfinding in Madame Cazanoux's house",  1, gk1CazanouxPathfindingSignature,  gk1CazanouxPathfindingPatch },
-	{  true,   380, "fix Gran's room obstacles and ego flicker",   1, gk1GranRoomInitSignature,         gk1GranRoomInitPatch },
-	{  true,   410, "fix day 2 binoculars lockup",                 1, gk1Day2BinocularsLockupSignature, gk1Day2BinocularsLockupPatch },
-	{  true,   420, "fix day 6 empty booth message",               6, gk1EmptyBoothMessageSignature,    gk1EmptyBoothMessagePatch },
-	{  true,   420, "fix lorelei dance timer",                     1, gk1LoreleiDanceTimerSignature,    gk1LoreleiDanceTimerPatch },
-	{ false,   471, "pc: fix cartoon timing",                      4, gk1CartoonTimingPcSignature1,     gk1CartoonTimingPatch1 },
-	{ false,   471, "pc: fix cartoon timing",                      3, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
-	{ false,   471, "mac: fix cartoon timing",                     4, gk1CartoonTimingMacSignature1,    gk1CartoonTimingPatch1 },
-	{ false,   471, "mac: fix cartoon timing",                     3, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
-	{ false,   480, "pc: fix cartoon timing",                     10, gk1CartoonTimingPcSignature1,     gk1CartoonTimingPatch1 },
-	{ false,   480, "pc: fix cartoon timing",                      7, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
-	{ false,   480, "mac: fix cartoon timing",                    10, gk1CartoonTimingMacSignature1,    gk1CartoonTimingPatch1 },
-	{ false,   480, "mac: fix cartoon timing",                     7, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
-	{  true,   480, "fix bayou cartoon view",                      1, gk1BayouCartoonViewSignature,     gk1BayouCartoonViewPatch },
-	{  true,   480, "win: play day 6 bayou ritual avi videos",     3, gk1BayouRitualAviSignature,       gk1BayouRitualAviPatch },
-	{ false,   720, "pc: fix cartoon timing",                      2, gk1CartoonTimingPcSignature1,     gk1CartoonTimingPatch1 },
-	{ false,   720, "pc: fix cartoon timing",                      6, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
-	{ false,   720, "mac: fix cartoon timing",                     2, gk1CartoonTimingMacSignature1,    gk1CartoonTimingPatch1 },
-	{ false,   720, "mac: fix cartoon timing",                     6, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
-	{ false,   891, "pc: fix cartoon timing",                      1, gk1CartoonTimingPcSignature1,     gk1CartoonTimingPatch1 },
-	{ false,   891, "mac: fix cartoon timing",                     1, gk1CartoonTimingMacSignature1,    gk1CartoonTimingPatch1 },
-	{ false,   892, "pc: fix cartoon timing",                      1, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
-	{ false,   892, "mac: fix cartoon timing",                     1, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
-	{ false,   894, "pc: fix cartoon timing",                      1, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
-	{ false,   894, "mac: fix cartoon timing",                     1, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
-	{ false,   670, "fix end game font",                           1, gk1EndGameFontSignature,          gk1EndGameFontPatch },
-	{  true,   710, "fix day 9 vine swing speech playing",         1, gk1Day9VineSwingSignature,        gk1Day9VineSwingPatch },
-	{  true,   710, "fix day 9 mummy animation (floppy)",          1, gk1MummyAnimateFloppySignature,   gk1MummyAnimateFloppyPatch },
-	{  true,   710, "fix day 9 mummy animation (cd)",              1, gk1MummyAnimateCDSignature,       gk1MummyAnimateCDPatch },
-	{  true,   800, "fix day 10 honfour unlock door lockup",       1, gk1HonfourUnlockDoorSignature,    gk1HonfourUnlockDoorPatch },
-	{ false, 64928, "floppy: Narrator lockup fix",                 1, sciNarratorLockupSignature,       sciNarratorLockupPatch },
-	{ false, 64928, "cd/mac: Narrator lockup fix",                 1, gk1NarratorLockupSignature,       gk1NarratorLockupPatch },
-	{  true, 64990, "increase number of save games (1/2)",         1, sci2NumSavesSignature1,           sci2NumSavesPatch1 },
-	{  true, 64990, "increase number of save games (2/2)",         1, sci2NumSavesSignature2,           sci2NumSavesPatch2 },
-	{  true, 64990, "disable change directory button",             1, sci2ChangeDirSignature,           sci2ChangeDirPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#pragma mark -
-#pragma mark Gabriel Knight 2
-
-// GK2 uses a kGetTime spin loop to delay for half a second while displaying
-//  the "bad" cursor when clicking an item on something it can't be used on.
-//  This leaves ScummVM unresponsive without displaying the cursor.
-//
-// We fix this by replacing the spin loop with a call to kScummVMSleep.
-//
-// Applies to: All versions
-// Responsible method: GKHotCursor:flashBad
-static const uint16 gk2FlashBadCursorSignature[] = {
-	0x8d, SIG_MAGICDWORD, 0x00,     // lst 00
-	0x76,                           // push0
-	0x43, 0x79, SIG_UINT16(0x0000), // callk GetTime 00
-	0x1e,                           // gt?
-	0x31, 0x02,                     // bnt 02 [ exit loop ]
-	0x33, 0xf4,                     // jmp f4 [ continue loop ]
-	SIG_END
-};
-
-static const uint16 gk2FlashBadCursorPatch[] = {
-	0x78,                           // push1
-	0x39, 0x1e,                     // pushi 1e [ half a second ]
-	0x43, kScummVMSleepId,          // callk ScummVMSleep 02
-	      PATCH_UINT16(0x0002),
-	0x32, PATCH_UINT16(0x0002),     // jmp 0002 [ exit loop ]
-	PATCH_END
-};
-
-// GK2's inventory scrolls smoothly when the mouse is held down in the original
-//  due to an inner loop in ScrollButton:track, but this causes slow scrolling
-//  in our interpreter since we throttle kFrameOut. The script's inner loop is
-//  itself throttled by ScrollButton:moveDelay, which is set to 25 and limits
-//  event processing to every 25th iteration. Removing this delay results in
-//  smooth scrolling as in the original.
-//
-// Applies to: All versions
-// Responsible method: ScrollButton:track
-static const uint16 gk2InventoryScrollSpeedSignature[] = {
-	SIG_MAGICDWORD,
-	0x63, 0x9c,                 // pToa moveDelay [ 25 ]
-	0xa5, 0x02,                 // sat 02
-	SIG_END
-};
-
-static const uint16 gk2InventoryScrollSpeedPatch[] = {
-	0x35, 0x01,                 // ldi 01
-	PATCH_END
-};
-
-// The down scroll button in GK2 jumps up a pixel on mousedown because there is
-//  a send to scrollSelections using an immediate value 1, which means to scroll
-//  up by 1 pixel. This patch fixes the send to scrollSelections by passing the
-//  button's delta instead of 1. The Italian version's vocab.997 is missing the
-//  scrollSelections selector so this patch avoids referencing it. Two versions
-//  are necessary to accomodate scripts compiled with and without line numbers.
-//
-// Applies to: All versions
-// Responsible method: ScrollButon:track
-// Fixes bug: #9648
-static const uint16 gk2InventoryScrollDirSignature1[] = {
-	SIG_MAGICDWORD,
-	0x78,                               // push1
-	0x63, 0x98,                         // pToa client
-	0x4a, SIG_UINT16(0x0006),           // send 06 [ client scrollSelections: 1 ]
-	0x7e,                               // line
-	SIG_END
-};
-
-static const uint16 gk2InventoryScrollDirPatch1[] = {
-	0x66, PATCH_UINT16(0x009a),         // pTos delta
-	0x62, PATCH_UINT16(0x0098),         // pToa client
-	0x4a, PATCH_UINT16(0x0006),         // send 06 [ client scrollSelections: delta ]
-	PATCH_END
-};
-
-static const uint16 gk2InventoryScrollDirSignature2[] = {
-	0x78,                               // push1
-	0x63, 0x98,                         // pToa client
-	0x4a, SIG_MAGICDWORD,               // send 06 [ client scrollSelections: 1 ]
-	      SIG_UINT16(0x0006),
-	0x35, 0x02,                         // ldi 02
-	0x65, 0x56,                         // aTop cel
-	SIG_END
-};
-
-static const uint16 gk2InventoryScrollDirPatch2[] = {
-	0x67, 0x9a,                         // pTos delta
-	0x63, 0x98,                         // pToa client
-	0x4a, PATCH_UINT16(0x0006),         // send 06 [ client scrollSelections: delta ]
-	0x7a,                               // push2
-	0x69, 0x56,                         // sTop cel
-	PATCH_END
-};
-
-// The init code 'GK2::init' that runs when GK2 starts up unconditionally resets
-// the music volume to 63, but the game should always use the volume stored in
-// ScummVM.
-// Applies to: All versions
-// Fixes bug: #9700
-static const uint16 gk2VolumeResetSignature[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x3f, // ldi $3f
-	0xa1, 0x4c, // sag global[$4c] (music volume)
-	SIG_END
-};
-
-static const uint16 gk2VolumeResetPatch[] = {
-	0x33, 0x02,  // jmp 2 [past volume changes]
-	PATCH_END
-};
-
-// GK2 has custom video benchmarking code that needs to be disabled in a local
-//  procedure called from GK2:init. It sets the game's detailLevel and returns
-//  a value which is assigned to GK2:speedRating and never used. The maximum
-//  detailLevel the game recognizes is six so we just set it to that.
-//
-// Applies to: All versions
-// Responsible method: GK2:init
-static const uint16 gk2BenchmarkSignature[] = {
-	0x76,                       // push0
-	0x40, SIG_ADDTOOFFSET(+2),  // call speed test proc
-	      SIG_MAGICDWORD,
-		  SIG_UINT16(0x0000),
-	0x65, 0x28,                 // aTop speedRating
-	SIG_END
-};
-
-static const uint16 gk2BenchmarkPatch[] = {
-	0x35, 0x06,                 // ldi 06
-	0x65, 0x18,                 // aTop _detailLevel
-	0x33, 0x02,                 // jmp 02
-	PATCH_END
-};
-
-// GK2 has a complex sound bug which causes seemingly random lockups when
-//  changing rooms in many areas including the Herrenchiemse Museum, the Hunt
-//  Club, and St. Georg Church. This also occurs in the original.
-//
-// SoundManager continuously plays an array of sounds provided to its play
-//  method. Sounds play in a random order with a random delay of five to ten
-//  seconds in between. SoundManager is attached to soundRegion and survives
-//  room changes. Rooms that set a new playlist call play on initialization.
-//  The problem is that SoundManager:play doesn't clear its delay timer. If play
-//  is called during a delay then the timer continues and expires during the
-//  next sound. This is noticeable throughout the game when background music is
-//  randomly interrupted by different music. Many room scripts change rooms by
-//  calling SoundManager:fade in handsOff mode and proceeding once they've been
-//  cued. If a stray SoundManager timer expires while a script is waiting for
-//  fade to complete then SoundManager:cue will play the next sound, overwrite
-//  gk2Music:client with itself, and the waiting script will never cue.
-//
-// We fix this by clearing SoundManager's timer state in SoundManager:play.
-//  This prevents the delay timer from ever running while music is playing.
-//  Note that this bug is unrelated to lockups when the music volume slider
-//  is set to its lowest value. We fix that in Sci::Audio32::fadeChannel().
-//
-// Applies to: All versions
-// Responsible method: SoundManager:play
-static const uint16 gk2SoundManagerLockupSignature1[] = {
-	0x7e, SIG_ADDTOOFFSET(+2),          // line
-	0x7e, SIG_ADDTOOFFSET(+2),          // line
-	SIG_MAGICDWORD,
-	0x35, 0x00,                         // ldi 00
-	0x65, 0x34,                         // aTop cleanup
-	SIG_END
-};
-
-static const uint16 gk2SoundManagerLockupPatch1[] = {
-	0x35, 0x00,                         // ldi 00
-	0x64, PATCH_UINT16(0x001e),         // aTop seconds
-	0x64, PATCH_UINT16(0x0012),         // aTop scratch
-	PATCH_END
-};
-
-static const uint16 gk2SoundManagerLockupSignature2[] = {
-	0x87, SIG_MAGICDWORD, 0x00,         // lap 00
-	0x18,                               // not
-	0x31, 0x10,                         // bnt 10 [ skip debug message ]
-	0x78,                               // push1
-	0x72,                               // lofsa "WARNING: 0 args passed to SoundManager!"
-	SIG_END
-};
-
-static const uint16 gk2SoundManagerLockupPatch2[] = {
-	0x35, 0x00,                         // ldi 00
-	0x65, 0x1e,                         // aTop seconds
-	0x65, 0x12,                         // aTop scratch
-	0x32, PATCH_UINT16(0x0014),         // jmp 0014 [ skip debug message ]
-	PATCH_END
-};
-
-// Clicking on Frau Miller in room 810 after exhausting her topics and then
-//  clicking on anything else can lockup or crash the game. rm810:newRoom fades
-//  the music before transitioning to room 8110, which takes several seconds.
-//  The game doesn't disable input during this period and if the player begins
-//  another action then rm810:cue can unexpectedly interrupt it. If Grace is
-//  walking then the room will reload in a handsOff state. Other edge cases
-//  include setting the room number to zero and subsequently crashing.
-//
-// We fix this by calling handsOff so that the player can't interrupt the Frau
-//  Miller room transition while waiting for the music to fade, which is
-//  consistent with the exit to the map.
-//
-// Applies to: All versions
-// Responsible method: rm810:newRoom
-static const uint16 gk2FrauMillerLockupSignature[] = {
-	SIG_MAGICDWORD,
-	0x39, 0x03,                         // pushi 03
-	0x8f, 0x01,                         // lsp 01
-	0x38, SIG_UINT16(0x1fae),           // pushi 1fae
-	0x38, SIG_UINT16(0x0320),           // pushi 0320
-	0x46, SIG_UINT16(0xfde7),           // calle proc64999_5 [ OneOf newRoomNumber 8110 800 ]
-	      SIG_UINT16(0x0005),
-	      SIG_UINT16(0x0006),
-	0x31,                               // bnt [ don't fade music ]
-	SIG_END
-};
-
-static const uint16 gk2FrauMillerLockupPatch[] = {
-	0x8f, 0x01,                         // lsp 01
-	0x34, PATCH_UINT16(0x1fae),         // ldi 1fae
-	0x24,                               // le? [ newRoomNumber <= 8110 ]
-	0x31, PATCH_GETORIGINALBYTEADJUST(+18, +11), // bnt [ don't fade music ]
-	0x38, PATCH_SELECTOR16(handsOff),   // pushi handsOff
-	0x39, 0x00,                         // pushi 00
-	0x80, PATCH_UINT16(0x0001),         // lag 0001
-	0x4a, PATCH_UINT16(0x0004),         // send 04 [ GK2 handsOff: ]
-	PATCH_END
-};
-
-// GK2 1.0 contains a deadend bug in chapter 3. Exhausting Leber's topics before
-//  reading Grace's letter prevents returning to the police station to ask about
-//  the Black Wolf, which is necessary to complete the chapter.
-//
-// We fix this as Sierra did by adding a flag 218 test so that the police
-//  station doesn't close before Leber has been asked about the Black Wolf.
-//
-// Applies to: English PC 1.0
-// Responsible method: rm3210:dispose
-static const uint16 gk2PoliceStationDeadendSignature[] = {
-	0x78,                               // push1
-	0x38, SIG_UINT16(0x00dd),           // pushi 00dd
-	0x47, 0x0b, 0x00, SIG_MAGICDWORD,   // calle proc11_0 [ is flag 221 set? ]
-	      SIG_UINT16(0x002),
-	0x31, 0x51,                         // bnt 51 [ skip closing police station ]
-	SIG_END
-};
-
-static const uint16 gk2PoliceStationDeadendPatch[] = {
-	0x80, PATCH_UINT16(0x00a3),         // lag 00a3 [ flags 208-223 ]
-	0x39, 0x24,                         // pushi 24
-	0x12,                               // and
-	0x39, 0x24,                         // pushi 24
-	0x1a,                               // eq? [ are flags 218 and 221 set? ]
-	PATCH_END
-};
-
-// In chapter 3, Xaver can be asked about the Black Wolf before learning about
-//  the Black Wolf from Grace's letter. The tBlackWolf topic in room 4320 is
-//  missing the readyFlagNum value of 514 that the other tBlackWolf topics in
-//  chapter 3 have, so we set it.
-//
-// Applies to: All versions
-// Responsible method: heap in script 4320
-static const uint16 gk2XaverBlackWolfSignature[] = {
-	SIG_MAGICDWORD,             // tBlackWolf
-	SIG_UINT16(0x010e),         // sceneNum = 270
-	SIG_UINT16(0x00f0),         // flagNum = 240
-	SIG_UINT16(0x0000),         // readyFlagNum = 0
-	SIG_END
-};
-
-static const uint16 gk2XaverBlackWolfkPatch[] = {
-	PATCH_ADDTOOFFSET(+4),
-	PATCH_UINT16(0x0202),       // readyFlagNum = 514
-	PATCH_END
-};
-
-// Chapter 4 has a bug in many versions of GK2 that is effectively a deadend.
-//  Asking Georg about "Ludwig's letter to the Conductor" is required to finish
-//  the chapter. This topic becomes available after looking at the "Ludwig and
-//  Wagner" plaque in Herrenchiemsee and then clicking again to read it aloud.
-//  The problem is that the rest of the game only cares about looking at the
-//  plaque. If Herrenchiemsee is completed without reading the plaque then the
-//  Hint feature claims everything is done and the player appears to be stuck.
-//
-// We fix this as Sierra did by making Georg's letter topic available upon just
-//  looking at the plaque, which is consistent with the rest of the scripts.
-//  Although Sierra advertised this fix in the readme for GK2PAT 1.11, the patch
-//  file seems to be missing, but appears in later versions and the GOG release.
-//
-// Applies to: English PC 1.0, 1.1, 1.11 Patch, Mac
-// Responsible method: Heap in script 8520
-static const uint16 gk2GeorgLetterTopicSignature[] = {
-	SIG_MAGICDWORD,             // tLtr2Conductor
-	SIG_UINT16(0x0211),         // sceneNum = 529
-	SIG_UINT16(0x012a),         // flagNum = 298
-	SIG_UINT16(0x0283),         // readyFlagNum = 643
-	SIG_END
-};
-
-static const uint16 gk2GeorgLetterTopicPatch[] = {
-	PATCH_ADDTOOFFSET(+4),
-	PATCH_UINT16(0x026f),       // readyFlagNum = 623
-	PATCH_END
-};
-
-// In early versions of GK2, clicking on the holy water basket after using the
-//  holy water locks up the game. The script is supposed to test the flag that's
-//  set when getting the water but some code mistakenly tests inventory instead.
-//  We fix this as Sierra did by replacing the inventory tests with flag tests.
-//
-// Applies to: English PC 1.0, Mac
-// Responsible methods: waterBasket:handleEvent, waterBasket:doVerb
-static const uint16 gk2HolyWaterLockupSignature[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(has),  // pushi has
-	0x78,                       // push1
-	0x39, 0x3e,                 // pushi 3e
-	0x81, 0x00,                 // lag 00
-	0x4a, SIG_UINT16(0x0006),   // send 06 [ GraceEgo has: 62 (invBottleOfWater) ]
-	SIG_END
-};
-
-static const uint16 gk2HolyWaterLockupPatch[] = {
-	0x38, PATCH_UINT16(0x0001), // pushi 0001
-	0x38, PATCH_UINT16(0x0476), // pushi 0476
-	0x47, 0x0b, 0x00,           // calle proc11_0 [ is flag 1142 set? ]
-	      PATCH_UINT16(0x0002),
-	PATCH_END
-};
-
-// In early versions of GK2, Neuschwanstein castle can flash when clicking the
-//  Hint button even after completing everything. The Hint script tests too many
-//  flags including one whose value is random since it toggles back and forth
-//  between two tape messages. We remove these flag tests as Sierra did.
-//
-// Applies to: English PC 1.0, Mac
-// Responsible method: local procedure #0 in script 800
-static const uint16 gk2NeuschwansteinHintSignature1[] = {
-	SIG_MAGICDWORD,
-	0x78,                       // push1
-	0x38, SIG_UINT16(0x024d),   // pushi 024d
-	0x47, 0x0b, 0x00,           // calle proc11_0 [ is flag 589 set? ]
-	SIG_UINT16(0x0002),
-	SIG_END
-};
-
-static const uint16 gk2NeuschwansteinHintSignature2[] = {
-	SIG_MAGICDWORD,
-	0x78,                       // push1
-	0x38, SIG_UINT16(0x024e),   // pushi 024e
-	0x47, 0x0b, 0x00,           // calle proc11_0 [ is flag 590 set? ]
-	SIG_UINT16(0x0002),
-	SIG_END
-};
-
-static const uint16 gk2NeuschwansteinHintSignature3[] = {
-	SIG_MAGICDWORD,
-	0x78,                       // push1
-	0x38, SIG_UINT16(0x0250),   // pushi 0250
-	0x47, 0x0b, 0x00,           // calle proc11_0 [ is flag 592 set? ]
-	SIG_UINT16(0x0002),
-	SIG_END
-};
-
-static const uint16 gk2NeuschwansteinHintPatch[] = {
-	0x35, 0x01,                 // ldi 01
-	0x33, 0x05,                 // jmp 05
-	PATCH_END
-};
-
-// Clicking an inventory item on the Wagner paintings in rooms 8616 and 8617
-//  causes a missing message error. The paintings only have responses for the
-//  "Do" verb but painting:doVerb passes the incoming verb to gk2Messager:say
-//  without any filtering. We fix this by always playing the "Do" message.
-//
-// Applies to: All versions
-// Responsible methods: painting:doVerb in scripts 8616 and 8617
-static const uint16 gk2WagnerPaintingMessageSignature[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(say),  // pushi say
-	0x38, SIG_UINT16(0x0006),   // pushi 0006
-	0x67, SIG_ADDTOOFFSET(+1),  // pTos noun
-	0x8f, 0x01,                 // lsp 01 [ verb ]
-	SIG_END
-};
-
-static const uint16 gk2WagnerPaintingMessagePatch[] = {
-	PATCH_ADDTOOFFSET(+8),
-	0x39, 0x3e,                 // pushi 3e [ "Do" verb ]
-	PATCH_END
-};
-
-// The game-over rooms 665 and 666 draw a pic over everything by setting the
-//  default plane's priority to 202, but this is already inventoryBorderPlane's
-//  priority. In our interpreter this causes a border fragment to be drawn above
-//  the pics. This worked by luck in Sierra's interpreter because it sorts on
-//  memory ID when planes have the same priority. In ScummVM the renderer
-//  guarantees a sort order based on the creation order of the planes. The
-//  default plane is created first and drawn before inventoryBorderPlane.
-//
-// We fix this by increasing the plane priority in the game-over rooms.
-//
-// Applies to: All versions
-// Responsible methods: gabeNews:init, uDie:init
-// Fixes bug: #11298
-static const uint16 gk2GameOverPrioritySignature[] = {
-	0x39, SIG_SELECTOR8(priority),  // pushi priority
-	SIG_MAGICDWORD,
-	0x78,                           // push1
-	0x38, SIG_UINT16(0x00ca),       // pushi 00ca
-	0x81, 0x03,                     // lag 03
-	0x4a, SIG_UINT16(0x0012),       // send 12 [ Plane ... priority: 202 ]
-	SIG_END
-};
-
-static const uint16 gk2GameOverPriorityPatch[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x38, PATCH_UINT16(0x00cb),     // pushi 00cb [ priority: 203 ]
-	PATCH_END
-};
-
-// GK2 fans have created patches that add subtitles to the entire game. There
-//  are at least English and Spanish patch sets. Sierra added the subtitle
-//  feature solely for the Portuguese version. The fan patches include these
-//  subtitle scripts, replace the Portuguese resources and embedded script
-//  strings, and configure Sierra's interpreter to use the Portuguese language
-//  through RESOURCE.CFG. This sets GK2:printLang which the scripts test for
-//  Portuguese in order to activate subtitles.
-//
-// The subtitle patches are compatible with ScummVM except for the requirement
-//  that GK2:printLang equals Portuguese (351) since we don't use RESOURCE.CFG.
-//  We fix this by patching the GK2:printLang tests to always activate subtitles
-//  when a sync resource is present for synchronizing text to video playback.
-//
-// Applies to: PC versions with a subtitle fan-patch applied
-// Responsible methods: Any that test GK2:printLang for Portuguese
-// Fixes bugs: #9677, #11282
-static const uint16 gk2SubtitleCompatibilitySignature[] = {
-	SIG_MAGICDWORD,
-	0x39, SIG_SELECTOR8(printLang), // pushi printLang
-	0x76,                           // push0
-	0x81, 0x01,                     // lag 01
-	0x4a, SIG_UINT16(0x0004),       // send 04 [ GK2 printLang? ]
-	SIG_END
-};
-
-static const uint16 gk2SubtitleCompatibilityPatch[] = {
-	0x34, PATCH_UINT16(0x015f),     // ldi 015f [ K_LANG_PORTUGUESE ]
-	0x33, 0x03,                     // jmp 03
-	PATCH_END
-};
-
-//          script, description,                                              signature                         patch
-static const SciScriptPatcherEntry gk2Signatures[] = {
-	{  true,     0, "disable volume reset on startup",                     1, gk2VolumeResetSignature,           gk2VolumeResetPatch },
-	{  true,     0, "disable video benchmarking",                          1, gk2BenchmarkSignature,             gk2BenchmarkPatch },
-	{  true,    23, "fix inventory scroll speed",                          2, gk2InventoryScrollSpeedSignature,  gk2InventoryScrollSpeedPatch },
-	{  true,    23, "fix inventory scroll direction",                      1, gk2InventoryScrollDirSignature1,   gk2InventoryScrollDirPatch1 },
-	{  true,    23, "fix inventory scroll direction (no line numbers)",    1, gk2InventoryScrollDirSignature2,   gk2InventoryScrollDirPatch2 },
-	{  true,    37, "fix sound manager lockup",                            1, gk2SoundManagerLockupSignature1,   gk2SoundManagerLockupPatch1 },
-	{  true,    37, "fix sound manager lockup (no line numbers)",          1, gk2SoundManagerLockupSignature2,   gk2SoundManagerLockupPatch2 },
-	{  true,   665, "fix game-over priority",                              1, gk2GameOverPrioritySignature,      gk2GameOverPriorityPatch },
-	{  true,   666, "fix game-over priority",                              1, gk2GameOverPrioritySignature,      gk2GameOverPriorityPatch },
-	{  true,   800, "fix neuschwanstein hint (1/3)",                       1, gk2NeuschwansteinHintSignature1,   gk2NeuschwansteinHintPatch },
-	{  true,   800, "fix neuschwanstein hint (2/3)",                       1, gk2NeuschwansteinHintSignature2,   gk2NeuschwansteinHintPatch },
-	{  true,   800, "fix neuschwanstein hint (3/3)",                       1, gk2NeuschwansteinHintSignature3,   gk2NeuschwansteinHintPatch },
-	{  true,   810, "fix frau miller lockup",                              1, gk2FrauMillerLockupSignature,      gk2FrauMillerLockupPatch },
-	{  true,  1020, "fix holy water lockup",                               2, gk2HolyWaterLockupSignature,       gk2HolyWaterLockupPatch },
-	{  true,  3210, "fix police station deadend",                          1, gk2PoliceStationDeadendSignature,  gk2PoliceStationDeadendPatch },
-	{  true,  4320, "fix xaver black wolf topic",                          1, gk2XaverBlackWolfSignature,        gk2XaverBlackWolfkPatch },
-	{  true,  8520, "fix georg letter topic",                              1, gk2GeorgLetterTopicSignature,      gk2GeorgLetterTopicPatch },
-	{  true,  8616, "fix wagner painting message",                         2, gk2WagnerPaintingMessageSignature, gk2WagnerPaintingMessagePatch },
-	{  true,  8617, "fix wagner painting message",                         2, gk2WagnerPaintingMessageSignature, gk2WagnerPaintingMessagePatch },
-	{  true, 64928, "Narrator lockup fix",                                 1, sciNarratorLockupSignature,        sciNarratorLockupPatch },
-	{  true, 64928, "Narrator lockup fix",                                 1, sciNarratorLockupLineSignature,    sciNarratorLockupLinePatch },
-	{  true, 64962, "flash bad cursor spin loop",                          1, gk2FlashBadCursorSignature,        gk2FlashBadCursorPatch },
-	{  true, 64990, "increase number of save games (1/2)",                 1, sci2NumSavesSignature1,            sci2NumSavesPatch1 },
-	{  true, 64990, "increase number of save games (2/2)",                 1, sci2NumSavesSignature2,            sci2NumSavesPatch2 },
-	{  true, 64990, "disable change directory button",                     1, sci2ChangeDirSignature,            sci2ChangeDirPatch },
-	{ false,     0, "subtitle patch compatibility",                        3, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
-	{ false,    11, "subtitle patch compatibility",                        7, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
-	{ false,    12, "subtitle patch compatibility",                        5, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
-	{ false,    91, "subtitle patch compatibility",                        7, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
-	{ false,   200, "subtitle patch compatibility",                        1, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
-	{ false,  1300, "subtitle patch compatibility",                        1, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
-	{ false, 64924, "subtitle patch compatibility",                        1, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#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
-};
-
-// At the pier in Honolulu, room 23, "climb down" causes ego to bypass boarding
-//  procedure, walk through the air, climb down the hatch, and get stuck in the
-//  submarine without triggering a room change. There is no "climb up" command.
-//
-// Boarding requires asking the officer permission. comeAboardScript gives him
-//  the orders, runs downTheHatchScript, and changes to room 31 when finished.
-//  downTheHatchScript only walks ego to the hatch and runs the climb animation.
-//  "climb down" simply runs downTheHatchScript and nothing else, leaving the
-//  room in a broken state by running this intermediate script out of context.
-//
-// We patch "climb down" to respond with the message for other hatch commands.
-//
-// Applies to: All versions
-// Responsible method: hatch:handleEvent
-// Fixes bug #11039
-static const uint16 icemanClimbDownHatchSignature[] = {
-	0x7a,                               // push2
-	SIG_MAGICDWORD,
-	0x39, 0x17,                         // pushi 17
-	0x39, 0x18,                         // pushi 18
-	0x47, 0xff, 0x00, 0x04,             // calle proc255_0 04 [ "You must follow proper boarding procedure." ]
-	0x32, SIG_UINT16(0x0021),           // jmp 0021 [ end of method ]
-	SIG_ADDTOOFFSET(+22),
-	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
-	0x78,                               // push1
-	0x72, SIG_UINT16(0xfc24),           // lofsa downTheHatchScript
-	SIG_END
-};
-
-static const uint16 icemanClimbDownHatchPatch[] = {
-	PATCH_ADDTOOFFSET(+34),
-	0x33, 0xdc,                         // jmp dc [ "You must follow proper boarding procedure." ]
-	PATCH_END
-};
-
-//         script, description,                                       signature                                      patch
-static const SciScriptPatcherEntry icemanSignatures[] = {
-	{ true,    23, "climb down hatch",                             1, icemanClimbDownHatchSignature,                 icemanClimbDownHatchPatch },
-	{ true,    99, "disable speed test",                           1, sci01SpeedTestLocalSignature,                  sci01SpeedTestLocalPatch },
-	{ true,   314, "destroyer timer (1/2)",                        1, icemanDestroyerTimer1Signature,                icemanDestroyerTimer1Patch },
-	{ true,   391, "destroyer timer (2/2)",                        1, icemanDestroyerTimer2Signature,                icemanDestroyerTimer2Patch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// Island of Dr. Brain
-
-// Narrator lockup fix, see sciNarratorLockupSignature.
-//  Island of Dr. Brain contains an early version of Narrator with the lockup
-//  bug so it requires its own patch.
-static const uint16 islandBrainNarratorLockupSignature[] = {
-	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
-	SIG_MAGICDWORD,
-	0x35, 0x3c,                         // ldi 3c
-	0x02,                               // add
-	0x36,                               // push
-	0x89, 0x56,                         // lsg 56 [ game time ]
-	0x76,                               // push0
-	0x43, 0x42, 0x00,                   // callk GetTime 00
-	0x02,                               // add
-	0x02,                               // add
-	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time + GetTime ]
-	0x35, 0x01,                         // ldi 01 [ true ]
-	0x48,                               // ret
-	SIG_END
-};
-
-static const uint16 islandBrainNarratorLockupPatch[] = {
-	0x76,                               // push0
-	0x43, 0x42, 0x00,                   // callk GetTime 00
-	0x39, 0x3c,                         // pushi 3c
-	0x02,                               // add
-	0x67, PATCH_GETORIGINALBYTE(+1),    // pTos ticks
-	0x02,                               // add
-	0x89, 0x56,                         // lsg 56 [ game time ]
-	0x02,                               // add
-	0x65, PATCH_GETORIGINALBYTE(+1),    // aTop ticks [ ticks = GetTime + 60 + game time + ticks ]
-	0x00,                               // bnot
-	0x31, 0xfb,                         // bnt fb [ set ticks to 0 if ticks == -1 ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                                 patch
-static const SciScriptPatcherEntry islandBrainSignatures[] = {
-	{  true,   928, "Narrator lockup fix",                         1, islandBrainNarratorLockupSignature,       islandBrainNarratorLockupPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// Jones In The Fast Lane
-
-//          script, description,                                      signature                         patch
-static const SciScriptPatcherEntry jonesSignatures[] = {
-	{  true,   764, "disable speed test",                          1, sci01SpeedTestLocalSignature,     sci01SpeedTestLocalPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// King's Quest 1
-
-// In the demo, the leprechaun dance runs awkwardly fast on modern computers.
-//  The demo script increases the speed from the default (5 or 6) to fastest (1)
-//  for this scene only. This appears to be an attempt to speed up the dance and
-//  also compensate for the original interpreter significantly slowing down.
-//  On a machine from the demo's era, the interpreter was unable to keep up with
-//  all of the animating dancers. As each dancer disappeared the lag decreased
-//  and the dance got noticeably faster. On modern computers the dancers cause
-//  no lag and the real game's scripts don't adjust the speed at all, so we just
-//  lower the temporary dance speed to one that matches the demo and the dance
-//  music duration.
-//
-// Applies to: PC Demo only
-// Responsible method: danceFever:changeState(0)
-// Fixes bug: #9825
-static const uint16 kq1SignatureDemoDanceSpeed[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x01,                         // ldi 01
-	0xa1, 0x03,                         // sag 03 [ gameSpeed = 1 (fastest) ]
-	SIG_END
-};
-
-static const uint16 kq1PatchDemoDanceSpeed[] = {
-	0x35, 0x04,                         // ldi 04
-	PATCH_END
-};
-
-//          script, description,                                      signature                         patch
-static const SciScriptPatcherEntry kq1Signatures[] = {
-	{  true,    77, "demo: dance speed",                           1, kq1SignatureDemoDanceSpeed,       kq1PatchDemoDanceSpeed },
-	{  true,    99, "demo: disable speed test",                    1, sci01SpeedTestGlobalSignature,    sci01SpeedTestGlobalPatch },
-	{  true,   777, "disable speed test",                          1, sci01SpeedTestGlobalSignature,    sci01SpeedTestGlobalPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// In KQ4 1.000.111, falling down the lower stairs in room 90 sends a message to
-//  a non-object, which also crashes the original. It appears that the fragment
-//  of code which instantiated the Sound object was accidentally deleted from
-//  the script. This line was intact in the previous version and in later
-//  versions it was rewritten to use a new local Sound object. We fix this by
-//  jumping from the broken code into the sound code in fallingToDeath, which
-//  correctly plays the same sound.
-//
-// Applies to: PC 1.000.111
-// Responsible method: fallingDown:changeState(0)
-static const uint16 kq4SignatureFallDownStairs[] = {
-	SIG_MAGICDWORD,
-	0x83, 0x01,                      // lal 01  [ not set, zero ]
-	0x4a, 0x10,                      // send 10 [ local1 number: 51 loop: 1 play: ]
-	SIG_ADDTOOFFSET(+0x0108),
-	0x38, SIG_SELECTOR16(new),       // pushi new
-	0x76,                            // push0
-	0x51, 0x31,                      // class Sound
-	0x4a, 0x04,                      // send 04  [ Sound new: ]
-	0x4a, 0x10,                      // send 10  [ sound number: 51 loop: 1 play: ]
-	0x32, SIG_UINT16(0x0040),        // jmp 0040 [ end of method ]
-	SIG_END
-};
-
-static const uint16 kq4PatchFallDownStairs[] = {
-	0x32, PATCH_UINT16(0x0109),      // jmp 0109
-	PATCH_ADDTOOFFSET(+0x0111),
-	0xa2, PATCH_UINT16(0x0001),      // sal 0001 [ local1 = the new sound ]
-	0x4a, 0x10,                      // send 10  [ local1 number: 51 loop: 1 play: ]
-	PATCH_END
-};
-
-// KQ4 1.003.006 is missing view 653 and crashes room 24 outside the waterfall.
-//  In the original this only occurred at high CPU speeds. View 653 animates the
-//  river's current, which was first added in this version, but it's only loaded
-//  when the game's speed test detects a fast machine. Sierra later released a
-//  KQ4FIX patch with the missing view and included it in subsequent versions.
-//  We fix this by not initializing view 653 when it's not present.
-//
-// Applies to: PC and Atari ST 1.003.006
-// Responsible method: Room24:init
-static const uint16 kq4SignatureMissingWaterfallView[] = {
-	0x39, SIG_SELECTOR8(new),       // pushi new
-	0x76,                           // push0
-	0x51, SIG_ADDTOOFFSET(+1),      // class Prop
-	0x4a, 0x04,                     // send 04 [ Prop new: ]
-	0xa3, 0x0c,                     // sal 0c  [ local12 = new Prop ]
-	SIG_ADDTOOFFSET(+14),
-	0x39, SIG_SELECTOR8(view),      // pushi view
-	SIG_MAGICDWORD,
-	0x78,                           // push1
-	0x38, SIG_UINT16(0x028d),       // pusi 028d
-	SIG_ADDTOOFFSET(+83),
-	0x83, 0x0d,                     // lal 0d
-	0x4a, 0x34,                     // send 34 [ local13 ... view: 653 ... ]
-	SIG_END
-};
-
-static const uint16 kq4PatchMissingWaterfallView[] = {
-	0x33, 0x72,                     // jmp 72 [ skip missing view (local12 and local13) ]
-	PATCH_END
-};
-
-// KQ4 1.003.006 draws pics incorrectly when riding the unicorn at night.
-//  The riding scene takes place within room 333 which simulates room changes by
-//  drawing each pic in the sequence. This version of KQ4 introduced overlays
-//  for drawing night instead of using alternate pics, but Sierra forgot to
-//  update this script. Instead of drawing the base pic followed by the night
-//  overlay, this script only draws the overlay as if it were a complete pic.
-//  This paints the screen almost entirely white except for the night sky.
-//
-// There are too many outdated Rm:drawPic calls in script 333 with too many
-//  differences to reasonably patch each with the new logic and additional
-//  Rm:overlay call. Instead we patch Rm:drawPic to detect and handle these
-//  attempts. Rm:drawPic and Rm:overlay do similar work, so we patch Rm:overlay
-//  to handle both and rewrite Rm:drawPic to call Rm:overlay appropriately. When
-//  Rm:drawPic is called with a night overlay (100-129) it now calls Rm:overlay
-//  twice to draw the associated base pic first and then the night overlay.
-//
-// Applies to: PC and Atari ST 1.003.006
-// Responsible methods: Rm:drawPic and Rm:overlay
-static const uint16 kq4SignatureUnicornNightRide[] = {
-	// Rm:drawPic
-	0x87, 0x01,                     // lap 01
-	0x65, 0x22,                     // aTop curPic [ curPic = picNumber ]
-	0x35, 0xff,                     // ldi ff
-	0xa1, 0x39,                     // sag 39 [ global57 = -1 ]
-	0x7a,                           // push2
-	0x8f, 0x01,                     // lsp 01
-	0x8f, 0x00,                     // lsp 00
-	0x35, 0x02,                     // ldi 02
-	0x1a,                           // eq?
-	0x30, SIG_UINT16(0x0005),       // bnt 0005
-	0x87, 0x02,                     // lap 02
-	0x32, SIG_UINT16(0x000f),       // jmp 000f
-	0x67, 0x14,                     // pTos style
-	0x35, 0xff,                     // ldi ff
-	0x1c,                           // ne?
-	0x30, SIG_UINT16(0x0005),       // bnt 0005
-	0x63, 0x14,                     // pToa style
-	0x32, SIG_UINT16(0x0002),       // jmp 0002
-	0x81, 0x11,                     // lag 11
-	0x36,                           // push
-	SIG_MAGICDWORD,
-	0x43, 0x08, 0x04,               // callk DrawPic 04
-	0x48,                           // ret
-	// Rm:overlay
-	SIG_ADDTOOFFSET(+16),
-	0x87, 0x02,                     // lap 02
-	SIG_ADDTOOFFSET(+11),
-	0x63, 0x14,                     // pToa style
-	SIG_ADDTOOFFSET(+3),
-	0x81, 0x11,                     // lag 11
-	0x36,                           // push
-	0x78,                           // push1
-	SIG_END
-};
-
-static const uint16 kq4PatchUnicornNightRide[] = {
-	// Rm:drawPic
-	0x76,                           // push0
-	0xa9, 0x1a,                     // ssg 1a [ global26 = 0, draw pic normally ]
-	0x38, PATCH_SELECTOR16(overlay),// pushi overlay
-	0x8f, 0x01,                     // lsp 01 [ picNumber ]
-	0x35, 0x64,                     // ldi 64
-	0x04,                           // sub
-	0x65, 0x22,                     // aTop curPic [ curPic = picNumber - 100 ]
-	0x39, 0x1e,                     // pushi 1e
-	0x28,                           // uge?   [ 30 >= (picNumber - 100) ]
-	0x31, 0x09,                     // bnt 09 [ jump if this is a correct drawPic call]
-	0x78,                           // push1
-	0x60,                           // pprev
-	0x54, 0x06,                     // self 06 [ self overlay: (picNumber - 100) ]
-	0x78,                           // push1
-	0xa9, 0x1a,                     // ssg 1a [ global26 = 1, draw pic as overlay ]
-	0x33, 0x11,                     // jmp 11 [ self overlay: &rest, ret ]
-	0x76,                           // push0
-	0x59, 0x01,                     // &rest 01
-	0x54, 0x04,                     // self 04 [ self overlay: &rest ]
-	0x87, 0x01,                     // lap 01
-	0x65, 0x22,                     // aTop curPic [ curPic = picNumber ]
-	0x35, 0xff,                     // ldi ff
-	0xa1, 0x39,                     // sag 39 [ global57 = -1 ]
-	0x78,                           // push1
-	0xa9, 0x1a,                     // ssg 1a [ global26 = 1, its original value ]
-	0x48,                           // ret
-	// Rm:overlay
-	PATCH_ADDTOOFFSET(+16),
-	0x8f, 0x02,                     // lsp 02
-	PATCH_ADDTOOFFSET(+11),
-	0x67, 0x14,                     // pTos style
-	PATCH_ADDTOOFFSET(+3),
-	0x89, 0x11,                     // lsg 11
-	0x89, 0x1a,                     // lsg 1a [ always 1 unless cleared in drawPic ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                                 patch
-static const SciScriptPatcherEntry kq4Signatures[] = {
-	{ false,    24, "missing waterfall view",                      1, kq4SignatureMissingWaterfallView,         kq4PatchMissingWaterfallView },
-	{  true,    90, "fall down stairs",                            1, kq4SignatureFallDownStairs,               kq4PatchFallDownStairs },
-	{  true,    98, "disable speed test",                          1, sci0EarlySpeedTestSignature,              sci0EarlySpeedTestPatch },
-	{  true,    99, "disable speed test",                          1, sci0EarlySpeedTestSignature,              sci0EarlySpeedTestPatch },
-	{  true,   994, "ride unicorn at night",                       1, kq4SignatureUnicornNightRide,             kq4PatchUnicornNightRide },
-	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
-//  master volume. This makes SSCI set the volume to max. We fix the procedure,
-//  so volume won't get modified in those cases.
-//
-// Applies to at least: PC CD
-// Responsible method: export 29 in script 0
-// Fixes bug: #5209
-static const uint16 kq5SignatureCdHarpyVolume[] = {
-	SIG_MAGICDWORD,
-	0x80, SIG_UINT16(0x0191),        // lag global[191h]
-	0x18,                            // not
-	0x30, SIG_UINT16(0x002c),        // bnt [jump further] (jumping, if global[191h] is 1)
-	0x35, 0x01,                      // ldi 01
-	0xa0, SIG_UINT16(0x0191),        // sag global[191h] (setting to 1)
-	0x38, SIG_UINT16(0x017b),        // pushi 017b
-	0x76,                            // push0
-	0x81, 0x01,                      // lag global[1]
-	0x4a, 0x04,                      // send 04 - read KQ5::masterVolume
-	0xa5, 0x03,                      // sat temp[3] (store volume)
-	0x38, SIG_UINT16(0x017b),        // 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
-};
-
-static const uint16 kq5PatchCdHarpyVolume[] = {
-	0x38, PATCH_UINT16(0x022f),      // 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)
-	0x80, PATCH_UINT16(0x0191),      // lag global[191h]
-	// saving 1 byte due optimization
-	0x2e, PATCH_UINT16(0x0023),      // bt [jump further] (jumping, if global[191h] is 1)
-	0x35, 0x01,                      // ldi 01
-	0xa0, PATCH_UINT16(0x0191),      // sag global[191h] (setting to 1)
-	0x38, PATCH_UINT16(0x017b),      // pushi 017b
-	0x76,                            // push0
-	0x81, 0x01,                      // lag global[1]
-	0x4a, 0x04,                      // send 04 - read KQ5::masterVolume
-	0xa5, 0x03,                      // sat temp[3] (store volume)
-	// saving 8 bytes due removing of duplicate code
-	0x39, 0x04,                      // pushi 04 (saving 1 byte due swapping)
-	0x22,                            // lt? (because we switched values)
-	PATCH_END
-};
-
-// The witchCage object in script 200 is broken and claims to have 12
-// properties instead of the 8 it should have because it is a Cage.
-// Additionally its top,left,bottom,right properties are set to 0 rather
-// than the right values. We fix the object by setting the right values.
-// If they are all zero, this causes an impossible position check in
-// witch::cantBeHere and an infinite loop when entering room 22.
-//
-// This bug is accidentally not triggered in SSCI because the invalid number
-// of variables effectively hides witchCage::doit, causing this position check
-// to be bypassed entirely.
-// See also the warning+comment in Object::initBaseObject
-//
-// Applies to at least: PC CD, English PC floppy
-// Responsible method: heap in script 200
-// Fixes bug: #4964
-static const uint16 kq5SignatureWitchCageInit[] = {
-	SIG_UINT16(0x0000),         // top
-	SIG_UINT16(0x0000),         // left
-	SIG_UINT16(0x0000),         // bottom
-	SIG_UINT16(0x0000),         // right
-	SIG_UINT16(0x0000),         // extra property #1
-	SIG_MAGICDWORD,
-	SIG_UINT16(0x007a),         // extra property #2
-	SIG_UINT16(0x00c8),         // extra property #3
-	SIG_UINT16(0x00a3),         // extra property #4
-	SIG_END
-};
-
-static const uint16 kq5PatchWitchCageInit[] = {
-	PATCH_UINT16(0x0000),       // top
-	PATCH_UINT16(0x007a),       // left
-	PATCH_UINT16(0x00c8),       // bottom
-	PATCH_UINT16(0x00a3),       // right
-	PATCH_END
-};
-
-// The multilingual releases of KQ5 hang right at the end during the magic
-// battle with Mordack. It seems additional code was added to wait for signals,
-// but the signals are never set and thus the game hangs. We disable that code,
-// so that the battle works again. This also happened in the original
-// interpreter. We must not change similar code, that happens before.
-//
-// Applies to at least: French PC floppy, German PC floppy, Spanish PC floppy
-// Responsible method: stingScript::changeState, dragonScript::changeState, snakeScript::changeState
-static const uint16 kq5SignatureMultilingualEndingGlitch[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x57,                      // lsg global[57h]
-	0x35, 0x00,                      // ldi 0
-	0x1a,                            // eq?
-	0x18,                            // not
-	0x30, SIG_UINT16(0x0011),        // bnt [skip signal check]
-	SIG_ADDTOOFFSET(+8),             // skip globalSound::prevSignal get code
-	0x36,                            // push
-	0x35, 0x0a,                      // ldi 0Ah
-	SIG_END
-};
-
-static const uint16 kq5PatchMultilingualEndingGlitch[] = {
-	PATCH_ADDTOOFFSET(+6),
-	0x32,                            // jmp (replace bnt)
-	PATCH_END
-};
-
-// In the final battle, the DOS version uses signals in the music to handle
-// timing, while in the Windows version another method is used and the GM
-// tracks do not contain these signals. The original kq5 interpreter used
-// global[400] to distinguish between Windows (1) and DOS (0) versions.
-//
-// We replace the global[400] checks with a fixed true. This is toggled with
-// enablePatch() below when alternative Windows GM MIDI tracks are used.
-//
-// Global[400] is also used to determine which cursor type to use: color view
-// resources for DOS or old black and white cursor resources for Windows.
-// We set this depending on if the user has used the "windows_cursors" option
-// in the Windows version. That doesn't affect this patch since it removes
-// global[400] from the code.
-//
-// Applies to at least: Win CD
-// Responsible method: mordOneScript::changeState(1), dragonScript::changeState(1),
-//                     fireScript::changeState() in script 124
-// Fixes bug: #6251
-static const uint16 kq5SignatureWinGMSignals[] = {
-	SIG_MAGICDWORD,
-	0x80, SIG_UINT16(0x0190),        // lag global[400]
-	0x18,                            // not
-	0x30, SIG_UINT16(0x001b),        // bnt 0x001b
-	0x89, 0x57,                      // lsg global[87]
-	SIG_END
-};
-
-static const uint16 kq5PatchWinGMSignals[] = {
-	0x34, PATCH_UINT16(0x0001),      // ldi 0x0001
-	PATCH_END
-};
-
-// During the introduction at Crispin's house in later floppy versions, Graham's
-//  initial message immediately disappears. This is another KQ5 sound regression
-//  caused by a broken signal that a script depends on.
-//
-// Sound 80's first signal is supposed to be set after 781 ticks to trigger the
-//  second message in room 109, but starting in the French version the sound
-//  changed to set this signal on the first tick. This causes the first message
-//  to miss the signal and display for too long until the second signal occurs
-//  and closes the first message and immediately closes the second.
-//
-// We fix this by replacing the first signal wait with a 13 second delay.
-//  781 ticks / 60 = 13 seconds and 1 tick. All subsequent signals in sound 80
-//  are correct. Sierra noticed this bug in the German Amiga Floppy version, but
-//  instead of fixing the broken sound, they peppered this script with similar
-//  delays except for the one place that needed it. This covers up that the
-//  wrong signals are still triggering messages with unintentional timings, but
-//  the results are acceptable. Due to this messy history, and that it involves
-//  multiple versions of multiple resources, we only enable this patch on game
-//  versions known to disappear Graham's message.
-//
-// Applies to: French PC Floppy, Italian PC Floppy, English Mac Floppy,
-//             English Amiga Floppy
-// Responsible method: a2s5Script:changeState(2)
-// Fixes bug: #11543
-static const uint16 kq5SignatureCrispinIntroSignal[] = {
-	SIG_MAGICDWORD,
-	0x36,                            // push
-	0x35, 0x0a,                      // ldi 0a
-	0x22,                            // lt? [ globalMusic:prevSignal < 10 ]
-	0x30, SIG_UINT16(0x0002),        // bnt 0002
-	0x6d, 0x0a,                      // dpToa state
-	0x35, 0x01,                      // ldi 01
-	0x65, 0x10,                      // aTop cycles
-	SIG_END
-};
-
-static const uint16 kq5PatchCrispinIntroSignal[] = {
-	0x38, PATCH_SELECTOR16(seconds), // pushi seconds
-	0x78,                            // push1
-	0x39, 0x0d,                      // pushi 0d
-	0x54, 0x06,                      // self 06 [ self seconds: 13 ]
-	0x32, PATCH_UINT16(0x0002),      // jmp 0002
-	PATCH_END
-};
-
-// Clicking Look or Do on the bandit's campfire in room 216 of the PC-98 version
-//  crashes the game or displays the wrong message after attempting to process
-//  hundreds of uninitialized parameters. The script has four calle instructions
-//  with frame size operands that don't match the number of parameters passed on
-//  the stack. The first real parameter, 216, is interpreted as the parameter
-//  count and chaos ensues.
-//
-// We fix this by setting the correct frame size. These instructions are correct
-//  in the later FM-Towns version so this appears to be a compiler bug.
-//
-// Applies to: Japanese PC-98
-// Responsible methods: fire:handleEvent, fireRing:handleEvent
-static const uint16 kq5SignaturePc98CampfireMessages[] = {
-	0x35, SIG_ADDTOOFFSET(+1),       // ldi
-	SIG_MAGICDWORD,
-	0x36,                            // push
-	0x46, SIG_UINT16(0x02f7),        // calle proc759_0 [ print message, 1 parameter ]
-	      SIG_UINT16(0x0000), 0x02,
-	SIG_END
-};
-
-static const uint16 kq5PatchPc98CampfireMessages[] = {
-	PATCH_ADDTOOFFSET(+8),
-	0x04,                            // calle proc759_0 [ print message, 2 parameters ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                  patch
-static const SciScriptPatcherEntry kq5Signatures[] = {
-	{  true,     0, "CD: harpy volume change",                     1, kq5SignatureCdHarpyVolume,            kq5PatchCdHarpyVolume },
-	{  true,     0, "timer rollover",                              1, sciSignatureTimerRollover,            sciPatchTimerRollover },
-	{  true,    99, "disable speed test",                          1, sci01SpeedTestLocalSignature,         sci01SpeedTestLocalPatch },
-	{  true,    99, "disable speed test",                          1, sci11SpeedTestSignature,              sci11SpeedTestPatch },
-	{ false,   109, "Crispin intro signal",                        1, kq5SignatureCrispinIntroSignal,       kq5PatchCrispinIntroSignal },
-	{  true,   124, "Multilingual: Ending glitching out",          3, kq5SignatureMultilingualEndingGlitch, kq5PatchMultilingualEndingGlitch },
-	{ false,   124, "Win: GM Music signal checks",                 4, kq5SignatureWinGMSignals,             kq5PatchWinGMSignals },
-	{  true,   200, "CD: witch cage init",                         1, kq5SignatureWitchCageInit,            kq5PatchWitchCageInit },
-	{  true,   216, "PC-98: campfire messages",                    4, kq5SignaturePc98CampfireMessages,     kq5PatchPc98CampfireMessages },
-	{  true,   973, "timer rollover",                              1, sciSignatureTimerRollover,            sciPatchTimerRollover },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// In the garden (room 480), when giving the milk bottle to one of the babies,
-// script 481 starts a looping a baby cry sound (cryMusic). However, that
-// particular sound has an overridden check() method that explicitly restarts
-// the sound, even if it's set to be looped. Thus the same sound is played
-// twice, squelching all other sounds.
-//
-// We just rip out the unnecessary check() method, 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.
-//
-// Applies to at least: PC-CD
-// Responsible method: cryMusic::check in script 481
-// Fixes bug: #4955
-static const uint16 kq6SignatureDuplicateBabyCry[] = {
-	SIG_MAGICDWORD,
-	0x83, 0x00,                      // lal local[0]
-	0x31, 0x1e,                      // bnt 1e [07f4]
-	0x78,                            // push1
-	0x39, 0x04,                      // pushi 04
-	0x43, 0x75, 0x02,                // callk DoAudio[75], 02
-	SIG_END
-};
-
-static const uint16 kq6PatchDuplicateBabyCry[] = {
-	0x48,                            // ret
-	PATCH_END
-};
-
-// 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 in script 907
-// Fixes bug: #5681
-static const uint16 kq6SignatureInventoryStackFix[] = {
-	0x67, 0x30,                         // pTos state
-	0x34, SIG_UINT16(0x2000),           // 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(0xdfff),           // ldi dfff
-	0x12,                               // and
-	0x65, 0x30,                         // aTop state
-	0x38, SIG_SELECTOR16(show),         // pushi show (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)
-};
-
-static 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(0x2000),         // ldi 2000
-	0x12,                               // and
-	0x2f, 0x02,                         // bt [not first refresh] - saves 3 bytes in total
-	0x65, 0x1e,                         // aTop curIcon
-	0x00,                               // bnot (neg, either 2000 or 0000 in acc, this will create dfff or ffff) - saves 2 bytes
-	0x12,                               // and
-	0x65, 0x30,                         // aTop state
-	0x38, PATCH_GETORIGINALUINT16(+22), // pushi show
-	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, PATCH_GETORIGINALBYTEADJUST(+39, +6), // bnt [menu exit code] (0x0e for pc, 0x0d for mac)
-	0x34, PATCH_UINT16(0x2000),         // ldi 2000
-	0x12,                               // and
-	0x2f, 0x05,                         // bt [to ret]
-	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
-};
-
-// The "Drink Me" bottle code doesn't repaint the AddToPics elements to the
-//  screen, when Alexander returns back from the effect of the bottle.
-//  It's pretty strange that Sierra didn't find this bug, because it occurs
-//  when drinking the bottle right on the screen, where the bottle is found.
-// This bug also occurs in Sierra SCI.
-//
-// Applies to at least: PC-CD, English PC floppy, German PC floppy, English Mac
-// Responsible method: drinkMeScript::changeState in script 87
-// Fixes bug: #5252
-static const uint16 kq6SignatureDrinkMeFix[] = {
-	SIG_MAGICDWORD,
-	0x3c,                               // dup
-	0x35, 0x0f,                         // ldi 0f
-	0x1a,                               // eq?
-	0x30, SIG_UINT16(0x00a4),           // bnt [skip to next check]
-	SIG_ADDTOOFFSET(+161),
-	0x32, SIG_UINT16(0x007f),           // jmp [return]
-	0x3c,                               // dup
-	0x35, 0x10,                         // ldi 10
-	0x1a,                               // eq?
-	0x31, 0x07,                         // bnt [skip to next check]
-	0x35, 0x03,                         // ldi 03
-	0x65, 0x1a,                         // aTop (cycles)
-	0x32, SIG_UINT16(0x0072),           // jmp [return]
-	0x3c,                               // dup
-	0x35, 0x11,                         // ldi 11
-	0x1a,                               // eq?
-	0x31, 0x13,                         // bnt [skip to next check]
-	SIG_ADDTOOFFSET(+20),
-	0x35, 0x12,                         // ldi 12
-	SIG_ADDTOOFFSET(+23),
-	0x35, 0x13,                         // ldi 13
-	SIG_END
-};
-
-static const uint16 kq6PatchDrinkMeFix[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x30, PATCH_UINT16(0x00b1),         // bnt 00b1 [ check for 11h code ]
-	PATCH_ADDTOOFFSET(+161),
-	0x39, PATCH_SELECTOR8(doit),        // pushi doit
-	0x76,                               // push0
-	0x81, 0x0a,                         // lag global[0a]
-	0x4a, 0x04,                         // send 04 (call addToPics::doit)
-	0x3a,                               // toss
-	0x48,                               // ret
-	PATCH_ADDTOOFFSET(+8),              // skip to check 11h code
-	0x35, 0x10,                         // ldi 10 (instead of 11)
-	PATCH_ADDTOOFFSET(+23),             // skip to check 12h code
-	0x35, 0x11,                         // ldi 11 (instead of 12)
-	PATCH_ADDTOOFFSET(+23),             // skip to check 13h code
-	0x35, 0x12,                         // ldi 12 (instead of 13)
-	PATCH_END
-};
-
-// KQ6 Mac is missing pic 981 and crashes when drinking the "Drink Me" bottle.
-//  This also crashed the original. Pic 981 is a black background and it's only
-//  used in this scene. Pic 98 is also a black background and used when the game
-//  starts and everywhere else. We restore this scene by switching to pic 98.
-//
-// This patch is only enabled on Mac as the script is the same in all versions.
-//  The pics have different palettes and applying it to PC would disable the
-//  palette cycling between red and black during this scene. KQ6 Mac didn't do
-//  these palette cycling effects as it didn't include any palette resources.
-//
-// Applies to: English Mac
-// Responsible method: drinkMeScript:changeState(0)
-static const uint16 kq6SignatureMacDrinkMePic[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x03d5),           // pushi 981d
-	0x39, 0x09,                         // pushi 09
-	0x43, 0x08, 0x04,                   // callk DrawPic 04
-	SIG_END
-};
-
-static const uint16 kq6PatchMacDrinkMePic[] = {
-	0x38, PATCH_UINT16(0x0062),         // pushi 98d
-	PATCH_END
-};
-
-// Looking at the ribbon in inventory says that there's a hair even after it's
-//  been removed. This occurs after the hair has been put in the skull or is on
-//  a different inventory page than the ribbon.
-//
-// The ribbon's Look handler has incorrect logic for determining if it contains
-//  a hair. It fails to test flag 143 which is set when getting the hair and so
-//  it displays the wrong message. The Do handler tests all the necessary flags.
-//  This bug probably would have been noticed except that both verb handlers
-//  also test inventory for hair, which is redundant as testing flags is enough,
-//  but it causes the right message some of the time. Testing inventory is wrong
-//  because possessing the hair is temporary, which is why the bug emerges after
-//  it's used, and it's broken because testing inventory across pages doesn't
-//  work in KQ6. ego:has returns false for any item on another page when the
-//  inventory window is open. As inventory increases the ribbon and hair end up
-//  on different pages and ribbon:doVerb can no longer see it.
-//
-// We fix the message by changing ribbon:doVerb(1) to test flag 143 like doVerb(5).
-//  This requires overwriting one of the redundant inventory tests.
-//
-// Beauty's clothes also have a hair and clothes:doVerb(1) has similar issues
-//  but it happens to work. Those items are always on the same page due to their
-//  low item numbers and the clothes are removed from inventory before the hair.
-//
-// Applies to: PC CD, PC Floppy, Mac Floppy
-// Responsible method: ribbon:doVerb(1) in script 907
-// Fixes bug: #10801
-static const uint16 kq6SignatureLookRibbonFix[] = {
-	0x30, SIG_ADDTOOFFSET(+2),          // bnt [ verb != Look ]
-	0x38, SIG_SELECTOR16(has),          // pushi has
-	0x78,                               // push1
-	0x39, 0x04,                         // pushi 04
-	0x81, SIG_MAGICDWORD, 0x00,         // lag global[0]
-	0x4a, 0x06,                         // send 6 [ ego:has 4 (beauty's hair) ]
-	0x2e,                               // bt [ continue hair tests ]
-	SIG_END
-};
-
-static const uint16 kq6PatchLookRibbonFix[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x78,                               // push1
-	0x38, PATCH_UINT16(0x008f),         // pushi 008f
-	0x46, PATCH_UINT16(0x0391),         // calle [export 0 of script 13], 02 [ is flag 8f set? ]
-	      PATCH_UINT16(0x0000), 0x02,
-	PATCH_END
-};
-
-// During the common Game Over cutscene, the CD audio for "Tickets, only" gets
-//  cut off. This only worked in the original interpreter at slow CPU speeds.
-//  modeLessScript sets a 4 second timer for the message to complete. This is
-//  enough time, but actor animations also cue modeLessScript, and they complete
-//  in 2 seconds unless the interpreter can't keep up due to a slow CPU.
-//
-// We fix this by ignoring the cue from deathCartoonScr if CD audio is enabled
-//  and the audio timeout hasn't completed. This does not change scene duration
-//  or actor delays or when messages start. Text-only mode is unaffected.
-//
-// Applies to: PC CD
-// Responsible method: modeLessScript:changeState
-static const uint16 kq6CDSignatureTicketsOnlyAudioTiming[] = {
-	0x31, 0x2b,                         // bnt 2b [ state 1 ]
-	SIG_ADDTOOFFSET(+38),
-	SIG_MAGICDWORD,
-	0x65, 0x1c,                         // aTop seconds
-	0x32, SIG_UINT16(0x0051),           // jmp 0051 [ end of method ]
-	0x3c,                               // dup
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	0x31, 0x0c,                         // bnt 0c [ state 2 ]
-	0x81, 0x19,                         // lag 19 [ dialog ]
-	0x30, SIG_UINT16(0x0046),           // bnt 0046
-	0x39, SIG_SELECTOR8(dispose),       // pushi dispose
-	0x76,                               // push0
-	0x4a, 0x04,                         // send 04 [ dialog dispose: ]
-	0x33, 0x3f,                         // jmp 3f
-	SIG_ADDTOOFFSET(+44),
-	0x65, 0x1c,                         // aTop seconds
-	SIG_ADDTOOFFSET(+8),
-	0x81, 0x19,                         // lag 19 [ dialog ]
-	SIG_END
-};
-
-static const uint16 kq6CDPatchTicketsOnlyAudioTiming[] = {
-	0x31, 0x28,                         // bnt 28 [ state 1 ]
-	PATCH_ADDTOOFFSET(+38),
-	0x33, 0x41,                         // jmp 41 [ aTop seconds, end of method ]
-	0x3c,                               // dup
-	0x18,                               // not [ acc = 1 ]
-	0x1a,                               // eq?
-	0x31, 0x10,                         // bnt 10 [ state 2 ]
-	0x81, 0x5a,                         // lag 5a [ mode ]
-	0x7a,                               // push2  [ audio ]
-	0x12,                               // and    [ is audio enabled? ]
-	0x31, 0x40,                         // bnt 40 [ if no audio then dispose dialog normally ]
-	0x63, 0x1c,                         // pToa seconds
-	0x2f, 0x04,                         // bt 04  [ ignore cue from deathCartoonScr if audio is playing ]
-	0x6b, 0x1a,                         // ipToa cycles [ cycles = 1 ]
-	0x33, 0x38,                         // jmp 38 [ dispose dialog normally ]
-	0x6d, 0x14,                         // dpToa state [ state = 0 so that state 1 can repeat ]
-	PATCH_END
-};
-
-// KQ6 CD introduced a bug in the wallflower dance in room 480. The dance is
-//  supposed to last until the music ends but in Text mode it stops after only
-//  three seconds once the user gains control. This isn't usually enough time
-//  to get the hole in the wall. This bug also occurs in Sierra's interpreter.
-//
-// wallFlowerDance was changed in the CD version for Speech mode but broke Text.
-//  In Text mode, changeState(9) creates a dialog with Print, which blocks, and
-//  then sets ticks to 12. Meanwhile, wallFlowerDance:handleEvent cues if an
-//  event is received in state 9. A mouse click starts a 12 tick race which
-//  handleEvent wins, cueing before the countdown expires, and so the countdown
-//  expires on state 10, skipping ahead to the three second fadeout. Closing the
-//  dialog with the keyboard works because Dialog claims keyboard events when
-//  blocking, preventing wallFlowerDance:handleEvent from receiving and cueing.
-//
-// We fix this by setting the Print dialog to modeless as it was in the floppy
-//  version and removing the countdown. wallFlowerDance:handleEvent now receives
-//  all events and is the only one responsible for advancing state 9 to 10 in
-//  Text mode. This patch does not affect audio modes Speech and Both.
-//
-// Applies to: PC CD
-// Responsible method: wallFlowerDance:changeState(9) in script 480
-// Fixes bug: #10811
-static const uint16 kq6CDSignatureWallFlowerDanceFix[] = {
-	SIG_MAGICDWORD,
-	0x39, SIG_SELECTOR8(init),          // pushi init
-	0x76,                               // push0
-	0x51, 0x15,                         // class Print [ Print: ... init ]
-	0x4a, 0x24,                         // send 24
-	0x35, 0x0c,                         // ldi 0c
-	0x65, 0x20,                         // aTop ticks
-	0x32, SIG_UINT16(0x00d0),           // jmp 00d0 [ end of method ]
-	SIG_END
-};
-
-static const uint16 kq6CDPatchWallFlowerDanceFix[] = {
-	0x38, PATCH_SELECTOR16(modeless),   // pushi modeless
-	0x78,                               // push1
-	0x78,                               // push1
-	0x39, PATCH_SELECTOR8(init),        // pushi init
-	0x76,                               // push0
-	0x51, 0x15,                         // class Print [ Print: ... modeless: 1, init ]
-	0x4a, 0x2a,                         // send 2a
-	0x3a,                               // toss
-	0x48,                               // ret
-	PATCH_END
-};
-
-// Attempting to pick a second head of frozen lettuce accidentally succeeds or
-//  fails depending on the time of day in real life.
-//
-// Upon picking the lettuce it starts to melt. After 150 seconds it's half
-//  melted, after 300 seconds it's a puddle, and after 450 seconds it disappears
-//  from inventory. When trying to pick a second head while one is inventory,
-//  lettuce:doVerb attempts to figure out if the lettuce is melted enough to
-//  replace or if it should say that Alexander already has frozen lettuce.
-//  The script's logic is:
-//
-//    if (kGetTime(1) - global157) < 150 then don't replace lettuce
-//
-// The first problem is that this code is outdated. Global 157 is never set, but
-//  presumably it was the original timer implementation before lettuceTimer.
-//  This code is supposed to test an elapsed time period, but since global 157
-//  is always zero, instead it's an accidental test of the current clock time.
-//  The second problem is that this is a signed comparison and kGetTime(1) is
-//  unsigned with the hour as the upper four bits. When the current clock time
-//  is between 8:00 and 12:59 (am or pm) then kGetTime(1) appears negative and
-//  the lettuce can never be replaced. During the other 14 hours of the day the
-//  lettuce can always be replaced, even if it's frozen.
-//
-// We fix this by replacing the time test with the correct frozen lettuce test.
-//
-// Applies to: All versions
-// Responsible method: lettuce:doVerb
-static const uint16 kq6SignatureSecondLettuceFix[] = {
-	0x31, 0x12,                         // bnt 12 [ skip message if clock hour < 8 (unintentional) ]
-	0x38, SIG_SELECTOR16(say),          // pushi say
-	SIG_ADDTOOFFSET(+15),
-	0x78,                               // push1
-	0x78,                               // push1
-	0x43, 0x42, 0x02,                   // callk GetTime 02
-	0x36,                               // push
-	0x81, 0x9d,                         // lag 9d [ always zero ]
-	0x04,                               // sub
-	0x36,                               // push
-	SIG_MAGICDWORD,
-	0x34, SIG_UINT16(0x012c),           // ldi 012c
-	0x22,                               // lt? [ (kGetTime(1) - global157) < 300 ]
-	0x31, 0x0a,                         // bnt 0a [ pick lettuce ]
-	0x78,                               // push1
-	0x7c,                               // pushSelf
-	0x46, SIG_UINT16(0x01e3),           // calle 01e3 ... [ pick lettuce ]
-	SIG_END
-};
-
-static const uint16 kq6PatchSecondLettuceFix[] = {
-	0x33, 0x12,                         // jmp 12 [ skip to correct lettuce logic ]
-	PATCH_ADDTOOFFSET(+18),
-	0x39, PATCH_SELECTOR8(at),          // pushi at
-	0x78,                               // push1
-	0x39, 0x15,                         // pushi 15
-	0x81, 0x09,                         // lag 09
-	0x4a, 0x06,                         // send 06 [ KqInv at: 21 ]
-	0x39, PATCH_SELECTOR8(message),     // pushi message
-	0x76,                               // push0
-	0x4a, 0x04,                         // send 04  [ lettuce message? ]
-	0x39, 0x34,                         // pushi 34 [ frozen ]
-	0x1a,                               // eq?      [ is lettuce frozen? ]
-	0x2f, 0xdb,                         // bt db    [ "Alexander already has a frozen head of lettuce." ]
-	0x33, 0x05,                         // jmp 05   [ pick lettuce ]
-	PATCH_END
-};
-
-// In room 300 at the bottom of the logic cliffs, clicking Walk while Alexander
-//  randomly wobbles on lower steps causes him to float around the room. Scripts
-//  attempt to prevent this by ignoring Walk when ego:view is 301 and ego:loop
-//  is 3, which is wobbling animation, but this is incomplete because egoWobbles
-//  also animates with view 3011. The rest of the cliff rooms directly test if
-//  egoWobbles is running and so they don't have this bug. egoWobbles isn't
-//  exported so room 300 is left testing ego's state.
-//
-// We fix this by adding the missing test for view 3011 so that the Walk verb is
-//  successfully ignored whenever egoWobbles is running.
-//
-// Applies to: All versions
-// Responsible methods: beach:doVerb, WalkFeature:doVerb
-static const uint16 kq6SignatureCliffStepFloatFix[] = {
-	0x36,                               // push
-	0x34, SIG_UINT16(0x012d),           // ldi 012d
-	0x1a,                               // eq?      [ ego:view == 301 ]
-	0x31, 0x12,                         // bnt 12   [ not wobbling ]
-	0x39, 0x03,                         // pushi 03 [ loop ]
-	0x76,                               // push0
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x04,                         // send 04  [ ego loop? ]
-	0x36,                               // push
-	0x35, SIG_MAGICDWORD, 0x03,         // ldi 03
-	0x1a,                               // eq?      [ ego:loop == 3 ]
-	0x31, 0x05,                         // bnt 05   [ not wobbling ]
-	0x35, 0x00,                         // ldi 00
-	0x32, SIG_ADDTOOFFSET(+2),          // jmp      [ end of method ]
-	0x76,                               // push0    [ y ]
-	0x76,                               // push0
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x04,                         // send 04  [ ego y? ]
-	0x36,                               // push
-	0x35, 0x26,                         // ldi 26
-	0x22,                               // lt?      [ ego:y < 38 ]
-	SIG_ADDTOOFFSET(+17),
-	0x32,                               // jmp      [ end of method ]
-	SIG_END
-};
-
-static const uint16 kq6PatchCliffStepFloatFix[] = {
-	0x38, PATCH_UINT16(0x0bc3),         // pushi 0bc3
-	0x1a,                               // eq?      [ ego:view == 3011 ]
-	0x2f, 0x12,                         // bt 12    [ wobbling ]
-	0x60,                               // pprev
-	0x34, PATCH_UINT16(0x012d),         // ldi 012d
-	0x1a,                               // eq?      [ ego:view == 301 ]
-	0x31, 0x0d,                         // bnt 0d   [ not wobbling ]
-	0x39, 0x03,                         // pushi 03
-	0x3c,                               // dup      [ loop ]
-	0x76,                               // push0
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x04,                         // send 04  [ ego loop? ]
-	0x1a,                               // eq?      [ ego:loop == 3 ]
-	0x31, 0x02,                         // bnt 02   [ not wobbling ]
-	0x33, 0x1a,                         // jmp 1a   [ end of method ]
-	0x76,                               // push0    [ y ]
-	0x76,                               // push0
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x04,                         // send 04  [ ego y? ]
-	0x39, 0x26,                         // pushi 26
-	0x20,                               // ge?      [ 38 >= ego:y ]
-	PATCH_END
-};
-
-// Similar to the patched bug above, clicking an item on the beach in room 300
-//  while wobbling on the bottom step causes Alexander to float around the room.
-//  The doVerb methods for the flower and the feather incorrectly test ego:y
-//  using a less than comparison instead of less than or equals to, which is
-//  what the rest of the methods in this script do.
-//
-// Applies to: All versions
-// Responsible methods: stench:doVerb, feather:doVerb
-static const uint16 kq6SignatureCliffItemFloatFix[] = {
-	SIG_MAGICDWORD,
-	0x36,                               // push
-	0x35, 0x69,                         // ldi 69
-	0x22,                               // lt?
-	SIG_END
-};
-
-static const uint16 kq6PatchCliffItemFloatFix[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x24,                               // le?
-	PATCH_END
-};
-
-// After casting the Make Rain spell, collecting the baby's tears a second time
-//  awards a duplicate point. The script getBabyTears is missing a flag check to
-//  prevent this. The falling water from Beast's fountain doesn't have this bug
-//  because it tests flag 14 before awarding its point. Flag 14 is set when the
-//  Druids catch Alexander. We add the missing flag check.
-//
-// Applies to: All versions
-// Responsible method: getBabyTears:changeState(4)
-static const uint16 kq6SignatureDuplicateBabyTearsPoint[] = {
-	0x31, 0x0f,                         // bnt 0f [ state 4 ]
-	SIG_ADDTOOFFSET(+12),
-	0x32, SIG_ADDTOOFFSET(+2),          // jmp [ end of method ]
-	0x3c,                               // dup
-	0x35, 0x04,                         // ldi 04
-	0x1a,                               // eq?
-	0x30, SIG_UINT16(0x0040),           // bnt 0040
-	0x89, 0xa1,                         // lsg a1
-	0x35, SIG_MAGICDWORD, 0x04,         // ldi 04
-	0x14,                               // or
-	0xa1, 0xa1,                         // sag a1
-	0x38, SIG_SELECTOR16(givePoints),   // pushi givePoints
-	0x78,                               // push1
-	0x78,                               // push1
-	0x81, 0x01,                         // lag 01
-	0x4a, 0x06,                         // send 06 [ Kq6 givePoints: 1 ]
-	SIG_ADDTOOFFSET(+45),
-	0x32,                               // jmp [ end of method ]
-	SIG_END
-};
-
-static const uint16 kq6PatchDuplicateBabyTearsPoint[] = {
-	0x31, 0x0c,                         // bnt 0c [ state 4 ]
-	PATCH_ADDTOOFFSET(+12),
-	0x3c,                               // dup
-	0x35, 0x04,                         // ldi 04
-	0x1a,                               // eq?
-	0x31, 0x44,                         // bnt 44
-	0x81, 0xa1,                         // lag a1
-	0x14,                               // or
-	0xa1, 0xa1,                         // sag a1
-	0x81, 0x89,                         // lag 89 [ flags ]
-	0x7a,                               // push2  [ flag 14 ]
-	0x12,                               // and    [ has storm occurred? ]
-	0x2f, 0x09,                         // bt 09  [ skip point ]
-	PATCH_ADDTOOFFSET(+54),
-	0x48,                               // ret    [ prevent toss, stack is empty ]
-	0x00,                               // bnot
-	0x00,                               // bnot
-	PATCH_END
-};
-
-// Clicking the lamp on the Baby Tears when the lamp already contains the sacred
-//  water awards the tears even if the babies aren't crying, allowing the puzzle
-//  to be bypassed. The script tests for the sacred water, even though the water
-//  shouldn't affect this sequence, and its only function is to skip the crying
-//  test which is always necessary. We fix this by disabling the water test.
-//
-// Applies to: All versions
-// Responsible method: Brat:doVerb
-static const uint16 kq6SignatureGetBabyTears[] = {
-	SIG_MAGICDWORD,
-	0x89, 0xa1,                         // lsg a1 [ lamp flags ]
-	0x35, 0x02,                         // ldi 02 [ sacred water ]
-	0x12,                               // and    [ is sacred water in lamp? ]
-	SIG_END
-};
-
-static const uint16 kq6PatchGetBabyTears[] = {
-	0x39, 0x00,                         // pushi 00 [ disable sacred water test ]
-	PATCH_END
-};
-
-// KQ6 truncates messages longer than 400 characters in the CD and Mac versions.
-//  This is most prominent when reading Cassima's letter to Alexander. When the
-//  Messager class was upgraded to support audio, a 400 character buffer was
-//  added to read messages into, but KQ6 has messages as long as 602 characters.
-//  This limitation is in other games with this same Messager class. LB2, for
-//  example, has the same class but no messages beyond 400 characters.
-//
-// We fix this by increasing the temporary variables in Messager:sayNext from
-//  202 to 303 to accommodate the longest message. This patch implicitly depends
-//  on the Audio+Subtitle patches below, as they coincidentally alter sayNext
-//  in a way that this patch would otherwise have to. The CD version uses
-//  temp201, which we would normally have to patch to temp302 since we're
-//  expanding the buffer before it, but the Audio+Subtitle patches happen to
-//  remove or disable all use of this variable.
-//
-// Applies to: PC CD, Macintosh
-// Responsible method: Messager:sayNext
-// Fixes bug: #10682
-static const uint16 kq6SignatureTruncatedMessagesFix[] = {
-	SIG_MAGICDWORD,
-	0x3f, 0xca,                         // link ca
-	0x87, 0x00,                         // lap 00
-	0x31, 0x18,                         // bnt 18
-	0x39, 0x07,                         // pushi 07
-	0x76,                               // push0
-	0x8f, 0x01,                         // lsp 01
-	0x8f, 0x02,                         // lsp 02
-	0x8f, 0x03,                         // lsp 03
-	0x8f, 0x04,                         // lsp 04
-	0x8f, 0x05,                         // lsp 05
-	0x5b, 0x04, 0x01,                   // lea 04 01
-	0x36,                               // push
-	0x43, 0x7c, 0x0e,                   // callk Message 0e
-	0xa5, 0x00,                         // sat 00
-	0x33, 0x0b,                         // jmp 0b
-	SIG_ADDTOOFFSET(+9),
-	0xa5, 0x00,                         // sat 00
-	SIG_END
-};
-
-static const uint16 kq6PatchTruncatedMessagesFix[] = {
-	0x3e, PATCH_UINT16(0x012f),         // link 012f
-	0x87, 0x00,                         // lap 00
-	0x31, 0x17,                         // bnt 17
-	0x39, 0x07,                         // pushi 07
-	0x76,                               // push0
-	0x8f, 0x01,                         // lsp 01
-	0x8f, 0x02,                         // lsp 02
-	0x8f, 0x03,                         // lsp 03
-	0x8f, 0x04,                         // lsp 04
-	0x8f, 0x05,                         // lsp 05
-	0x5b, 0x04, 0x01,                   // lea 04 01
-	0x36,                               // push
-	0x43, 0x7c, 0x0e,                   // callk Message 0e
-	0x32, PATCH_UINT16(0x0009),         // jmp 0009
-	PATCH_END
-};
-
-// WORKAROUND
-//
-// Dangling Participle and Rotten Tomato are inventory items that can talk, but
-//  their mouths are animated by inner loops that call kDrawCel with unthrottled
-//  inner inner loops that spin to create a delay between frames. This prevents
-//  updating the screen and responding to input. We replace the spin loops with
-//  calls to kScummVMSleep for 5 ticks so that the speed is reasonable, the
-//  screen updates, and the game is responsive.
-//
-// Applies to: All versions
-// Responsible method: participle:doVerb, tomato:doVerb
-static const uint16 kq6SignatureTalkingInventory[] = {
-	0x35, 0x00,                         // ldi 00
-	0xa5, 0x01,                         // sat 01
-	0x8d, 0x01,                         // lst 01
-	SIG_MAGICDWORD,
-	0x34, SIG_UINT16(0x1b58),           // ldi 1b58
-	0x22,                               // lt? [ temp1 < 7000 ]
-	SIG_END
-};
-
-static const uint16 kq6PatchTalkingInventory[] = {
-	PATCH_ADDTOOFFSET(+2),
-	0x78,                               // push1
-	0x39, 0x05,                         // pushi 05
-	0x43, kScummVMSleepId, 0x02,        // callk kScummVMSleep 02 [ 5 ticks ]
-	0x35, 0x00,                         // ldi 00 [ exit loop ]
-	PATCH_END
-};
-
-// Exiting the pawnshop while the Genie's eye is glinting locks up the game.
-//  Unlike the bookstore, the pawnshop script fails to dispose the "eye" object
-//  if it's in the middle of animating, causing the door animation in the next
-//  room to loop forever. Sierra added a simple workaround in later versions to
-//  prevent this: the eye no longer glints when ego is close the pawnshop exit.
-//  We apply this same workaround to vulnerable versions.
-//
-// Applies to: English, French, and German PC Floppy, English Mac Floppy,
-//             English PC CD 1.000.000
-// Responsible method: genieBrowseScr:changeState(3)
-static const uint16 kq6SignaturePawnshopGenieEye[] = {
-	0x39, 0x03,                         // pushi 03
-	SIG_MAGICDWORD,
-	0x7a,                               // push2
-	0x76,                               // push0
-	0x7a,                               // push2
-	0x43, 0x3c, 0x04,                   // callk Random [ Random 0 2 ]
-	0x36,                               // push
-	0x76,                               // push0
-	0x78,                               // push1
-	0x46, SIG_UINT16(0x03e7),           // calle proc999_5 [ OneOf (Random 0 2) 0 1 ]
-	      SIG_UINT16(0x0005), 0x06,
-	SIG_END
-};
-
-static const uint16 kq6PatchPawnshopGenieEye[] = {
-	0x39, 0x43,                         // pushi 43
-	0x78,                               // push1 [ x ]
-	0x76,                               // push0
-	0x81, 0x00,                         // lag 00
-	0x4a, 0x04,                         // send 04 [ ego x? ]
-	0x22,                               // lt?     [ 67 < ego:x ]
-	0x31, 0x06,                         // bnt 06  [ skip glint ]
-	0x7a,                               // push2
-	0x76,                               // push0
-	0x7a,                               // push2
-	0x43, 0x3c, 0x04,                   // callk Random [ Random 0 2 ]
-	PATCH_END
-};
-
-// During the wedding close-up with the Vizier and the Genie in room 740,
-//  clicking almost any of the wrong lamps on the Genie results in the wrong
-//  message sequence. Alexander says "I have this lamp, 'princess'" twice
-//  instead of the Genie responding after the first message. The script passes
-//  the wrong sequence number in the second message tuple.
-//
-// Applies to: All versions
-// Responsible method: genieHead:doVerb
-static const uint16 kq6SignatureWeddingGenieLampMessage[] = {
-	0x39, SIG_SELECTOR8(add),           // pushi add
-	0x39, 0x05,                         // pushi 05
-	0x67, SIG_ADDTOOFFSET(+1),          // pTos modNum
-	0x67, SIG_ADDTOOFFSET(+1),          // pTos noun
-	SIG_MAGICDWORD,
-	0x39, 0x39,                         // pushi 39 [ verb ]
-	0x76,                               // push0    [ cond ]
-	0x78,                               // push1    [ wrong seq ]
-	SIG_END
-};
-
-static const uint16 kq6PatchWeddingGenieLampMessage[] = {
-	PATCH_ADDTOOFFSET(+11),
-	0x7a,                               // push2 [ correct seq ]
-	PATCH_END
-};
-
-// Clicking Look on the first catacombs room (405) or the dead-end room (407)
-//  while in text-mode breaks the CD and Spanish versions. The message boxes
-//  never leave the screen, even after restarting. The doVerb methods in these
-//  rooms are missing the necessary "return true" statements that were added to
-//  all other rooms in the CD version. In earlier versions, Messager:say always
-//  set the accumulator to non-zero and these statements weren't necessary.
-//
-// Applies to: PC CD, Spanish PC Floppy
-// Responsible methods: rm405:doVerb(1), rm407:doVerb(1)
-static const uint16 kq6SignatureRoom405LookMessage[] = {
-	0x33, 0x1f,                         // jmp 1f
-	SIG_ADDTOOFFSET(+18),
-	0x33, 0x0b,                         // jmp 0b
-	SIG_ADDTOOFFSET(+8),
-	SIG_MAGICDWORD,
-	0x57, 0x93, 0x06,                   // super LabRoom 06 [ super doVerb: param1 &rest ]
-	0x3a,                               // toss
-	0x48,                               // ret
-	SIG_END
-};
-
-static const uint16 kq6PatchRoom405LookMessage[] = {
-	0x14,                               // or [ acc |= 1  ]
-	0x48,                               // ret
-	PATCH_ADDTOOFFSET(+18),
-	0x14,                               // or [ acc |= 1  ]
-	0x48,                               // ret
-	PATCH_END
-};
-
-static const uint16 kq6SignatureRoom407LookMessage[] = {
-	0x33, 0x0b,                         // jmp 0b
-	SIG_ADDTOOFFSET(+8),
-	SIG_MAGICDWORD,
-	0x57, 0x93, 0x06,                   // super LabRoom 06 [ super doVerb: param1 &rest ]
-	0x3a,                               // toss
-	0x48,                               // ret
-	SIG_END
-};
-
-static const uint16 kq6PatchRoom407LookMessage[] = {
-	0x14,                               // or [ acc |= 1  ]
-	0x48,                               // ret
-	PATCH_END
-};
-
-// After lighting the torch in the dark catacombs room and then re-entering,
-//  using items such as a book results in a message that the room is too dark.
-//  rm406:scriptCheck tests for darkness with a local variable that is set when
-//  lighting the torch instead of a persistent global. We could change the
-//  darkness test but it turns out that this method is never called in the dark.
-//  KQ6Room:setScript only calls scriptCheck when ego:view is 900 and that is
-//  only true once the torch is lit.
-//
-// We fix this by patching rm406:scriptCheck to always allow items since the
-//  condition it tries to prevent can never occur.
-//
-// Applies to: All versions
-// Responsible method: rm406:scriptCheck
-static const uint16 kq6SignatureDarkRoomInventory[] = {
-	0x3f, 0x01,                         // link 01
-	0x35, 0x00,                         // ldi 00
-	0xa5, 0x00,                         // sat temp0
-	0x8b, SIG_MAGICDWORD, 0x01,         // lsl 01
-	0x35, 0x64,                         // ldi 64
-	0x22,                               // lt? [ has lightItUp not run yet? ]
-	SIG_END
-};
-
-static const uint16 kq6PatchDarkRoomInventory[] = {
-	0x35, 0x01,                         // ldi 01
-	0x48,                               // ret [ return true, allow items ]
-	PATCH_END
-};
-
-// The Girl In The Tower theme plays from a CD audio track during the credits.
-//  In ScummVM this requires an actual CD, or a mounted CD image, or extracting
-//  the audio to a "track1" file ahead of time. If the track can't be played
-//  then there is silence for the entire credits, but the game includes a 5 MB
-//  Audio version to fall back on when CD audio is unavailable. The script plays
-//  this when the CD audio driver fails to load, though this never occurs in our
-//  our implementation and doesn't address a missing track.
-//
-// We ensure that the credits theme always plays by patching the script to also
-//  fall back on the Audio version when CD audio playback fails.
-//
-// Applies to: PC CD
-// Responsible method: sCredits:init
-static const uint16 kq6CDSignatureGirlInTheTowerPlayback[] = {
-	SIG_MAGICDWORD,
-	0x39, 0x05,                         // pushi 05
-	0x39, 0x0a,                         // pushi 0a   [ kSciAudioCD ]
-	0x7a,                               // push2      [ play ]
-	0x7a,                               // push2      [ track ]
-	0x76,                               // push0      [ start ]
-	0x38, SIG_UINT16(0x00ec),           // pushi 00ec [ end ]
-	0x43, 0x75, 0x0a,                   // callk DoAudio 0a
-	0x33,                               // jmp [ skip Audio version ]
-	SIG_END
-};
-
-static const uint16 kq6CDPatchGirlInTheTowerPlayback[] = {
-	PATCH_ADDTOOFFSET(+13),
-	0x2f,                               // bt [ skip Audio version if CD audio succeeded ]
-	PATCH_END
-};
-
-// Audio + subtitles support - SHARED! - used for King's Quest 6 and Laura Bow 2.
-//  This patch gets enabled when the user selects "both" in the ScummVM
-//  "Speech + Subtitles" menu. We currently use global[98d] to hold a kMemory
-//  pointer.
-// Applies to at least: KQ6 PC-CD, LB2 PC-CD
-// Patched method: Messager::sayNext / lb2Messager::sayNext (always use text branch)
-static const uint16 kq6laurabow2CDSignatureAudioTextSupport1[] = {
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x02,                         // ldi 02
-	0x12,                               // and
-	SIG_MAGICDWORD,
-	0x31, 0x13,                         // bnt [audio call]
-	0x38, SIG_SELECTOR16(modNum),       // pushi modNum
-	SIG_END
-};
-
-static const uint16 kq6laurabow2CDPatchAudioTextSupport1[] = {
-	PATCH_ADDTOOFFSET(+5),
-	0x33, 0x13,                         // jmp [audio call]
-	PATCH_END
-};
-
-// Applies to at least: KQ6 PC-CD, LB2 PC-CD
-// Patched method: Messager::sayNext / lb2Messager::sayNext (allocate audio memory)
-static const uint16 kq6laurabow2CDSignatureAudioTextSupport2[] = {
-	0x7a,                               // push2
-	0x78,                               // push1
-	0x39, 0x0c,                         // pushi 0c
-	0x43, SIG_MAGICDWORD, 0x72, 0x04,   // callk Memory
-	0xa5, 0xc9,                         // sat temp[c9]
-	SIG_END
-};
-
-static const uint16 kq6laurabow2CDPatchAudioTextSupport2[] = {
-	PATCH_ADDTOOFFSET(+7),
-	0xa1, 0x62,                         // sag global[62] (global[98d])
-	PATCH_END
-};
-
-// Applies to at least: KQ6 PC-CD, LB2 PC-CD
-// Patched method: Messager::sayNext / lb2Messager::sayNext (release audio memory)
-static const uint16 kq6laurabow2CDSignatureAudioTextSupport3[] = {
-	0x7a,                               // push2
-	0x39, 0x03,                         // pushi 03
-	SIG_MAGICDWORD,
-	0x8d, 0xc9,                         // lst temp[c9]
-	0x43, 0x72, 0x04,                   // callk Memory
-	SIG_END
-};
-
-static const uint16 kq6laurabow2CDPatchAudioTextSupport3[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x89, 0x62,                         // lsg global[62] (global[98d])
-	PATCH_END
-};
-
-// startText call gets acc = 0 for text-only and acc = 2 for audio+text
-// Applies to at least: KQ6 PC-CD, LB2 PC-CD
-// Patched method: Narrator::say (use audio memory)
-static const uint16 kq6laurabow2CDSignatureAudioTextSupport4[] = {
-	// set caller property code
-	0x31, 0x08,                         // bnt [set acc to 0 for caller]
-	0x87, 0x02,                         // lap param[2]
-	0x31, 0x04,                         // bnt [set acc to 0 for caller]
-	0x87, 0x02,                         // lap param[2]
-	0x33, 0x02,                         // jmp [set caller]
-	0x35, 0x00,                         // ldi 00
-	0x65, 0x68,                         // aTop caller
-	// call startText + startAudio code
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x01,                         // ldi 01
-	0x12,                               // and
-	0x31, 0x08,                         // bnt [skip code]
-	0x38, SIG_SELECTOR16(startText),    // pushi startText
-	0x78,                               // push1
-	0x8f, 0x01,                         // lsp param[1]
-	0x54, 0x06,                         // self 06
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x02,                         // ldi 02
-	0x12,                               // and
-	0x31, 0x08,                         // bnt [skip code]
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(startAudio),   // pushi startAudio
-	0x78,                               // push1
-	0x8f, 0x01,                         // lsp param[1]
-	0x54, 0x06,                         // self 06
-	SIG_END
-};
-
-static const uint16 kq6laurabow2CDPatchAudioTextSupport4[] = {
-	0x31, 0x02,                         // bnt [set caller]
-	0x87, 0x02,                         // lap param[2]
-	0x65, 0x68,                         // aTop caller
-	0x81, 0x5a,                         // lag global[5a]
-	0x78,                               // push1
-	0x12,                               // and
-	0x31, 0x11,                         // bnt [skip startText code]
-	0x81, 0x5a,                         // lag global[5a]
-	0x7a,                               // push2
-	0x12,                               // and
-	0x33, 0x03,                         // jmp 3 [skip unused bytes]
-	PATCH_ADDTOOFFSET(+22),
-	0x89, 0x62,                         // lsg global[62] (global[98d])
-	PATCH_END
-};
-
-// Applies to at least: KQ6 PC-CD, LB2 PC-CD
-// Patched method: Talker::display/Narrator::say (remove reset saved mouse cursor code)
-//  code would screw over mouse cursor
-static const uint16 kq6laurabow2CDSignatureAudioTextSupport5[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x00,                         // ldi 00
-	0x65, 0x82,                         // aTop saveCursor
-	SIG_END
-};
-
-static const uint16 kq6laurabow2CDPatchAudioTextSupport5[] = {
-	0x18, 0x18, 0x18, 0x18,             // (waste bytes)
-	PATCH_END
-};
-
-// Additional patch specifically for King's Quest 6
-//  Fixes text window placement, when in "dual" mode
-// Applies to at least: PC-CD
-// Patched method: Kq6Talker::init
-static const uint16 kq6CDSignatureAudioTextSupport1[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x02,                         // ldi 02
-	0x1a,                               // eq?
-	0x31, SIG_ADDTOOFFSET(+1),          // bnt [jump-to-text-code]
-	0x78,                               // push1
-	SIG_END
-};
-
-static const uint16 kq6CDPatchAudioTextSupport1[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x12,                               // and
-	PATCH_END
-};
-
-// Additional patch specifically for King's Quest 6
-//  Fixes low-res portrait staying on screen for hi-res mode
-// Applies to at least: PC-CD
-// Patched method: Talker::startText
-//  this method is called by Narrator::say and acc is 0 for text-only and 2 for dual mode (audio+text)
-static const uint16 kq6CDSignatureAudioTextSupport2[] = {
-	SIG_MAGICDWORD,
-	0x3f, 0x01,                         // link 01
-	0x63, 0x8a,                         // pToa viewInPrint
-	0x18,                               // not
-	0x31, 0x06,                         // bnt [skip following code]
-	0x38, SIG_UINT16(0x00e1),           // pushi 00e1
-	0x76,                               // push0
-	0x54, 0x04,                         // self 04
-	SIG_END
-};
-
-static const uint16 kq6CDPatchAudioTextSupport2[] = {
-	PATCH_ADDTOOFFSET(+2),
-	0x67, 0x8a,                         // pTos viewInPrint
-	0x14,                               // or
-	0x2f,                               // bt [skip following code]
-	PATCH_END
-};
-
-// Additional patch specifically for King's Quest 6
-//  Fixes special windows, used for example in...
-//   The Pawn shop (room 280), when the man in a robe complains about no more
-//    mints.
-//   Room 300 at the cliffs (aka copy protection), when Alexander falls down
-//    the cliffs (closes automatically, but too late).
-//   Room 210, when Alexander gives the ring to the nightingale (these need a
-//    mouse click).
-//
-//  We have to change even more code because the game uses PODialog class for
-//   text windows and myDialog class for audio. Both are saved to
-//   KQ6Print::dialog.
-//
-//  Changing KQ6Print::dialog is disabled for now, because it has side-effects
-//   (breaking game over screens).
-//
-//  Original comment:
-//  Sadly PODialog is created during KQ6Print::addText, myDialog is set during
-//   KQ6Print::showSelf, which is called much later and KQ6Print::addText
-//   requires KQ6Print::dialog to be set, which means we have to set it before
-//   calling addText for audio mode, otherwise the user would have to click to
-//   get those windows disposed.
-//
-// Applies to at least: PC-CD
-// Patched method: KQ6Print::say
-static const uint16 kq6CDSignatureAudioTextSupport3[] = {
-	0x31, 0x6e,                         // bnt [to text code]
-	SIG_ADDTOOFFSET(+85),
-	SIG_MAGICDWORD,
-	0x8f, 0x01,                         // lsp param[1]
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	0x31, 0x0c,                         // bnt [code to set property repressText to 1]
-	0x38,                               // pushi (selector addText)
-	SIG_ADDTOOFFSET(+9),                // skip addText-calling code
-	0x33, 0x10,                         // jmp [to ret]
-	0x35, 0x01,                         // ldi 01
-	0x65, 0x2e,                         // aTop repressText
-	0x33, 0x0a,                         // jmp [to ret]
-	SIG_END
-};
-
-static const uint16 kq6CDPatchAudioTextSupport3[] = {
-	0x31, 0x68,                         // bnt (adjust branch to reuse audio mode addText-calling code)
-	PATCH_ADDTOOFFSET(+85),             // (right at the MAGIC_DWORD)
-	// check, if text is supposed to be shown. If yes, skip the follow-up check (param[1])
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x01,                         // ldi 01
-	0x12,                               // and
-	0x2f, 0x07,                         // bt [skip over param check]
-	// original code, checks param[1]
-	0x8f, 0x01,                         // lsp param[1]
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	0x31, 0x10,                         // bnt [code to set property repressText to 1], adjusted
-	// waste 5 bytes instead of using myDialog class for now
-	// setting myDialog class all the time causes game over screens to misbehave (bug #9771)
-	0x34, PATCH_UINT16(0x0000),         // ldi 0 (waste 3 bytes)
-	0x35, 0x00,                         // ldi 0 (waste 2 bytes)
-	// use myDialog class, so that text box automatically disappears (this is not done for text only mode, like in the original)
-	//0x72, 0x0e, 0x00,                   // lofsa myDialog
-	//0x65, 0x12,                         // aTop dialog
-	// followed by original addText-calling code
-	0x38,
-	PATCH_GETORIGINALUINT16(+95),       // pushi (addText)
-	0x78,                               // push1
-	0x8f, 0x02,                         // lsp param[2]
-	0x59, 0x03,                         // &rest 03
-	0x54, 0x06,                         // self 06
-	0x48,                               // ret
-
-	0x35, 0x01,                         // ldi 01
-	0x65, 0x2e,                         // aTop repressText
-	0x48,                               // ret
-	PATCH_END
-};
-
-// Additional patch specifically for King's Quest 6
-//  Fixes text-window size for hires portraits mode
-//   Otherwise at least at the end some text-windows will be way too small
-// Applies to at least: PC-CD
-// Patched method: Talker::init
-static const uint16 kq6CDSignatureAudioTextSupport4[] = {
-	SIG_MAGICDWORD,
-	0x63, 0x94,                         // pToa raving
-	0x31, 0x0a,                         // bnt [no rave code]
-	0x35, 0x00,                         // ldi 00
-	SIG_ADDTOOFFSET(+6),                // skip reset of bust, eyes and mouth
-	0x33, 0x24,                         // jmp [to super class code]
-	SIG_END
-};
-
-static const uint16 kq6CDPatchAudioTextSupport4[] = {
-	PATCH_ADDTOOFFSET(+12),
-	0x33, PATCH_GETORIGINALBYTEADJUST(+13, -6), // (adjust jump to also include setSize call)
-	PATCH_END
-};
-
-//  Fixes text window placement, when dual mode is active (Guards in room 220)
-// Applies to at least: PC-CD
-// Patched method: tlkGateGuard1::init & tlkGateGuard2::init
-static const uint16 kq6CDSignatureAudioTextSupportGuards[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	SIG_END                             // followed by bnt for Guard1 and bt for Guard2
-};
-
-static const uint16 kq6CDPatchAudioTextSupportGuards[] = {
-	PATCH_ADDTOOFFSET(+2),
-	0x35, 0x02,                         // ldi 02
-	0x1c,                               // ne?
-	PATCH_END
-};
-
-//  Fixes text window placement, when portrait+text is shown (Stepmother in room 250)
-// Applies to at least: PC-CD
-// Patched method: tlkStepmother::init
-static const uint16 kq6CDSignatureAudioTextSupportStepmother[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x02,                         // ldi 02
-	0x12,                               // and
-	0x31,                               // bnt [jump-for-text-code]
-	SIG_END
-};
-
-static const uint16 kq6CDPatchAudioTextSupportJumpAlways[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x1a,                               // eq?
-	PATCH_END
-};
-
-//  Fixes "Girl In The Tower" to get played in dual mode as well
-//  Also changes credits to use CD audio for dual mode.
-//
-// Applies to at least: PC-CD
-// Patched method: rm740::cue (script 740), sCredits::init (script 52)
-static const uint16 kq6CDSignatureAudioTextSupportGirlInTheTower[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x02,                         // ldi 02
-	0x1a,                               // eq?
-	0x31,                               // bnt [jump-for-text-code]
-	SIG_END
-};
-
-static const uint16 kq6CDPatchAudioTextSupportGirlInTheTower[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x12,                               // and
-	PATCH_END
-};
-
-//  Fixes dual mode for scenes with Azure and Ariel (room 370)
-//   Effectively same patch as the one for fixing "Girl In The Tower"
-// Applies to at least: PC-CD
-// Patched methods: rm370::init, caughtAtGateCD::changeState, caughtAtGateTXT::changeState, toLabyrinth::changeState
-// Fixes bug: #6750
-static const uint16 kq6CDSignatureAudioTextSupportAzureAriel[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x02,                         // ldi 02
-	0x1a,                               // eq?
-	0x31,                               // bnt [jump-for-text-code]
-	SIG_END
-};
-
-static const uint16 kq6CDPatchAudioTextSupportAzureAriel[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x12,                               // and
-	PATCH_END
-};
-
-// Fixes Alexander's yell in dual mode when the Minotaur knocks him into the
-//  firey pit in room 440.
-//
-// Applies to: PC-CD
-// Patched method: hornSwaggled:changeState
-static const uint16 kq6CDSignatureAudioTextSupportMinotaurLair[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x02,                         // ldi 02
-	0x1a,                               // eq?
-	SIG_ADDTOOFFSET(+41),
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x02,                         // ldi 02
-	0x1c,                               // ne?
-	SIG_END
-};
-
-static const uint16 kq6CDPatchAudioTextSupportMinotaurLair[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x12,                               // and
-	PATCH_ADDTOOFFSET(+43),
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	PATCH_END
-};
-
-// Additional patch specifically for King's Quest 6
-//  Adds another button state for the text/audio button. We currently use the "speech" view for "dual" mode.
-// View 947, loop 9, cel 0+1 -> "text"
-// View 947, loop 8, cel 0+1 -> "speech"
-// View 947, loop 12, cel 0+1 -> "dual" (this view is injected by us into the game)
-// Applies to at least: PC-CD
-// Patched method: iconTextSwitch::show, iconTextSwitch::doit
-static const uint16 kq6CDSignatureAudioTextMenuSupport[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x02,                         // ldi 02
-	0x1a,                               // eq?
-	0x31, 0x06,                         // bnt [set text view]
-	0x35, 0x08,                         // ldi 08
-	0x65, 0x14,                         // aTop loop
-	0x33, 0x04,                         // jmp [skip over text view]
-	0x35, 0x09,                         // ldi 09
-	0x65, 0x14,                         // aTop loop
-	SIG_ADDTOOFFSET(+102),              // skip to iconTextSwitch::doit code
-	0x89, 0x5a,                         // lsg global[5a]
-	0x3c,                               // dup
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	0x31, 0x06,                         // bnt [set text mode]
-	0x35, 0x02,                         // ldi 02
-	0xa1, 0x5a,                         // sag global[5a]
-	0x33, 0x0a,                         // jmp [skip over text mode code]
-	0x3c,                               // dup
-	0x35, 0x02,                         // ldi 02
-	0x1a,                               // eq?
-	0x31, 0x04,                         // bnt [skip over text ode code]
-	0x35, 0x01,                         // ldi 01
-	0xa1, 0x5a,                         // sag global[5a]
-	0x3a,                               // toss
-	0x67, 0x14,                         // pTos loop
-	0x35, 0x09,                         // ldi 09
-	0x1a,                               // eq?
-	0x31, 0x04,                         // bnt [set text view]
-	0x35, 0x08,                         // ldi 08
-	0x33, 0x02,                         // jmp [skip text view]
-	0x35, 0x09,                         // ldi 09
-	0x65, 0x14,                         // aTop loop
-	SIG_END
-};
-
-static const uint16 kq6CDPatchAudioTextMenuSupport[] = {
-	PATCH_ADDTOOFFSET(+13),
-	0x33, 0x79,                         // jmp [to new text+dual code]
-	PATCH_ADDTOOFFSET(+104),            // seek to iconTextSwitch::doit
-	0x81, 0x5a,                         // lag global[5a]
-	0x78,                               // push1
-	0x02,                               // add
-	0xa1, 0x5a,                         // sag global[5a]
-	0x36,                               // push
-	0x35, 0x03,                         // ldi 03
-	0x1e,                               // gt?
-	0x31, 0x03,                         // bnt [skip over]
-	0x78,                               // push1
-	0xa9, 0x5a,                         // ssg global[5a]
-	0x33, 0x17,                         // jmp [iconTextSwitch::show call]
-	// additional code for iconTextSwitch::show
-	0x89, 0x5a,                         // lsg global[5a]
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	0x31, 0x04,                         // bnt [dual mode]
-	0x35, 0x09,                         // ldi 09
-	0x33, 0x02,                         // jmp [skip over dual mode]
-	0x35, 0x0c,                         // ldi 0c (view 947, loop 12, cel 0+1 is our "dual" view, injected by view.cpp)
-	0x65, 0x14,                         // aTop loop
-	0x32, PATCH_UINT16(0xff75),         // jmp [back to iconTextSwitch::show]
-	PATCH_END
-};
-
-// When caught by guard dogs in the castle, sometimes their music doesn't stop.
-//  Sound 710 continues playing in the dungeon and afterwards, drowning out the
-//  real room music. This script bug also occurs in the original. It's a
-//  regression in the CD version and subsequent localized floppy versions.
-//
-// When changing rooms, CastleRoom:newRoom fades out sound 710 if it's already
-//  playing, which it detects by testing if globalSound2:prevSignal != -1.
-//  This worked in the original floppy versions but the CD version introduced a
-//  newer Sound class with different behavior. prevSignal is no longer reset to
-//  0 by every Sound:play. This prevents CastleRoom:newRoom from detecting and
-//  stopping the music when globalSound2:prevSignal is -1 from an earlier sound.
-//
-// We fix this by testing globalSound2:handle instead of prevSignal. handle is
-//  always set while a sound is being played and always cleared afterwards. This
-//  is the same bug as in LB2CD's Act 5 finale music, and the same fix.
-//
-// Applies to: PC CD, Italian PC Floppy, Spanish PC Floppy
-// Responsible method: CastleRoom:newRoom
-// Fixes bug: #11746
-static const uint16 kq6SignatureGuardDogMusic[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x00ac),           // pushi prevSignal [ hard-coded for affected versions ]
-	0x76,                               // push0
-	0x81, 0x67,                         // lag 67  [ globalSound2 ]
-	0x4a, 0x04,                         // send 04 [ globalSound2 prevSignal? ]
-	0x36,                               // push
-	0x35, 0xff,                         // ldi ff
-	SIG_END
-};
-
-static const uint16 kq6PatchGuardDogMusic[] = {
-	0x38, PATCH_SELECTOR16(handle),     // pushi handle
-	PATCH_ADDTOOFFSET(+6),
-	0x35, 0x00,                         // ldi 00
-	PATCH_END
-};
-
-// Quickly clicking on certain Features multiple times can lockup and crash the
-//  the game. Examples: giving the rose to Beauty and looking at the peephole in
-//  the passage outside of Cassima's room. This also occurs in the original.
-//
-// The bug is in the Feature and CueObj classes but only a few Features are
-//  vulnerable. Factors include approach properties (coordinates, dist), the
-//  surrounding obstacles, and timing. Clicking on a Feature causes ego to walk
-//  towards it, turn towards it, wait three cycles, and then call doVerb. CueObj
-//  handles most of this sequence. However, if ego is already close to the
-//  Feature, then CueObj is advanced to its final state to immediately call
-//  doVerb. The problem is that this doesn't take into account that ego might be
-//  in the middle of turning. If a second click occurs while ego is turning from
-//  the first click, doVerb will be called immediately, CueObj will be reset to
-//  its initial state, and then ego's turn will complete and CueObj will proceed
-//  to call doVerb again. If doVerb runs a hands-off script then it will be
-//  interrupted and restarted at which point the game breaks in various ways.
-//
-// We fix this by removing a simple line that resets CueObj to its initial state
-//  after it calls Feature:doVerb. Nothing depends on this; every caller resets
-//  CueObj:state explicitly. But without this line, a stray cue from ego turning
-//  will advance CueObj from its final state (three) to an unused state (four)
-//  where it will have no effect. Although this buggy Feature script is in other
-//  games, so far it's only known to cause problems in KQ6.
-//
-// Applies to: All versions
-// Responsible method: CueObj:changeState(3)
-static const uint16 kq6SignatureFeatureEventHandling[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x00,                         // ldi 00
-	0x65, 0x14,                         // atop state [ state = 0 ]
-	SIG_END
-};
-
-static const uint16 kq6PatchFeatureEventHandling[] = {
-	0x33, 0x02,                         // jmp 02 [ don't reset CueObj state ]
-	PATCH_END
-};
-
-// KQ6 Mac sets a three second delay before playing its QuickTime opening movie
-//  in order to sync it with the music, but setting Script:seconds produces
-//  inconsistent delays. (See GK1 cartoon timing patches.) Converting the delay
-//  from seconds to ticks results in consistent timing in sync with the movie.
-//
-// Applies to: English Mac only
-// Responsible method: showMovie:changeState(2)
-static const uint16 kq6MacSignatureMacOpeningMovieDelay[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x03,                         // ldi 03
-	0x65, 0x1c,                         // aTop seconds [ seconds = 3 ]
-	0x33, 0x24,                         // jmp 24       [ end of method ]
-	SIG_END
-};
-
-static const uint16 kq6MacPatchMacOpeningMovieDelay[] = {
-	0x34, PATCH_UINT16(0x00b4),         // ldi 00b4
-	0x64, PATCH_UINT16(0x0020),         // aTop ticks [ ticks = 180 ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                                 patch
-static const SciScriptPatcherEntry kq6Signatures[] = {
-	{  true,    52, "CD: Girl In The Tower playback",                 1, kq6CDSignatureGirlInTheTowerPlayback,     kq6CDPatchGirlInTheTowerPlayback },
-	{  true,    80, "fix guard dog music",                            1, kq6SignatureGuardDogMusic,                kq6PatchGuardDogMusic },
-	{  true,    87, "fix Drink Me bottle",                            1, kq6SignatureDrinkMeFix,                   kq6PatchDrinkMeFix },
-	{ false,    87, "Mac: Drink Me pic",                              1, kq6SignatureMacDrinkMePic,                kq6PatchMacDrinkMePic },
-	{  true,    99, "disable speed test",                             1, sci11SpeedTestSignature,                  sci11SpeedTestPatch },
-	{  true,   105, "Mac: opening movie delay",                       1, kq6MacSignatureMacOpeningMovieDelay,      kq6MacPatchMacOpeningMovieDelay },
-	{  true,   281, "fix pawnshop genie eye",                         1, kq6SignaturePawnshopGenieEye,             kq6PatchPawnshopGenieEye },
-	{  true,   300, "fix floating off steps",                         2, kq6SignatureCliffStepFloatFix,            kq6PatchCliffStepFloatFix },
-	{  true,   300, "fix floating off steps",                         2, kq6SignatureCliffItemFloatFix,            kq6PatchCliffItemFloatFix },
-	{  true,   405, "fix catacombs room message",                     1, kq6SignatureRoom405LookMessage,           kq6PatchRoom405LookMessage },
-	{  true,   406, "fix catacombs dark room inventory",              1, kq6SignatureDarkRoomInventory,            kq6PatchDarkRoomInventory },
-	{  true,   407, "fix catacombs room message",                     1, kq6SignatureRoom407LookMessage,           kq6PatchRoom407LookMessage },
-	{  true,   480, "CD: fix wallflower dance",                       1, kq6CDSignatureWallFlowerDanceFix,         kq6CDPatchWallFlowerDanceFix },
-	{  true,   480, "fix picking second lettuce",                     1, kq6SignatureSecondLettuceFix,             kq6PatchSecondLettuceFix },
-	{  true,   480, "fix getting baby tears",                         1, kq6SignatureGetBabyTears,                 kq6PatchGetBabyTears },
-	{  true,   481, "fix duplicate baby cry",                         1, kq6SignatureDuplicateBabyCry,             kq6PatchDuplicateBabyCry },
-	{  true,   481, "fix duplicate baby tears point",                 1, kq6SignatureDuplicateBabyTearsPoint,      kq6PatchDuplicateBabyTearsPoint },
-	{  true,   640, "fix 'Tickets Only' audio timing",                1, kq6CDSignatureTicketsOnlyAudioTiming,     kq6CDPatchTicketsOnlyAudioTiming },
-	{  true,   745, "fix wedding genie lamp message",                 1, kq6SignatureWeddingGenieLampMessage,      kq6PatchWeddingGenieLampMessage },
-	{  true,   907, "fix inventory stack leak",                       1, kq6SignatureInventoryStackFix,            kq6PatchInventoryStackFix },
-	{  true,   907, "fix hair detection for ribbon's look msg",       1, kq6SignatureLookRibbonFix,                kq6PatchLookRibbonFix },
-	{  true,   907, "talking inventory workaround",                   4, kq6SignatureTalkingInventory,             kq6PatchTalkingInventory },
-	{  true,   924, "CD/Mac: fix truncated messages",                 1, kq6SignatureTruncatedMessagesFix,         kq6PatchTruncatedMessagesFix },
-	{  true,   928, "Narrator lockup fix",                            1, sciNarratorLockupSignature,               sciNarratorLockupPatch },
-	{  true,   950, "fix Feature event handling",                     1, kq6SignatureFeatureEventHandling,         kq6PatchFeatureEventHandling },
-	// King's Quest 6 and Laura Bow 2 share basic patches for audio + text support
-	// *** King's Quest 6 audio + text support ***
-	{ false,   924, "CD: audio + text support KQ6&LB2 1",             1, kq6laurabow2CDSignatureAudioTextSupport1,     kq6laurabow2CDPatchAudioTextSupport1 },
-	{ false,   924, "CD: audio + text support KQ6&LB2 2",             1, kq6laurabow2CDSignatureAudioTextSupport2,     kq6laurabow2CDPatchAudioTextSupport2 },
-	{ false,   924, "CD: audio + text support KQ6&LB2 3",             1, kq6laurabow2CDSignatureAudioTextSupport3,     kq6laurabow2CDPatchAudioTextSupport3 },
-	{ false,   928, "CD: audio + text support KQ6&LB2 4",             1, kq6laurabow2CDSignatureAudioTextSupport4,     kq6laurabow2CDPatchAudioTextSupport4 },
-	{ false,   928, "CD: audio + text support KQ6&LB2 5",             2, kq6laurabow2CDSignatureAudioTextSupport5,     kq6laurabow2CDPatchAudioTextSupport5 },
-	{ false,   909, "CD: audio + text support KQ6 1",                 2, kq6CDSignatureAudioTextSupport1,              kq6CDPatchAudioTextSupport1 },
-	{ false,   928, "CD: audio + text support KQ6 2",                 1, kq6CDSignatureAudioTextSupport2,              kq6CDPatchAudioTextSupport2 },
-	{ false,   104, "CD: audio + text support KQ6 3",                 1, kq6CDSignatureAudioTextSupport3,              kq6CDPatchAudioTextSupport3 },
-	{ false,   928, "CD: audio + text support KQ6 4",                 1, kq6CDSignatureAudioTextSupport4,              kq6CDPatchAudioTextSupport4 },
-	{ false,  1009, "CD: audio + text support KQ6 Guards",            2, kq6CDSignatureAudioTextSupportGuards,         kq6CDPatchAudioTextSupportGuards },
-	{ false,  1027, "CD: audio + text support KQ6 Stepmother",        1, kq6CDSignatureAudioTextSupportStepmother,     kq6CDPatchAudioTextSupportJumpAlways },
-	{ false,    52, "CD: audio + text support KQ6 Girl In The Tower", 1, kq6CDSignatureAudioTextSupportGirlInTheTower, kq6CDPatchAudioTextSupportGirlInTheTower },
-	{ false,   740, "CD: audio + text support KQ6 Girl In The Tower", 1, kq6CDSignatureAudioTextSupportGirlInTheTower, kq6CDPatchAudioTextSupportGirlInTheTower },
-	{ false,   370, "CD: audio + text support KQ6 Azure & Ariel",     6, kq6CDSignatureAudioTextSupportAzureAriel,     kq6CDPatchAudioTextSupportAzureAriel },
-	{ false,   441, "CD: audio + text support KQ6 Minotaur lair",     1, kq6CDSignatureAudioTextSupportMinotaurLair,   kq6CDPatchAudioTextSupportMinotaurLair },
-	{ false,   903, "CD: audio + text support KQ6 menu",              1, kq6CDSignatureAudioTextMenuSupport,           kq6CDPatchAudioTextMenuSupport },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#ifdef ENABLE_SCI32
-#pragma mark -
-#pragma mark Kings Quest 7
-
-// KQ7's subtitles were left unfinished in the shipped game, so there are
-// several problems when enabling them from the ScummVM launcher:
-//
-// 1. `kqMessager::findTalker` tries to determine which class to use for
-//    displaying subtitles using the talker number of each message, but the
-//    talker data is often bogus (e.g. princess messages normally use talker 7,
-//    but talker 99 (which is for the narrator) is used for her messages at the
-//    start of chapter 2), so it can't be used.
-// 2. Some display classes render subtitles at the top or middle of the game
-//    area, blocking the view of what is on the screen.
-// 3. In some areas, the colors of the subtitles are changed arbitrarily (e.g.
-//    pink/purple at the start of chapter 2).
-//
-// To work around these problems, we always use KQTalker, force the text area to
-// the bottom of the game area, and force it to always use black & white, which
-// are guaranteed to not be changed by game scripts.
-//
-// We make 2 changes to KQNarrator::init and one to Narrator::say.
-//
-// Applies to at least: PC CD 1.4 English, 1.51 English, 1.51 German, 2.00 English
-static const uint16 kq7SubtitleFixSignature1[] = {
-	SIG_MAGICDWORD,
-	0x39, SIG_SELECTOR8(fore), // pushi fore ($25)
-	0x78,                      // push1
-	0x39, 0x06,                // pushi 6 - sets fore to 6
-	0x39, SIG_SELECTOR8(back), // pushi back ($26)
-	0x78,                      // push1
-	0x78,                      // push1 - sets back to 1
-	0x39, SIG_SELECTOR8(font), // pushi font ($2a)
-	0x78,                      // push1
-	0x89, 0x16,                // lsg global[$16] - sets font to global[$16]
-	0x7a,                      // push2 (y)
-	0x78,                      // push1
-	0x76,                      // push0 - sets y to 0
-	0x54, SIG_UINT16(0x0018),  // self $18
-	SIG_END
-};
-
-static const uint16 kq7SubtitleFixPatch1[] = {
-	0x33, 0x12, // jmp [skip special init code]
-	PATCH_END
-};
-
-// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English
-static const uint16 kq7SubtitleFixSignature2[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x5a,                         // lsg global[$5a]
-	0x35, 0x02,                         // ldi 2
-	0x12,                               // and
-	0x31, 0x1e,                         // bnt [skip audio volume code]
-	0x38, SIG_SELECTOR16(masterVolume), // pushi masterVolume (0212h for 2.00, 0219h for 1.51)
-	0x76,                               // push0
-	0x81, 0x01,                         // lag global[1]
-	0x4a, SIG_UINT16(0x0004),           // send 4
-	0x65, 0x32,                         // aTop curVolume
-	0x38, SIG_SELECTOR16(masterVolume), // pushi masterVolume (0212h for 2.00, 0219h for 1.51)
-	0x78,                               // push1
-	0x67, 0x32,                         // pTos curVolume
-	0x35, 0x02,                         // ldi 2
-	0x06,                               // mul
-	0x36,                               // push
-	0x35, 0x03,                         // ldi 3
-	0x08,                               // div
-	0x36,                               // push
-	0x81, 0x01,                         // lag global[1]
-	0x4a, SIG_UINT16(0x0006),           // send 6
-	// end of volume code
-	0x35, 0x01,                         // ldi 1
-	0x65, 0x28,                         // aTop initialized
-	SIG_END
-};
-
-static const uint16 kq7SubtitleFixPatch2[] = {
-	PATCH_ADDTOOFFSET(+5),    // skip to bnt
-	0x31, 0x1b,               // bnt [skip audio volume code]
-	PATCH_ADDTOOFFSET(+15),   // right after "aTop curVolume / pushi masterVolume / push1"
-	0x7a,                     // push2
-	0x06,                     // mul (saves 3 bytes in total)
-	0x36,                     // push
-	0x35, 0x03,               // ldi 3
-	0x08,                     // div
-	0x36,                     // push
-	0x81, 0x01,               // lag global[1]
-	0x4a, PATCH_UINT16(0x06), // send 6
-	// end of volume code
-	0x35, 0x76,               // ldi 118
-	0x65, 0x16,               // aTop y
-	0x78,                     // push1 (saves 1 byte)
-	0x69, 0x28,               // sTop initialized
-	PATCH_END
-};
-
-// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English
-static const uint16 kq7SubtitleFixSignature3[] = {
-	SIG_MAGICDWORD,
-	0x63, 0x28,                 // pToa initialized
-	0x18,                       // not
-	0x31, 0x07,                 // bnt [skip init code]
-	0x38, SIG_SELECTOR16(init), // pushi init ($8e for 2.00, $93 for 1.51)
-	0x76,                       // push0
-	0x54, SIG_UINT16(0x0004),   // self 4
-	// end of init code
-	0x8f, 0x00,                 // lsp param[0]
-	0x35, 0x01,                 // ldi 1
-	0x1e,                       // gt?
-	0x31, 0x08,                 // bnt [set acc to 0]
-	0x87, 0x02,                 // lap param[2]
-	0x31, 0x04,                 // bnt [set acc to 0]
-	0x87, 0x02,                 // lap param[2]
-	0x33, 0x02,                 // jmp [over set acc to 0 code]
-	0x35, 0x00,                 // ldi 00
-	0x65, 0x18,                 // aTop caller
-	SIG_END
-};
-
-static const uint16 kq7SubtitleFixPatch3[] = {
-	PATCH_ADDTOOFFSET(+2),              // skip over "pToa initialized code"
-	0x2f, 0x0c,                         // bt [skip init code] - saved 1 byte
-	0x38, PATCH_GETORIGINALUINT16(+6),  // pushi init
-	0x76,                               // push0
-	0x54, PATCH_UINT16(0x0004),         // self 4
-	// additionally set background color here (5 bytes)
-	0x34, PATCH_UINT16(0x00ff),         // ldi 255
-	0x65, 0x2e,                         // aTop back
-	// end of init code
-	0x8f, 0x00,                         // lsp param[0]
-	0x35, 0x01,                         // ldi 1 (this may get optimized to get another byte)
-	0x1e,                               // gt?
-	0x31, 0x04,                         // bnt [set acc to 0]
-	0x87, 0x02,                         // lap param[2]
-	0x2f, 0x02,                         // bt [over set acc to 0 code]
-	PATCH_END
-};
-
-// KQ7 has custom video benchmarking code that needs to be disabled in a subroutine
-// that is called by KQ7CD::init; see sci2BenchmarkSignature
-static const uint16 kq7BenchmarkSignature[] = {
-	0x38, SIG_SELECTOR16(new), // pushi new
-	0x76,                      // push0
-	0x51, SIG_ADDTOOFFSET(+1), // class Actor
-	0x4a, SIG_UINT16(0x0004),  // send 4
-	0xa5, 0x00,                // sat temp[0]
-	0x39, SIG_SELECTOR8(view), // pushi view ($e)
-	SIG_MAGICDWORD,
-	0x78,                      // push1
-	0x38, SIG_UINT16(0xfdd4),  // pushi 64980
-	SIG_END
-};
-
-static const uint16 kq7BenchmarkPatch[] = {
-	0x34, PATCH_UINT16(10000), // ldi 10000
-	0x48,                      // ret
-	PATCH_END
-};
-
-// When attempting to use an inventory item on an object that does not interact
-// with that item, the game briefly displays an X cursor. It does this by
-// spinning for 90000 cycles, which makes the duration dependent on CPU speed,
-// maxes out the CPU for no reason, and keeps the engine from polling for
-// events (which may make the window appear nonresponsive to the OS).
-//
-// We replace the loop with a call to kScummVMSleep.
-//
-// Applies to at least: KQ7 English 2.00b
-// Responsible method: KQ7CD::pragmaFail in script 0
-static const uint16 kq7PragmaFailSpinSignature[] = {
-	0x35, 0x00,               // ldi 0
-	0xa5, 0x02,               // sat temp[2]
-	SIG_MAGICDWORD,
-	0x8d, 0x02,               // lst temp[2]
-	0x35, 0x03,               // ldi 3
-	0x22,                     // lt?
-	SIG_END
-};
-
-static const uint16 kq7PragmaFailSpinPatch[] = {
-	0x78,                                     // push1
-	0x39, 0x12,                               // pushi 18 (~300ms)
-	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, 2
-	0x35, 0x00,                               // ldi 0 [ exit loop ]
-	PATCH_END
-};
-
-// Room 6100 creates an extra ambrosia, usually floating in upper left of the
-//  screen, due to an off by one error. The script's local arrays contain four
-//  ambrosia coordinates but the loop that accesses them iterates five times.
-//
-// Applies to: All versions
-// Responsible method: rm6100:init
-// Fixes bug #9790
-static const uint16 kq7ExtraAmbrosiaSignature[] = {
-	SIG_MAGICDWORD,
-	0x8d, 0x00,                 // lst 00
-	0x35, 0x04,                 // ldi 04
-	0x24,                       // le?
-	SIG_END
-};
-
-static const uint16 kq7ExtraAmbrosiaPatch[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x22,                       // lt?
-	PATCH_END
-};
-
-// In KQ7 1.4, after giving the statue to the snake oil salesman, the curtain is
-//  drawn on top of ego when walking in front of the wagon. The script doesn't
-//  dispose of the salesman and this leaves his final cel stuck on the screen.
-//  We add the missing call to snakeSalesman:dispose.
-//
-// Applies to: English PC 1.4
-// Responsible method: giveStatue:changeState
-// Fixes bug: #10221
-static const uint16 kq7SnakeOilSalesmanSignature[] = {
-	0x38, SIG_SELECTOR16(setHeading),   // pushi setHeading
-	SIG_ADDTOOFFSET(+0x281),
-	0x72, SIG_UINT16(0x15b4),           // lofsa snakeSalesman
-	SIG_ADDTOOFFSET(+0x3f),
-	0x3c,                               // dup
-	0x35, SIG_MAGICDWORD, 0x0c,         // ldi 0c
-	0x1a,                               // eq?
-	0x30, SIG_UINT16(0x0010),           // bnt 0010 [ state 13 ]
-	0x38, SIG_SELECTOR16(setHeading),   // pushi setHeading
-	0x7a,                               // pushi2
-	0x38, SIG_UINT16(0x00b4),           // pushi 00b4
-	0x7c,                               // pushSelf
-	0x81, 0x00,                         // lag 00
-	0x4a, SIG_UINT16(0x0008),           // send 08  [ KQEgo setHeading: 180 self ]
-	0x32, SIG_UINT16(0x0017),           // jmp 0017 [ end of method ]
-	SIG_END
-};
-
-static const uint16 kq7SnakeOilSalesmanPatch[] = {
-	PATCH_ADDTOOFFSET(+0x02cd),
-	0x38, PATCH_SELECTOR16(dispose),    // pushi dispose
-	0x76,                               // push0
-	0x72, PATCH_UINT16(0x15b4),         // lofsa snakeSalesman
-	0x4a, PATCH_UINT16(0x0004),         // send 04  [ snakeSalesman: dispose ]
-	0x32, PATCH_UINT16(0xfd26),         // jmp fd26 [ KQEgo setHeading and end of method ]
-	PATCH_END
-};
-
-// In KQ7 1.65c, when Chicken Petite appears in room 5300 after leaving the
-//  china shop, the script sends a message to a non-object. Several script and
-//  export numbers changed from the previous version, but chickenCartoon2 wasn't
-//  updated to call ScriptID with the new values. Instead, the stale values
-//  return a procedure address instead of the chickenTimerScript object.
-//
-// We fix this by using chickenTimerScript's correct script and export numbers.
-//
-// Applies to: English PC 1.65c, French PC 1.65c, probably German 1.65c
-// Responsible method: chickenCartoon2:changeState(9)
-// Fixes bug: #11575
-static const uint16 kq7ChickenCartoonSignature[] = {
-	0x38, SIG_MAGICDWORD, SIG_UINT16(0x14b4), // pushi 14b4
-	0x39, 0x03,                               // pushi 03
-	0x43, 0x02, SIG_UINT16(0x0004),           // callk ScriptID [ ScriptID 5300 3 ]
-	SIG_ADDTOOFFSET(+0x037b),
-	// this part of the signature matches 1.65c while excluding earlier versions
-	0x38, SIG_UINT16(0x14b5),                 // pushi 14b5
-	0x39, 0x03,                               // pushi 03
-	0x43, 0x02, SIG_UINT16(0x0004),           // callk ScriptID [ ScriptID 5301 3 ]
-	SIG_END
-};
-
-static const uint16 kq7ChickenCartoonPatch[] = {
-	0x38, PATCH_UINT16(0x14b6),               // pushi 14b6 [ script 5302 ]
-	0x39, 0x16,                               // pushi 16   [ export 22   ]
-	PATCH_END
-};
-
-// KQ7 allows a maximum of 10 save games but English version 2.00 introduced a
-//  script bug which removed the check that enforces this. We add the missing
-//  check so that the game doesn't break. Sierra later released English version
-//  2.00b whose only change was to fix this.
-//
-// Applies to: English PC 2.00
-// Responsible method: startBut:doVerb
-static const uint16 kq7TooManySavesSignature[] = {
-	0x47, 0x15, 0x00, SIG_UINT16(0x0000),   // calle proc21_0 [ get save count ]
-	0xa5, 0x00,                             // sat 00 [ unused ]
-	SIG_MAGICDWORD,
-	0x35, 0x00,                             // ldi 00
-	0x31, 0x16,                             // bnt 16 [ allow save ]
-	SIG_END
-};
-
-static const uint16 kq7TooManySavesPatch[] = {
-	PATCH_ADDTOOFFSET(+5),
-	0x36,                                   // push
-	0x35, 0x0a,                             // ldi 0a
-	0x20,                                   // ge? [ save count >= 10 ]
-	PATCH_END
-};
-
-// During the chapter one opening cartoon, clicking the skip-scene button too
-//  quickly breaks the game. openingCartoon sets a 20 tick timer in state 0 and
-//  initializes ego in state 1. If skip-scene is clicked during this window then
-//  KQEgo:init is never called, Valanice never appears, and clicking eventually
-//  crashes the game. This also happens in Sierra's interpreter.
-//
-// We fix this by adding code to the skip-scene handler in openingCartoon to
-//  call KQEgo:init if the script was in state 0 when skip-scene was clicked.
-//  We make room by overwriting an unnecessary state check.
-//
-// Applies to: All versions
-// Responsible method: openingCartoon:changeState
-static const uint16 kq7OpeningCartoonSignature[] = {
-	SIG_MAGICDWORD,
-	0x18,                                   // not
-	0x30, SIG_UINT16(0x0544),               // bnt 05444 [ skip if skip-scene clicked ]
-	SIG_ADDTOOFFSET(+0x0541),
-	0x32, SIG_ADDTOOFFSET(+2),              // jmp [ ret ]
-	0x87, 0x01,                             // lap 01
-	0x65, 0x16,                             // aTop state
-	0x36,                                   // push
-	0x3c,                                   // dup
-	0x35, 0x00,                             // ldi 00
-	0x1a,                                   // eq? [ is state 0? always true ]
-	0x30, SIG_ADDTOOFFSET(+2),              // bnt [ toss, ret ]
-	SIG_END
-};
-
-static const uint16 kq7OpeningCartoonPatch[] = {
-	PATCH_ADDTOOFFSET(+1),
-	0x30, PATCH_UINT16(0x0542),             // bnt 0542 [ skip if skip-scene clicked ]
-	PATCH_ADDTOOFFSET(+0x0541),
-	0x48,                                   // ret
-	0x63, 0x22,                             // pToa ticks [ non-zero if we were in state 0 ]
-	0x31, 0x09,                             // bnt 09     [ skip ego init if state > 0 ]
-	0x38, PATCH_SELECTOR16(init),           // pushi init
-	0x76,                                   // push0
-	0x81, 0x00,                             // lag 00
-	0x4a, PATCH_UINT16(0x0004),             // send 0004 [ KQEgo init: ]
-	0x36,                                   // push [ to satisfy toss ]
-	PATCH_END
-};
-
-// In chapter one, moving the top gem in the statue all the way to the right and
-//  exiting the puzzle shows the gems in the wrong position. The script that
-//  determines which cel to display duplicates a chunk of code for every gem
-//  combination but the final copy is missing an entire switch block.
-//
-// We fix this by patching a branch so that one of the many copies of the
-//  missing code is executed for the buggy gem combination.
-//
-// Applies to: All versions
-// Responsible method: collar:init
-static const uint16 kq7StatueGemCelSignature[] = {
-	0x30, SIG_UINT16(0x003b),               // bnt 003b [ incomplete code ]
-	SIG_ADDTOOFFSET(+0x07),
-	0x88, SIG_UINT16(0x0148),               // lsg 0148
-	SIG_ADDTOOFFSET(+0x2e),
-	0xa3, SIG_MAGICDWORD, 0x06,             // sal 06
-	0x3a,                                   // toss
-	0x3a,                                   // toss
-	0x3a,                                   // toss
-	SIG_END
-};
-
-static const uint16 kq7StatueGemCelPatch[] = {
-	0x30, PATCH_UINT16(0x0007),             // bnt 0007 [ copy of missing code ]
-	PATCH_END
-};
-
-// KQ7 fails to reset most of its global variables when starting a new game. The
-//  script implicitly relies on initial values from the heap. Starting a new
-//  game after returning to the main menu causes the previous game's state to
-//  persist and create various glitches. A simple example is on the first screen
-//  of chapter 1: if a new game is started after playing a later chapter, the
-//  top gem in the statue will be in its solved position. nameGameRoom:init does
-//  reset some globals, but only those whose initial heap values weren't zero.
-//
-// We fix this by writing our own loop to reset all global variables correctly
-//  when starting a new game. We do this by combining the existing loops that
-//  reset flag globals to zero and inventory indexes to -1. All other game
-//  globals are now reset to zero, except for the two objects which must remain.
-//  We also restore a global which must contain the result of kMemoryInfo 0, and
-//  initialize global372 to -1 which Sierra forgot to do. After our reset loop,
-//  nameGameRoom:init proceeds with its initialization of non-zero globals.
-//
-// Applies to: All versions
-// Responsible method: nameGameRoom:init
-static const uint16 kq7InitGameGlobalsSignature[] = {
-	SIG_MAGICDWORD,
-	0x34, SIG_UINT16(0x04d2),               // ldi 04d2
-	0xa1, 0x65,                             // sag 65 [ redundant write of unused global ]
-	SIG_ADDTOOFFSET(+0x30),
-	0x35, 0xff,                             // ldi ff
-	0xa0, SIG_UINT16(0x0149),               // sag 0149 [ global329 = -1 ]
-	0x35, 0xff,                             // ldi ff
-	0xa0, SIG_UINT16(0x014a),               // sag 014a [ global330 = -1 ]
-	// loop: set all inventory indexes to -1
-	0x35, 0x00,                             // ldi 00
-	0xa5, 0x00,                             // sat 00 [ temp0 = 0 ]
-	0x8d, 0x00,                             // lst 00
-	0x35, 0x10,                             // ldi 10
-	0x22,                                   // lt?    [ temp0 < 16 ]
-	0x31, 0x12,                             // bnt 12
-	0x39, 0xff,                             // pushi ff
-	0x85, 0x00,                             // lat 00
-	0xb0, SIG_UINT16(0x0151),               // sagi 0151 [ global337[temp0] = -1 ]
-	0x39, 0xff,                             // pushi ff
-	0x85, 0x00,                             // lat 00
-	0xb0, SIG_UINT16(0x0161),               // sagi 0161 [ global353[temp0] = -1 ]
-	0xc5, 0x00,                             // +at 00 [ ++temp0 ]
-	0x33, 0xe7,                             // jmp e7 [ iterate ]
-	// loop: set all flag globals to 0
-	0x35, 0x24,                             // ldi 24
-	0xa5, 0x02,                             // sat 02 [ temp2 = 36 ]
-	0x35, 0x00,                             // ldi 00
-	0xa5, 0x00,                             // sat 00 [ temp0 = 0 ]
-	0x8d, 0x00,                             // lst 00
-	0x85, 0x02,                             // lst 02
-	0x22,                                   // lt?    [ temp0 < temp2 (36) ]
-	0x31, 0x09,                             // bnt 09
-	0x76,                                   // push0
-	0x85, 0x00,                             // lat 00
-	0xb1, 0x7f,                             // sagi 7f [ global127[temp0] = 0 ]
-	0xc5, 0x00,                             // +at 00 [ ++temp0 ]
-	0x33, 0xf0,                             // jmp f0 [ iterate ]
-	SIG_END
-};
-
-static const uint16 kq7InitGameGlobalsPatch[] = {
-	0x34, PATCH_UINT16(0x007f),             // ldi 007f
-	0x33, 0x43,                             // jmp 43 [ init loop ]
-	PATCH_ADDTOOFFSET(+0x35),
-	0xa0, PATCH_UINT16(0x014a),             // sag 014a [ global330 = -1 ]
-	0xa0, PATCH_UINT16(0x0174),             // sag 0174 [ global372 = -1 (reset chicken little) ]
-	0x34, PATCH_UINT16(0x7fe8),             // ldi 7fe8
-	0xa0, PATCH_UINT16(0x0142),             // sag 0142 [ global332 = kMemoryInfo 0 result ]
-	0x33, 0x2c,                             // jmp 2c   [ continue room init ]
-	// init loop
-	0xa5, 0x00,                             // sat 00 [ temp0 = 127 ]
-	// loop condition
-	0x38, PATCH_UINT16(0x017b),             // pushi 017b
-	0x1a,                                   // eq?    [ global == 379 ]
-	0x2f, 0xb5,                             // bt b5  [ exit loop and init specific globals ]
-	// skip kqResponseCode, it can't be reset
-	0x60,                                   // pprev
-	0x34, PATCH_UINT16(0x0136),             // ldi 0136
-	0x1a,                                   // eq?    [ global == 310 ]
-	0x2f, 0x19,                             // bt 19  [ skip reset ]
-	// skip theUseObjCursor, it can't be reset
-	0x8d, 0x00,                             // lst 00
-	0x34, PATCH_UINT16(0x014c),             // ldi 014c
-	0x1a,                                   // eq?    [ global == 332 ]
-	0x2f, 0x11,                             // bt 11  [ skip reset ]
-	// reset globals 337 through 368 to -1, all others to 0
-	0x39, 0x20,                             // pushi 20
-	0x38, PATCH_UINT16(0x0170),             // pushi 0170
-	0x85, 0x00,                             // lat 00
-	0x04,                                   // sub    [ 368 - temp0 ]
-	0x28,                                   // uge?   [ 32 u>= (368 - temp0) ]
-	0x31, 0x01,                             // bnt 01 [ skip if global not in -1 range ]
-	0x16,                                   // neg    [ acc = -1 ]
-	0x36,                                   // push   [ 0 or -1 ]
-	0x85, 0x00,                             // lat 00
-	0xb1, 0x00,                             // sagi 00 [ global[temp0] = 0 or -1 ]
-	0xc5, 0x00,                             // +at 00  [ ++temp0 ]
-	0x33, 0xd6,                             // jmp d6  [ iterate ]
-	PATCH_END
-};
-
-// KQ7 doesn't reset the chapter 6 volcano timers when exiting to the main menu
-//  without saving. The volcano can then erupt on the main menu or in a new game
-//  in the wrong chapter. The quit menu has several copies of the code that
-//  resets the game for the main menu but only one of them stops the timers.
-//
-// We fix this by patching the incomplete code to jump to the complete version.
-//
-// Applies to: PC 2.00 and 2.00b
-// Responsible method: chapInset:dispose
-static const uint16 kq7StopTimersSignature[] = {
-	0x38, SIG_SELECTOR16(eachElementDo),    // pushi eachElementDo [ start of complete reset ]
-	SIG_ADDTOOFFSET(+0xbf),
-	0x38, SIG_SELECTOR16(eachElementDo),    // pushi eachElementDo [ start of incomplete reset ]
-	SIG_ADDTOOFFSET(+0x49),
-	0x33, SIG_MAGICDWORD, 0x2f,             // jmp 2f
-	0x38, SIG_SELECTOR16(eachElementDo),    // pushi eachElementDo [ start of incomplete reset ]
-	SIG_END
-};
-
-static const uint16 kq7StopTimersPatch[] = {
-	PATCH_ADDTOOFFSET(+0xc2),
-	0x32, PATCH_UINT16(0xff3b),             // jmp ff3b [ jump to complete reset ]
-	PATCH_ADDTOOFFSET(+0x4b),
-	0x32, PATCH_UINT16(0xfeed),             // jmp feed [ jump to complete reset ]
-	PATCH_END
-};
-
-// The wooden nickel can't be given to the Faux Shop owner in early versions of
-//  KQ7 because the script doesn't register the hotspot. This was fixed in later
-//  versions. We add the missing shopOwner:addRespondVerb call.
-//
-// Applies to: PC 1.4 and PC 1.51 English/German/French
-// Responsible method: rm5000:init
-static const uint16 kq7FauxShopWoodenNickelSignature[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(ignoreActors),     // pushi ignoreActors
-	0x78,                                   // push1
-	0x78,                                   // push1
-	SIG_ADDTOOFFSET(+13),
-	0x34, SIG_UINT16(0x1000),               // ldi 1000 [ signal ]
-	SIG_ADDTOOFFSET(+2),
-	0x38, SIG_SELECTOR16(setCel),           // pushi setCel
-	0x78,                                   // push1
-	0x39, 0x09,                             // pushi 09
-	0x38, SIG_SELECTOR16(init),             // pushi init
-	0x76,                                   // push0
-	SIG_END
-};
-
-static const uint16 kq7FauxShopWoodenNickelPatch[] = {
-	0x39, PATCH_SELECTOR8(cel),             // pushi cel
-	0x78,                                   // push1
-	0x39, 0x09,                             // pushi 09
-	PATCH_ADDTOOFFSET(+13),
-	0x34, PATCH_UINT16(0x5000),             // ldi 5000 [ signal | ignoreActors flag ]
-	PATCH_ADDTOOFFSET(+2),
-	0x38, PATCH_SELECTOR16(init),           // pushi init
-	0x76,                                   // push0
-	0x38, PATCH_SELECTOR16(addRespondVerb), // pushi addRespondVerb
-	0x78,                                   // push1
-	0x39, 0x3b,                             // pushi 3b [ wooden nickel ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                                 patch
-static const SciScriptPatcherEntry kq7Signatures[] = {
-	{  true,     0, "disable video benchmarking",                  1, kq7BenchmarkSignature,                    kq7BenchmarkPatch },
-	{  true,     0, "remove hardcoded spin loop",                  1, kq7PragmaFailSpinSignature,               kq7PragmaFailSpinPatch },
-	{  true,    20, "fix initializing game globals",               1, kq7InitGameGlobalsSignature,              kq7InitGameGlobalsPatch },
-	{  true,    25, "fix stopping timers",                         1, kq7StopTimersSignature,                   kq7StopTimersPatch },
-	{  true,    30, "fix allowing too many saves",                 1, kq7TooManySavesSignature,                 kq7TooManySavesPatch },
-	{  true,  1250, "fix opening cartoon",                         1, kq7OpeningCartoonSignature,               kq7OpeningCartoonPatch },
-	{  true,  1250, "fix statue gem cel",                          1, kq7StatueGemCelSignature,                 kq7StatueGemCelPatch },
-	{  true,  5000, "fix wooden nickel in faux shop",              1, kq7FauxShopWoodenNickelSignature,         kq7FauxShopWoodenNickelPatch },
-	{  true,  5300, "fix snake oil salesman disposal",             1, kq7SnakeOilSalesmanSignature,             kq7SnakeOilSalesmanPatch },
-	{  true,  5301, "fix chicken cartoon",                         1, kq7ChickenCartoonSignature,               kq7ChickenCartoonPatch },
-	{  true,  6100, "fix extra ambrosia",                          1, kq7ExtraAmbrosiaSignature,                kq7ExtraAmbrosiaPatch },
-	{  true,    31, "enable subtitles (1/3)",                      1, kq7SubtitleFixSignature1,                 kq7SubtitleFixPatch1 },
-	{  true, 64928, "enable subtitles (2/3)",                      1, kq7SubtitleFixSignature2,                 kq7SubtitleFixPatch2 },
-	{  true, 64928, "enable subtitles (3/3)",                      1, kq7SubtitleFixSignature3,                 kq7SubtitleFixPatch3 },
-	{  true, 64928, "Narrator lockup fix",                         1, sciNarratorLockupSignature,               sciNarratorLockupPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#pragma mark -
-#pragma mark Lighthouse
-
-// When going to room 5 (sierra logo & menu room) from room 380 (the credits
-// room), the game tries to clear flags from 0 (global[116] bit 0) to 1423
-// (global[204] bit 15), but global[201] is not a flag global (it holds a
-// reference to theInvisCursor). This patch stops clearing after flag 1359
-// (global[200] bit 15). Hopefully that is good enough to not break the game.
-// Applies to at least: English 1.0c & 2.0a
-static const uint16 lighthouseFlagResetSignature[] = {
-	SIG_MAGICDWORD,
-	0x34, SIG_UINT16(0x58f), // ldi 1423
-	0x24,                    // le?
-	SIG_END
-};
-
-static const uint16 lighthouseFlagResetPatch[] = {
-	0x34, PATCH_UINT16(0x54f), // ldi 1359
-	PATCH_END
-};
-
-// When doing a system check on the portal computer in the lighthouse, the game
-// counts up to 1024MB, one megabyte at a time. In SSCI, this count speed would
-// be video speed dependent, but with our frame rate throttler, it takes 17
-// seconds. So, replace this slowness with a much faster POST that is more
-// accurate to the original game.
-// Applies to at least: US English 1.0c
-static const uint16 lighthouseMemoryCountSignature[] = {
-	SIG_MAGICDWORD,
-	0x8d, 0x02,             // lst temp[2]
-	0x35, 0x0a,             // ldi 10
-	0x24,                   // le?
-	0x31, 0x3b,             // bnt [to second digit overflow]
-	SIG_ADDTOOFFSET(+4),    // ldi, sat
-	0x8d, 0x03,             // lst temp[3]
-	0x35, 0x0a,             // ldi 10
-	SIG_END
-};
-
-static const uint16 lighthouseMemoryCountPatch[] = {
-	PATCH_ADDTOOFFSET(+2), // lst temp[2]
-	0x35, 0x02,            // ldi 2
-	PATCH_ADDTOOFFSET(+9), // le?, bnt, ldi, sat, lst
-	0x35, 0x02,            // ldi 2
-	PATCH_END
-};
-
-// In Lighthouse version 2.0, entering the submarine while the compass is out
-//  causes a message to be sent to a non-object. The PanelProps ppCompass and
-//  ppCompassFace are missing initialization code. Room 212 disposes of compass
-//  objects, but since they weren't correctly initialized, Feature:dispose
-//  attempts to remove them from a nonexistent Set in global 105.
-//
-// We fix this by patching the init methods of both compass objects to jump to
-//  ppOptions:init where there is a copy of the missing initialization code.
-//  This is effectively what Sierra did in their LITE2FIX patch.
-//
-// Applies to: Version 2.0
-// Responsible methods: ppCompass:init, ppCompassFace:init
-static const uint16 lighthouseCompassSignature[] = {
-	// ppCompass:init
-	0x4a, SIG_MAGICDWORD,               // send 10
-	      SIG_UINT16(0x0010),
-	0x48,                               // ret
-	0x00, 0x00,                         // unused padding
-	SIG_ADDTOOFFSET(+0x00fa),
-	// ppCompassFace:init
-	0x39, SIG_SELECTOR8(init),          // pushi init
-	0x76,                               // push0
-	0x59, 0x01,                         // &rest 01
-	0x57, 0x81, SIG_UINT16(0x0004),     // super 04 [ PanelProp init: 1 &rest ]
-	0x48,                               // ret
-	SIG_ADDTOOFFSET(+0x0b84),
-	// ppOptions:init
-	0x39, SIG_SELECTOR8(init),          // pushi init
-	0x76,                               // push0
-	0x59, 0x01,                         // &rest 01
-	0x57, 0x81, SIG_UINT16(0x0004),     // super 04 [ PanelProp init: 1 &rest ]
-	0x62, SIG_UINT16(0x01b6),           // pToa approachX
-	0x31, 0x16,                         // bnt 16
-	SIG_ADDTOOFFSET(+0x11),
-	0x35, 0x00,                         // ldi 00
-	0x64, SIG_UINT16(0x01b6),           // aTop approachX
-	0x48,                               // ret
-	SIG_END
-};
-
-static const uint16 lighthouseCompassPatch[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x32, PATCH_UINT16(0x0c91),         // jmp 0c91 [ ppCompass:init => ppOptions:init ]
-	PATCH_ADDTOOFFSET(+0x00fa),
-	0x32, PATCH_UINT16(0x0b8b),         // jmp 0b8b [ ppCompassFace:init => ppOptions:init ]
-	PATCH_END
-};
-
-// The script for opening the underwater safe has a timing bug that relies on
-//  the original interpreter being too slow to play the robot video at the
-//  specified frame rate. In ScummVM this causes the submarine arm animation to
-//  be out of sync with the safe door, repeat itself, and end on the wrong cel.
-//
-// openSafe:changeState(0) starts two animations: robot 596 (the safe door) and
-//  view 595 (the submarine arm). State 1 cues when the robot completes and
-//  resets the view's cel on the assumption that the view's cycler has already
-//  completed. But the robot is 50 frames at 2 ticks per frame (100 ticks) while
-//  the view is 39 ticks at 6 ticks per frame (234 ticks) so the robot should
-//  complete first. This worked in the original interpreter because it wasn't
-//  fast enough to run this scene at 2 ticks per frame and because Lighthouse's
-//  RobotPlayer script has a bug in its time calculations that amplifies delays
-//  when the specified frame rate can't be achieved. This combination caused the
-//  the robot to animate slower than specified and complete after the view.
-//
-// We fix this by lowering the robot's specified frame rate to the effective
-//  frame rate from the original.
-//
-// Applies to: All versions
-// Responsible Method: openSafe:changeState(0)
-// Fixes bug: #10226
-static const uint16 lighthouseOpenSafeSpeedSignature[] = {
-	0x39, SIG_SELECTOR8(init),             // pushi init
-	SIG_MAGICDWORD,
-	0x3c,                                  // dup
-	0x38, SIG_UINT16(0x0254),              // pushi 0254 [ view 585 ]
-	SIG_ADDTOOFFSET(+10),
-	0x38, SIG_SELECTOR16(start),           // pushi start
-	0x7a,                                  // push2
-	0x78,                                  // push1
-	0x39, 0x1e,                            // pushi 1e [ 30 frames per second (100 ticks) ]
-	SIG_END
-};
-
-static const uint16 lighthouseOpenSafeSpeedPatch[] = {
-	PATCH_ADDTOOFFSET(+21),
-	0x39, 0x0a,                            // pushi 0a [ 10 frames per second (300 ticks) ]
-	PATCH_END
-};
-
-// At the top of the roost tower there can be up to three mechanical birds, but
-//  they can appear and disappear inconsistently depending on which direction
-//  the player was facing before turning. rm510:changeScene has two bugs that
-//  set the wrong scene/pic links on the exit cursors once Birdman has appeared:
-//
-// 1. When facing the ladder (scene 504) and there are 3 birds, exitRight:curPic
-//    is set to 7506 (no birds) instead of 7504 (left and broken center bird).
-// 2. When facing right of the perch and there are no birds (scene 502), there
-//    is no code to handle the bird count being 0, and so exitLeft:curPic is set
-//    to 4511 (left and broken center bird) instead of 501 (no birds).
-//
-// We fix this by setting the correct scene/pic view when facing the ladder and
-//  adding the missing bird count test when facing right of the perch.
-//
-// Applies to: All versions
-// Responsible method: rm510:changeScene
-// Fixes bug: #10265
-static const uint16 lighthouseRoostBirdPicSignature1[] = {
-	0x3c,                                  // dup
-	0x35, 0x03,                            // ldi 03
-	0x1a,                                  // eq? [ bird count == 3 ]
-	0x31, 0x14,                            // bnt 14
-	0x38, SIG_SELECTOR16(newPic),          // pushi newPic
-	SIG_MAGICDWORD,
-	0x7a,                                  // push2
-	0x38, SIG_UINT16(0x1d52),              // pushi 1d52 [ no birds ]
-	0x39, 0x04,                            // pushi 04
-	0x7a,                                  // push2
-	0x78,                                  // push1
-	0x39, 0x04,                            // pushi 04
-	0x43, 0x02, SIG_UINT16(0x0004),        // callk ScriptID 04 [ exitRight ]
-	0x4a, SIG_UINT16(0x0008),              // send 08 [ exitRight newPic: 7506 4 ]
-	SIG_END
-};
-
-static const uint16 lighthouseRoostBirdPicPatch1[] = {
-	PATCH_ADDTOOFFSET(+10),
-	0x38, PATCH_UINT16(0x1d50),            // pushi 1d50 [ left bird + broken bird ]
-	PATCH_END
-};
-
-static const uint16 lighthouseRoostBirdPicSignature2[] = {
-	SIG_MAGICDWORD,
-	0x3c,                                  // dup
-	0x34, SIG_UINT16(0x01f6),              // ldi 01f6
-	0x1a,                                  // eq? [ is scene 502? ]
-	0x31, 0x68,                            // bnt 68
-	0x78,                                  // push1
-	0x38, SIG_UINT16(0x0182),              // pushi 0182 [ flag 386 ]
-	0x45, 0x05, SIG_UINT16(0x0002),        // callb proc5_2 [ has birdman attacked? ]
-	0x31, 0x33,                            // bnt 33 [ no birds to the left ]
-	0x89, 0xd1,                            // lsg d1 [ bird count ]
-	0x35, 0x01,                            // ldi 01
-	0x1a,                                  // eq?
-	SIG_END
-};
-
-static const uint16 lighthouseRoostBirdPicPatch2[] = {
-	PATCH_ADDTOOFFSET(+7),
-	0x89, 0x8c,                            // lsg 8c   [ flag global ]
-	0x34, PATCH_UINT16(0x2000),            // ldi 2000 [ flag 386 ]
-	0x12,                                  // and      [ is flag 386 set? ]
-	0x31, 0x35,                            // bnt 35   [ no birds to left ]
-	0x81, 0xd1,                            // lag d1   [ bird count ]
-	0x31, 0x31,                            // bnt 31   [ no birds to left if bird count == 0 ]
-	0x39, 0x01,                            // pushi 01
-	PATCH_END
-};
-
-//          script, description,                                      signature                         patch
-static const SciScriptPatcherEntry lighthouseSignatures[] = {
-	{  true,     5, "fix bad globals clear after credits",         1, lighthouseFlagResetSignature,     lighthouseFlagResetPatch },
-	{  true,     9, "fix compass in submarine",                    1, lighthouseCompassSignature,       lighthouseCompassPatch },
-	{  true,   360, "fix slow computer memory counter",            1, lighthouseMemoryCountSignature,   lighthouseMemoryCountPatch },
-	{  true,   510, "fix roost bird pic",                          1, lighthouseRoostBirdPicSignature1, lighthouseRoostBirdPicPatch1 },
-	{  true,   510, "fix roost bird pic",                          1, lighthouseRoostBirdPicSignature2, lighthouseRoostBirdPicPatch2 },
-	{  true,   700, "fix open safe speed",                         1, lighthouseOpenSafeSpeedSignature, lighthouseOpenSafeSpeedPatch },
-	{  true, 64928, "Narrator lockup fix",                         1, sciNarratorLockupSignature,       sciNarratorLockupPatch },
-	{  true, 64990, "increase number of save games (1/2)",         1, sci2NumSavesSignature1,           sci2NumSavesPatch1 },
-	{  true, 64990, "increase number of save games (2/2)",         1, sci2NumSavesSignature2,           sci2NumSavesPatch2 },
-	{  true, 64990, "disable change directory button",             1, sci2ChangeDirSignature,           sci2ChangeDirPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#endif
-
-// ===========================================================================
-// When Robin hands out the scroll to Marion and then types his name using the
-// hand code, the German version's script contains a typo (likely a copy/paste
-// error), and the local procedure that shows each letter is called twice. The
-// The procedure expects a letter arg and returns no value, so the first call
-// takes its letter and feeds an undefined value to the second call. Thus the
-// kStrCat() within the procedure reads a random pointer and crashes.
-//
-// We patch all of the 5 doubled local calls (one for each letter typed from
-// "R", "O", "B", "I", "N") to be the same as the English version.
-// Applies to at least: German floppy
-// Responsible method: giveScroll::changeState(19,21,23,25,27) in script 210
-// Fixes bug: #5264
-static const uint16 longbowSignatureShowHandCode[] = {
-	0x78,                            // push1 (1 call arg)
-									 //
-	0x78,                            // push1 (1 call arg)
-	0x72, SIG_ADDTOOFFSET(+2),       // lofsa (letter that was typed)
-	0x36,                            // push
-	0x40, SIG_ADDTOOFFSET(+2), 0x02, // call [localproc], 02
-									 //
-	0x36,                            // push (the result is an arg for the next call)
-	0x40, SIG_ADDTOOFFSET(+2), SIG_MAGICDWORD, 0x02, // call [localproc], 02
-									 //
-	0x38, SIG_SELECTOR16(setMotion), // pushi setMotion (0x11c in Longbow German)
-	0x39, SIG_SELECTOR8(x),          // pushi x (0x04 in Longbow German)
-	0x51, 0x1e,                      // class MoveTo
-	SIG_END
-};
-
-static 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 untouched
-	// The following will remove the first push & call
-	0x32, PATCH_UINT16(0x0002),      // jmp 02 [to the second push & call]
-	0x35, 0x00,                      // ldi 0 (waste 2 bytes)
-	PATCH_END
-};
-
-// When walking through the forest, arithmetic errors may occur at "random".
-// The scripts try to add a value and a pointer to the object "berryBush".
-//
-// This is caused by a local variable overflow.
-//
-// The scripts create berry bush objects dynamically. The array storage for
-// those bushes may hold a total of 8 bushes. But sometimes 10 bushes
-// are created. This overwrites 2 additional locals in script 225 and
-// those locals are used normally for value lookups.
-//
-// Changing the total of bushes could cause all sorts of other issues,
-// that's why I rather patched the code, that uses the locals for a lookup.
-// Which means it doesn't matter anymore when those locals are overwritten.
-//
-// Applies to at least: English PC floppy, German PC floppy, English Amiga floppy
-// Responsible method: export 2 of script 225
-// Fixes bug: #6751
-static const uint16 longbowSignatureBerryBushFix[] = {
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x03,                      // ldi 03h
-	0x1a,                            // eq?
-	0x2e, SIG_UINT16(0x002d),        // bt [process code]
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x04,                      // ldi 04h
-	0x1a,                            // eq?
-	0x2e, SIG_UINT16(0x0025),        // bt [process code]
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x05,                      // ldi 05h
-	0x1a,                            // eq?
-	0x2e, SIG_UINT16(0x001d),        // bt [process code]
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x06,                      // ldi 06h
-	0x1a,                            // eq?
-	0x2e, SIG_UINT16(0x0015),        // bt [process code]
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x18,                      // ldi 18h
-	0x1a,                            // eq?
-	0x2e, SIG_UINT16(0x000d),        // bt [process code]
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x19,                      // ldi 19h
-	0x1a,                            // eq?
-	0x2e, SIG_UINT16(0x0005),        // bt [process code]
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x1a,                      // ldi 1Ah
-	0x1a,                            // eq?
-	// jump location for the "bt" instructions
-	0x30, SIG_UINT16(0x0011),        // bnt [skip over follow up code, to offset 0c35]
-	// 55 bytes until here
-	0x85, 0x00,                      // lat temp[0]
-	SIG_MAGICDWORD,
-	0x9a, SIG_UINT16(0x0110),        // lsli local[110h] -> 110h points normally to 110h / 2Bh
-	// 5 bytes
-	0x7a,                            // push2
-	SIG_END
-};
-
-static const uint16 longbowPatchBerryBushFix[] = {
-	PATCH_ADDTOOFFSET(+4),           // keep: lsg global[70h], ldi 03h
-	0x22,                            // lt? (global < 03h)
-	0x2f, 0x42,                      // bt [skip over all the code directly]
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x06,                      // ldi 06h
-	0x24,                            // le? (global <= 06h)
-	0x2f, 0x0e,                      // bt [to kRandom code]
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x18,                      // ldi 18h
-	0x22,                            // lt? (global < 18h)
-	0x2f, 0x34,                      // bt [skip over all the code directly]
-	0x89, 0x70,                      // lsg global[70h]
-	0x35, 0x1a,                      // ldi 1Ah
-	0x24,                            // le? (global <= 1Ah)
-	0x31, 0x2d,                      // bnt [skip over all the code directly]
-	// 28 bytes, 27 bytes saved
-	// kRandom code
-	0x85, 0x00,                      // lat temp[0]
-	0x2f, 0x05,                      // bt [skip over case 0]
-	// temp[0] == 0
-	0x38, PATCH_UINT16(0x0110),      // pushi 0110h - that's what's normally at local[110h]
-	0x33, 0x18,                      // jmp [kRandom call]
-	// check temp[0] further
-	0x78,                            // push1
-	0x1a,                            // eq?
-	0x31, 0x05,                      // bnt [skip over case 1]
-	// temp[0] == 1
-	0x38, PATCH_UINT16(0x002b),      // pushi 002Bh - that's what's normally at local[111h]
-	0x33, 0x0f,                      // jmp [kRandom call]
-	// temp[0] >= 2
-	0x8d, 0x00,                      // lst temp[0]
-	0x35, 0x02,                      // ldi 02
-	0x04,                            // sub
-	0x9a, PATCH_UINT16(0x0112),      // lsli local[112h] -> look up value in 2nd table
-	                                 // this may not be needed at all and was just added for safety reasons
-	// waste 9 spare bytes
-	0x35, 0x00,                      // ldi 00
-	0x35, 0x00,                      // ldi 00
-	0x34, PATCH_UINT16(0x0000),      // ldi 0000
-	PATCH_END
-};
-
-// The camp (room 150) has a bug that can prevent the outlaws from ever rescuing
-//  the boys at sunset on day 5 or 6. The rescue occurs when entering camp as an
-//  abbey monk after leaving town exactly 3 times but this assumes that the
-//  counter can't exceed this. Wearing a different disguise can increment the
-//  counter beyond 3 at which point sunset can never occur.
-//
-// We fix this by patching the counter tests to greater than or equals. This
-//  makes them consistent with the other scripts that test this global variable.
-//
-// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
-// Responsible method: local procedure #3 in script 150
-// Fixes bug: #10839
-static const uint16 longbowSignatureCampSunsetFix[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x8e,                     // lsg global[8e] [ times left town ]
-	0x35, 0x03,                     // ldi 03
-	0x1a,                           // eq?
-	SIG_END
-};
-
-static const uint16 longbowPatchCampSunsetFix[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x20,                        	// ge?
-	PATCH_END
-};
-
-// The town map (room 260) has a bug that can send Robin to the wrong room.
-//  Loading the map from town on day 5 or 6 automatically sends Robin to camp
-//  (room 150) after leaving town more than twice. The intent is to start the
-//  sunset scene where the outlaws rescue the boys, but the map doesn't test the
-//  correct sunset conditions and can load an empty camp, even on the wrong day.
-//
-// We fix this by changing the map's logic to match the camp's by requiring the
-//  abbey monk disguise to be worn and the rescue flag to not be set.
-//
-// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
-// Responsible method: rm260:init
-// Fixes bug: #10839
-static const uint16 longbowSignatureTownMapSunsetFix[] = {
-	SIG_MAGICDWORD,
-	0x39, 0x05,                     // pushi 05
-	0x81, 0x82,                     // lag global[82] [ day ]
-	0x24,                           // le?
-	0x30, SIG_UINT16(0x0089),       // bnt 0089 [ no sunset if day < 5 ]
-	0x60,                           // pprev
-	0x35, 0x06,                     // ldi 06
-	0x24,                           // le?
-	0x30, SIG_UINT16(0x0082),       // bnt 0082 [ no sunset if day > 6 ]
-	0x89, 0x8e,                     // lsg global[8e]
-	0x35, 0x01,                     // ldi 01
-	SIG_END
-};
-
-static const uint16 longbowPatchTownMapSunsetFix[] = {
-	0x89, 0x7e,                     // lsg global[7e] [ current disguise ]
-	0x35, 0x05,                     // ldi 05 [ abbey monk ]
-	0x1c,                           // ne?
-	0x2f, 0x06,                     // bt 06 [ no sunset if disguise != abbey monk ]
-	0x78,                           // push1
-	0x39, 0x38,                     // pushi 38
-	0x45, 0x05, 0x02,               // callb [export 5 of script 0], 02 [ is rescue flag set? ]
-	0x2e, PATCH_UINT16(0x0081),     // bt 0081 [ no sunset if rescue flag is set ]
-	0x81, 0x8e,                     // lag global[8e]
-	0x78,                           // push1 [ save a byte ]
-	PATCH_END
-};
-
-// Ending day 5 or 6 by choosing to attack the castle fails to set the rescue
-//  flag which tells the next day what to do. This flag is set when rescuing
-//  the boys yourself and when the outlaws rescue them at sunset. Without this
-//  flag, the sunset rescue can repeat the next day and break the game.
-//
-// We fix this by setting the flag when returning the boys to their mother in
-//  room 250 after the attack.
-//
-// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
-// Responsible method: boysSaved:changeState(0)
-// Fixes bug: #10839
-static const uint16 longbowSignatureRescueFlagFix[] = {
-	0x3c,                           // dup
-	0x35, 0x00,                     // ldi 00
-	0x1a,                           // eq?
-	0x30, SIG_MAGICDWORD,           // bnt 0003 [ state 1 ]
-	      SIG_UINT16(0x0003),
-	0x32, SIG_UINT16(0x025b),       // jmp 025b [ end of method ]
-	SIG_END
-};
-
-static const uint16 longbowPatchRescueFlagFix[] = {
-	0x2f, 0x08,                     // bt 08 [ state 1 ]
-	0x78,                           // push1
-	0x39, 0x38,                     // pushi 38
-	0x45, 0x06, 0x02,               // callb [export 6 of script 0], 02 [ set rescue flag ]
-	0x3a,                           // toss
-	0x48,                           // ret
-	PATCH_END
-};
-
-// On day 7, Tuck can appear at camp to say that the widow wants to see you when
-//  she really doesn't. This scene is only supposed to occur if you haven't
-//  received the net but the script only tests if the net is currently in
-//  inventory, which it isn't if you've already used it or are in disguise.
-//
-// We fix this by testing the net's owner instead of inventory. If net:owner is
-//  non-zero then it's in inventory or in your cave or has been used.
-//
-// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
-// Responsible method: local procedure #3 in script 150
-// Fixes bug: #10847
-static const uint16 longbowSignatureTuckNetFix[] = {
-	SIG_MAGICDWORD,
-	0x30, SIG_UINT16(0x03a2),       // bnt 03a2 [ end of method ]
-	0x38, SIG_SELECTOR16(has),      // pushi has
-	0x78,                           // push1
-	0x39, 0x04,                     // pushi 04
-	0x81, 0x00,                     // lag global[0]
-	0x4a, 0x06,                     // send 6 [ ego: has 4 ]
-	0x18,                           // not
-	0x30, SIG_UINT16(0x0394),       // bnt 0394 [ end of method if net not in inventory ]
-	0x78,                           // push1
-	0x39, 0x47,                     // pushi 47
-	0x45, 0x05, 0x02,               // callb [export 5 of script 0], 02 [ is flag 47 set? ]
-	0x18,                           // not
-	0x30, SIG_UINT16(0x038a),       // bnt 038a [ end of method ]
-	SIG_ADDTOOFFSET(+60),
-	0x32, SIG_UINT16(0x034b),       // jmp 034b [ end of method ]
-	SIG_END
-};
-
-static const uint16 longbowPatchTuckNetFix[] = {
-	0x31, 0x55,                     // bnt 55 [ skip scene, save a byte ]
-	0x39, PATCH_SELECTOR8(at),      // pushi at
-	0x78,                           // push1
-	0x39, 0x04,                     // pushi 04
-	0x81, 0x09,                     // lag global[9]
-	0x4a, 0x06,                     // send 6 [ Inv: at 4 ]
-	0x38, PATCH_SELECTOR16(owner),  // pushi owner
-	0x76,                           // push0
-	0x4a, 0x04,                     // send 4 [ net: owner? ]
-	0x2f, 0x44,                     // bt 44 [ skip scene if net:owner != 0 ]
-	0x78,                           // push1
-	0x39, 0x47,                     // pushi 47
-	0x45, 0x05, 0x02,               // callb [export 5 of script 0], 02 [ is flag 47 set? ]
-	0x2f, 0x3c,                     // bt 3c [ skip scene, save 2 bytes ]
-	PATCH_END
-};
-
-// On day 9, room 350 outside the cobbler's hut is initialized incorrectly if
-//  disguised as a monk. The entrance to the hut is broken and several minor
-//  messages are incorrect. This is due to the room's script assuming that the
-//  only disguises that day are yeoman and merchant. A monk disguise causes some
-//  tests to pass and others to fail, leaving the room in an inconsistent state.
-//
-// We fix this by changing the yeoman disguise tests in the script to include
-//  the monk disguises. The disguise global is set to 4 for yeoman and 5 or 6
-//  for monk disguises so we patch the tests to be greater than or equals to.
-//
-// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
-// Responsible methods: rm350:init, lobbsHut:doVerb, lobbsDoor:doVerb,
-//                      lobbsCover:doVerb, tailorDoor:doVerb
-// Fixes bug: #10834
-static const uint16 longbowSignatureCobblerHut[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x7e,                     // lsg global[7e] [ current disguise ]
-	0x35, 0x04,                     // ldi 04 [ yeoman ]
-	0x1a,                           // eq?    [ is current disguise yeoman? ]
-	SIG_END
-};
-
-static const uint16 longbowPatchCobblerHut[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x20,                           // ge? [ is current disguise yeoman or monk? ]
-	PATCH_END
-};
-
-// The Amiga version of room 530 adds a broken fDrunk:onMe method which prevents
-//  messages when clicking on the drunk on the floor of the pub and causes a
-//  signature mismatch on every click in the room. fDrunk:onMe passes an Event
-//  object as an integer x coordinate and an uninitialized parameter as a y
-//  coordinate to kOnControl. This is a signature mismatch and would cause onMe
-//  to return false on every click and prevent hit testing from dispatching
-//  events to fDrunk. It's unclear why Sierra added this method to this one
-//  Feature in the room. Even if it worked, Feature:onMe already does this.
-//
-// We fix this by replacing fDrunk:onMe's contents with a call to super:onMe
-//  which calls kOnControl correctly and does proper hit testing, making its
-//  behavior consistent with the DOS version, which doesn't override onMe.
-//
-// Applies to: English Amiga Floppy
-// Responsible method: fDrunk:onMe
-// Fixes bug: #9688
-static const uint16 longbowSignatureAmigaPubFix[] = {
-	SIG_MAGICDWORD,
-	0x67, 0x20,                     // pTos onMeCheck
-	0x39, 0x03,                     // pushi 03
-	0x39, 0x04,                     // pushi 04
-	0x8f, 0x01,                     // lsp param[1]
-	0x8f, 0x02,                     // lsp param[2]
-	0x43, 0x4e, 0x06,               // callk OnControl, 6
-	SIG_END
-};
-
-static const uint16 longbowPatchAmigaPubFix[] = {
-	0x38, PATCH_UINT16(0x00c4),     // pushi 00c4 [ onMe, hard-coded for amiga ]
-	0x76,                           // push0
-	0x59, 0x01,                     // &rest 1
-	0x57, 0x2c, 0x04,               // super Feature, 4 [ super: onMe &rest ]
-	0x48,                           // ret
-	PATCH_END
-};
-
-// WORKAROUND: Script needed, because of differences in our pathfinding
-// algorithm
-// When the guards kick Robin out of archery room 320 the game locks up due to
-//  pathfinding algorithm differences. Ours sends ego in the wrong direction,
-//  colliding with a guard, and preventing the script from continuing.
-//
-// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
-// Responsible method: takeHimOut:changeState(1)
-// Fixes bug: #10896
-static const uint16 longbowSignatureArcherPathfinding[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x00c8),       // pushi 00c8 [ y = 200 ]
-	0x7c,                           // pushSelf
-	0x81, 0x00,                     // lag 00
-	0x4a, 0x0c,                     // send 0c [ ego setMotion: PolyPath (ego x?) 200 self ]
-	SIG_END
-};
-
-static const uint16 longbowPatchArcherPathfinding[] = {
-	0x38, PATCH_UINT16(0x00c4),     // pushi 00c4 [ y = 196 ]
-	PATCH_END
-};
-
-// Longbow 1.0 has two random but common game-breaking bugs: Green Man's riddle
-//  scene never ends and the Sheriff's men catch Robin too quickly when sweeping
-//  the forest. Both are due to reusing an uninitialized global variable.
-//
-// Global 137 is used by the abbey hedge maze to store ego's cel during room
-//  transitions. Exiting the maze leaves this as a random value between 0 and 5.
-//  The forest sweep also uses this global but as a counter it expects to start
-//  at 0. It increments as Robin changes rooms during a sweep until it reaches a
-//  a maximum and he is caught. This is usually 7 but in some rooms it's only 3.
-//  A high initial value can make this sequence impossible. rm180:doit also
-//  tests the sweep counter and doesn't allow scripts to respond to a hand code
-//  when greater than 2. This breaks the riddle scene after the first answer.
-//
-// We fix this by clearing global 137 at the start of days 1-7 and 11 so that
-//  stale hedge maze values from days 5/6 and 10 don't affect the day 7 riddles
-//  or the sweeps on days 9 and 12. Ideally we could just clear this at the
-//  start of each day but there's no day initialization script. Instead we add
-//  our day-specific code to Robin's cave (room 140), similar to Sierra's patch
-//  and later versions.
-//
-// Applies to: English PC Floppy 1.0
-// Responsible method: localproc_001a in script 140
-// Fixes bug #5036
-static const uint16 longbowSignatureGreenManForestSweepFix[] = {
-	0x89, SIG_MAGICDWORD, 0x82,     // lsg 82 [ day ]
-	0x35, 0x01,                     // ldi 01
-	0x1a,                           // eq?
-	0x30, SIG_UINT16(0x0019),       // bnt 0019 [ skip horn init ]
-	0x38, SIG_SELECTOR16(has),      // pushi has
-	0x78,                           // push1
-	0x78,                           // push1
-	0x81, 0x00,                     // lag 00
-	0x4a, 0x06,                     // send 06 [ ego has: 1 ]
-	0x18,                           // not
-	0x30, SIG_UINT16(0x000c),       // bnt 000c [ skip horn init ]
-	0x39, SIG_SELECTOR8(init),      // pushi init
-	0x76,                           // push0
-	0x38, SIG_ADDTOOFFSET(+2),      // pushi stopUpd
-	0x76,                           // push0
-	0x72, SIG_UINT16(0x19b2),       // lofsa horn
-	0x4a, 0x08,                     // send 08 [ horn init: stopUpd: ]
-	0x89, 0x7e,                     // lsg 7e
-	0x35, 0x00,                     // ldi 00
-	0x1a,                           // eq?
-	0x2e, SIG_UINT16(0005),         // bt 0005
-	SIG_ADDTOOFFSET(+19),
-	0x39, SIG_SELECTOR8(init),      // push init
-	0x76,                           // push0
-	0x38, SIG_ADDTOOFFSET(+2),      // pushi stopUpd
-	0x76,                           // push0
-	0x72, SIG_UINT16(0x1912),       // lofsa bow
-	SIG_END
-};
-
-static const uint16 longbowPatchGreenManForestSweepFix[] = {
-	0x39, 0x07,                     // pushi 07
-	0x81, 0x82,                     // lag 82 [ day ]
-	0x22,                           // lt?
-	0x31, 0x06,                     // bnt 06
-	0x60,                           // pprev  [ day ]
-	0x35, 0x0b,                     // ldi 0b
-	0x1c,                           // ne?
-	0x2f, 0x02,                     // bt 02
-	0xa1, 0x89,                     // sag 89 [ sweep-count = 0 if day <= 7 or day == 11 ]
-	0x81, 0x82,                     // lag 82 [ day ]
-	0x78,                           // push1
-	0x1a,                           // eq?
-	0x31, 0x10,                     // bnt 10 [ skip horn init ]
-	0x38, PATCH_SELECTOR16(has),    // pushi has
-	0x78,                           // push1
-	0x78,                           // push1
-	0x81, 0x00,                     // lag 00
-	0x4a, 0x06,                     // send 06 [ ego has: 1 ]
-	0x2f, 0x05,                     // bt 05 [ skip horn init ]
-	0x72, PATCH_UINT16(0x19b2),     // lofsa horn
-	0x33, 0x1a,                     // jmp 1c [ continue horn init ]
-	0x81, 0x7e,                     // lag 7e
-	0x31, 0x08,                     // bnt 08
-	PATCH_ADDTOOFFSET(+19),
-	0x72, PATCH_UINT16(0x1912),     // lofsa bow
-	0x39, PATCH_SELECTOR8(init),    // push init
-	0x76,                           // push0
-	0x38, PATCH_GETORIGINALUINT16(+25), // pushi stopUpd
-	0x76,                           // push0
-	PATCH_END
-};
-
-// After rescuing Fulk in the Amiga version, rescueOfFulk stores the boat speed
-//  in a temporary variable during one state and expects it to still be there in
-//  a later state, which only worked by accident in Sierra's interpreter. This
-//  Amiga tweak was made so that on slower machines the boat would animate after
-//  Fulk and Robin leave the screen. We fix this by using the script's register
-//  property for storage instead of a temporary variable.
-//
-// Applies to: English Amiga Floppy
-// Responsible method: rescueOfFulk:changeState
-// Fixes bug: #11137
-static const uint16 longbowSignatureAmigaFulkRescue[] = {
-	SIG_MAGICDWORD,
-	0xa5, 0x00,                     // sat 00
-	0x89, 0x57,                     // lsg 87
-	SIG_ADDTOOFFSET(+10),
-	0x8d, 0x00,                     // lst 00
-	SIG_ADDTOOFFSET(+635),
-	0x8d, 0x00,                     // lst 00
-	SIG_END
-};
-
-static const uint16 longbowPatchAmigaFulkRescue[] = {
-	0x65, 0x1a,                     // aTop register
-	PATCH_ADDTOOFFSET(+12),
-	0x67, 0x1a,                     // pTos register
-	PATCH_ADDTOOFFSET(+635),
-	0x67, 0x1a,                     // pTos register
-	PATCH_END
-};
-
-// The Amiga version has an unusual speed test which takes 10 seconds to run in
-//  ScummVM, causing the test to assume a slow machine speed and reduce details
-//  throughout the game. We disable the speed test and its long delay before the
-//  the Sierra logo so that the fastest machine speed is used.
-//
-// Applies to: English Amiga Floppy
-// Responsible method: speedScript:changeState
-static const uint16 longbowSignatureAmigaSpeedTest[] = {
-	// state 1
-	0x32, SIG_UINT16(0x0164),       // jmp 0164 [ end of method ]
-	SIG_ADDTOOFFSET(+0xe9),
-	// state 2
-	SIG_MAGICDWORD,
-	0x35, 0x02,                     // ldi 02   [ fastest machine speed ]
-	0x32, SIG_UINT16(0x000f),       // jmp 000f [ set machine speed ]
-	SIG_END
-};
-
-static const uint16 longbowPatchAmigaSpeedTest[] = {
-	0x32, PATCH_UINT16(0x00e9),     // jmp 00e9 [ skip test, use fastest machine speed ]
-	PATCH_END
-};
-
-// The Amiga version introduced a script bug that prevents setting the flag when
-//  saving the peasant woman on day one. To get a perfect score, Robin must give
-//  the woman money as she walks away, but this causes the rest of the game to
-//  behave as if she was left to die. The script savedTheWoman was altered to
-//  set flag 173 in a later state than before, but this was a mistake because
-//  giveWomanBucks interrupts savedTheWoman and completes the scene. The Amiga
-//  script also allows exiting to the map before flag 173 is set.
-//
-// We fix this by setting flag 173 as soon as savedTheWoman enables input, just
-//  like in the PC versions. We make room by overwriting an Amiga-only test of
-//  the machine's speed. This is unnecessary as we disable the speed test above.
-//
-// Applies to: English Amiga Floppy
-// Responsible method: savedTheWoman:changeState(13)
-static const uint16 longbowSignatureAmigaPeasantWoman[] = {
-	0x89, SIG_MAGICDWORD, 0x57,     // lsg 87 [ machine speed, always 2 ]
-	0x35, 0x01,                     // ldi 01
-	0x20,                           // ge?    [ machine speed >= 1 ]
-	0x30, SIG_UINT16(0x0012),       // bnt 0012
-	SIG_END
-};
-
-static const uint16 longbowPatchAmigaPeasantWoman[] = {
-	0x39, 0x01,                     // pushi 01
-	0x38, PATCH_UINT16(0x00ad),     // pushi 00ad    [ flag 173 ]
-	0x45, 0x06, 0x02,               // callb proc0_6 [ set saved-woman flag ]
-	PATCH_END
-};
-
-// When Robin is sentenced to death, King Richard and Robin discuss Marian's
-//  death even if she is alive and just finished testifying at the trial.
-//
-// At the end of the game, troub:init calculates which ending to use based on
-//  the ransom raised, the number of outlaws left, interactions with others, and
-//  whether or not Marian lived. These calculations are complex and the worst of
-//  the four endings is to be hung. Room 422 handles this ending, but unlike the
-//  other trial scripts, it doesn't test any flags. Instead it always displays
-//  messages that begin with Marian's death even though this ending is possible
-//  when Marian is alive.
-//
-// We fix this by skipping the messages that discuss Marian's death if she is
-//  alive. We make room for this by overwriting redundant code that disables the
-//  icon bar. The icon bar is already disabled by the previous room, and even if
-//  it weren't, the subsequent call to HandsOff would have disabled it.
-//
-// Applies to: All versions
-// Responsible method: hanging:init
-static const uint16 longbowSignatureMarianMessagesFix[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(disable),  // pushi disable
-	0x39, 0x08,                     // pushi 08
-	0x76,                           // push0
-	0x78,                           // push1
-	0x7a,                           // push2
-	0x39, 0x03,                     // pushi 03
-	0x39, 0x04,                     // pushi 04
-	0x39, 0x05,                     // pushi 05
-	0x39, 0x06,                     // pushi 06
-	0x39, 0x07,                     // pushi 07
-	0x81, 0x45,                     // lag 45
-	0x4a, 0x14,                     // send 14 [ IconBar disable: 1 2 3 4 5 6 7 ]
-	SIG_END
-};
-
-static const uint16 longbowPatchMarianMessagesFix[] = {
-	0x76,                           // push0
-	0x39, 0x3e,                     // pushi 3e      [ flag 62 ]
-	0x45, 0x05, 0x02,               // callb proc0_5 [ is Marian alive? ]
-	0x31, 0x0e,                     // bnt 0e
-	0x38, PATCH_UINT16(0x0093),     // pushi 0093
-	0xab, 0x0a,                     // ssl 0a [ start message sequence at 147 ]
-	0x76,                           // push0
-	0xab, 0x0c,                     // ssl 0c [ stop sequence after first message ]
-	0x33, 0x04,                     // jmp 04
-	PATCH_END
-};
-
-// In the abbey hedge maze, the music stops if the interpreter loads the next
-//  maze room in under half a second. ScummVM can achieve this on fast machines.
-//  When changing maze rooms, the old room sets the music to slowly fade to zero
-//  without waiting. The new room then sets the music to fade back in to full
-//  volume (127). This has no noticeable effect since the second fade reverts
-//  the first almost instantly, but if the new room loads before the fade timer
-//  has lowered the volume at all then kDoSoundFade ignores the second fade
-//  because the volume is already at the target. The first fade then proceeds to
-//  lower the volume to zero and stop the sound, after which it never resumes.
-//
-// We fix this by patching HedgeRow:dispose to only fade out the music when
-//  exiting the maze. This doesn't change the music since the fades canceled
-//  each other out when changing maze rooms. There is already a nearby check for
-//  exiting the maze so this patch re-orders the instructions.
-//
-// Applies to: All versions
-// Responsible method: HedgeRow:dispose
-// Fixes bug: #13674
-static const uint16 longbowSignatureHedgeMazeMusic[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(fade),     // pushi fade
-	0x39, 0x04,                     // pushi 04
-	0x76,                           // push0
-	0x39, 0x1e,                     // pushi 1e
-	0x39, 0x08,                     // pushi 08
-	0x78,                           // push1
-	0x81, 0x64,                     // lag 64
-	0x4a, 0x0c,                     // send 0c [ rgnMusic fade: 0 30 8 1 ]
-	0x38, SIG_SELECTOR16(enable),   // pushi enable
-	0x78,                           // push1
-	0x39, 0x05,                     // pushi 05
-	0x81, 0x45,                     // lag 45
-	0x4a, 0x06,                     // send 06 [ IconBar enable: 5 ]
-	0x89, 0x0d,                     // lsg 0d  [ new room ]
-	0x35, 0x55,                     // ldi 55  [ max maze room ]
-	0x1e,                           // gt?     [ exiting hedge maze? ]
-	0x30, SIG_UINT16(0x0020),       // bnt 0020
-	SIG_END
-};
-
-static const uint16 longbowPatchHedgeMazeMusic[] = {
-	0x38, PATCH_SELECTOR16(enable), // pushi enable
-	0x78,                           // push1
-	0x39, 0x05,                     // pushi 05
-	0x81, 0x45,                     // lag 45
-	0x4a, 0x06,                     // send 06 [ IconBar enable: 5 ]
-	0x89, 0x0d,                     // lsg 0d  [ new room ]
-	0x35, 0x55,                     // ldi 55  [ max maze room ]
-	0x1e,                           // gt?     [ exiting hedge maze? ]
-	0x30, PATCH_UINT16(0x002f),     // bnt 002f
-	0x38, PATCH_SELECTOR16(fade),   // pushi fade
-	0x39, 0x04,                     // pushi 04
-	0x76,                           // push0
-	0x39, 0x1e,                     // pushi 1e
-	0x39, 0x08,                     // pushi 08
-	0x78,                           // push1
-	0x81, 0x64,                     // lag 64
-	0x4a, 0x0c,                     // send 0c [ rgnMusic fade: 0 30 8 1 ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                                patch
-static const SciScriptPatcherEntry longbowSignatures[] = {
-	{  true,    29, "amiga day 1 peasant woman",                   1, longbowSignatureAmigaPeasantWoman,       longbowPatchAmigaPeasantWoman},
-	{  true,   140, "green man riddles and forest sweep fix",      1, longbowSignatureGreenManForestSweepFix,  longbowPatchGreenManForestSweepFix },
-	{  true,   150, "day 5/6 camp sunset fix",                     2, longbowSignatureCampSunsetFix,           longbowPatchCampSunsetFix },
-	{  true,   150, "day 7 tuck net fix",                          1, longbowSignatureTuckNetFix,              longbowPatchTuckNetFix },
-	{  true,   210, "hand code crash",                             5, longbowSignatureShowHandCode,            longbowPatchShowHandCode },
-	{  true,   225, "arithmetic berry bush fix",                   1, longbowSignatureBerryBushFix,            longbowPatchBerryBushFix },
-	{  true,   250, "day 5/6 rescue flag fix",                     1, longbowSignatureRescueFlagFix,           longbowPatchRescueFlagFix },
-	{  true,   260, "day 5/6 town map sunset fix",                 1, longbowSignatureTownMapSunsetFix,        longbowPatchTownMapSunsetFix },
-	{  true,   320, "day 8 archer pathfinding workaround",         1, longbowSignatureArcherPathfinding,       longbowPatchArcherPathfinding },
-	{  true,   350, "day 9 cobbler hut fix",                      10, longbowSignatureCobblerHut,              longbowPatchCobblerHut },
-	{  true,   422, "marian messages fix",                         1, longbowSignatureMarianMessagesFix,       longbowPatchMarianMessagesFix },
-	{  true,   490, "hedge maze music",                            1, longbowSignatureHedgeMazeMusic,          longbowPatchHedgeMazeMusic },
-	{  true,   530, "amiga pub fix",                               1, longbowSignatureAmigaPubFix,             longbowPatchAmigaPubFix },
-	{  true,   600, "amiga fulk rescue fix",                       1, longbowSignatureAmigaFulkRescue,         longbowPatchAmigaFulkRescue },
-	{  true,   803, "amiga speed test",                            1, longbowSignatureAmigaSpeedTest,          longbowPatchAmigaSpeedTest },
-	{  true,   803, "disable speed test",                          1, sci01SpeedTestLocalSignature,            sci01SpeedTestLocalPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// Leisure Suit Larry 1 (Spanish)
-//
-// It seems originally the Spanish version of Larry 1 used some beta code at
-// least for the man wearing a barrel, who walks around in front of the casino.
-// The script inside the resource files even uses a class, that does not exist
-// inside those resource files, which causes a hard error.
-// The patch files included with the Spanish version (300.scr,300.tex, 927.scr)
-// add this class, but at least inside ScummVM a write to a non-existent selector
-// happens right after the player tries to buy an apple from that man.
-//
-// In the original English releases (2.0+2.1) this was handled differently.
-// Which is why this script patch changes that code to work just like in the English release.
-//
-// Attention: for at least some release of this game, view 302 (man wearing a barrel) is fully
-//            broken! Which also causes a crash. The original interpreter crashes as well.
-//            The only way to fix this is to dump that view from another release of Larry 1
-//            and then use the view patch file on this release.
-//
-// Applies to at least: Spanish floppy
-// Responsible method: sBuyApple::changeScript(2)
-// Fixes bug: #10240
-static const uint16 larry1SignatureBuyApple[] = {
-	// end of state 0
-	0x35, 0x01,                      // ldi 01
-	0x65, 0x10,                      // aTop cycles
-	0x32, SIG_UINT16(0x0248),        // jmp [ret]
-	0x3c,                            // dup
-	0x35, 0x01,                      // ldi 01
-	0x1a,                            // eq?
-	0x30, SIG_UINT16(0x0007),        // bnt [step 2 check]
-	// state 1 code
-	0x35, 0x01,                      // ldi 01
-	0x65, 0x10,                      // aTop cycles
-	0x32, SIG_UINT16(0x023a),        // jmp [ret]
-	0x3c,                            // dup
-	0x35, 0x02,                      // ldi 02
-	0x1a,                            // eq?
-	0x30, SIG_UINT16(0x0036),        // bnt [step 3 check]
-	// state 2 code
-	0x35, 0x02,                      // ldi 02
-	0x38, SIG_UINT16(0x0091),        // pushi setCycle
-	0x78,                            // push1
-	0x51, 0x18,                      // class Walk
-	0x36,                            // push
-	0x38, SIG_UINT16(0x0126),        // pushi setAvoider
-	0x78,                            // push1
-	0x51, SIG_ADDTOOFFSET(+1),       // class PAvoider (original 0x25, w/ patch file 0x6d)
-	0x36,                            // push
-	0x38, SIG_UINT16(0x0116),        // pushi setMotion
-	SIG_MAGICDWORD,
-	0x39, 0x04,                      // pushi 04
-	0x51, 0x24,                      // class PolyPath
-	0x36,                            // push
-	0x39, 0x04,                      // pushi 04
-	0x76,                            // push0
-	0x72, SIG_UINT16(0x0f4e),        // lofsa aAppleMan
-	0x4a, 0x04,                      // send 04
-	0x36,                            // push
-	0x35, 0x1d,                      // ldi 1Dh
-	0x02,                            // add
-	0x36,                            // push
-	0x39, 0x03,                      // pushi 03
-	0x76,                            // push0
-	0x72, SIG_UINT16(0x0f4e),        // lofsa aAppleMan
-	0x4a, 0x04,                      // send 04
-	0x36,                            // push
-	0x7c,                            // pushSelf
-	0x81, 0x00,                      // lag global[0]
-	0x4a, 0x18,                      // send 18h
-	0x32, SIG_UINT16(0x01fd),        // jmp [ret]
-	SIG_END
-};
-
-static const uint16 larry1PatchBuyApple[] = {
-	PATCH_ADDTOOFFSET(+11),
-	0x2f, 0xf3,                        // bt [jump to end of step 1 code], saves 8 bytes
-	0x3c,                              // dup
-	0x35, 0x02,                        // ldi 02
-	0x1a,                              // eq?
-	0x31, 0x3f,                        // bnt [step 3 check]
-	0x38, PATCH_UINT16(0x00e1),        // pushi distanceTo
-	0x78,                              // push1
-	0x72, PATCH_UINT16(0x0f4e),        // lofsa sAppleMan
-	0x36,                              // push
-	0x81, 0x00,                        // lag global[0]
-	0x4a, 0x06,                        // send 06
-	0x36,                              // push
-	0x35, 0x1e,                        // ldi 1Eh
-	0x1e,                              // gt?
-	0x31, 0xdb,                        // bnt [jump to end of step 1 code]
-	0x38, PATCH_SELECTOR16(setCycle),  // pushi setCycle
-	0x78,                              // push1
-	0x51, 0x18,                        // class Walk
-	0x36,                              // push
-	0x38, PATCH_SELECTOR16(setMotion), // pushi setMotion
-	0x39, 0x04,                        // pushi 04
-	0x51, 0x24,                        // class PolyPath
-	0x36,                              // push
-	0x39, 0x04,                        // pushi 04
-	0x76,                              // push0
-	0x72, PATCH_UINT16(0x0f4e),        // lofsa aAppleMan
-	0x4a, 0x04,                        // send 04
-	0x36,                              // push
-	0x35, 0x1d,                        // ldi 1Dh
-	0x02,                              // add
-	0x36,                              // push
-	0x39, 0x03,                        // pushi 03
-	0x76,                              // push0
-	0x72, PATCH_UINT16(0x0f4e),        // lofsa aAppleMan
-	0x4a, 0x04,                        // send 04
-	0x36,                              // push
-	0x7c,                              // pushSelf
-	0x81, 0x00,                        // lag global[0]
-	0x4a, 0x12,                        // send 12h
-	PATCH_END
-};
-
-//          script, description,                               signature                patch
-static const SciScriptPatcherEntry larry1Signatures[] = {
-	{  true,   300, "Spanish: buy apple from barrel man",    1, larry1SignatureBuyApple, larry1PatchBuyApple },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// Leisure Suit Larry 2
-
-// On the plane, Larry is able to wear the parachute. This grants 4 points.
-// In early versions of LSL2, it was possible to get "unlimited" points by
-//  simply wearing it multiple times.
-// They fixed it in later versions by remembering, if the parachute was already
-//  used before.
-// But instead of adding it properly, it seems they hacked the script / forgot
-//  to replace script 0 as well, which holds information about how many global
-//  variables are allocated at the start of the game.
-// The script tries to read an out-of-bounds global variable, which somewhat
-//  "worked" in SSCI, but ScummVM/SCI doesn't allow that.
-// That's why those points weren't granted here at all.
-// We patch to use global[5a], which seems to be unused in the whole game.
-// Applies to at least: English floppy
-// Responsible method: rm63Script::handleEvent
-// Fixes bug: #6346
-static const uint16 larry2SignatureWearParachutePoints[] = {
-	0x35, 0x01,                      // ldi 01
-	0xa1, SIG_MAGICDWORD, 0x8e,      // sag global[8e]
-	0x80, SIG_UINT16(0x01e0),        // lag global[1e0]
-	0x18,                            // not
-	0x30, SIG_UINT16(0x000f),        // bnt [don't give points]
-	0x35, 0x01,                      // ldi 01
-	0xa0, 0xe0, 0x01,                // sag global[1e0]
-	SIG_END
-};
-
-static const uint16 larry2PatchWearParachutePoints[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x80, PATCH_UINT16(0x005a),      // lag global[5a]
-	PATCH_ADDTOOFFSET(+6),
-	0xa0, PATCH_UINT16(0x005a),      // sag global[5a]
-	PATCH_END
-};
-
-// When buying a lottery ticket, the message box "Processing..." is displayed
-//  three times with no delay between the messages. In the original, each was
-//  visibly erased before the next because the interpreter drew directly to the
-//  screen. This created the necessary flicker effect indicating that the three
-//  identical messages were separate. In ScummVM there is no flicker because the
-//  window is updated with the screen buffer when processing events or between
-//  game cycles. The result is a single message box that appears to not respond
-//  to Enter or clicks until the third one dismisses it.
-//
-// We fix this by adding a brief delay in the "Processing..." loop with a call
-//  to kScummVMSleep so that the screen is redrawn between message boxes and the
-//  intended effect occurs as in the original. This patch is broken up into two
-//  parts because different versions have different instructions in the loop.
-//
-// Applies to: All versions
-// Responsible method: rm114Script:changeState(15)
-static const uint16 larry2SignatureLotteryTicketMessages1[] = {
-	0x35, 0x00,                      // ldi 00
-	0xa5, 0x00,                      // sat 00 [ temp0 = 0 ]
-	0x8d, 0x00,                      // lst 00 [ start loop ]
-	SIG_MAGICDWORD,
-	0x35, 0x03,                      // ldi 03
-	0x22,                            // lt?    [ temp0 < 3 ]
-	0x30, SIG_ADDTOOFFSET(+1), 0x00, // bnt    [ exit loop ]
-	SIG_END
-};
-
-static const uint16 larry2PatchLotteryTicketMessages1[] = {
-	0xa5, 0x00,                      // sat 00 [ temp0 = 0 (acc already 0) ]
-	0x7a,                            // push2  [ start loop ]
-	0x20,                            // ge?    [ 2 >= temp0 ]
-	0x31, PATCH_GETORIGINALBYTEADJUST(+10, +6), // bnt [ exit loop ]
-	0x78,                            // push1
-	0x39, 0x02,                      // pushi 02
-	0x43, kScummVMSleepId, 0x02,     // callk kScummVMSleep 02 [ 2 ticks ]
-	PATCH_END
-};
-
-static const uint16 larry2SignatureLotteryTicketMessages2[] = {
-	0x47, 0xff, SIG_MAGICDWORD, 0x00, 0x0c, // calle proc255_0 0c [ Print "Processing..." ]
-	0xc5, 0x00,                             // +at 00 [ temp0++, acc = temp0 ]
-	0x32, SIG_ADDTOOFFSET(+1), 0xff,        // jmp    [ continue loop ]
-	SIG_END
-};
-
-static const uint16 larry2PatchLotteryTicketMessages2[] = {
-	PATCH_ADDTOOFFSET(+6),
-	0x32, PATCH_GETORIGINALBYTEADJUST(+7, -2), 0xff, // jmp [ continue loop ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                              patch
-static const SciScriptPatcherEntry larry2Signatures[] = {
-	{  true,    63, "plane: no points for wearing parachute",      1, larry2SignatureWearParachutePoints,    larry2PatchWearParachutePoints },
-	{  true,    99, "disable speed test",                          1, sci0EarlySpeedTestSignature,           sci0EarlySpeedTestPatch },
-	{  true,    99, "disable speed test",                          1, sci01SpeedTestGlobalSignature,         sci01SpeedTestGlobalPatch },
-	{  true,   114, "lottery ticket messages (1/2)",               1, larry2SignatureLotteryTicketMessages1, larry2PatchLotteryTicketMessages1 },
-	{  true,   114, "lottery ticket messages (2/2)",               1, larry2SignatureLotteryTicketMessages2, larry2PatchLotteryTicketMessages2 },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// Leisure Suit Larry 3
-
-// Disable the LSL3 speed test by always setting the machine speed to 40 (PC AT)
-//  so that all graphics are enabled and the weight room behaves reasonably.
-//  40 is the minimum value that enables everything such as incrementing the
-//  score and the lighting effects in rooms 390, 430, and 431. The weight room
-//  (room 380) uses the machine speed to calculate how many exercises are
-//  required and the results would be much too high (in the thousands) if the
-//  speed test were to run unthrottled at modern speeds.
-//
-// Applies to: All versions
-// Responsible method: rm290:doit
-// Fixes bug: #11967
-static const uint16 larry3PatchSpeedTest[] = {
-	0x34, PATCH_UINT16(0x0028),         // ldi 0028
-	0xa1, PATCH_GETORIGINALBYTE(+1),    // sag [ machine-speed = 40 ]
-	0x18,                               // not [ always skip initialization ]
-	PATCH_END
-};
-
-// The LSL3 volume dialog initialize its slider to the current volume by calling
-//  kDoSoundMasterVolume, but it passes an uninitialized variable as an extra
-//  parameter. This changes the volume instead of just querying it, leaving the
-//  slider out of sync with the abruptly changed volume.
-//
-// We remove the uninitialized parameter so that this code correctly queries the
-//  volume instead of setting it. This was fixed in later versions but the buggy
-//  one was used as the basis for SCI Studio's template script, which is also
-//  included with SCI Companion, and so this bug lives on in fan games.
-//
-// Applies to: English PC, English Amiga, English Atari ST
-// Responsible method: TheMenuBar:handleEvent
-static const uint16 larry3SignatureVolumeSlider[] = {
-	SIG_MAGICDWORD,
-	0x39, SIG_SELECTOR8(doit),       // pushi doit
-	0x78,                            // push1
-	0x7a,                            // push2
-	0x39, 0x08,                      // pushi 08 [ volume ]
-	0x8d, 0x01,                      // lst 01   [ uninitialized variable ]
-	0x43, 0x31, 0x04,                // callk DoSound 04 [ set volume and return previous ]
-	SIG_END
-};
-
-static const uint16 larry3PatchVolumeSlider[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x39, 0x01,                      // pushi 01
-	0x38, PATCH_UINT16(0x0008),      // pushi 0008 [ volume ]
-	0x43, 0x31, 0x02,                // callk DoSound 02 [ return volume ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                      patch
-static const SciScriptPatcherEntry larry3Signatures[] = {
-	{  true,   290, "disable speed test",                          1, sci01SpeedTestGlobalSignature, larry3PatchSpeedTest },
-	{  true,   997, "fix volume slider",                           1, larry3SignatureVolumeSlider,   larry3PatchVolumeSlider },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// Leisure Suit Larry 5
-// In Miami the player can call the green card telephone number and get
-//  green card including limo at the same time in the English 1.000 PC release.
-// This results later in a broken game in case the player doesn't read
-//  the second telephone number for the actual limousine service, because
-//  in that case it's impossible for the player to get back to the airport.
-//
-// We disable the code, that is responsible to make the limo arrive.
-//
-// This bug was fixed in the European (dual language) versions of the game.
-//
-// Applies to at least: English PC floppy (1.000)
-// Responsible method: sPhone::changeState(40)
-static const uint16 larry5SignatureGreenCardLimoBug[] = {
-	0x7a,                               // push2
-	SIG_MAGICDWORD,
-	0x39, 0x07,                         // pushi 07
-	0x39, 0x0c,                         // pushi 0Ch
-	0x45, 0x0a, 0x04,                   // callb [export 10 of script 0], 04
-	0x78,                               // push1
-	0x39, 0x26,                         // pushi 26h (limo arrived flag)
-	0x45, 0x07, 0x02,                   // callb [export 7 of script 0], 02 (sets flag)
-	SIG_END
-};
-
-static const uint16 larry5PatchGreenCardLimoBug[] = {
-	PATCH_ADDTOOFFSET(+8),
-	0x34, PATCH_UINT16(0x0000),         // ldi 0000 (dummy)
-	0x34, PATCH_UINT16(0x0000),         // ldi 0000 (dummy)
-	PATCH_END
-};
-
-// In one of the conversations near the end (to be exact - room 380 and the text
-//  about using champagne on Reverse Biaz - only used when you actually did that
-//  in the game), the German text is too large, causing the textbox to get too large.
-// Because of that the talking head of Patti is drawn over the textbox. A translation oversight.
-// Applies to at least: German floppy
-// Responsible method: none, position of talker object on screen needs to get modified
-static const uint16 larry5SignatureGermanEndingPattiTalker[] = {
-	SIG_MAGICDWORD,
-	SIG_UINT16(0x006e),                 // object pattiTalker::x (110)
-	SIG_UINT16(0x00b4),                 // object pattiTalker::y (180)
-	SIG_ADDTOOFFSET(+469),              // verify that it's really the German version
-	0x59, 0x6f, 0x75,                   // (object name) "You"
-	0x23, 0x47, 0x44, 0x75,             // "#GDu"
-	SIG_END
-};
-
-static const uint16 larry5PatchGermanEndingPattiTalker[] = {
-	PATCH_UINT16(0x005a),               // object pattiTalker::x (90)
-	PATCH_END
-};
-
-//          script, description,                                      signature                               patch
-static const SciScriptPatcherEntry larry5Signatures[] = {
-	{  true,   280, "English-only: fix green card limo bug",       1, larry5SignatureGreenCardLimoBug,        larry5PatchGreenCardLimoBug },
-	{  true,   380, "German-only: Enlarge Patti Textbox",          1, larry5SignatureGermanEndingPattiTalker, larry5PatchGermanEndingPattiTalker },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// 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).
-// Applies to at least: German PC-CD
-// Responsible method: unknown
-static const uint16 larry6SignatureDeathDialog[] = {
-	SIG_MAGICDWORD,
-	0x3e, SIG_UINT16(0x0133),        // link 0133 (offset 0x20)
-	0x35, 0xff,                      // ldi ff
-	0xa3, 0x00,                      // sal local[0]
-	SIG_ADDTOOFFSET(+680),           // ...
-	0x8f, 0x01,                      // lsp param[1] (offset 0x2cf)
-	0x7a,                            // push2
-	0x5a, SIG_UINT16(0x0004), SIG_UINT16(0x010e), // lea temp[010e]
-	0x36,                            // push
-	0x43, 0x7c, 0x0e,                // callk Message[7c], 0e
-	SIG_ADDTOOFFSET(+90),            // ...
-	0x38, SIG_UINT16(0x00d6),        // pushi 00d6 (offset 0x335)
-	0x78,                            // push1
-	0x5a, SIG_UINT16(0x0004), SIG_UINT16(0x010e), // lea temp[010e]
-	0x36,                            // push
-	SIG_ADDTOOFFSET(+76),            // ...
-	0x38, SIG_UINT16(0x00cd),        // pushi 00cd (offset 0x38b)
-	0x39, 0x03,                      // pushi 03
-	0x5a, SIG_UINT16(0x0004), SIG_UINT16(0x010e), // lea temp[010e]
-	0x36,
-	SIG_END
-};
-
-static const uint16 larry6PatchDeathDialog[] = {
-	0x3e, 0x00, 0x02,                                 // link 0200
-	PATCH_ADDTOOFFSET(+687),
-	0x5a, PATCH_UINT16(0x0004), PATCH_UINT16(0x0140), // lea temp[0140]
-	PATCH_ADDTOOFFSET(+98),
-	0x5a, PATCH_UINT16(0x0004), PATCH_UINT16(0x0140), // lea temp[0140]
-	PATCH_ADDTOOFFSET(+82),
-	0x5a, PATCH_UINT16(0x0004), PATCH_UINT16(0x0140), // lea temp[0140]
-	PATCH_END
-};
-
-//          script, description,                                      signature                   patch
-static const SciScriptPatcherEntry larry6Signatures[] = {
-	{  true,    82, "death dialog memory corruption",              1, larry6SignatureDeathDialog, larry6PatchDeathDialog },
-	{  true,    99, "disable speed test",                          1, sci11SpeedTestSignature,    sci11SpeedTestPatch },
-	{  true,   928, "Narrator lockup fix",                         1, sciNarratorLockupSignature, sciNarratorLockupPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#ifdef ENABLE_SCI32
-#pragma mark -
-#pragma mark Leisure Suit Larry 6 Hires
-
-// When entering room 270 (diving board) from room 230, a typo in the game
-// script means that `setScale` is called accidentally instead of `setScaler`.
-// In SSCI this did not do much because the first argument happened to be
-// smaller than the y-position of `ego`, but in ScummVM the first argument is
-// larger and so a debug message "y value less than vanishingY" is displayed.
-static const uint16 larry6HiresSetScaleSignature[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(setScale), // pushi setScale ($14b)
-	0x38, SIG_UINT16(0x0005),       // pushi 5
-	0x51, 0x2c,                     // class Scaler
-	SIG_END
-};
-
-static const uint16 larry6HiresSetScalePatch[] = {
-	0x38, PATCH_SELECTOR16(setScaler), // pushi setScaler ($14f)
-	PATCH_END
-};
-
-// The init code that runs when LSL6hires starts up unconditionally resets the
-// master music volume to 12 (and the volume dial to 11), but the game should
-// always use the volume stored in ScummVM. Mac version initializes to 5.
-//
-// Applies to at least: English CD, Mac CD
-// Responsible method: initCode:init
-// Fixes bug: #9700
-static const uint16 larry6HiresVolumeResetSignature[] = {
-	SIG_MAGICDWORD,
-	0x4a, SIG_UINT16(0x0006),           // send 06 [ LSL6 masterVolume: ... ]
-	0x35, SIG_ADDTOOFFSET(+1),          // ldi 0b on PC, 05 on Mac
-	0xa1, 0xc2,                         // sag c2
-	SIG_END
-};
-
-static const uint16 larry6HiresVolumeResetPatch[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x33, 0x02,                         // jmp 02 [ skip volume change ]
-	PATCH_END
-};
-
-// Mac version stores the master music volume in an additional global which it
-//  sets the volume to on every restore. We disable this code so that the
-//  current ScummVM volume is used.
-//
-// Applies to: Mac CD only
-// Responsible method: LSL6:replay
-static const uint16 larry6HiresMacVolumeRestoreSignature[] = {
-	0x7a,                               // push2
-	SIG_MAGICDWORD,
-	0x76,                               // push0
-	0x88, SIG_UINT16(0x0103),           // lsg 0103
-	0x43, 0x40, SIG_UINT16(0x0004),     // callk DoSound 04 [ kDoSound MasterVolume global259 ]
-	SIG_END
-};
-
-static const uint16 larry6HiresMacVolumeRestorePatch[] = {
-	0x33, 0x07,                         // jmp 07 [ skip volume change ]
-	PATCH_END
-};
-
-// Filling the whale oil lamp with cellulite locks up the game when the PATCHES
-//  directory is missing. The patch files for script 330 override a very broken
-//  version in the resource volumes that always goes into an infinite loop.
-//  Unfortunately, the Leisure Suit Larry Collection CD includes a RESOURCE.CFG
-//  with an incorrect path to the PATCHES directory. Sierra's fix was to issue a
-//  save file with a full oil lamp that was compatible with the broken scripts.
-//  This shouldn't affect ScummVM since we don't use RESOURCE.CFG, but something
-//  about the way the collection was packaged causes players to continue to miss
-//  this directory and not realize until it's too late. The lockup occurs late
-//  in the game and adding the missing patch files invalidates all saves. 
-//
-// We don't generally fix "bugs" that are consequences of not providing all of
-//  the game's data files, but this is a severe case that keeps coming up.
-//  Fortunately, the script bug is simple, so we might as well just patch it and
-//  allow the player to proceed.
-//
-// We mitigate this by patching fillLampScr:changeState(2) to increment its
-//  register property. This is the counter that's supposed to animate the lamp
-//  but instead register is never incremented and the loop never ends.
-//
-// Applies to: English PC CD when PATCHES is missing (TODO: check localizations)
-// Responsible method: fillLampScr:changeState(2)
-// Fixes bug: #10484
-static const uint16 larry6HiresWhaleOilLampSignature[] = {
-	0x39, SIG_SELECTOR8(loop),          // pushi loop
-	0x78,                               // push1
-	0x78,                               // push1
-	0x39, SIG_MAGICDWORD,               // pushi cel
-	      SIG_SELECTOR8(cel),
-	0x78,                               // push1
-	0x67, 0x26,                         // pTos register
-	0x81, 0x00,                         // lag 00
-	0x4a, SIG_UINT16(0x000c),           // send 0c [ ego loop: 1 cel: register ]
-	SIG_END
-};
-
-static const uint16 larry6HiresWhaleOilLampPatch[] = {
-	PATCH_ADDTOOFFSET(+7),
-	0x6f,                               // ipTos register [ increment register ]
-	PATCH_END
-};
-
-// When attempting to take the guard's weapons, missleDeathScr calculates an
-//  excessively long delay in game cycles based on the initial speed test. The
-//  script attempts to use this delay as a backup if the user quickly dismisses
-//  the "Without thinking twice..." message so that it doesn't get stuck. We
-//  patch the speed test to use the best value so that all details are enabled,
-//  but we also throttle game cycles, and this results in a 30+ second delay.
-//
-// We fix this incompatibility by patching the delay down to 60 cycles, but this
-//  exposes a real script bug. The backup delay is always active and interrupts
-//  the message audio if the delay lasts less than six seconds. The script
-//  attempts to prevent this by polling the message's audio position, but it
-//  passes the wrong audio tuple. We also fix the tuple and now the delay works.
-//
-// Applies to: All versions
-// Responsible method: missleDeathScr:changeState(3), missleDeathScr:doit
-// Fixes bug: #13501
-static const uint16 larry6HiresGuardDelaySignature1[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x57,                         // lsg 57 [ how-fast ]
-	0x35, 0x4b,                         // ldi 4b
-	0x06,                               // mul
-	0x65, 0x26,                         // aTop register [ register = how-fast * 75 ]
-	SIG_END
-};
-
-static const uint16 larry6HiresGuardDelayPatch1[] = {
-	0x35, 0x3c,                         // ldi 3c [ 60 cycles ]
-	0x32, PATCH_UINT16(0x0000),         // jmp 0000
-	PATCH_END
-};
-
-static const uint16 larry6HiresGuardDelaySignature2[] = {
-	SIG_MAGICDWORD,
-	0x39, 0x06,                         // pushi 06
-	0x3c,                               // dup [ kDoAudioPosition ]
-	0x38, SIG_UINT16(0x0352),           // pushi 0352
-	0x39, 0x03,                         // pushi 03 [ noun ]
-	0x39, 0x05,                         // pushi 05 [ verb ]
-	0x76,                               // push0    [ cond ]
-	0x76,                               // push0    [ seq  ]
-	SIG_END
-};
-
-static const uint16 larry6HiresGuardDelayPatch2[] = {
-	PATCH_ADDTOOFFSET(+6),
-	0x39, 0x04,                         // pushi 04 [ correct noun ]
-	PATCH_ADDTOOFFSET(+3),
-	0x78,                               // push1    [ correct seq  ]
-	PATCH_END
-};
-
-// When using the phone with text enabled, dialing certain combinations crashes.
-//  This is due to a bug introduced when script 610 was altered for the hi-res
-//  version. The showTitle property of the phone's talker is only supposed to be
-//  set when talking to someone with a name, but now showTitle is never cleared.
-//  The operator is the one voice without a name, so talking to someone else
-//  first leaves these properties out of sync. Talking to the operator in this
-//  state causes Print:addTitle to attempt to duplicate the null name string.
-//
-// We fix this by clearing the phone talker's showTitle property when the name
-//  property is cleared. This keeps both properties in sync as before.
-//
-// Applies to: All versions
-// Responsible method: Export 2 of script 610
-// Fixes bug: #13554
-static const uint16 larry6HiresPhoneOperatorSignature[] = {
-	0x39, SIG_SELECTOR8(name),          // pushi name
-	0x76,                               // push0
-	0x72, SIG_ADDTOOFFSET(+2),          // lofsa talker
-	0x4a, SIG_UINT16(0x0004),           // send 04 [ talker name? ]
-	0x31, SIG_MAGICDWORD, 0x1a,         // bnt 1a  [ skip if no name ]
-	0x38, SIG_SELECTOR16(dispose),      // pushi dispose
-	0x76,                               // push0
-	0x39, SIG_SELECTOR8(name),          // pushi name
-	0x76,                               // push0
-	0x72, SIG_ADDTOOFFSET(+2),          // lofsa talker
-	0x4a, SIG_UINT16(0x0004),           // send 04 [ talker name? ]
-	0x4a, SIG_UINT16(0x0004),           // send 04 [ name dispose: ]
-	0x39, SIG_SELECTOR8(name),          // pushi name
-	0x78,                               // push1
-	0x76,                               // push0
-	0x72, SIG_ADDTOOFFSET(+2),          // lofsa talker
-	0x4a, SIG_UINT16(0x0006),           // send 06 [ talker name: 0 ]
-	SIG_END
-};
-
-static const uint16 larry6HiresPhoneOperatorPatch[] = {
-	PATCH_ADDTOOFFSET(+15),
-	0x4a, PATCH_UINT16(0x0004),         // send 04 [ name dispose: ]
-	0x38, PATCH_SELECTOR16(showTitle),  // pushi showTitle
-	0x78,                               // push1
-	0x76,                               // push0
-	0x33, 0x02,                         // jmp 02
-	PATCH_ADDTOOFFSET(+9),
-	0x4a, PATCH_UINT16(0x000c),         // send 0c [ talker showTitle: 0 name: 0 ]
-	PATCH_END
-};
-
-//          script, description,                                      signature                             patch
-static const SciScriptPatcherEntry larry6HiresSignatures[] = {
-	{  true,     0, "disable mac volume restore",                  1, larry6HiresMacVolumeRestoreSignature, larry6HiresMacVolumeRestorePatch },
-	{  true,    71, "disable volume reset on startup (1/2)",       1, sci2VolumeResetSignature,             sci2VolumeResetPatch },
-	{  true,    71, "disable volume reset on startup (2/2)",       1, larry6HiresVolumeResetSignature,      larry6HiresVolumeResetPatch },
-	{  true,    71, "disable video benchmarking",                  1, sci2BenchmarkSignature,               sci2BenchmarkPatch },
-	{  true,   270, "fix incorrect setScale call",                 1, larry6HiresSetScaleSignature,         larry6HiresSetScalePatch },
-	{  true,   330, "fix whale oil lamp lockup",                   1, larry6HiresWhaleOilLampSignature,     larry6HiresWhaleOilLampPatch },
-	{  true,   610, "phone operator crash",                        1, larry6HiresPhoneOperatorSignature,    larry6HiresPhoneOperatorPatch },
-	{  true,   850, "guard delay (1/2)",                           1, larry6HiresGuardDelaySignature1,      larry6HiresGuardDelayPatch1 },
-	{  true,   850, "guard delay (2/2)",                           1, larry6HiresGuardDelaySignature2,      larry6HiresGuardDelayPatch2 },
-	{  true, 64928, "Narrator lockup fix",                         1, sciNarratorLockupSignature,           sciNarratorLockupPatch },
-	{  true, 64990, "increase number of save games (1/2)",         1, sci2NumSavesSignature1,               sci2NumSavesPatch1 },
-	{  true, 64990, "increase number of save games (2/2)",         1, sci2NumSavesSignature2,               sci2NumSavesPatch2 },
-	{  true, 64990, "disable change directory button",             1, sci2ChangeDirSignature,               sci2ChangeDirPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#pragma mark -
-#pragma mark Leisure Suit Larry 7
-
-// The init code that runs when LSL7 starts up unconditionally resets the audio
-// volumes to defaults, but the game should always use the volume stored in
-// ScummVM. This patch is basically identical to the patch for Torin, except
-// that they left line numbers in the LSL7 scripts and changed the music volume.
-// Applies to at least: English CD
-static const uint16 larry7VolumeResetSignature1[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x41,                         // ldi $41
-	0xa1, 0xe3,                         // sag global[$e3] (music volume)
-	0x7e, SIG_ADDTOOFFSET(+2),          // (line whatever)
-	0x35, 0x3c,                         // ldi $3c
-	0xa1, 0xe4,                         // sag global[$e4] (sfx volume)
-	0x7e, SIG_ADDTOOFFSET(+2),          // (line whatever)
-	0x35, 0x64,                         // ldi $64
-	0xa1, 0xe5,                         // sag global[$e5] (speech volume)
-	SIG_END
-};
-
-static const uint16 larry7VolumeResetPatch1[] = {
-	0x33, 0x10,                         // jmp [past volume resets]
-	PATCH_END
-};
-
-// The init code that runs when LSL7 starts up unconditionally resets the
-// audio volumes to values stored in larry7.prf, but the game should always use
-// the volume stored in ScummVM. This patch is basically identical to the patch
-// for Torin, except that they left line numbers in the LSL7 scripts.
-// Applies to at least: English CD
-static const uint16 larry7VolumeResetSignature2[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(readWord),     // pushi readWord
-	0x76,                               // push0
-	SIG_ADDTOOFFSET(+6),                // ...
-	0xa1, 0xe3,                         // sag global[$e3] (music volume)
-	SIG_ADDTOOFFSET(+3),                // (line whatever)
-	SIG_ADDTOOFFSET(+10),               // ...
-	0xa1, 0xe4,                         // sag global[$e4] (sfx volume)
-	SIG_ADDTOOFFSET(+3),                // (line whatever)
-	SIG_ADDTOOFFSET(+10),               // ...
-	0xa1, 0xe5,                         // sag global[$e5] (speech volume)
-	SIG_END
-};
-
-static const uint16 larry7VolumeResetPatch2[] = {
-	PATCH_ADDTOOFFSET(+10),
-	0x18, 0x18,                         // (waste bytes)
-	PATCH_ADDTOOFFSET(+3),              // (line whatever)
-	PATCH_ADDTOOFFSET(+10),             // ...
-	0x18, 0x18,                         // (waste bytes)
-	PATCH_ADDTOOFFSET(+3),              // (line whatever)
-	PATCH_ADDTOOFFSET(+10),             // ...
-	0x18, 0x18,                         // (waste bytes)
-	PATCH_END
-};
-
-// In room 540 of Leisure Suit Larry 7, when using the cheese maker,
-// `soMakeCheese::changeState(6)` incorrectly pushes `self` as the end cel
-// instead of a cel number to the End cycler. In SSCI, this bad argument would
-// get corrected down to the final cel in the loop by `CycleCueList::init`, but
-// because ScummVM currently always sorts numbers higher than objects, the
-// comparison fails and the cel number is not corrected, so the cycler never
-// calls back and the game softlocks.
-// Here, we fix the call so a proper cel number is given for the second argument
-// instead of a bogus object pointer.
-//
-// Applies to at least: English PC-CD, German PC-CD
-static const uint16 larry7MakeCheeseCyclerSignature[] = {
-	0x38, SIG_UINT16(0x04), // pushi 4
-	0x51, 0xc4,             // class End
-	0x36,                   // push
-	SIG_MAGICDWORD,
-	0x7c,                   // pushSelf
-	0x39, 0x04,             // pushi 4
-	0x7c,                   // pushSelf
-	SIG_END
-};
-
-static const uint16 larry7MakeCheeseCyclerPatch[] = {
-	0x39, 0x04, // pushi 4 - save 1 byte
-	0x51, 0xc4, // class End
-	0x36,       // push
-	0x7c,       // pushSelf
-	0x39, 0x04, // pushi 4
-	0x39, 0x10, // pushi $10 (last cel of view 54007, loop 0)
-	PATCH_END
-};
-
-// During the cheese maker cutscene, `soMakeCheese::changeState(2)` sets the
-// priority of ego to 500 to draw him over the cheese maker, but this is also
-// above the guillotine (view 54000, cel 7, priority 400), so ego gets
-// incorrectly drawn on top of the guillotine as well. The cheese maker has a
-// priority of 373, so use priority 374 instead of 500.
-// Applies to at least: English PC-CD, German PC-CD
-// Responsible method: soMakeCheese::changeState(2) in script 540
-static const uint16 larry7MakeCheesePrioritySignature[] = {
-	0x38, SIG_SELECTOR16(setPri),    // pushi setPri
-	SIG_MAGICDWORD,
-	0x78,                            // push1
-	0x38, SIG_UINT16(0x01f4),        // pushi 500
-	SIG_END
-};
-
-static const uint16 larry7MakeCheesePriorityPatch[] = {
-	PATCH_ADDTOOFFSET(+4),           // pushi setPri, push1
-	0x38, PATCH_UINT16(0x0176),      // pushi 374
-	PATCH_END
-};
-
-// LSL7 tries to reset the message type twice at startup, first with a default
-// value in script 0, then with a stored value from larry7.prf (if that file
-// exists) or the same default value (if it does not) in script 64000. Since
-// message type sync relies on the game only setting this value once at startup,
-// we must stop the second attempt or the value from ScummVM will be
-// overwritten.
-// Applies to at least: English CD
-static const uint16 larry7MessageTypeResetSignature[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x02, // ldi 2
-	0xa1, 0x5a, // sag global[$5a]
-	SIG_END
-};
-
-static const uint16 larry7MessageTypeResetPatch[] = {
-	0x33, 0x02, // jmp [past reset]
-	PATCH_END
-};
-
-// LSL7 Russian by Softclub can crash when Peggy catches Larry in room 551 after
-//  Jamie receives the polyester. This is a script bug that exists in every
-//  version of the game, but the Softclub release happens to have a sync
-//  resource with an internal value that exposes the problem.
-//
-// When talking to Peggy on the deck in room 261, MouthSync:oSpecialSync is set
-//  to coHandleLaugh to handle Peggy's laugh animation, but the script fails to
-//  clear this property. The only other place that uses this feature is room 256
-//  where oSpecialSync is correctly cleared. MouthSync:doit cues oSpecialSync
-//  whenever a sync resource has a cue value >= 8.  After talking to Peggy, any
-//  sync with a cue value of 9 causes coHandleLaugh to draw Peggy laughing in
-//  the wrong room and crash the game due to an invalid plane. In the English
-//  version this never came up because no other syncs contain a 9, but two of
-//  Peggy's Russian syncs in room 551 contain a 9 cue.
-//
-// We fix this by clearing MouthSync:oSpecialSync when exiting room 261. This
-//  also fixes script 261 never unloading. This patch applies to all PC versions
-//  but not Mac, since Mac scripts were compiled without debugging instructions.
-//  There is no need for a Mac patch since that version is only in English.
-//
-// Applies to: All PC versions
-// Responsible method: ro261:dispose
-// Fixes bug: #13209
-static const uint16 larry7PeggySyncHandlerSignature[] = {
-	0x7d, SIG_ADDTOOFFSET(+7),              // file "261.sc"
-	0x7e, SIG_ADDTOOFFSET(+2),              // line
-	0x35, SIG_MAGICDWORD, 0x00,             // ldi 00
-	0xa0, SIG_UINT16(0x0155),               // sag 0155 [ global341 = 0 ]
-	SIG_END
-};
-
-static const uint16 larry7PeggySyncHandlerPatch[] = {
-	0x38, PATCH_SELECTOR16(oSpecialSync),   // pushi oSpecialSync
-	0x39, 0x01,                             // pushi 01
-	0x76,                                   // push0
-	0x51, 0x27,                             // class MouthSync
-	0x4a, PATCH_UINT16(0x0006),             // send 06 [ MouthSync oSpecialSync: 0 ]
-	PATCH_END
-};
-
-//          script, description,                                signature                           patch
-static const SciScriptPatcherEntry larry7Signatures[] = {
-	{  true,     0, "disable message type reset on startup", 1, larry7MessageTypeResetSignature,    larry7MessageTypeResetPatch },
-	{  true,   261, "fix peggy sync handler",                1, larry7PeggySyncHandlerSignature,    larry7PeggySyncHandlerPatch },
-	{  true,   540, "fix make cheese cutscene (cycler)",     1, larry7MakeCheeseCyclerSignature,    larry7MakeCheeseCyclerPatch },
-	{  true,   540, "fix make cheese cutscene (priority)",   1, larry7MakeCheesePrioritySignature,  larry7MakeCheesePriorityPatch },
-	{  true, 64000, "disable volume reset on startup (1/2)", 1, larry7VolumeResetSignature1,        larry7VolumeResetPatch1 },
-	{  true, 64000, "disable volume reset on startup (2/2)", 1, larry7VolumeResetSignature2,        larry7VolumeResetPatch2 },
-	{  true, 64866, "increase number of save games",         1, torinLarry7NumSavesSignature,       torinLarry7NumSavesPatch },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-#endif
-
-// ===========================================================================
-// Laura Bow 1 - Colonel's Bequest
-//
-// This is basically just a broken easter egg in Colonel's Bequest.
-// A plane can show up in room 4, but that only happens really rarely.
-// Anyway the Sierra developer seems to have just entered the wrong loop,
-// which is why the statue view is used instead (loop 0).
-// We fix it to use the correct loop.
-//
-// This is only broken in the PC version. It was fixed for Amiga + Atari ST.
-//
-// Credits to OmerMor, for finding it.
-//
-// Applies to at least: English PC Floppy
-// Responsible method: room4::init
-static const uint16 laurabow1SignatureEasterEggViewFix[] = {
-	0x78,                               // push1
-	0x76,                               // push0
-	SIG_MAGICDWORD,
-	0x38, SIG_SELECTOR16(setLoop),      // pushi setLoop
-	0x78,                               // push1
-	0x39, 0x03,                         // pushi 3 (loop 3, view only has 3 loops)
-	SIG_END
-};
-
-static const uint16 laurabow1PatchEasterEggViewFix[] = {
-	PATCH_ADDTOOFFSET(+7),
-	0x02,                               // (change loop to 2)
-	PATCH_END
-};
-
-// When oiling the armor or opening the visor of the armor, the scripts first
-//  check if Laura/ego is near the armor and if she is not, they will move her
-//  to the armor. After that, further code is executed.
-//
-// The current location is checked by a ego::inRect() call.
-//
-// The given rect for the inRect call inside openVisor::changeState was made
-//  larger for Atari ST/Amiga versions. We change the PC version to use the
-//  same rect.
-//
-// Additionally, the coordinate that Laura is moved to (152, 107) may not be
-//  reachable depending on where Laura was when "use oil on helmet of armor"
-//  or "open visor of armor" got entered. Bad coordinates such as (82, 110),
-//  cause collisions and effectively an endless loop, effectively freezing the
-//  game. The user is only able to restore a previous game.
-//
-//  We change the destination coordinate to (152, 110), which seems to be
-//   reachable all the time.
-//
-// The following patch fixes the rect for the PC version of the game.
-//
-// Applies to at least: English PC Floppy
-// Responsible method: openVisor::changeState (script 37)
-// Fixes bug: #7119
-static const uint16 laurabow1SignatureArmorOpenVisorFix[] = {
-	0x39, 0x04,                         // pushi 04
-	SIG_MAGICDWORD,
-	0x39, 0x6a,                         // pushi 6a (106d)
-	0x38, SIG_UINT16(0x0096),           // pushi 0096 (150d)
-	0x39, 0x6c,                         // pushi 6c (108d)
-	0x38, SIG_UINT16(0x0098),           // pushi 0098 (152d)
-	SIG_END
-};
-
-static const uint16 laurabow1PatchArmorOpenVisorFix[] = {
-	PATCH_ADDTOOFFSET(+2),
-	0x39, 0x68,                         // pushi 68 (104d)   (-2)
-	0x38, PATCH_UINT16(0x0094),         // pushi 0094 (148d) (-2)
-	0x39, 0x6f,                         // pushi 6f (111d)   (+3)
-	0x38, PATCH_UINT16(0x009a),         // pushi 009a (154d) (+2)
-	PATCH_END
-};
-
-// This here fixes the destination coordinate (exact details are above).
-//
-// Applies to at least: English PC Floppy, English Atari ST Floppy, English Amiga Floppy
-// Responsible method: openVisor::changeState, oiling::changeState (script 37)
-// Fixes bug: #7119
-static const uint16 laurabow1SignatureArmorMoveToFix[] = {
-	SIG_MAGICDWORD,
-	0x36,                               // push
-	0x39, 0x6b,                         // pushi 6B (107d)
-	0x38, SIG_UINT16(0x0098),           // pushi 98 (152d)
-	0x7c,                               // pushSelf
-	0x81, 0x00,                         // lag global[0]
-	SIG_END
-};
-
-static const uint16 laurabow1PatchArmorMoveToFix[] = {
-	PATCH_ADDTOOFFSET(+1),
-	0x39, 0x6e,                         // pushi 6E (110d) - adjust x, so that no collision can occur anymore
-	PATCH_END
-};
-
-// When oiling the left arm of the armor that holds the axe, pressing 'E' to
-//  exit the screen leaves input disabled in the PC version. The local procedure
-//  that restores room 37 enables directional control but not input when the axe
-//  arm is is oiled. Sierra fixed this in the Amiga and Atari ST versions by
-//  adding a call to User:canInput(1) so that the procedure always enables both.
-//
-// We also fix this by enabling both control and input, but we do it by calling
-//  the HandsOn procedure instead, which this procedure already does in every
-//  case except the buggy one when the axe arm is being oiled. We simply patch
-//  out the tests that prevent HandsOn from being called when it's needed.
-//
-// Applies to: English PC Floppy
-// Responsible method: 3rd subroutine in script 37, called by Room37:handleEvent
-// Fixes bug: #7154
-static const uint16 laurabow1SignatureArmorOilingArmFix[] = {
-	SIG_MAGICDWORD,
-	0x72, SIG_UINT16(0x18f3),           // lofsa valve [ included offset so that only PC version is patched ]
-	0x4a, 0x04,                         // send 04 [ valve hide: ]
-	0x8b, 0x34,                         // lsl 34  [ oil-target ]
-	0x35, 0x02,                         // ldi 02  [ left arm ]
-	0x1c,                               // ne?
-	0x30, SIG_UINT16(0x0014),           // bnt 0014 [ skip HandsOn if oiled left arm ]
-	SIG_ADDTOOFFSET(+0x10),             // [ more oil-target tests: left elbow, axe ]
-	0x76,                               // push0
-	0x45, 0x04, 0x00,                   // callb proc0_4 [ HandsOn ]
-	0x48,                               // ret
-	SIG_END
-};
-
-static const uint16 laurabow1PatchArmorOilingArmFix[] = {
-	PATCH_ADDTOOFFSET(+5),
-	0x33, 0x16,                         // jmp 16 [ always call HandsOn ]
-	PATCH_END
-};
-
-// Jeeves lights the chapel candles (room 58) in act 2 but they don't stay
-//  lit when re-entering until the next act. This is due to Room58:init
-//  incorrectly testing the global variable that tracks Jeeves' act 2 state.
-//
-// We fix this by changing the test from if global[155] equals 11, which it
-//  never does, to if it's greater than 11. The global is set to 12 in
-//  lightCandles:changeState(11) and it continues to increment as Jeeves'
-//  chore sequence progresses, ending with 17.
-//
-// Applies to: DOS, Amiga, Atari ST
-// Responsible method: Room58:init
-// Fixes bug: #10743
-static const uint16 laurabow1SignatureChapelCandlesPersistence[] = {
-	SIG_MAGICDWORD,
-	0x89, 0x9b,                         // lsg global[155] [ Jeeves' act 2 state ]
-	0x35, 0x0b,                         // ldi b
-	0x1a,                               // eq?
-	SIG_END
-};
-
-static const uint16 laurabow1PatchChapelCandlesPersistence[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x1e,                               // gt?
-	PATCH_END
-};
-
-// LB1 DOS doesn't acknowledge Lillian's presence in room 44 when she's sitting
-//  on the bed in act 4. Look, talk, etc respond that she's not there.
-//  This is due to not setting global[195] which tracks who is in the room.
-//  We fix this by setting the global as Amiga and Atari ST versions do.
-//
-// Applies to: DOS only
-// Responsible method: Room44:init
-// Fixes bug: #10742
-static const uint16 laurabow1SignatureLillianBedFix[] = {
-	SIG_MAGICDWORD,
-	0x72, SIG_UINT16(0x10f8),           // lofsa suit2 [ only matches DOS version ]
-	0x4a, 0x14,                         // send 14
-	SIG_ADDTOOFFSET(+8),
-	0x89, 0x76,                         // lsg global[118]
-	0x35, 0x02,                         // ldi 2
-	0x12,                               // and
-	0x30, SIG_UINT16(0x000d),           // bnt d [ haven't seen Lillian in study ]
-	0x35, 0x01,                         // ldi 1
-	SIG_END
-};
-
-static const uint16 laurabow1PatchLillianBedFix[] = {
-	PATCH_ADDTOOFFSET(+13),
-	0x81, 0x76,                         // lag global[118]
-	0x7a,                               // push2
-	0x12,                               // and
-	0x31, 0x0f,                         // bnt f [ haven't seen Lillian in study ]
-	0x35, 0x20,                         // ldi 20 [ Lillian ]
-	0xa1, 0xc3,                         // sag global[195] [ set Lillian as in the room ]
-	PATCH_END
-};
-
-// Entering Laura's bedroom resets the cursor position to the upper right corner
-//  of the screen as if the game were starting. Room44:init calls kSetCursor to
-//  initialize the game because it's the first room where the user has control,
-//  but this part of the script is missing the startup test and so it happens
-//  every time. We fix this by adding the missing startup test.
-//
-// Applies to: All versions
-// Responsible method: Room44:init
-static const uint16 laurabow1SignatureRoom44CursorFix[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x00,                         // ldi 00
-	0xa1, 0xbe,                         // sag be [ global190 = 0 ]
-	0x39, SIG_SELECTOR8(init),          // pushi init
-	0x76,                               // push0
-	0x57, 0x37, 0x04,                   // super Rm 04 [ super init: ]
-	SIG_ADDTOOFFSET(+10),
-	0x43, 0x28, 0x08,                   // callk SetCursor 08 [ SetCursor 997 1 300 0 ]
-	SIG_ADDTOOFFSET(+439),
-	0x89, 0xa5,                         // lsg a5
-	0x35, 0x00,                         // ldi 00
-	0x1a,                               // eq?
-	0x30,                               // bnt
-	SIG_END
-};
-
-static const uint16 laurabow1PatchRoom44CursorFix[] = {
-	0x39, PATCH_SELECTOR8(init),        // pushi init
-	0x76,                               // push0
-	0x57, 0x37, 0x04,                   // super Rm 04 [ super init: ]
-	0x81, 0xcb,                         // lag cb [ global203 == 0 when game is starting ]
-	0x2f, 0x0d,                         // bt 0d  [ skip SetCursor if game already started ]
-	PATCH_ADDTOOFFSET(+452),
-	0x76,                               // push0
-	0xa9, 0xbe,                         // ssg be [ global190 = 0 ]
-	0x81, 0xa5,                         // lag a5
-	0x2e,                               // bt
-	PATCH_END
-};
-
-// When you tell Lilly about Gertie in room 35, Lilly will then walk to the
-// left and off the screen. If Laura (ego) is in the way, the whole game will
-// basically block and you won't be able to do anything except saving or
-// restoring the game.
-//
-// If this happened already, the player can enter "send Lillian ignoreActors 1"
-// inside the debugger to fix this situation.
-//
-// This issue is very difficult to solve, because Lilly also walks diagonally
-// after walking to the left right under the kitchen table. This means that
-// even if we added a few more rectangle checks, there could still be spots,
-// where the game would block.
-//
-// Also the mover "PathOut" is used for Lillian instead of the regular
-// "MoveTo", which would avoid other actors by itself.
-//
-// So instead we set Lilly to ignore other actors during that cutscene, which
-// is the least invasive solution.
-//
-// Applies to at least: English PC Floppy, English Amiga Floppy, English Atari ST Floppy
-// Responsible method: goSee::changeState(1) in script 236
-// Fixes bug: (happened during GOG Let's Play)
-static const uint16 laurabow1SignatureTellLillyAboutGerieBlockingFix1[] = {
-	0x7a,                               // puah2
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x00c1),           // pushi 00C1h
-	0x38, SIG_UINT16(0x008f),           // pushi 008Fh
-	0x38, SIG_SELECTOR16(ignoreActors), // pushi ignoreActors
-	0x78,                               // push1
-	0x76,                               // push0
-	SIG_END
-};
-
-static const uint16 laurabow1PatchTellLillyAboutGertieBlockingFix1[] = {
-	PATCH_ADDTOOFFSET(+11),             // skip over until push0
-	0x78,                               // push1 (change push0 to push1)
-	PATCH_END
-};
-
-// a second patch to call Lillian::ignoreActors(1) on goSee::changeState(9) in script 236
-static const uint16 laurabow1SignatureTellLillyAboutGerieBlockingFix2[] = {
-	0x3c,                               // dup
-	0x35, 0x09,                         // ldi 09
-	0x1a,                               // eq?
-	0x30, SIG_UINT16(0x003f),           // bnt [ret]
-	0x39, SIG_ADDTOOFFSET(+1),          // pushi view
-	0x78,                               // push1
-	0x38, SIG_UINT16(0x0203),           // pushi 203h (515d)
-	0x38, SIG_ADDTOOFFSET(+2),          // pushi posn
-	0x7a,                               // push2
-	0x38, SIG_UINT16(0x00c9),           // pushi C9h (201d)
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x0084),           // pushi 84h (132d)
-	0x72, SIG_ADDTOOFFSET(+2),          // lofsa Lillian (different offsets for different platforms)
-	0x4a, 0x0e,                         // send 0Eh
-	SIG_END
-};
-
-static const uint16 laurabow1PatchTellLillyAboutGertieBlockingFix2[] = {
-	0x38, PATCH_SELECTOR16(ignoreActors), // pushi ignoreActors
-	0x78,                                 // push1
-	0x76,                                 // push0
-	0x33, 0x00,                           // ldi 00 (waste 2 bytes)
-	PATCH_ADDTOOFFSET(+19),               // skip over until send
-	0x4a, 0x14,                           // send 14h
-	PATCH_END
-};
-
-// LB1 contains over 20 commands which lockup the game if entered while ego is
-//  colliding with an obstacle. Opening and moving closets in room 43 are prime
-//  examples. They are all symptoms of a global bug.
-
-// Every cycle, CB1:doit checks to see if ego appears to be walking and blocked,
-//  and if so it stops ego's motion and sets ego's view to 11 (standing). If ego
-//  has just collided with an obstacle but is still displaying view 1 (walking)
-//  when a command is entered which disables input and sets ego's motion without
-//  setting an avoider then CB1:doit will stop that new motion at the start of
-//  the next cycle and lockup the game. This occurs in part because CB1:doit
-//  tests potentially stale values that the new motion hasn't yet had a chance
-//  to set. Scripts which set an avoider aren't vulnerable because CB1:doit
-//  won't stop ego if one is set. Other SCI games don't have this kind of code
-//  in their Game's doit and so they don't have this bug.
-
-// We fix this by clearing the kSignalHitObstacle flag whenever Act:setMotion is
-//  called with a new motion. This causes CB1:doit's subsequent call to
-//  ego:isBlocked to return false, instead of a stale true value, preventing
-//  CB1:doit from stopping the new motion before it's had a chance to start.
-//  Should the new motion actually be blocked then the interpreter will then set
-//  the flag when processing the motion as usual. This patch closes the short
-//  window during which this value is stale and CB1:doit tests it.
-
-// Applies to: DOS, Amiga, Atari ST and occurs in Sierra's interpreter.
-// Responsible method: Act:setMotion
-// Fixes bug: #10733
-static const uint16 laurabow1SignatureObstacleCollisionLockupsFix[] = {
-	SIG_MAGICDWORD,
-	0x30, SIG_UINT16(0x002f),           // bnt 2f
-	0x38, SIG_UINT16(0x00a3),           // pushi a3 [ startUpd ]
-	0x76,                               // push0
-	0x54, 0x04,                         // self 4
-	0x7a,                               // push2 [ -info- ]
-	0x76,                               // push0
-	0x87, 0x01,                         // lap param[1]
-	0x4a, 0x04,                         // send 4
-	0x36,                               // push
-	0x34, SIG_UINT16(0x8000),           // ldi 8000
-	0x12,                               // and
-	0x30, SIG_UINT16(0x000a),           // bnt a
-	0x39, 0x56,                         // pushi 56 [ new ]
-	0x76,                               // push0
-	0x87, 0x01,                         // lap param[1]
-	0x4a, 0x04,                         // send 4
-	0x32, SIG_UINT16(0x0002),           // jmp 2
-	0x87, 0x01,                         // lap param[1]
-	0x65, 0x4c,                         // aTop mover
-	0x39, 0x57,                         // pushi 57 [ init ]
-	0x78,                               // push1
-	0x7c,                               // pushSelf
-	0x59, 0x02,                         // &rest 2
-	0x63, 0x4c,                         // pToa mover
-	0x4a, 0x06,                         // send 6
-	0x32, SIG_UINT16(0x0004),           // jmp 4
-	0x35, 0x00,                         // ldi 0
-	SIG_END
-};
-
-static const uint16 laurabow1PatchObstacleCollisionLockupsFix[] = {
-	0x31, 0x32,                         // bnt 32 [ save 1 byte ]
-
-	0x63, 0x1c,                         // pToa signal
-	0x38, PATCH_UINT16(0xfbff),         // pushi fbff
-	0x12,                               // and
-	0x65, 0x1c,                         // aTop signal [ clear kSignalHitObstacle (0400) ]
-
-	0x38, PATCH_UINT16(0x00a3),         // pushi a3 [ startUpd ]
-	0x76,                               // push0
-	0x54, 0x04,                         // self 4
-	0x7a,                               // push2 [ -info- ]
-	0x76,                               // push0
-	0x87, 0x01,                         // lap param[1]
-	0x4a, 0x04,                         // send 4
-	0x38, PATCH_UINT16(0x8000),         // pushi 8000 [ save 1 byte ]
-	0x12,                               // and
-	0x31, 0x09,                         // bnt 9 [ save 1 byte ]
-	0x39, 0x56,                         // pushi 56 [ new ]
-	0x76,                               // push0
-	0x87, 0x01,                         // lap param[1]
-	0x4a, 0x04,                         // send 4
-	0x33, 0x02,                         // jmp 2 [ save 1 byte ]
-	0x87, 0x01,                         // lap param[1]
-	0x65, 0x4c,                         // aTop mover
-	0x39, 0x57,                         // pushi 57 [ init ]
-	0x78,                               // push1
-	0x7c,                               // pushSelf
-	0x59, 0x02,                         // &rest 2
-	0x63, 0x4c,                         // pToa mover
-	0x4a, 0x06,                         // send 6
-	0x48,                               // ret  [ save 4 bytes ]
-	PATCH_END
-};
-
-// Laura can get stuck walking up the attic stairs diagonally in room 47 and
-//  lockup the game. This also occurs in the original. Room47:doit loads the
-//  attic when ego is on control $10 at the base of the stairs and facing north.
-//  Room47:handleEvent prevents the user from moving ego when on control $10.
-//  Walking up the stairs diagonally puts ego in control $10 facing left or
-//  right and so the room never changes and the user never regains control.
-//
-// We fix this by allowing ego to face any direction except south to trigger the
-//  attic room change. This also fixes an edge case that allows walking through
-//  the staircase wall into Clarence's room.
-//
-// Applies to: DOS, Amiga, Atari ST
-// Responsible method: Room47:doit
-// Fixes bug: #9949
-static const uint16 laurabow1SignatureAtticStairsLockupFix[] = {
-	SIG_MAGICDWORD,
-	0x39, SIG_SELECTOR8(loop),          // pushi loop
-	0x76,                               // push0
-	0x81, 0x00,                         // lag global[0]
-	0x4a, 0x04,                         // send 4 [ ego:loop? ]
-	0x36,                               // push
-	0x35, 0x03,                         // ldi 03 [ facing north ]
-	0x1a,                               // eq?
-	SIG_END
-};
-
-static const uint16 laurabow1PatchAtticStairsLockupFix[] = {
-	PATCH_ADDTOOFFSET(+8),
-	0x35, 0x02,                         // ldi 02 [ facing south ]
-	0x1c,                               // ne?
-	PATCH_END
-};
-
-// Laura can get stuck at the top of the left stairs in room 47 and lockup the
-//  game. This also occurs in the original. There is a 30x2 control area at the
-//  top of the stairs in which Room47:handleEvent prevents input. This assumes
-//  that ego can't be interrupted when walking through the area, but there is a
-//  notch in the left wall that ego can collide with, leaving ego stuck with
-//  input disabled. The right wall doesn't have a notch.
-//
-// We fix this by allowing input at the top of the stairs. Up and down movements
-//  are allowed when on the staircase's control area ($0200) and we extend that
-//  to include the top of the stairs ($0800).
-//
-// Applies to: DOS, Amiga, Atari ST
-// Responsible method: Room47:handleEvent
-// Fixes bug #10879
-static const uint16 laurabow1SignatureLeftStairsLockupFix[] = {
-	SIG_MAGICDWORD,
-	0x34, SIG_UINT16(0x0200),           // ldi 0200 [ left stairs ]
-	0x1a,                               // eq? [ is ego entirely on the stairs? ]
-	SIG_END
-};
-
-static const uint16 laurabow1PatchLeftStairsLockupFix[] = {
-	0x34, PATCH_UINT16(0x0a00),         // ldi 0a00 [ left stairs | top of left stairs ]
-	0x12,                               // and [ is ego touching the stairs or the top? ]
-	PATCH_END
-};
-
-// LB1's fingerprint copy protection randomly rejects the correct answer and may
-//  even fail to draw a fingerprint. myCopy:init selects the fingerprint by
-//  generating random loop and cel numbers for view 553, but it passes incorrect
-//  ranges to kRandom. If kRandom returns the maximum value then the loop or cel
-//  overflow and a different image is displayed than what was intended.
-//
-// We correct the ranges from 0-600 and 1-1000 to 0-599 and 0-999 so that
-//  invalid cel 6 and loop 10 are never used after the script divides by 10.
-//
-// Applies to: DOS, Amiga, Atari ST
-// Responsible method: myCopy:init
-static const uint16 laurabow1SignatureCopyProtectionRandomFix[] = {
-	0x38, SIG_UINT16(0x0258),           // pushi 600d
-	SIG_ADDTOOFFSET(+10),
-	SIG_MAGICDWORD,
-	0x78,                               // push1
-	0x38, SIG_UINT16(0x03e8),           // pushi 1000d
-	SIG_END
-};
-
-static const uint16 laurabow1PatchCopyProtectionRandomFix[] = {
-	0x38, PATCH_UINT16(0x0257),         // pushi 599d
-	PATCH_ADDTOOFFSET(+10),
-	0x76,                               // push0
-	0x38, PATCH_UINT16(0x03e7),         // pushi 999d
-	PATCH_END
-};
-
-// At the end of the game a dialog asks if you'd like to review your notes.
-//  Pressing the escape key dismisses the dialog and locks up the game with the
-//  menu and input disabled. The script is missing a handler for this result.
-//  We fix this by repeating the dialog when escape is pressed, just like the
-//  other dialogs do in room 786. Sierra fixed this in later versions.
-//
-// Applies to: DOS
-// Responsible method: Notes:changeState(1)
-static const uint16 laurabow1SignatureReviewNotesDialog[] = {
-	0x39, 0x0f,                         // pushi 0f
-	SIG_ADDTOOFFSET(+0x20),
-	SIG_MAGICDWORD,
-	0x7a,                               // push2
-	0x47, 0xff, 0x00, 0x1e,             // calle proc255_0 [ print dialog ]
-	0x36,                               // push
-	0x3c,                               // dup
-	0x35, 0x01,                         // ldi 01
-	0x1a,                               // eq?
-	SIG_END
-};
-
-static const uint16 laurabow1PatchReviewNotesDialog[] = {
-	PATCH_ADDTOOFFSET(+0x27),
-	0x31, 0xd7,                         // bnt -29 [ repeat dialog if escape pressed ]
-	0x36,                               // push
-	0x78,                               // push1
-	PATCH_END
-};
-
-//          script, description,                                signature                                             patch
-static const SciScriptPatcherEntry laurabow1Signatures[] = {
-	{  true,     4, "easter egg view fix",                      1, laurabow1SignatureEasterEggViewFix,                laurabow1PatchEasterEggViewFix },
-	{  true,    37, "armor open visor fix",                     1, laurabow1SignatureArmorOpenVisorFix,               laurabow1PatchArmorOpenVisorFix },
-	{  true,    37, "armor move to fix",                        2, laurabow1SignatureArmorMoveToFix,                  laurabow1PatchArmorMoveToFix },
-	{  true,    37, "allowing input, after oiling arm",         1, laurabow1SignatureArmorOilingArmFix,               laurabow1PatchArmorOilingArmFix },
-	{  true,    44, "lillian bed fix",                          1, laurabow1SignatureLillianBedFix,                   laurabow1PatchLillianBedFix },
-	{  true,    44, "room 44 cursor fix",                       1, laurabow1SignatureRoom44CursorFix,                 laurabow1PatchRoom44CursorFix },
-	{  true,    47, "attic stairs lockup fix",                  1, laurabow1SignatureAtticStairsLockupFix,            laurabow1PatchAtticStairsLockupFix },
-	{  true,    47, "left stairs lockup fix",                   3, laurabow1SignatureLeftStairsLockupFix,             laurabow1PatchLeftStairsLockupFix },
-	{  true,    58, "chapel candles persistence",               1, laurabow1SignatureChapelCandlesPersistence,        laurabow1PatchChapelCandlesPersistence },
-	{  true,    99, "disable speed test",                       1, sci01SpeedTestGlobalSignature,                     sci01SpeedTestGlobalPatch },
-	{  true,   236, "tell Lilly about Gertie blocking fix 1/2", 1, laurabow1SignatureTellLillyAboutGerieBlockingFix1, laurabow1PatchTellLillyAboutGertieBlockingFix1 },
-	{  true,   236, "tell Lilly about Gertie blocking fix 2/2", 1, laurabow1SignatureTellLillyAboutGerieBlockingFix2, laurabow1PatchTellLillyAboutGertieBlockingFix2 },
-	{  true,   414, "copy protection random fix",               1, laurabow1SignatureCopyProtectionRandomFix,         laurabow1PatchCopyProtectionRandomFix },
-	{  true,   786, "review notes dialog fix",                  1, laurabow1SignatureReviewNotesDialog,               laurabow1PatchReviewNotesDialog },
-	{  true,   998, "obstacle collision lockups fix",           1, laurabow1SignatureObstacleCollisionLockupsFix,     laurabow1PatchObstacleCollisionLockupsFix },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
-// ===========================================================================
-// Laura Bow 2
-//
-// Moving away the painting in the room with the hidden safe is problematic
-//  for the CD version of the game. safePic::doVerb gets triggered by the mouse-click.
-// This method sets local[0] as signal, which is only meant to get handled, when
-//  the player clicks again to move the painting back. This signal is processed by
-//  the room doit-script.
-// That doit-script checks safePic::cel to be not equal 0 and would then skip over
-//  the "close painting" trigger code. On very fast computers this script may
-//  get called too early (which is the case when running under ScummVM and when
-//  running the game using Sierra SCI in DOS-Box with cycles 15000) and thinks
-//  that it's supposed to move the painting back. Which then results in the painting
-//  getting moved to its original position immediately (which means it won't be possible
-//  to access the safe behind it).
-//
-// We patch the script, so that we check for cel to be not equal 4 (the final cel) and
-//  we also reset the safePic-signal immediately as well.
-//
-// In the floppy version Laura's coordinates are checked directly in rm560::doit
-//  and as soon as she moves, the painting will automatically move to its original position.
-//  This is not the case for the CD version of the game. The painting will only "move" back,
-//  when the player actually exits the room and re-enters.
-//
-// Applies to at least: English PC-CD
-// Responsible method: rm560::doit
-// Fixes bug: #6460
-static const uint16 laurabow2CDSignaturePaintingClosing[] = {
-	0x39, 0x04,                         // pushi 04 (cel)
-	0x76,                               // push0
-	SIG_MAGICDWORD,
-	0x7a,                               // push2
-	0x38, SIG_UINT16(0x0231),           // pushi 0231h (561)
-	0x76,                               // push0
-	0x43, 0x02, 0x04,                   // callk ScriptID, 04 (get export 0 of script 561)
-	0x4a, 0x04,                         // send 04 (gets safePicture::cel)
-	0x18,                               // not
-	0x31, 0x21,                         // bnt [exit]
-	0x38, SIG_UINT16(0x0283),           // pushi 0283h
-	0x76,                               // push0
-	0x7a,                               // push2
-	0x39, 0x20,                         // pushi 20
-	0x76,                               // push0
-	0x43, 0x02, 0x04,                   // callk ScriptID, 04 (get export 0 of script 32)
-	0x4a, 0x04,                         // send 04 (get sHeimlich::room)
-	0x36,                               // push
-	0x81, 0x0b,                         // lag global[b] (current room)
-	0x1c,                               // ne?
-	0x31, 0x0e,                         // bnt [exit]
-	0x35, 0x00,                         // ldi 00
-	0xa3, 0x00,                         // sal local[0] (reset safePic signal)
-	SIG_END
-};
-
-static const uint16 laurabow2CDPatchPaintingClosing[] = {
-	PATCH_ADDTOOFFSET(+2),
-	0x3c,                               // dup (1 additional byte)
-	0x76,                               // push0
-	0x3c,                               // dup (1 additional byte)
-	0xab, 0x00,                         // ssl local[0] (reset safePic signal)
-	0x7a,                               // push2
-	0x38, PATCH_UINT16(0x0231),         // pushi 0231h (561)
-	0x76,                               // push0
-	0x43, 0x02, 0x04,                   // callk ScriptID, 04 (get export 0 of script 561)
-	0x4a, 0x04,                         // send 04 (gets safePicture::cel)
-	0x1a,                               // eq?
-	0x31, 0x1d,                         // bnt [exit]
-	0x38, PATCH_UINT16(0x0283),         // pushi 0283h
-	0x76,                               // push0
-	0x7a,                               // push2
-	0x39, 0x20,                         // pushi 20
-	0x76,                               // push0
-	0x43, 0x02, 0x04,                   // callk ScriptID, 04 (get export 0 of script 32)
-	0x4a, 0x04,                         // send 04 (get sHeimlich::room)
-	0x36,                               // push
-	0x81, 0x0b,                         // lag global[b] (current room)
-	0x1a,                               // eq? (2 opcodes changed, to save 2 bytes)
-	0x2f, 0x0a,                         // bt [exit]
-	PATCH_END
-};
-
-// In the CD version the system menu is disabled for certain rooms. LB2::handsOff is called,
-//  when leaving the room (and in other cases as well). This method remembers the disabled
-//  icons of the icon bar. In the new room LB2::handsOn will get called, which then enables
-//  all icons, but also disabled the ones, that were disabled before.
-//
-// Because of this behaviour certain rooms, that should have the system menu enabled, have
-//  it disabled, when entering those rooms from rooms, where the menu is supposed to be
-//  disabled.
-//
-// We patch this by injecting code into LB2::newRoom (which is called right after a room change)
-//  and reset the global variable there, that normally holds the disabled buttons.
-//
-// This patch may cause side-effects and it's difficult to test, because it affects every room
-//  in the game. At least for the intro, the speakeasy and plenty of rooms in the beginning it
-//  seems to work correctly.
-//
-// Applies to at least: English PC-CD
-// Responsible method: LB2::newRoom, LB2::handsOff, LB2::handsOn
-// Fixes bug: #6440
-static const uint16 laurabow2CDSignatureFixProblematicIconBar[] = {
-	SIG_MAGICDWORD,
-	0x38, SIG_UINT16(0x00f1),           // pushi 00f1 (disable) - hardcoded, we only want to patch the CD version
-	0x76,                               // push0
-	0x81, 0x45,                         // lag global[45]
-	0x4a, 0x04,                         // send 04
-	SIG_END
-};
-
-static const uint16 laurabow2CDPatchFixProblematicIconBar[] = {
-	0x35, 0x00,                      // ldi 00
-	0xa1, 0x74,                      // sag global[74]
-	0x35, 0x00,                      // ldi 00 (waste bytes)
-	0x35, 0x00,                      // ldi 00
-	PATCH_END
-};
-
-// LB2 CD responds with the wrong message when asking Yvette about Tut in acts 3+.
-//
-// aYvette:doVerb(6) tests flag 134, which is set when Pippin dies, to determine
-//  which Tut message to display but they got it backwards. One of the messages
-//  has additional dialogue about Pippin's murder.
-//
-// This is a regression introduced by Sierra when they fixed a bug from the floppy
-//  versions where asking Yvette about Tut in act 2 responds with the message
-//  about Pippin's murder which hasn't occurred yet, bug #10723. Sierra correctly
-//  fixed that in Yvette:doVerb in script 93, which applies to act 2, but then went
-//  on to add incorrect code to aYvette:doVerb in script 90, which applies to the
-//  later acts after the murder.
-//
-// We fix this by reversing the flag test so that the correct message is displayed.
-//
-// Applies to: CD version, at least English
-// Responsible method: aYvette:doVerb
-// Fixes bug: #10724
-static const uint16 laurabow2CDSignatureFixYvetteTutResponse[] = {
-	SIG_MAGICDWORD,
-	0x34, SIG_UINT16(0x010f),           // ldi 010f [ tut ]
-	0x1a,                               // eq? [ asked about tut? ]
-	0x30, SIG_UINT16(0x0036),           // bnt 0036
-	0x78,                               // push1
-	0x38, SIG_UINT16(0x0086),           // pushi 0086 [ pippin-dead flag ]
-	0x45, 0x02, 0x02,                   // callb [export 2 of script 0], 02 [ is pippin-dead flag set? ]
-	0x30, SIG_UINT16(0x0016),           // bnt 0016 [ pippin-dead message ]
-	SIG_END
-};
-
-static const uint16 laurabow2CDPatchFixYvetteTutResponse[] = {
-	PATCH_ADDTOOFFSET(+14),
-	0x2e,                               // bt (replace bnt)
-	PATCH_END
-};
-
-// In the CD version, Wolf stands facing the wrong direction in most scenes.
-//  O'Riley also does this in the Old Masters Gallery. Their views were reduced
-//  from nine loops to five in the CD version, but the scripts weren't updated.
-//  They still set the actors' loops to eight instead of four. kAnimate adjusts
-//  invalid cels and the result is usually the last cel in the last loop, which
-//  is the actor standing facing north west.
-//
-// We fix this by setting the correct loop in the CD version so that Wolf and
-//  O'Riley face the direction the scripts request like in the floppy versions.
-//  This patch is only enabled in the CD version since the scripts don't change.
-//
-// Applies to: English CD
-// Responsible methods: sPartysOver:changeState, rm400:init, sHeimlichShoos:changeState
-//                      sEnterNorth:changeState, rm500:init, rm650:init
-static const uint16 laurabow2CDSignatureFixMuseumActorLoops1[] = {
-	0x38, SIG_SELECTOR16(setLoop),      // pushi setLoop
-	0x78,                               // push1
-	0x39, SIG_MAGICDWORD, 0x08,         // pushi 08 [ standing loop in floppy ]
-	0x38, SIG_SELECTOR16(setCel),       // pushi setCel
-	SIG_END
-};
-
-static const uint16 laurabow2CDPatchFixMuseumActorLoops1[] = {
-	PATCH_ADDTOOFFSET(+4),
-	0x39, 0x04,                         // pushi 04 [ standing loop in CD ]
-	PATCH_END
-};
-
-static const uint16 laurabow2CDSignatureFixMuseumActorLoops2[] = {
-	0x39, SIG_SELECTOR8(loop),          // pushi loop
-	0x78,                               // push1
-	SIG_MAGICDWORD,
-	0x39, 0x08,                         // pushi 08 [ standing loop in floppy ]
-	0x39, SIG_SELECTOR8(cel),           // pushi cel
-	SIG_END
-};
-
-static const uint16 laurabow2CDPatchFixMuseumActorLoops2[] = {
-	PATCH_ADDTOOFFSET(+3),
-	0x39, 0x04,                         // pushi 04 [ standing loop in CD ]
-	PATCH_END
-};
-
-// When entering the main museum party room (w/ the golden Egyptian head), Laura
-// is walking a bit into the room automatically. If you press a mouse button
-// while this is happening, you will get stuck inside that room and won't be
-// able to exit it anymore.
-//
-// Users, who played the game w/ a previous version of ScummVM can simply enter
-// the debugger and then enter "send rm350 script 0:0", which will fix the
-// script state.
-//
-// This is caused by the user controls not being locked at that point. Pressing
-// a button will cause the cue from the PolyPath walker to never happen, which
-// then causes sEnterSouth to never dispose itself.
-//
-// User controls are locked in the previous room 335, but controls are unlocked
-// by frontDoor::cue. We do not want to change this, because it could have
-// side-effects. We instead add another LB2::handsOff call inside the script
-// responsible for Laura's walk into the room (sEnterSouth::changeState(0).
-//
-// Applies to at least: English PC-CD, English PC-Floppy, German PC-Floppy
-// Responsible method: sEnterSouth::changeState
-// Fixes bug: (no bug report, from GOG forum post)
-static const uint16 laurabow2SignatureMuseumPartyFixEnteringSouth1[] = {
-	0x3c,                              // dup
-	0x35, 0x00,                        // ldi 00
-	0x1a,                              // eq?
-	0x30, SIG_UINT16(0x0097),          // bnt [state 1 code]
-	SIG_ADDTOOFFSET(+141),             // skip to end of follow-up code
-	0x32, SIG_ADDTOOFFSET(+2),         // jmp [ret] (0x008d for CD, 0x007d for floppy)
-	0x35, 0x01,                        // ldi 01
-	0x65, 0x1a,                        // aTop cycles
-	0x32, SIG_ADDTOOFFSET(+2),         // jmp [ret] (0x0086 for CD, 0x0076 for floppy)
-	// state 1 code
-	0x3c,                              // dup
-	0x35, 0x01,                        // ldi 01
-	0x1a,                              // eq?
-	SIG_MAGICDWORD,
-	0x31, 0x05,                        // bnt [state 2 code]
-	0x35, 0x00,                        // ldi 00
-	0x32, SIG_ADDTOOFFSET(+2),         // jmp [ret] (0x007b for CD, 0x006b for floppy)
-	// state 2 code
-	0x3c,                              // dup
-	SIG_END
-};
-
-static const uint16 laurabow2PatchMuseumPartyFixEnteringSouth1[] = {
-	0x2e, PATCH_UINT16(0x00a6),        // bt [state 2 code] (we skip state 1, because it's a NOP anyways)
-	// state 0 processing
-	0x32, PATCH_UINT16(0x0097),        // jmp 151d [after this ret]
-	PATCH_ADDTOOFFSET(+149),           // skip to end of follow-up code
-	// save 1 byte by replacing jump to [ret] into straight toss/ret
-	0x3a,                              // toss
-	0x48,                              // ret
-
-	// additional code, that gets called right at the start of step 0 processing
-	0x18,                              // not -- this here is where pushi handsOff will be inserted by the second patch
-	0x18,                              // not    offset and handsOff is different for floppy + CD, that's why we do this
-	0x18,                              // not    floppy also does not have a selector table, so we can't go by "handsOff" name
-	0x18,                              // not
-	0x76,                              // push0
-	0x81, 0x01,                        // lag global[1]
-	0x4a, 0x04,                        // send 04
-	0x32, PATCH_UINT16(0xff5e),        // jmp [back to start of step 0 processing]
-	PATCH_END
-};
-
-// Second patch, which only inserts pushi handsOff inside our new code. There
-// is no other way to do this except making 2 full patches for floppy + CD,
-// because handsOff/handsOn is not the same value between floppy + CD *and*
-// floppy doesn't even have a vocab, so we can't figure out the id by
-// ourselves.
-static const uint16 laurabow2SignatureMuseumPartyFixEnteringSouth2[] = {
-	0x18,                              // our injected code
-	0x18,
-	0x18,
-	SIG_ADDTOOFFSET(+92),              // skip to the handsOn code, that we are interested in
-	0x38, SIG_ADDTOOFFSET(+2),         // pushi handsOn (0x0189 for CD, 0x024b for floppy)
-	0x76,                              // push0
-	0x81, 0x01,                        // lag global[1]
-	0x4a, 0x04,                        // send 04
-	0x38, SIG_ADDTOOFFSET(+2),         // pushi 0274h
-	SIG_MAGICDWORD,
-	0x78,                              // push1
-	0x38, SIG_UINT16(0x033f),          // pushi 033f
-	SIG_END
-};
-
-static const uint16 laurabow2PatchMuseumPartyFixEnteringSouth2[] = {
-	0x38, PATCH_GETORIGINALUINT16ADJUST(+96, -1), // pushi handsOff (@handsOn - 1)
-	PATCH_END
-};
-
-// Opening/Closing the east door in the pterodactyl room doesn't check, if it's
-//  locked and will open/close the door internally even when it is.
-//
-// It will get wired shut later in the game by Laura Bow and will be "locked"
-//  because of this. We patch in a check for the locked state. We also add
-//  code, that will set the "locked" state in case our eastDoor-wired-global is
-//  set. This makes the locked state effectively persistent.
-//
-// Applies to at least: English PC-CD, English PC-Floppy
-// Responsible method (CD): eastDoor::doVerb
-// Responsible method (Floppy): eastDoor::<noname300>
-// Fixes bug: #6458 (partly, see additional patch below)
-static const uint16 laurabow2SignatureFixWiredEastDoor[] = {
-	0x30, SIG_UINT16(0x0022),           // bnt [skip hand action]
-	0x67, SIG_ADDTOOFFSET(+1),          // pTos (CD: doorState, Floppy: state)
-	0x35, 0x00,                         // ldi 00
-	0x1a,                               // eq?
-	0x31, 0x08,                         // bnt [close door code]
-	0x78,                               // push1
-	SIG_MAGICDWORD,
-	0x39, 0x63,                         // pushi 63h
-	0x45, 0x04, 0x02,                   // callb [export 4 of script 0], 02 (sets door-bitflag)
-	0x33, 0x06,                         // jmp [super-code]
-	0x78,                               // push1
-	0x39, 0x63,                         // pushi 63h
-	0x45, 0x03, 0x02,                   // callb [export 3 of script 0], 02 (resets door-bitflag)
-	0x38, SIG_ADDTOOFFSET(+2),          // pushi (CD: 011dh, Floppy: 012ch)
-	0x78,                               // push1
-	0x8f, 0x01,                         // lsp param[1]
-	0x59, 0x02,                         // rest 02
-	0x57, SIG_ADDTOOFFSET(+1), 0x06,    // super (CD: LbDoor, Floppy: Door), 06
-	0x33, 0x0b,                         // jmp [ret]
-	SIG_END
-};
-
-static const uint16 laurabow2PatchFixWiredEastDoor[] = {
-	0x31, 0x23,                         // bnt [skip hand action] (saves 1 byte)
-	0x81, 0x61,                         // lag global[97d] (get our eastDoor-wired-global)
-	0x31, 0x04,                         // bnt [skip setting locked property]
-	0x35, 0x01,                         // ldi 01
-	0x65, 0x6a,                         // aTop locked (set eastDoor::locked to 1)
-	0x63, 0x6a,                         // pToa locked (get eastDoor::locked)
-	0x2f, 0x17,                         // bt [skip hand action]
-	0x63, PATCH_GETORIGINALBYTE(+4),    // pToa (CD: doorState, Floppy: state)
-	0x78,                               // push1
-	0x39, 0x63,                         // pushi 63h
-	0x2f, 0x05,                         // bt [close door code]
-	0x45, 0x04, 0x02,                   // callb [export 4 of script 0], 02 (sets door-bitflag)
-	0x33, 0x0b,                         // jmp [super-code]
-	0x45, 0x03, 0x02,                   // callb [export 3 of script 0], 02 (resets door-bitflag)
-	0x33, 0x06,                         // jmp [super-code]
-	PATCH_END
-};
-
-// We patch in code, so that our eastDoor-wired-global will get set to 1.
-//  This way the wired-state won't get lost when exiting room 430.
-//
-// Applies to at least: English PC-CD, English PC-Floppy
-// Responsible method (CD): sWireItShut::changeState
-// Responsible method (Floppy): sWireItShut::<noname144>
-// Fixes bug: #6458 (partly, see additional patch above)
-static const uint16 laurabow2SignatureRememberWiredEastDoor[] = {
-	SIG_MAGICDWORD,
-	0x33, 0x27,                         // jmp [ret]
-	0x3c,                               // dup
-	0x35, 0x06,                         // ldi 06
-	0x1a,                               // eq?
-	0x31, 0x21,                         // bnt [skip step]
-	SIG_END
-};
-
-static const uint16 laurabow2PatchRememberWiredEastDoor[] = {
-	PATCH_ADDTOOFFSET(+2),              // skip jmp [ret]
-	0x34, PATCH_UINT16(0x0001),         // ldi 0001
-	0xa1, PATCH_UINT16(0x0061),         // sag global[97d] (set our eastDoor-wired-global)
-	PATCH_END
-};
-
-// WORKAROUND: Script needed, because of differences in our pathfinding
-// algorithm
-// It's possible to walk through the closed door in room 448 and enter the crate
-//  room before act 5 due to differences in our pathfinding algorithm from Sierra's.
-//  This edge case appears to be due to one of the door's points being one pixel
-//  within the room's walkable boundary, allowing ego to walk through this edge
-//  from certain positions. We work around this by moving the door's point by
-//  two pixels so that it's outside the room's walkable boundary.
-//
-// Applies to: All Floppy and CD versions
-// Responsible method: transomDoor:createPoly
-// Fixes bug: #9952
-static const uint16 laurabow2SignatureFixArmorHallDoorPathfinding[] = {
-	SIG_MAGICDWORD,
-	0x39, 0x50,                         // pushi 50 [ x =  80 ]
-	0x39, 0x7d,                         // pushi 7d [ y = 125 ]
-	SIG_END
-};
-
-static const uint16 laurabow2PatchFixArmorHallDoorPathfinding[] = {
-	PATCH_ADDTOOFFSET(+2),
-	0x39, 0x7f,                         // pushi 7f [ y = 127 ]
-	PATCH_END
-};
-
-// Clicking most inventory items on the Dagger of Amon Ra case in the Egyptian
-//  exhibit errors the floppy versions. The doVerb methods contain nonsensical
-//  instructions that attempt to access a non-existent class and property.
-//  This would silently fail in the original. It was fixed in the CD version.
-//
-// We patch out the illegal class instructions to avoid the error.
-//
-// Applies to: All floppy versions
-// Responsible methods: glass:doVerb, daggerCase:doVerb
-static const uint16 laurabow2SignatureFixDaggerCaseError[] = {
-	0x81, SIG_MAGICDWORD, 0x5b,         // lag 5b
-	0x4a, 0x0a,                         // send 4a
-	0x33, SIG_ADDTOOFFSET(+1),          // jmp [ end of method ]
-	0x50, SIG_ADDTOOFFSET(+2),          // class ????
-	SIG_END
-};
-
-static const uint16 laurabow2PatchFixDaggerCaseError[] = {
-	PATCH_ADDTOOFFSET(+6),
-	0x18,                               // not [ acc = 1 ]
-	0x3a,                               // toss
-	0x48,                               // ret
-	PATCH_END
-};
-
-// The crate room (room 460) in act 5 locks up the game if you enter from the
-//  elevator (room 660), swing the hanging crate, and then attempt to leave
-//  back through the elevator door.
-//
-// The state of the wall crate that blocks the elevator door is tracked by
-//  setting local[0] to 1 when you push it out of the way, but Sierra forgot
-//  to reinitialize local[0] when you re-enter via the elevator door, causing
-//  it to be out of sync with the room state. When you then swing the hanging
-//  crate, sSwingIt:changeState(6) tests local[0] to see which polygon it
-//  should set as the room's obstacle and incorrectly uses the one that blocks
-//  both doors. Attempting to use the elevator door then locks up the game as
-//  the obstacle polygon prevents ego from reaching the destination.
-//
-// Someone noticed that local[0] wasn't always initialized as
-//  shoveCrate:doVerb(4) tests both local[0] and the previous room to see if it
-//  was the elevator.
-//
-// We fix this by setting local[0] to 1 if the previous room was the elevator
-//  during sSwingIt:changeState(3), just in time before it gets tested in
-//  sSwingIt:changeState(6). Luckily for us, the handlers for states 3 and 4
-//  don't do anything but load zero, making them two consecutive conditions
-//  of no-ops. By merging them into a single condition for state 3 we have
-//  a whopping 13 bytes available to add code to set local[0] correctly.
-//
-// Applies to: All Floppy and CD versions
-// Fixes bug: #10701
-static const uint16 laurabow2SignatureFixCrateRoomEastDoorLockup[] = {
-	0x1a,                               // eq? [ state 3? ]
-	SIG_MAGICDWORD,
-	0x31, 0x05,                         // bnt [ state 4 ]
-	0x35, 0x00,                         // ldi 0
-	0x32, SIG_ADDTOOFFSET(+2),          // jmp [ exit switch. floppy: b3, cd: bb ]
-	0x3c,                               // dup
-	0x35, 0x04,                         // ldi 4
-	0x1a,                               // eq? [ state 4? ]
-	0x31, 0x05,                         // bnt [ state 5 ]
-	SIG_END
-};
-
-static const uint16 laurabow2PatchFixCrateRoomEastDoorLockup[] = {
-	PATCH_ADDTOOFFSET(+1),              // eq? [ state 3? ]
-	0x31, 0x10,                         // bnt [ state 5 ]
-	0x89, 0x0c,                         // lsg global[0c] [ previous room # ]
-	0x34, PATCH_UINT16(0x0294),         // ldi 660d [ elevator room # ]
-	0x1a,                               // eq?
-	0x8b, 0x00,                         // lsl local[0]
-	0x02,                               // add
-	0xa3, 0x00,                         // sal local[0] [ local[0] += (global[0c] == 660d) ]
-	PATCH_END
-};
-
-// Ego can get stuck in the elevator (room 660) by walking to the lower left.
-//  This also happens in Sierra's interpreter. We adjust the room's obstacle
-//  polygon so that ego can't reach the problematic corner positions.
-//  This is a heap patch for the coordinates used in poly2660a:points.
-//
-// Applies to: All Floppy and CD versions
-// Fixes bug: #10702
-static const uint16 laurabow2SignatureFixElevatorLockup[] = {
-	SIG_MAGICDWORD,
-	SIG_UINT16(0x008b),                 // x = 139d
-	SIG_UINT16(0x0072),                 // y = 114d
-	SIG_UINT16(0x007b),                 // x = 123d
-	SIG_UINT16(0x008d),                 // y = 141d
-	SIG_END
-};
-
-static const uint16 laurabow2PatchFixElevatorLockup[] = {
-	PATCH_UINT16(0x008f),               // x = 143d
-	PATCH_ADDTOOFFSET(+4),
-	PATCH_UINT16(0x00aa),               // y = 170d
-	PATCH_END
-};
-
-// The act 4 back rub scene in Yvette's (room 550) locks up the game when
-//  entered from Carrington's (room 560) instead of the hallway (room 510).
-//
-// The difference is that entering from the hallway sets the room script to
-//  eRS (Enter Room Script) and entering from Carrington's doesn't set any
-//  room script. When sBackRubInterrupted moves ego off screen to the south,
-//  lRS (Leave Room Script) is run by LBRoom:doit if a room script isn't set,
-//  and lRS:changState(0) calls handsOff. Since control is already disabled,
-//  this unexpected second handsOff causes handsOn(1) to restore the disabled
-//  state in the hallway and the user never regains control.
-//
-// We fix this by setting sBackRubInterrupted as the room's script instead of
-//  backRub's script in backRub:doVerb/<noname300>(0). The script executes the
-//  same but having it set as the room script prevents LBRoom:doit from running
-//  lRS which prevents the extra handsOff. This patch overwrites backRub's
-//  default verb handler but that's okay because that code never executes.
-//  doVerb is only called by sBackRubViewing:changeState(6) which passes verb 0.
-//  The entire scene is in handsOff mode so the user can't send any verbs.
-//
-// Affects: All Floppy and CD versions
-// Responsible method: backRub:doVerb/<noname300> in script 550
-// Fixes bug: #10729
-static const uint16 laurabow2SignatureFixBackRubEastEntranceLockup[] = {
-	SIG_MAGICDWORD,
-	0x31, 0x0c,                         // bnt 0c    [ unused default verb handler ]
-	0x38, SIG_UINT16(0x0092),           // pushi 0092 [ setScript/<noname146> ]
-	0x78,                               // push1
-	0x72, SIG_ADDTOOFFSET(+2),          // lofsa sBackRubInterrupted [ cd: 0c94, floppy: 0c70 ]
-	0x36,                               // push
-	0x54, 0x06,                         // self 6 [ self:setScript sBackRubInterrupted ]


Commit: c483a688e44519456d56fd3fe95f12fe68be7fce
    https://github.com/scummvm/scummvm/commit/c483a688e44519456d56fd3fe95f12fe68be7fce
Author: Hubert Maier (raziel- at users.noreply.github.com)
Date: 2022-11-01T17:09:25+02:00

Commit Message:
SCI: Correct spelling mistake

Uploaded file with two fixed spelling mistakes

accomodate -> accommodate
firey -> fiery

Changed paths:
  A engines/sci/engine/script_patches.cpp


diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
new file mode 100644
index 00000000000..2454b564bdc
--- /dev/null
+++ b/engines/sci/engine/script_patches.cpp
@@ -0,0 +1,24480 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "sci/sci.h"
+#include "sci/engine/kernel.h"
+#include "sci/engine/script.h"
+#include "sci/engine/state.h"
+#include "sci/engine/features.h"
+#include "sci/engine/script_patches.h"
+#ifdef ENABLE_SCI32
+#include "sci/engine/guest_additions.h"
+#endif
+
+#include "common/util.h"
+
+namespace Sci {
+
+// IMPORTANT:
+// every patch entry needs the following:
+//  - script number (pretty obvious)
+//
+//  - apply count
+//     specifies the number of times a patch is supposed to get applied.
+//     Most of the time, it should be 1.
+//
+//  - magicDWORD + magicOffset
+//     please ALWAYS put 0 for those two. Both will get filled out at runtime by the patcher.
+//
+//  - signature data (is used to identify certain script code, that needs patching)
+//     every signature needs to contain SIG_MAGICDWORD once.
+//      The following 4 bytes after SIG_MAGICDWORD - which don't have to be fixed, you may for example
+//      use SIG_SELECTOR16, will get used to quickly search for a partly match before verifying that
+//      the whole signature actually matches. If it's not included, the script patcher will error() out
+//      right when loading up the game.
+//     If selector-IDs are included, please use SIG_SELECTOR16 + SIG_SELECTOR8 [1]. Simply
+//      specify the selector that way, so that the patcher will search for the specific
+//      selector instead of looking for a hardcoded value. Selectors may not be the same
+//      between game versions.
+//     For UINT16s either use SIG_UINT16 or SIG_SELECTOR16.
+//      Macintosh versions of SCI games are using BE ordering instead of LE since SCI1.1 for UINT16s in scripts
+//      By using those 2 commands, it's possible to make patches work for PC and Mac versions of the same game.
+//     You may also skip bytes by using the SIG_ADDTOOFFSET command
+//     Every signature data needs to get terminated using SIGNATURE_END
+//
+//  - patch data (is used for actually patching scripts)
+//     When a match is found, the patch data will get applied.
+//     Patch data is similar to signature data. Just use PATCH_SELECTOR16 + PATCH_SELECTOR8 [1]
+//      for patching in selectors.
+//     There are also patch specific commands.
+//     Those are PATCH_GETORIGINALBYTE, which fetches a byte from the original script
+//      and PATCH_GETORIGINALBYTEADJUST, which does the same but gets a second value
+//      from the uint16 array and uses that value to adjust the original byte.
+//     Every patch data needs to get terminated using PATCH_END
+//
+//  - and please always add a comment about why the patch was done and what's causing issues.
+//     If possible make sure, that the patch works on localized (or just different) game versions
+//      as well in case those need patching too.
+//
+// [1] - selectors need to get specified in selectorTable[] and ScriptPatcherSelectors-enum
+//        before they can get used using the SIG_SELECTORx and PATCH_SELECTORx commands.
+//        You have to use the exact same order in both the table and the enum, otherwise
+//        it won't work.
+//        ATTENTION: selectors will only work here, when they are also in SelectorCache (selector.h)
+
+static const char *const selectorNameTable[] = {
+	"cycles",       // system selector
+	"seconds",      // system selector
+	"init",         // system selector
+	"dispose",      // system selector
+	"new",          // system selector
+	"curEvent",     // system selector
+	"disable",      // system selector
+	"doit",         // system selector
+	"show",         // system selector
+	"x",            // system selector
+	"cel",          // system selector
+	"setMotion",    // system selector
+	"overlay",      // system selector
+	"setPri",       // system selector - for setting priority
+	"play",         // system selector
+	"number",       // system selector
+	"setScript",    // system selector
+	"setCycle",     // system selector
+	"setStep",      // system selector
+	"cycleSpeed",   // system selector
+	"handsOff",     // system selector
+	"handsOn",      // system selector
+	"type",         // system selector
+	"client",       // system selector
+	"state",        // system selector
+	"localize",     // Freddy Pharkas
+	"roomFlags",    // Iceman
+	"put",          // Police Quest 1 VGA
+	"approachVerbs", // Police Quest 1 VGA, QFG4
+	"newRoom",      // Police Quest 3, GK1
+	"register",     // Quest For Glory 1 EGA, QFG4
+	"changeState",  // Quest For Glory 1 VGA, QFG4
+	"hide",         // Quest For Glory 1 VGA, QFG4
+	"say",          // Quest For Glory 1 VGA, QFG4
+	"script",       // Quest For Glory 1 VGA
+	"isEmpty",      // Quest For Glory 3
+	"solvePuzzle",  // Quest For Glory 3
+	"curIcon",      // Quest For Glory 3, QFG4
+	"curInvIcon",   // Quest For Glory 3, QFG4
+	"startText",    // King's Quest 6 CD / Laura Bow 2 CD for audio+text support
+	"startAudio",   // King's Quest 6 CD / Laura Bow 2 CD for audio+text support
+	"modNum",       // King's Quest 6 CD / Laura Bow 2 CD for audio+text support
+	"handle",       // King's Quest 6 / Laura Bow 2 / RAMA
+	"add",          // King's Quest 6
+	"givePoints",   // King's Quest 6
+	"has",          // King's Quest 6, GK1
+	"modeless",     // King's Quest 6 CD
+	"message",      // King's Quest 6
+	"forceUpd",     // Police Quest 3
+	"cycler",       // Space Quest 4 / system selector
+	"setCel",       // Space Quest 4, Phant2, GK1
+	"addToPic",     // Space Quest 4
+	"stop",         // Space Quest 4
+	"canControl",   // Space Quest 4
+	"looper",       // Space Quest 4
+	"nMsgType",     // Space Quest 4
+	"doVerb",       // Space Quest 4
+	"setRegions",   // Space Quest 4
+	"cursor",       // Space Quest 5
+	"showSelf",     // Space Quest 5
+	"claimed",      // Space Quest 5, QFG4
+	"setCursor",    // Space Quest 5, QFG4
+	"setSpeed",     // Space Quest 5, QFG4
+	"loop",         // Laura Bow 1 Colonel's Bequest, QFG4
+	"setLoop",      // Laura Bow 1 Colonel's Bequest, QFG4
+	"ignoreActors", // Laura Bow 1 Colonel's Bequest
+	"setVol",       // Laura Bow 2 CD
+	"at",           // Longbow, QFG4
+	"owner",        // Longbow, QFG4
+	"fade",         // Longbow, Shivers
+	"enable",       // Longbow, SQ6
+	"delete",       // EcoQuest 1
+	"size",         // EcoQuest 1
+	"signal",       // EcoQuest 1, GK1
+	"obstacles",    // EcoQuest 1, QFG4
+	"handleEvent",  // EcoQuest 2, Shivers
+	"view",         // King's Quest 4, RAMA benchmarking, GK1, QFG4
+#ifdef ENABLE_SCI32
+	"newWith",      // SCI2 array script
+	"posn",         // GK1, Phant2, QFG4
+	"printLang",    // GK2
+	"test",         // Torin
+	"get",          // Torin, GK1
+	"normalize",    // GK1
+	"setReal",      // GK1
+	"set",          // Torin
+	"clear",        // Torin
+	"masterVolume", // SCI2 master volume reset
+	"data",         // Phant2, QFG4
+	"format",       // Phant2
+	"mouseMoved",   // Phant2
+	"setSize",      // Phant2
+	"iconV",        // Phant2
+	"track",        // Phant2
+	"update",       // Phant2
+	"xOff",         // Phant2
+	"addRespondVerb",// KQ7
+	"eachElementDo",// KQ7
+	"fore",         // KQ7
+	"back",         // KQ7
+	"font",         // KQ7
+	"setHeading",   // KQ7
+	"newPic",       // Lighthouse
+	"start",        // Lighthouse
+	"setScale",     // LSL6hires, QFG4
+	"setScaler",    // LSL6hires, QFG4
+	"showTitle",    // LSL6hires
+	"name",         // LSL6hires
+	"oSpecialSync", // LSL7
+	"readWord",     // LSL7, Phant1, Torin
+	"points",       // PQ4
+	"select",       // PQ4
+	"addObstacle",  // QFG4
+	"saveFilePtr",  // RAMA
+	"priority",     // RAMA
+	"plane",        // RAMA
+	"getSubscriberObj", // RAMA
+	"advance",      // QFG4
+	"advanceCurIcon", // QFG4
+	"amount",       // QFG4
+	"cue",          // QFG4
+	"drop",         // QFG4
+	"getCursor",    // QFG4
+	"heading",      // QFG4
+	"moveSpeed",    // QFG4
+	"retreat",      // QFG4
+	"sayMessage",   // QFG4
+	"setLooper",    // QFG4
+	"use",          // QFG4
+	"useStamina",   // QFG4
+	"value",        // QFG4
+	"setupExit",    // SQ6
+	"vol",          // SQ6
+	"walkIconItem", // SQ6
+#endif
+	nullptr
+};
+
+enum ScriptPatcherSelectors {
+	SELECTOR_cycles = 0,
+	SELECTOR_seconds,
+	SELECTOR_init,
+	SELECTOR_dispose,
+	SELECTOR_new,
+	SELECTOR_curEvent,
+	SELECTOR_disable,
+	SELECTOR_doit,
+	SELECTOR_show,
+	SELECTOR_x,
+	SELECTOR_cel,
+	SELECTOR_setMotion,
+	SELECTOR_overlay,
+	SELECTOR_setPri,
+	SELECTOR_play,
+	SELECTOR_number,
+	SELECTOR_setScript,
+	SELECTOR_setCycle,
+	SELECTOR_setStep,
+	SELECTOR_cycleSpeed,
+	SELECTOR_handsOff,
+	SELECTOR_handsOn,
+	SELECTOR_type,
+	SELECTOR_client,
+	SELECTOR_state,
+	SELECTOR_localize,
+	SELECTOR_roomFlags,
+	SELECTOR_put,
+	SELECTOR_approachVerbs,
+	SELECTOR_newRoom,
+	SELECTOR_register,
+	SELECTOR_changeState,
+	SELECTOR_hide,
+	SELECTOR_say,
+	SELECTOR_script,
+	SELECTOR_isEmpty,
+	SELECTOR_solvePuzzle,
+	SELECTOR_curIcon,
+	SELECTOR_curInvIcon,
+	SELECTOR_startText,
+	SELECTOR_startAudio,
+	SELECTOR_modNum,
+	SELECTOR_handle,
+	SELECTOR_add,
+	SELECTOR_givePoints,
+	SELECTOR_has,
+	SELECTOR_modeless,
+	SELECTOR_message,
+	SELECTOR_forceUpd,
+	SELECTOR_cycler,
+	SELECTOR_setCel,
+	SELECTOR_addToPic,
+	SELECTOR_stop,
+	SELECTOR_canControl,
+	SELECTOR_looper,
+	SELECTOR_nMsgType,
+	SELECTOR_doVerb,
+	SELECTOR_setRegions,
+	SELECTOR_cursor,
+	SELECTOR_showSelf,
+	SELECTOR_claimed,
+	SELECTOR_setCursor,
+	SELECTOR_setSpeed,
+	SELECTOR_loop,
+	SELECTOR_setLoop,
+	SELECTOR_ignoreActors,
+	SELECTOR_setVol,
+	SELECTOR_at,
+	SELECTOR_owner,
+	SELECTOR_fade,
+	SELECTOR_enable,
+	SELECTOR_delete,
+	SELECTOR_size,
+	SELECTOR_signal,
+	SELECTOR_obstacles,
+	SELECTOR_handleEvent,
+	SELECTOR_view
+#ifdef ENABLE_SCI32
+	,
+	SELECTOR_newWith,
+	SELECTOR_posn,
+	SELECTOR_printLang,
+	SELECTOR_test,
+	SELECTOR_get,
+	SELECTOR_normalize,
+	SELECTOR_setReal,
+	SELECTOR_set,
+	SELECTOR_clear,
+	SELECTOR_masterVolume,
+	SELECTOR_data,
+	SELECTOR_format,
+	SELECTOR_mouseMoved,
+	SELECTOR_setSize,
+	SELECTOR_iconV,
+	SELECTOR_track,
+	SELECTOR_update,
+	SELECTOR_xOff,
+	SELECTOR_addRespondVerb,
+	SELECTOR_eachElementDo,
+	SELECTOR_fore,
+	SELECTOR_back,
+	SELECTOR_font,
+	SELECTOR_setHeading,
+	SELECTOR_newPic,
+	SELECTOR_start,
+	SELECTOR_setScale,
+	SELECTOR_setScaler,
+	SELECTOR_showTitle,
+	SELECTOR_name,
+	SELECTOR_oSpecialSync,
+	SELECTOR_readWord,
+	SELECTOR_points,
+	SELECTOR_select,
+	SELECTOR_addObstacle,
+	SELECTOR_saveFilePtr,
+	SELECTOR_priority,
+	SELECTOR_plane,
+	SELECTOR_getSubscriberObj,
+	SELECTOR_advance,
+	SELECTOR_advanceCurIcon,
+	SELECTOR_amount,
+	SELECTOR_cue,
+	SELECTOR_drop,
+	SELECTOR_getCursor,
+	SELECTOR_heading,
+	SELECTOR_moveSpeed,
+	SELECTOR_retreat,
+	SELECTOR_sayMessage,
+	SELECTOR_setLooper,
+	SELECTOR_use,
+	SELECTOR_useStamina,
+	SELECTOR_value,
+	SELECTOR_setupExit,
+	SELECTOR_vol,
+	SELECTOR_walkIconItem
+#endif
+};
+
+#ifdef ENABLE_SCI32
+// It is not possible to change the directory for ScummVM save games, so disable
+// the "change directory" button in the standard save dialogue
+static const uint16 sci2ChangeDirSignature[] = {
+	0x72, SIG_ADDTOOFFSET(+2), // lofsa changeDirI
+	0x4a, SIG_UINT16(0x0004),  // send 4
+	SIG_MAGICDWORD,
+	0x36,                      // push
+	0x35, 0xf7,                // ldi $f7
+	0x12,                      // and
+	0x36,                      // push
+	SIG_END
+};
+
+static const uint16 sci2ChangeDirPatch[] = {
+	PATCH_ADDTOOFFSET(+3),    // lofsa changeDirI
+	PATCH_ADDTOOFFSET(+3),    // send 4
+	PATCH_ADDTOOFFSET(+1),    // push
+	0x35, 0x00,               // ldi 0
+	PATCH_END
+};
+
+// Save game script hardcodes the maximum number of save games to 20, but
+// this is an artificial constraint that does not apply to ScummVM
+static const uint16 sci2NumSavesSignature1[] = {
+	SIG_MAGICDWORD,
+	0x8b, 0x02,                    // lsl local[2]
+	0x35, 0x14,                    // ldi 20
+	0x22,                          // lt?
+	SIG_END
+};
+
+static const uint16 sci2NumSavesPatch1[] = {
+	PATCH_ADDTOOFFSET(+2),         // lsl local[2]
+	0x35, 0x63,                    // ldi 99
+	PATCH_END
+};
+
+static const uint16 sci2NumSavesSignature2[] = {
+	SIG_MAGICDWORD,
+	0x8b, 0x02,                    // lsl local[2]
+	0x35, 0x14,                    // ldi 20
+	0x1a,                          // eq?
+	SIG_END
+};
+
+static const uint16 sci2NumSavesPatch2[] = {
+	PATCH_ADDTOOFFSET(+2),         // lsl local[2]
+	0x35, 0x63,                    // ldi 99
+	PATCH_END
+};
+
+// Phantasmagoria & SQ6 try to initialize the first entry of an int16 array
+// using an empty string, which is not valid (it should be a number)
+static const uint16 sci21IntArraySignature[] = {
+	0x38, SIG_SELECTOR16(newWith), // pushi newWith
+	0x7a,                          // push2
+	0x39, 0x04,                    // pushi $4
+	0x72, SIG_ADDTOOFFSET(+2),     // lofsa string ""
+	SIG_MAGICDWORD,
+	0x36,                          // push
+	0x51, 0x0b,                    // class IntArray
+	0x4a, 0x08,                    // send $8
+	SIG_END
+};
+
+static const uint16 sci21IntArrayPatch[] = {
+	PATCH_ADDTOOFFSET(+6),      // push $b9; push2; pushi $4
+	0x76,                       // push0
+	0x34, PATCH_UINT16(0x0001), // ldi 0001 (waste bytes)
+	PATCH_END
+};
+
+// Most SCI32 games have a video performance benchmarking loop at the
+// beginning of the game. Running this benchmark with calls to
+// `OSystem::updateScreen` will often cause the benchmark to return a low value,
+// which causes games to disable some visual effects. Running without calls to
+// `OSystem::updateScreen` on any reasonably modern CPU will cause the benchmark
+// to overflow, leading to randomly disabled effects. This patch changes the
+// benchmarking code to always return the game's maximum speed value.
+//
+// The speed test function in script 64908 changes between games and is compiled
+//  differently between versions of the same game, so to generically patch this
+//  we replace the call-sites with zero, which is the fastest result. RAMA's
+//  speed test function reverses this and returns a high value for fast machines
+//  so it requires a different patch.
+//
+// Applies to: GK1, PQ4, LSL6hires, Phant1, Shivers, SQ6, RAMA
+static const uint16 sci2BenchmarkSignature[] = {
+	SIG_MAGICDWORD,
+	0x76,                       // push0
+	0x46, SIG_UINT16(0xfd8c),   // calle proc64908_0 [ speed test function ]
+	      SIG_UINT16(0x0000),
+	      SIG_UINT16(0x0000),
+	SIG_END
+};
+
+static const uint16 sci2BenchmarkPatch[] = {
+	0x35, 0x00,                 // ldi 00 [ fastest speed test result ]
+	0x33, 0x04,                 // jmp 04
+	PATCH_END
+};
+
+static const uint16 sci2BenchmarkReversePatch[] = {
+	0x34, PATCH_UINT16(0x2710), // ldi 10000 [ fastest speed test result for RAMA ]
+	0x33, 0x03,                 // jmp 03
+	PATCH_END
+};
+
+// The init code that runs in many SCI32 games unconditionally resets the music
+// volume, but the game should always use the volume stored in ScummVM.
+// Applies to at least: LSL6hires, MGDX, PQ:SWAT, QFG4
+static const uint16 sci2VolumeResetSignature[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(masterVolume), // pushi masterVolume
+	0x78,                               // push1
+	0x39, SIG_ADDTOOFFSET(+1),          // pushi [default volume]
+	0x81, 0x01,                         // lag global[1]
+	0x4a, SIG_UINT16(0x0006),           // send 6
+	SIG_END
+};
+
+static const uint16 sci2VolumeResetPatch[] = {
+	0x32, PATCH_UINT16(0x0008),         // jmp 8 [past volume reset]
+	PATCH_END
+};
+
+// At least Gabriel Knight 1 and Police Quest 4 floppy have a broken Str::strip inside script 64918.
+// The code never passes over the actual string to kStringTrim, so that would not work and also trigger
+// a signature mismatch.
+// Localized version of Police Quest 4 were also affected.
+// Gabriel Knight although affected doesn't seem to ever call the code, so there is no reason to patch it.
+// Police Quest 4 CD got this fixed.
+static const uint16 sci2BrokenStrStripSignature[] = {
+	SIG_MAGICDWORD,
+	0x85, 0x06,                         // lat temp[6]
+	0x31, 0x10,                         // bnt [jump to code that passes 2 parameters]
+	0x38, SIG_UINT16(0x00c2),           // pushi 00c2 (callKernel)
+	0x38, SIG_UINT16(0x0003),           // pushi 03
+	0x39, 0x0e,                         // pushi 0e
+	0x8d, 0x0b,                         // lst temp[0b]
+	0x36,                               // push
+	0x54, SIG_UINT16(0x000a),           // self 0a
+	0x33, 0x0b,                         // jmp [ret]
+	// 2 parameter code
+	0x38, SIG_UINT16(0x00c2),           // pushi 00c2
+	0x7a,                               // push2
+	0x39, 0x0e,                         // pushi 0e
+	0x8d, 0x0b,                         // lst temp[0b]
+	0x54, SIG_UINT16(0x0008),           // self 08
+	SIG_END
+};
+
+static const uint16 sci2BrokenStrStripPatch[] = {
+	PATCH_ADDTOOFFSET(+2),
+	0x85, 0x06,                         // lat temp[6] (once more]
+	PATCH_ADDTOOFFSET(+3),              // jump over pushi callKernel
+	0x39, 0x04,                         // pushi 04
+	0x39, 0x0e,                         // pushi 0e
+	// Attention: data is 0x14 in PQ4 CD, in floppy it's 0x12
+	0x67, 0x12,                         // pTos data (pass actual data)
+	0x8d, 0x0b,                         // lst temp[0b]
+	0x36,                               // push
+	0x54, PATCH_UINT16(0x000c),         // self 0c
+	0x48,                               // ret
+	PATCH_END
+};
+
+// Torin/LSL7-specific version of sci2NumSavesSignature1/2
+// Applies to at least: English CD
+static const uint16 torinLarry7NumSavesSignature[] = {
+	SIG_MAGICDWORD,
+	0x36,       // push
+	0x35, 0x14, // ldi 20
+	0x20,       // ge?
+	SIG_END
+};
+
+static const uint16 torinLarry7NumSavesPatch[] = {
+	PATCH_ADDTOOFFSET(+1), // push
+	0x35, 0x63,            // ldi 99
+	PATCH_END
+};
+
+#endif
+
+// Most SCI games run an initial speed test. The results are used to enable
+//  animations and other details but some games go further. For example, LSL3
+//  calculates how many times the player has to do a task using machine speed.
+//
+// We disable speed tests by patching them to return fixed results so that all
+//  graphics are enabled and games behave consistently. This also fixes the bug
+//  where tests fail on fast CPUs because their scores overflow. (bug #13529)
+//  We still have a heuristic in GfxAnimate::throttleSpeed() that attempts to
+//  detect tests and unthrottle the engine so that they score well. That should
+//  reasonably handle any games or versions that haven't been patched yet.
+//
+// Note that these patches are only for SCI16 games; the test was rewritten for
+//  SCI32 and we have separate patches for those.
+//
+// The first generation of speed tests measured how many game cycles occurred
+//  within a fixed amount of time and stored it in a global. Initialize this
+//  to a value that always passes and skip the real initialization so that the
+//  test immediately completes. This also removes a 1-2 second startup delay.
+static const uint16 sci0EarlySpeedTestSignature[] = {
+	0xc9, SIG_ADDTOOFFSET(+1),          // +sg machine-speed
+	SIG_MAGICDWORD,
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	0x30,                               // bnt [ skip initialization ]
+	SIG_END
+};
+
+static const uint16 sci0EarlySpeedTestPatch[] = {
+	0x34, PATCH_UINT16(0x00ff),         // ldi 00ff
+	0xa1, PATCH_GETORIGINALBYTE(+1),    // sag [ machine-speed = 255 ]
+	0x32,                               // jmp [ always skip initialization ]
+	PATCH_END
+};
+
+// Same as previous but the +sg instruction became +ag/push
+static const uint16 sci01SpeedTestGlobalSignature[] = {
+	0xc1, SIG_ADDTOOFFSET(+1),          // +ag machine-speed
+	SIG_MAGICDWORD,
+	0x36,                               // push
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	SIG_END                             // bnt [ skip initialization ]
+};
+
+static const uint16 sci01SpeedTestGlobalPatch[] = {
+	0x34, PATCH_UINT16(0x00ff),         // ldi 00ff
+	0xa1, PATCH_GETORIGINALBYTE(+1),    // sag [ machine-speed = 255 ]
+	0x18,                               // not [ always skip initialization ]
+	PATCH_END
+};
+
+// Same as previous but a local variable is used instead of a global
+static const uint16 sci01SpeedTestLocalSignature[] = {
+	0xc3, SIG_ADDTOOFFSET(+1),          // +al machine-speed
+	SIG_MAGICDWORD,
+	0x36,                               // push
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	SIG_END                             // bnt [ skip initialization ]
+};
+
+static const uint16 sci01SpeedTestLocalPatch[] = {
+	0x34, PATCH_UINT16(0x00ff),         // ldi 00ff
+	0xa3, PATCH_GETORIGINALBYTE(+1),    // sal [ machine-speed = 255 ]
+	0x18,                               // not [ always skip initialization ]
+	PATCH_END
+};
+
+// The second generation of speed tests measured how much time it takes to do a
+//  fixed amount of work. Patch the duration calculation to always be zero.
+static const uint16 sci11SpeedTestSignature[] = {
+	0x76,                               // push0
+	0x43, 0x42, 0x00,                   // callk GetTime 00
+	0x36,                               // push
+	SIG_MAGICDWORD,
+	0x83, 0x01,                         // lal 01
+	0x04,                               // sub    [ GetTime() - start-time ]
+	0xa3, 0x00,                         // sal 00 [ local0 = test-duration ]
+	SIG_END
+};
+
+static const uint16 sci11SpeedTestPatch[] = {
+	0x35, 0x00,                         // ldi 00
+	0x33, 0x04,                         // jmp 04 [ local0 = 0, best result ]
+	PATCH_END
+};
+
+// The Narrator class contains a bug that's responsible for rare random lockups
+//  in almost every Messager SCI game from 1992 to 1996. The later first-person
+//  and FMV games have structures that tend to survive this bug. It was finally,
+//  and only, fixed in LSL7.
+//
+// When a message is said, either through text or audio, Narrator:say calculates
+//  the game time when the message will end and stores this in Narrator:ticks.
+//  Narrator:doit disposes of itself once ticks is reached unless the user has
+//  already dismissed the message. When Narrator isn't saying a message it sets
+//  ticks to the sentinel value -1 which prevents doit and handleEvent from
+//  doing anything. The one rule of a sentinel value is that it can't appear in
+//  normal data, but game time is unsigned and there's nothing preventing
+//  Narrator:say from correctly calculating ticks as 65535 (-1). At 60 ticks per
+//  second, game time rolls over every 18 minutes and 12 seconds, and as each
+//  rollover approaches it's an opportunity for lockup. If a message is said
+//  when game time is high and Narrator:say calculates ticks as 65535 then the
+//  message never ends because handleEvent ignores user input and doit won't
+//  dispose of the message.
+//
+// We fix this by preventing Narrator:say from setting ticks to 65535 (-1). When
+//  it attempts this we use 0 instead, avoiding lockup by adding 1/60th of a
+//  second to the expiration time. Narrator:say changes over time but most
+//  versions can be handled by a generic patch, plus another for SCI32 versions
+//  that were compiled with debug instructions. A few games customized or cloned
+//  Narrator and require specific patches. Others use versions that predate the
+//  problem or don't use their Narrator class at all, but otherwise we patch all
+//  buggy versions.
+//
+// Applies to: Most games that use Messager/Narrator
+// Responsible method: Narrator:say
+static const uint16 sciNarratorLockupSignature[] = {
+	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
+	SIG_MAGICDWORD,
+	0x35, 0x3c,                         // ldi 3c
+	0x02,                               // add
+	0x36,                               // push
+	0x81, 0x58,                         // lag 58 [ game time ]
+	0x02,                               // add
+	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time ]
+	0x35, 0x01,                         // ldi 01 [ true ]
+	0x48,                               // ret
+	SIG_END
+};
+
+static const uint16 sciNarratorLockupPatch[] = {
+	PATCH_ADDTOOFFSET(+5),
+	0x89, 0x58,                         // lsg 58 [ game time ]
+	0x02,                               // add
+	0x65, PATCH_GETORIGINALBYTE(+1),    // aTop ticks [ ticks += 60 + game time ]
+	0x00,                               // bnot
+	0x31, 0xfb,                         // bnt fb [ set ticks to 0 if ticks == -1 ]
+	PATCH_END
+};
+
+#ifdef ENABLE_SCI32
+// Same signature/patch as above but for SCI32 games with debug line instructions.
+//  Some games use both because different versions were compiled differently.
+static const uint16 sciNarratorLockupLineSignature[] = {
+	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
+	SIG_MAGICDWORD,
+	0x35, 0x3c,                         // ldi 3c
+	0x02,                               // add
+	0x36,                               // push
+	0x81, 0x58,                         // lag 58 [ game time ]
+	0x02,                               // add
+	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time ]
+	0x7e, SIG_ADDTOOFFSET(+2),          // line
+	SIG_END
+};
+
+static const uint16 sciNarratorLockupLinePatch[] = {
+	PATCH_ADDTOOFFSET(+11),
+	0x00,                               // bnot
+	0x31, 0xfb,                         // bnt fb [ set ticks to 0 if ticks == -1 ]
+	PATCH_END
+};
+#endif
+
+// ECO1 CD and SQ4 CD share an early Narrator:say variant
+static const uint16 ecoquest1Sq4CdNarratorLockupSignature[] = {
+	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
+	SIG_MAGICDWORD,
+	0x35, 0x3c,                         // ldi 3c
+	0x02,                               // add
+	0x36,                               // push
+	0x81, 0x58,                         // lag 58 [ game time ]
+	0x02,                               // add
+	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time ]
+	0x63, SIG_ADDTOOFFSET(+1),          // pToa modeless
+	0x18,                               // not
+	0x31, SIG_ADDTOOFFSET(+1),          // bnt [ skip fastCast event handling ]
+	0x81, 0x54,                         // lag 54
+	0x31, SIG_ADDTOOFFSET(+1),          // bnt [ skip fastCast event handling ]
+	0x81, 0x54,                         // lag 54
+	0x31, SIG_ADDTOOFFSET(+1),          // bnt [ skip fastCast event handling ]
+	SIG_END
+};
+
+static const uint16 ecoquest1Sq4CdNarratorLockupPatch[] = {
+	PATCH_ADDTOOFFSET(+11),
+	0x00,                               // bnot
+	0x30, PATCH_UINT16(0xfffa),         // bnt fffa [ set ticks to 0 if ticks == -1 ]
+	0x63, PATCH_GETORIGINALBYTE(+12),   // pToa modeless
+	0x18,                               // not
+	PATCH_END
+};
+
+// Several SCI Version 1 games use a Timer class that doesn't handle kGetTime
+//  rollover correctly. When Timer:set60ths is called with a tick value that
+//  elapses after kGetTime rolls over from 65535 to 0, the timer instantly cues.
+//  The CD versions of KQ5 and Mixed Up Mother Goose set a timer this way when
+//  playing speech that can't be skipped. As rollover approaches every 18
+//  minutes and 12 seconds, these messages can instantly complete and cause
+//  entire scenes to randomly skip. For example, this can happen in KQ5CD's
+//  Harpy and Hermit cutscenes.
+//
+// We fix this by replacing the Timer's tick calculation with the correct logic
+//  that appears in later versions when set60ths was renamed to setTicks.
+//
+// Applies to: Games that use Timer:set60ths
+// Responsible methods: Timer:doit, SpeakTimer:doit in KQ5CD
+static const uint16 sciSignatureTimerRollover[] = {
+	0x67, SIG_ADDTOOFFSET(+1),       // pTos ticksToDo
+	0x63, SIG_ADDTOOFFSET(+1),       // pToa lastTime
+	0x02,                            // add
+	0x36,                            // push
+	0x76,                            // push0
+	SIG_MAGICDWORD,
+	0x43, 0x42, 0x00,                // callk GetTime 00
+	0x2a,                            // ult? [ ticksToDo + lastTime u< kGetTime ]
+	0x2e, SIG_UINT16(0x0013),        // bt 0013
+	0x67, SIG_ADDTOOFFSET(+1),       // pTos lastTime
+	0x76,                            // push0
+	SIG_ADDTOOFFSET(+16),
+	0x30,                            // bnt [ cue client if acc == true ]
+	SIG_END
+};
+
+static const uint16 sciPatchTimerRollover[] = {
+	0x76,                            // push0
+	0x43, 0x42, 0x00,                // callk GetTime 00
+	0x36,                            // push
+	0x67, PATCH_GETORIGINALBYTE(+1), // pTos ticksToDo
+	0x63, PATCH_GETORIGINALBYTE(+3), // pToa lastTime
+	0x02,                            // add
+	0x04,                            // sub
+	0x36,                            // push
+	0x35, 0x00,                      // ldi 00
+	0x1e,                            // gt? [ kGetTime - (ticksToDo + lastTime) > 0 ]
+	0x33, 0x10,                      // jmp 10 [ cue client if acc == true ]
+	PATCH_END
+};
+
+// ===========================================================================
+// Conquests of Camelot
+// At the bazaar in Jerusalem, it's possible to see a girl taking a shower.
+//  If you get too close, you get warned by the father - if you don't get away,
+//  he will kill you.
+// Instead of walking there manually, it's also possible to enter "look window"
+//  and ego will automatically walk to the window. It seems that this is something
+//  that wasn't properly implemented, because instead of getting killed, you will
+//  get an "Oops" message in Sierra SCI.
+//
+// This is caused by peepingTom in script 169 not getting properly initialized.
+// peepingTom calls the object behind global[b9h]. This global variable is
+//  properly initialized when walking there manually (method fawaz::doit).
+// When you instead walk there automatically (method fawaz::handleEvent), that
+//  global isn't initialized, which then results in the Oops-message in Sierra SCI
+//  and an error message in ScummVM/SCI.
+//
+// We fix the script by patching in a jump to the proper code inside fawaz::doit.
+// Responsible method: fawaz::handleEvent
+// Fixes bug: #6402
+static const uint16 camelotSignaturePeepingTom[] = {
+	0x72, SIG_MAGICDWORD, SIG_UINT16(0x077e), // lofsa fawaz <-- start of proper initializion code
+	0xa1, 0xb9,                      // sag global[b9h]
+	SIG_ADDTOOFFSET(+571),           // ...
+	0x39, 0x7a,                      // pushi 7a <-- initialization code when walking automatically
+	0x78,                            // push1
+	0x7a,                            // push2
+	0x38, SIG_UINT16(0x00a9),        // pushi 00a9 - script 169
+	0x78,                            // push1
+	0x43, 0x02, 0x04,                // callk ScriptID
+	0x36,                            // push
+	0x81, 0x00,                      // lag global[0]
+	0x4a, 0x06,                      // send 06
+	0x32, SIG_UINT16(0x0520),        // jmp [end of fawaz::handleEvent]
+	SIG_END
+};
+
+static const uint16 camelotPatchPeepingTom[] = {
+	PATCH_ADDTOOFFSET(+576),
+	0x32, PATCH_UINT16(0xfdbd),      // jmp [to fawaz::doit] (properly init peepingTom code)
+	PATCH_END
+};
+
+// If the butcher's daughter in room 62 closes her window while Arthur interacts
+//  with the relic merchant then the game locks up. The script daughterAppears
+//  attempts to dispose the script peepingTom, but it does so by clearing ego's
+//  script no matter what it is, which breaks the game if the script is buyRelic
+//  or one of the other handsOff merchant scripts.
+//
+// We fix this by calling peepingTom:dispose instead of clearing ego's script.
+//  As this is an earlier SCI game prior to Script:dispose clearing the client
+//  property, we need to do that ourselves in peepingTom:doit when Arthur turns
+//  away from the window, or else peepingTom:client will still point to ego
+//  after disposal, and the subsequent peepingTom:dispose will end ego's script.
+//
+// Applies to: All versions
+// Responsible methods: daughterAppears:changeState(6), peepingTom:doit
+// Fixes bug: #11025
+static const uint16 camelotSignatureRelicMerchantLockup1[] = {
+	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
+	0x78,                               // push1
+	0x76,                               // push0
+	0x81, SIG_MAGICDWORD, 0x00,         // lag 00
+	0x4a, 0x06,                         // send 06 [ ego setScript: 0 ]
+	0x3a,                               // toss
+	SIG_END
+};
+
+static const uint16 camelotPatchRelicMerchantLockup1[] = {
+	0x39, PATCH_SELECTOR8(dispose),     // pushi dispose
+	0x76,                               // push0
+	0x72, PATCH_UINT16(0x01f3),         // lofsa peepingTom
+	0x4a, 0x04,                         // send 04 [ peepingTom dispose: ]
+	PATCH_END
+};
+
+static const uint16 camelotSignatureRelicMerchantLockup2[] = {
+	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
+	0x78,                               // push1
+	0x76,                               // push0
+	0x81, SIG_MAGICDWORD, 0x00,         // lag 00
+	0x4a, 0x06,                         // send 06 [ ego setScript: 0 ]
+	0x48,                               // ret
+	SIG_END
+};
+
+static const uint16 camelotPatchRelicMerchantLockup2[] = {
+	0x39, PATCH_SELECTOR8(dispose),     // pushi dispose
+	0x76,                               // push0
+	0x54, 0x04,                         // self 04 [ self dispose: ]
+	0x76,                               // push0
+	0x69, 0x08,                         // sTop client [ client = 0 ]
+	PATCH_END
+};
+
+// The hunter in room 11 doesn't award soul points if you buy his furs with the
+//  "buy furs" command first and "pay" second. Two points are awarded if these
+//  commands are entered in the opposite order.
+//
+// We fix this by adding the missing function call to award the soul points as
+//  Sierra did in later versions. Fortunately, the GiveMoney script contains
+//  redundant code that can be replaced as it is occurs later in the method.
+//
+// Applies to: PC only
+// Responsible method: GiveMoney:changeState(3)
+// Fixes bug: #11027
+static const uint16 camelotSignatureHunterMissingPoints[] = {
+	SIG_MAGICDWORD,
+	0x30, SIG_UINT16(0x0020),           // bnt 0020 [ matches PC only ]
+	0x35, 0x00,                         // ldi 00
+	0xa3, 0x00,                         // sal 00 [ local0 = 0 ]
+	// unnecessary code which is repeated later in the method
+	0x89, 0xdd,                         // lsg dd
+	0x81, 0x84,                         // lag 84
+	0x02,                               // add
+	0xa1, 0xdd,                         // sag dd [ global221 += global132 ]
+	0x35, 0x00,                         // ldi 00
+	0xa1, 0x84,                         // sag 84 [ global132 = 0 ]
+	SIG_END
+};
+
+static const uint16 camelotPatchHunterMissingPoints[] = {
+	PATCH_ADDTOOFFSET(+7),
+	0x38, PATCH_UINT16(0x0003),         // pushi 0003
+	0x38, PATCH_UINT16(0x00f5),         // pushi 00f5 [ point flag 245 ]
+	0x7a,                               // push2 [ soul points ]
+	0x7a,                               // push2 [ +2 points ]
+	0x45, 0x0a, 0x06,                   // callb proc0_10 06 [ +2 soul points ]
+	PATCH_END
+};
+
+// When giving away the mule in room 56, the merchant's first long message is
+//  immediately replaced by the next. mo:handleEvent displays the first and
+//  starts the script getMule, which proceeds to display its own messages
+//  without waiting.
+//
+// We fix this by adding code to getMule to wait for the merchant's message to
+//  complete if you gave away the mule and a message is on screen.
+//
+// Applies to: All versions
+// Responsible method: getMule:changeState(4)
+// Fixes bug: #11026
+static const uint16 camelotSignatureGiveMuleMessage[] = {
+	0x30, SIG_UINT16(0x0023),           // bnt 0023 [ state 4 ]
+	SIG_ADDTOOFFSET(+0x20),
+	SIG_MAGICDWORD,
+	0x32, SIG_UINT16(0x0239),           // jmp 0239 [ end of method ]
+	0x3c,                               // dup
+	0x35, 0x04,                         // ldi 04
+	0x1a,                               // eq?
+	0x30, SIG_UINT16(0x0016),           // bnt 0016 [ state 5 ]
+	0x83, 0x02,                         // lal 02   [ gave away mule? ]
+	0x30, SIG_UINT16(0x000a),           // bnt 000a [ skip state 14 if mule was sold ]
+	0x39, SIG_SELECTOR8(changeState),   // pushi changeState
+	0x78,                               // push1
+	0x39, 0x0e,                         // pushi 0e
+	0x54, 0x06,                         // self 06 [ self changeState: 14 ]
+	0x32, SIG_UINT16(0x0223),           // jmp 0223 [ end of method ]
+	0x35, 0x01,                         // ldi 01
+	0x65, 0x10,                         // aTop cycles [ cycles = 1 ]
+	0x32, SIG_UINT16(0x021c),           // jmp 021c [ end of method ]
+	SIG_END
+};
+
+static const uint16 camelotPatchGiveMuleMessage[] = {
+	0x30, PATCH_UINT16(0x0020),         // bnt 0020 [ state 4 ]
+	PATCH_ADDTOOFFSET(+0x20),
+	0x3c,                               // dup
+	0x35, 0x04,                         // ldi 04
+	0x1a,                               // eq?
+	0x31, 0x1a,                         // bnt 1a [ state 5 ]
+	0x83, 0x02,                         // lal 02 [ gave away mule? ]
+	0x31, 0x13,                         // bnt 13 [ skip state 14 if mule was sold ]
+	0x35, 0x0d,                         // ldi 0d
+	0x65, 0x0a,                         // aTop state [ state = 13 ]
+	0x38, PATCH_UINT16(0x0121),         // pushi talkCue [ same value in all versions ]
+	0x78,                               // push1
+	0x7c,                               // pushSelf
+	0x38, PATCH_UINT16(0x0122),         // pushi tS1 [ same value in all versions ]
+	0x76,                               // push0
+	0x81, 0x6f,                         // lag 6f
+	0x4a, 0x0a,                         // send 0a [ tObj talkCue: self tS1? ]
+	0x2f, 0x03,                         // bt 03   [ don't set cycles if message on screen ]
+	0x78,                               // push1
+	0x69, 0x10,                         // sTop cycles [ cycles = 1 ]
+	PATCH_END
+};
+
+// In Fatima's house in room 64, "look room" and "look trap" respond with the
+//  wrong messages due to testing the wrong flag. Flag 162 is set when falling
+//  through the trap door and alters responses the next time in the room, but
+//  the script tests flag 137 instead, which is set when entering the room.
+//
+// Sierra fixed the first flag test in Amiga and Atari ST but not the second, so
+//  this patch is applied only once to those versions and twice to PC.
+//
+// Applies to: All versions
+// Responsible method: Rm64:handleEvent
+// Fixes bug: #11028
+static const uint16 camelotSignatureFatimaRoomMessages[] = {
+	0x78,                               // push1
+	0x38, SIG_MAGICDWORD,               // pushi 0089 [ flag 137, always true ]
+	      SIG_UINT16(0x0089),
+	0x45, 0x09, 0x02,                   // callb proc0_9 02 [ is flag 137 set? ]
+	SIG_END
+};
+
+static const uint16 camelotPatchFatimaRoomMessages[] = {
+	PATCH_ADDTOOFFSET(+1),
+	0x38, PATCH_UINT16(0x00a2),         // pushi 00a2 [ flag 162, set by trap ]
+	PATCH_END
+};
+
+// Sheathing the sword by pressing F8 while entering or exiting a room breaks
+//  the game by placing ego in an invalid state that allows walking through
+//  obstacles and prevents room changes. This affects rooms that subclass eRoom
+//  in areas that allow walking with sword drawn such as the monk's ruins and
+//  the desert. This is most likely to occur while battling the monk.
+//
+// eRoom walks ego in and out of rooms in handsOff mode. It sets ego:illegalBits
+//  to 0, enables ignoreActors, and sets a motion that cues when complete to
+//  restore ego's properties. Sheathing the sword interrupts the motion, which
+//  prevents eRoom:cue, and prematurely restores control to the user with ego in
+//  the temporary state. There are almost no restrictions on sheathing because
+//  it's used when input is disabled and during several handsOff scenes.
+//
+// We fix this by preventing sword scripts from starting when an eRoom is in the
+//  middle of controlling ego. eRoom tracks this with the comingIn and goingOut
+//  properties and we require that both be cleared to execute a sword command.
+//
+// Applies to: All versions
+// Responsible method: ARTHUR:doit
+// Fixes bug: #11042
+static const uint16 camelotSignatureSwordSheathing[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x7d,                         // lsg 7d [ sword-command ]
+	0x3c,                               // dup
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq? [ sword-command == 1 (draw) ]
+	0x30, SIG_UINT16(0x0013),           // bnt 0013
+	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
+	0x78,                               // push1
+	0x7a,                               // push2
+	0x38, SIG_UINT16(0x038e),           // pushi 910d
+	0x76,                               // push0
+	0x43, 0x02, 0x04,                   // callk ScriptID 04 [ ScriptID 910 0 (DrawSword) ]
+	0x36,                               // push
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x06,                         // send 06 [ ego setScript: DrawSword ]
+	0x32, SIG_UINT16(0x0085),           // jmp 0085 [ end of switch ]
+	0x3c,                               // dup
+	0x35, 0x02,                         // ldi 02
+	0x1a,                               // eq? [ sword-command == 2 (sheathe) ]
+	0x30, SIG_UINT16(0x0013),           // bnt 0013
+	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
+	0x78,                               // push1
+	0x7a,                               // push2
+	0x38, SIG_UINT16(0x038e),           // pushi 910d
+	0x78,                               // push1
+	0x43, 0x02, 0x04,                   // callk ScriptID 04 [ ScriptID 910 1 (SheatheSword) ]
+	0x36,                               // push
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x06,                         // send 06 [ ego setScript: SheatheSword ]
+	0x32, SIG_UINT16(0x006b),           // jmp 006b [ end of switch ]
+	0x3c,                               // dup
+	0x35, 0x03,                         // ldi 03
+	0x1a,                               // eq? [ sword-command == 3 (parry) ]
+	0x30, SIG_UINT16(0x0013),           // bnt 0013
+	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
+	0x78,                               // push1
+	0x7a,                               // push2
+	0x38, SIG_UINT16(0x0390),           // pushi 912d
+	0x78,                               // push1
+	0x43, 0x02, 0x04,                   // callk ScriptID 04 [ ScriptID 912 1 (DoParry) ]
+	SIG_ADDTOOFFSET(+15),
+	0x81, 0x7c,                         // lag 7c [ start of sword-command == 0 handler ]
+	SIG_ADDTOOFFSET(+72),
+	0x3a,                               // toss [ end of switch ]
+	SIG_END
+};
+
+static const uint16 camelotPatchSwordSheathing[] = {
+	0x81, 0x7d,                         // lag 7d [ sword-command ]
+	0x31, 0x53,                         // bnt 53 [ sword-command == 0 handler ]
+	0x39, 0x03,                         // pushi 03
+	0x20,                               // ge? [ 3 >= sword-command ]
+	0x31, 0x3e,                         // bnt 3e [ exit if sword-command > 3 ]
+	0x7a,                               // push2
+	0x89, 0x02,                         // lsg 02
+	0x38, PATCH_UINT16(0x014b),         // pushi comingIn [ same value in all versions ]
+	0x43, 0x07, 0x04,                   // callk RespondsTo 04 [ RespondsTo currentRoom comingIn ]
+	0x31, 0x14,                         // bnt 14 [ skip eRoom checks if room isn't an eRoom ]
+	0x38, PATCH_UINT16(0x014b),         // pushi comingIn
+	0x76,                               // push0
+	0x81, 0x02,                         // lag 02
+	0x4a, 0x04,                         // send 04 [ currentRoom comingIn? ]
+	0x2f, 0x29,                         // bt 29   [ skip sword scripts if entering room ]
+	0x38, PATCH_UINT16(0x014c),         // pushi goingOut [ same value in all versions ]
+	0x76,                               // push0
+	0x81, 0x02,                         // lag 02
+	0x4a, 0x04,                         // send 04 [ currentRoom goingOut? ]
+	0x2f, 0x1f,                         // bt 1f   [ skip sword scripts if exiting room ]
+	0x39, PATCH_SELECTOR8(setScript),   // pushi setScript
+	0x78,                               // push1
+	0x7a,                               // push2
+	0x81, 0x7d,                         // lag 7d
+	0x7a,                               // push2
+	0x20,                               // ge? [ 2 >= sword-command ]
+	0x31, 0x05,                         // bnt 05
+	0x38, PATCH_UINT16(0x038e),         // pushi 910d
+	0x33, 0x03,                         // jmp 03
+	0x38, PATCH_UINT16(0x0390),         // pushi 912d
+	0x81, 0x7d,                         // lag 7d
+	0x78,                               // push1
+	0x1c,                               // ne? [ sword-command != 1 ]
+	0x36,                               // push
+	0x43, 0x02, 0x04,                   // callk ScriptID 04 [ ScriptID (sword-command <= 2) ? 910 : 912, (sword-command != 1) ]
+	0x36,                               // push
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x06,                         // send 06 [ ego setScript: sword-script ]
+	0x48,                               // ret
+	PATCH_ADDTOOFFSET(+89),
+	0x48,                               // ret [ remove toss since dup instructions were removed ]
+	PATCH_END
+};
+
+// When Arthur's sword is drawn, ARTHUR:doit calls kGetEvent a second time on
+//  each cycle to test if a shift key is pressed, causing input events to be
+//  frequently dropped. This is similar to Freddy Pharkas and QFG1VGA where this
+//  technique just happened to usually work in Sierra's interpreter. We fix this
+//  in the same way by using the current event instead of consuming a new one.
+//
+// Applies to: All versions
+// Responsible method: ARTHUR:doit
+// Fixes bug: #11269
+static const uint16 camelotSignatureSwordEvents[] = {
+	0x30, SIG_MAGICDWORD,               // bnt 0045
+	      SIG_UINT16(0x0045),
+	0x39, SIG_SELECTOR8(new),           // pushi new
+	0x76,                               // push0
+	0x51, 0x07,                         // class Event
+	0x4a, 0x04,                         // send 04 [ Event new: ]
+	0xa5, 0x01,                         // sat 01 [ temp1 = Event new: ]
+	SIG_ADDTOOFFSET(+53),
+	0x39, SIG_SELECTOR8(dispose),       // pushi dispose
+	0x76,                               // push0
+	0x85, 0x01,                         // lat 01
+	0x4a, 0x04,                         // send 04 [ temp1 dispose: ]
+	SIG_END
+};
+
+static const uint16 camelotPatchSwordEvents[] = {
+	0x31, 0x46,                         // bnt 46
+	0x38, PATCH_SELECTOR16(curEvent),   // pushi curEvent
+	0x76,                               // push0
+	0x51, 0x30,                         // class User [ User: curEvent ]
+	PATCH_ADDTOOFFSET(+57),
+	0x33, 0x05,                         // jmp 05 [ don't dispose event ]
+	PATCH_END
+};
+
+//         script, description,                                       signature                             patch
+static const SciScriptPatcherEntry camelotSignatures[] = {
+	{ true,     0, "fix sword sheathing",                          1, camelotSignatureSwordSheathing,       camelotPatchSwordSheathing },
+	{ true,     0, "fix sword events",                             1, camelotSignatureSwordEvents,          camelotPatchSwordEvents },
+	{ true,    11, "fix hunter missing points",                    1, camelotSignatureHunterMissingPoints,  camelotPatchHunterMissingPoints },
+	{ true,    62, "fix peepingTom Sierra bug",                    1, camelotSignaturePeepingTom,           camelotPatchPeepingTom },
+	{ true,    64, "fix Fatima room messages",                     2, camelotSignatureFatimaRoomMessages,   camelotPatchFatimaRoomMessages },
+	{ true,   112, "disable speed test",                           1, sci01SpeedTestLocalSignature,         sci01SpeedTestLocalPatch },
+	{ true,   158, "fix give mule message",                        1, camelotSignatureGiveMuleMessage,      camelotPatchGiveMuleMessage },
+	{ true,   169, "fix relic merchant lockup (1/2)",              1, camelotSignatureRelicMerchantLockup1, camelotPatchRelicMerchantLockup1 },
+	{ true,   169, "fix relic merchant lockup (2/2)",              1, camelotSignatureRelicMerchantLockup2, camelotPatchRelicMerchantLockup2 },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// Castle of Dr. Brain
+
+//          script, description,                                      signature                                 patch
+static const SciScriptPatcherEntry castleBrainSignatures[] = {
+	{  true,   802, "disable speed test",                          1, sci01SpeedTestGlobalSignature,            sci01SpeedTestGlobalPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// stayAndHelp::changeState (0) is called when ego swims to the left or right
+//  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
+// Applies to at least: PC-CD
+// Responsible method: stayAndHelp::changeState
+// Fixes bug: #5107
+static 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 [export 1 of script 0], 00 (switching control off)
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x0122),        // pushi 0122
+	0x78,                            // push1
+	0x76,                            // push0
+	0x81, 0x00,                      // lag global[0]
+	0x4a, 0x06,                      // send 06 - call ego::setMotion(0)
+	0x39, SIG_SELECTOR8(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
+};
+
+static 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 [export 1 of script 0], 00 (switching control off)
+	0x38, PATCH_UINT16(0x0122),      // pushi 0122
+	0x78,                            // push1
+	0x76,                            // push0
+	0x81, 0x00,                      // lag global[0]
+	0x4a, 0x06,                      // send 06 - call ego::setMotion(0)
+	0x39, PATCH_SELECTOR8(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(0x0280),      // pushi 280 (additional 3 bytes)
+	0x51, 0x82,                      // class EcoNarrator
+	0x4a, 0x10,                      // send 10 - call EcoNarrator::init(2, 0, 0, 23, self, 640)
+	PATCH_END
+};
+
+// Giving the oily shell to Superfluous when he's out of the mask runs the
+//  wrong animation and skips messages in the CD version. Sierra modified
+//  getInOilyShell for the CD version by adding a new state to the beginning
+//  but forgot to increment the state numbers passed to self:changeState to
+//  their new values, causing the script to change to the wrong states.
+//
+// We fix this by incrementing the state numbers passed to self:changeState.
+//
+// Applies to: PC CD
+// Responsible method: getInOilyShell:changeState
+// Fixes bug #10881
+static const uint16 ecoquest1SignatureGiveOilyShell[] = {
+	0x30, SIG_UINT16(0x000a),       // bnt 000a
+	0x38, SIG_UINT16(0x0090),       // pushi changeState [ hard coded for CD ]
+	0x78,                           // push1
+	0x7a,                           // push2 [ state 2 ]
+	0x54, SIG_MAGICDWORD, 0x06,     // self 06
+	0x32, SIG_UINT16(0x0195),       // jmp 0195
+	SIG_ADDTOOFFSET(+209),
+	0x39, 0x08,                     // pushi 08 [ state 8 ]
+	SIG_ADDTOOFFSET(+16),
+	0x39, 0x0b,                     // pushi 0b [ state 11 ]
+	SIG_END
+};
+
+static const uint16 ecoquest1PatchGiveOilyShell[] = {
+	0x31, 0x0b,                     // bnt 0b
+	0x38, PATCH_UINT16(0x0090),     // pushi changeState [ hard coded for CD ]
+	0x78,                           // push1
+	0x39, 0x03,                     // pushi 03 [ state 3 ]
+	PATCH_ADDTOOFFSET(+214),
+	0x39, 0x09,                     // pushi 09 [ state 9 ]
+	PATCH_ADDTOOFFSET(+16),
+	0x39, 0x0c,                     // pushi 0c [ state 12 ]
+	PATCH_END
+};
+
+// Reading the prophecy scroll in the CD version breaks messages in at least
+//  rooms 100 and 120. scrollScript:init overwrites the global that holds the
+//  noun for the room's message tuples. This global was added in the CD version
+//  and is set by most rooms during initialization. This pattern was mistakenly
+//  applied to scrollScript which isn't a room and doesn't depend on the global.
+//
+// We fix this by skipping the problematic code which overwrites the global.
+//
+// Applies to: PC CD
+// Responsible method: scrollScript:init
+// Fixes bug #10883
+static const uint16 ecoquest1SignatureProphecyScroll[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x01,                     // ldi 01
+	0xa1, 0xfa,                     // sag fa [ global250 = 1 ]
+	SIG_END
+};
+
+static const uint16 ecoquest1PatchProphecyScroll[] = {
+	0x33, 0x02,                     // jmp 02 [ don't set global250 ]
+	PATCH_END
+};
+
+// The empty apartments have several broken messages in the CD version due to
+//  not setting the global that holds the current room's noun, so we set it.
+//
+// Applies to: PC CD
+// Responsible method: rm220:init
+// Fixes bug #10903
+static const uint16 ecoquest1SignatureEmptyApartmentMessages[] = {
+	SIG_MAGICDWORD,
+	0x54, 0x0c,                     // self 0c [ self setRegions: 51, addObstacle: ... ]
+	0x39, SIG_SELECTOR8(init),      // pushi init
+	0x76,                           // push0
+	0x59, 0x01,                     // &rest 01 [ unused by ApartmentRoom:init ]
+	0x57, 0x96, 0x04,               // super ApartmentRoom 04 [ super init: &rest ]
+	SIG_END
+};
+
+static const uint16 ecoquest1PatchEmptyApartmentMessages[] = {
+	0x35, 0x01,                     // ldi 01 [ the room's noun ]
+	PATCH_ADDTOOFFSET(+3),
+	0xa1, 0xfa,                     // sag fa [ global250 = 1 ]
+	0x57, 0x96, 0x10,               // super ApartmentRoom 10 [ combine self and super ]
+	PATCH_END
+};
+
+// The temple has a complex script bug in the CD version which can crash the
+//  interpreter when solving the mosaic puzzle after loading a game that was
+//  saved during the puzzle. The bug causes invalid memory access which locks up
+//  Sierra's interpreter and can cause ours to fail an assertion.
+//
+// Room 140 has three insets and a conch shell in the middle. This room's script
+//  was significantly changed in the CD version and transition animations were
+//  added. Due to these changes the shell no longer renders beneath the insets
+//  and so Sierra added code to hide the shell while they're displayed.
+//  Unfortunately this code is incorrect and leaves the game in a state that's
+//  unsafe to save. The shell is removed from the cast when showing an inset and
+//  then shell:init is called when hiding. This leaves shell:underBits pointing
+//  to hunk memory while temporarily not a member of the cast. Hunk memory isn't
+//  persisted in saved games but underBits' values are. SCI games handle this in
+//  Game:replay by clearing the underBits of cast members when restoring. Saving
+//  while the puzzle is displayed causes shell:underBits' stale hunk value to
+//  survive restoring. Solving the puzzle adds the shell back to the cast via
+//  init followed by a call to kAnimate that accesses the potentially stale
+//  shell:underBits. If the hunk segment id upon restoring in ScummVM is the
+//  same as when saved then this out of bounds access will fail an assertion.
+//
+// We fix this by fully disposing the shell when showing an inset so that its
+//  resources are cleaned up and it's safe to save the game. In order to do this
+//  without changing the animation effect we set shell's disposal flag and then
+//  immediately call shell:delete. This is equivalent to shell:dispose but
+//  prevents hiding the shell before the transition animation takes place.
+//
+// Applies to: PC CD
+// Responsible methods: MosaicWall:doVerb, localproc_2ab6 in script 140
+// Fixes bug #10884
+static const uint16 ecoquest1SignatureMosaicPuzzleFix[] = {
+	0x36,                           // push     [ conchShell:owner ]
+	0x34, SIG_UINT16(0x008c),       // ldi 008c [ room number ]
+	0x1a,                           // eq?      [ is conchShell owned by room 140? ]
+	0x30, SIG_UINT16(0x000b),       // bnt 000b [ no shell to hide ]
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(delete),    // pushi delete
+	0x78,                           // push1
+	0x72, SIG_UINT16(0x056a),       // lofsa shell
+	0x36,                           // push
+	0x81, 0x05,                     // lag 05
+	0x4a, 0x06,                     // send 06 [ cast delete: shell ]
+	SIG_END
+};
+
+static const uint16 ecoquest1PatchMosaicPuzzleFix[] = {
+	0x89, 0x0b,                     // lsg 0b [ current room number, saves 2 bytes ]
+	0x1a,                           // eq?    [ is conchShell owned by room 140? ]
+	0x31, 0x0e,                     // bnt 0e [ no shell to hide, save a byte ]
+	0x39, PATCH_SELECTOR8(signal),  // pushi signal
+	0x78,                           // push1
+	0x38, PATCH_UINT16(0xc014),     // pushi c014 [ kSignalDisposeMe | shell:signal ]
+	0x39, PATCH_SELECTOR8(delete),  // pushi delete
+	0x76,                           // push0
+	0x72, PATCH_UINT16(0x056a),     // lofsa shell
+	0x4a, 0x0a,                     // send 0a [ shell signal: c014, delete ]
+	PATCH_END
+};
+
+// The column puzzle in room 160 can be put in a state that can't be completed.
+//  This is a bug in the original that affects all versions.
+//
+// The puzzle consists of nine columns that must be rotated to their correct
+//  positions in the correct order. As each column is solved it is locked. When
+//  leaving the room the puzzle state is saved to globals but this state is
+//  insufficient to recreate the puzzle. The game saves column positions but not
+//  lock states. Instead it infers lock states from positions when restoring but
+//  this is inaccurate because columns can be put in their correct positions out
+//  of order. If the player leaves the room while all columns are in their
+//  correct positions but before the puzzle is solved then all columns will be
+//  locked when returning and the game can't be completed.
+//
+// The proper solution would be to save and restore lock states but it would be
+//  impractical to patch in that functionality while retaining save game
+//  compatibility. Instead we patch the loop that reinitializes lock states to
+//  skip the last column so that it's always unlocked and the player can't get
+//  stuck. This code only runs when the puzzle isn't solved and should never
+//  have been able to lock the last column.
+//
+// Applies to: All Floppy and CD versions
+// Responsible method: Local procedure 5 in script 160
+// Fixes bug #10885
+static const uint16 ecoquest1SignatureColumnPuzzleFix[] = {
+	0x39, SIG_SELECTOR8(size),      // pushi size
+	0x76,                           // push0
+	0x72, SIG_ADDTOOFFSET(+2),      // lofsa columnList [ columns in solution order ]
+	0x4a, 0x04,                     // send 04 [ columnList:size ]
+	0x22,                           // lt? [ temp0 < columnList:size (9) ]
+	0x30, SIG_ADDTOOFFSET(+2),      // bnt [ end of method ]
+	0x39, SIG_MAGICDWORD,           // pushi cel
+	      SIG_SELECTOR8(cel),
+	0x76,                           // push0
+	0x39, SIG_SELECTOR8(at),        // pushi at
+	SIG_END
+};
+
+static const uint16 ecoquest1PatchColumnPuzzleFix[] = {
+	0x34, PATCH_UINT16(0x0008),     // ldi 0008 [ only initialize 8 of 9 columns ]
+	0x32, PATCH_UINT16(0x0002),     // jmp 0002
+	PATCH_END
+};
+
+// The ocean cliffs that border rooms 320 and 321 aren't displayed in the CD
+//  version. Instead they are drawn above the visible area and on more screens
+//  than they should. This also occurs in the original.
+//
+// Cliff views 325 and 326 have y displacements greater than 127 in the floppy
+//  versions. In the CD version these offsets were changed to zero. Sierra
+//  attempted to compensate for this by adding rows of empty pixels to the views
+//  but it appears that someone mistook the unsigned offsets for negative values
+//  and added the wrong number of rows to the wrong side of the views, causing
+//  the cliffs to be drawn 256 pixels higher than normal.
+//
+// The ocean scripts were changed to use different techniques for adding and
+//  removing the cliffs but this introduced more errors. Room 321 reinitializes
+//  the cliffs instead of disposing them, causing them to be redrawn on the
+//  wrong screens, and room 320 disposes the eastern cliffs instead of western.
+//
+// We fix the cliffs by adjusting their positions by 256 and disposing of them
+//  in room 321. We leave room 320's incorrect cliff disposal in place since
+//  both are automatically disposed of when that room's pic changes.
+//
+// Applies to: PC CD
+// Responsible methods: Heap in scripts 320 and 321, toEast:changeState, toWest:changeState
+// Fixes bug #10893
+static const uint16 ecoquest1SignatureSouthCliffsPosition[] = {
+	SIG_MAGICDWORD,
+	SIG_UINT16(0x0095),             // easternCliffs:x = 149
+	SIG_UINT16(0x0033),             // easternCliffs:y = 51
+	SIG_ADDTOOFFSET(+88),
+	SIG_UINT16(0x0004),             // westernCliffs:x = 4
+	SIG_UINT16(0x0014),             // westernCliffs:y = 20
+	SIG_END
+};
+
+static const uint16 ecoquest1PatchSouthCliffsPosition[] = {
+	PATCH_ADDTOOFFSET(+2),
+	PATCH_UINT16(0x0133),           // easternCliffs:y = 307
+	PATCH_ADDTOOFFSET(+90),
+	PATCH_UINT16(0x0114),           // westernCliffs:y = 276
+	PATCH_END
+};
+
+static const uint16 ecoquest1SignatureNorthCliffsPosition[] = {
+	SIG_MAGICDWORD,
+	SIG_UINT16(0x00eb),             // easternCliffs:x = 236
+	SIG_UINT16(0x0038),             // easternCliffs:y = 56
+	SIG_ADDTOOFFSET(+88),
+	SIG_UINT16(0x0000),             // westernCliffs:x = 0
+	SIG_UINT16(0x0032),             // westernCliffs:y = 50
+	SIG_END
+};
+
+static const uint16 ecoquest1PatchNorthCliffsPosition[] = {
+	PATCH_ADDTOOFFSET(+2),
+	PATCH_UINT16(0x0138),           // easternCliffs:y = 312
+	PATCH_ADDTOOFFSET(+90),
+	PATCH_UINT16(0x0132),           // westernCliffs:y = 306
+	PATCH_END
+};
+
+static const uint16 ecoquest1SignatureNorthCliffsDisposal[] = {
+	0x39, SIG_SELECTOR8(init),          // pushi init
+	0x76,                               // push0
+	0x72, SIG_ADDTOOFFSET(+2),          // lofsa easternCliffs or westernCliffs
+	0x4a, SIG_MAGICDWORD, 0x04,         // send 04 [ cliffs init: ]
+	0x38, SIG_SELECTOR16(obstacles),    // pushi obstacles
+	SIG_END
+};
+
+static const uint16 ecoquest1PatchNorthCliffsDisposal[] = {
+	0x39, PATCH_SELECTOR8(dispose),     // pushi dispose
+	PATCH_END
+};
+
+// The Spanish version of EcoQuest accidentally shipped with temporary test code
+//  that breaks the game when entering Olympia's apartment. (room 226)
+//
+// A message box's position was localized in the Spanish version. This message
+//  occurs after saving Olympia by pumping bleach out of the window. To test
+//  this change, a developer added code to forcibly run the usePump script upon
+//  entering the room, but then forgot to remove it. This breaks the puzzle and
+//  locks up the game upon re-entering the room.
+//
+// We fix this by disabling the test code that should not have been shipped.
+//
+// Applies to: Spanish PC Floppy
+// Responsible method: rm226:init
+// Fixes bug #10900
+static const uint16 ecoquest1SignatureBleachPumpTest[] = {
+	SIG_MAGICDWORD,
+	0x78,                               // push1
+	0x39, 0x35,                         // pushi 35
+	0x46, SIG_UINT16(0x0333),           // calle proc819_3 [ set recycled-bleach flag ]
+	      SIG_UINT16(0x0003), 0x02,
+	0x38, SIG_SELECTOR16(setScript),    // pushi setScript
+	0x78,                               // push1
+	0x72, SIG_UINT16(0x0a44),           // lofsa usePump
+	0x36,                               // push
+	0x54, 0x06,                         // self 06 [ self setScript: usePump ]
+	SIG_END
+};
+
+static const uint16 ecoquest1PatchBleachPumpTest[] = {
+	0x32, PATCH_UINT16(0x0010),         // jmp 0010 [ skip test code ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                                 patch
+static const SciScriptPatcherEntry ecoquest1Signatures[] = {
+	{  true,   140, "CD: mosaic puzzle fix",                       2, ecoquest1SignatureMosaicPuzzleFix,        ecoquest1PatchMosaicPuzzleFix },
+	{  true,   160, "CD: give superfluous oily shell",             1, ecoquest1SignatureGiveOilyShell,          ecoquest1PatchGiveOilyShell },
+	{  true,   160, "CD/Floppy: column puzzle fix",                1, ecoquest1SignatureColumnPuzzleFix,        ecoquest1PatchColumnPuzzleFix },
+	{  true,   220, "CD: empty apartment messages",                1, ecoquest1SignatureEmptyApartmentMessages, ecoquest1PatchEmptyApartmentMessages },
+	{  true,   226, "Spanish: disable bleach pump test",           1, ecoquest1SignatureBleachPumpTest,         ecoquest1PatchBleachPumpTest },
+	{  true,   320, "CD: south cliffs position",                   1, ecoquest1SignatureSouthCliffsPosition,    ecoquest1PatchSouthCliffsPosition },
+	{  true,   321, "CD: north cliffs position",                   1, ecoquest1SignatureNorthCliffsPosition,    ecoquest1PatchNorthCliffsPosition },
+	{  true,   321, "CD: north cliffs disposal",                   2, ecoquest1SignatureNorthCliffsDisposal,    ecoquest1PatchNorthCliffsDisposal },
+	{  true,   660, "CD: bad messagebox and freeze",               1, ecoquest1SignatureStayAndHelp,            ecoquest1PatchStayAndHelp },
+	{  true,   803, "disable speed test",                          1, sci01SpeedTestGlobalSignature,            sci01SpeedTestGlobalPatch },
+	{  true,   816, "CD: prophecy scroll",                         1, ecoquest1SignatureProphecyScroll,         ecoquest1PatchProphecyScroll },
+	{  true,   928, "CD: EcoTalker lockup fix",                    1, ecoquest1Sq4CdNarratorLockupSignature,    ecoquest1Sq4CdNarratorLockupPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// When the Ecorder is turned on and displays its initial welcome text, the
+//  doMyThing script stores the string in temporary space in one state and then
+//  accesses it in a later state. This worked in Sierra's interpreter by
+//  accident. We reset temporary space every time.
+//
+// We fix this by storing the string in local space instead of temporary space.
+//  Script 50 has 200 bytes of local space reserved for a local procedure to
+//  use as temporary string space so we use that.
+//
+// Applies to: All versions
+// Responsible method: doMyThing:changeState
+// Fixes bug: #4993
+static const uint16 ecoquest2SignatureEcorder[] = {
+	SIG_MAGICDWORD,
+	0x5b, 0x04, 0x1e,                // lea 04 1e [ @temp30 ]
+	0x36,                            // push
+	SIG_END
+};
+
+static const uint16 ecoquest2PatchEcorder[] = {
+	0x5b, 0x02, 0x10,                // lea 02 10 [ @local16 ]
+	PATCH_END
+};
+
+// This is the same Ecorder patch as above, but it's for the introduction when
+//  you're given the Ecorder. The showEcorder script has the same bug and we
+//  fix it the same way by using local space instead of temporary space.
+//
+// Applies to: All versions
+// Responsible method: showEcorder:changeState
+// Fixes bug: #5467
+static const uint16 ecoquest2SignatureEcorderTutorial[] = {
+	SIG_MAGICDWORD,
+	0x5b, 0x04, 0x1f,                // lea 04 1f [ @temp31 ]
+	0x36,                            // push
+	SIG_END
+};
+
+static const uint16 ecoquest2PatchEcorderTutorial[] = {
+	0x5b, 0x02, 0x02,                // lea 02 02 [ @local2 ]
+	PATCH_END
+};
+
+// Clicking an icon during the icon bar tutorial in room 100 sends messages to
+//  an uninitialized temporary variable. This is supposed to be the dispatched
+//  Event object that's passed around earlier in the call stack. In Sierra's
+//  interpreter that's what happened to be at this location and it worked.
+//
+// We fix this by using the global variable that stores the current Event object
+//  instead of the uninitialized temp variable that accidentally points to it.
+//  User:handleEvent sets this global before dispatching an event.
+//
+// Applies to: All versions
+// Responsible methods: iconWalk:select, iconLook:select, ...
+// Fixes bug: #11081
+static const uint16 ecoquest2SignatureIconBarTutorial[] = {
+	0x7a,                               // push2
+	0x38, SIG_SELECTOR16(handleEvent),  // pushi handleEvent
+	SIG_MAGICDWORD,
+	0x8d, 0x01,                         // lst 01  [ uninitialized ]
+	0x4a, 0x08,                         // send 08 [ EventHandler firstTrue: handleEvent temp1 ]
+	SIG_END
+};
+
+static const uint16 ecoquest2PatchIconBarTutorial[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x89, 0x18,                         // lsg 18 [ current event ]
+	PATCH_END
+};
+
+// The electronic organizer and password paper reappear in room 500 after they
+//  fall into the water when entering the canoe. rm500:init only tests if these
+//  items are in inventory. It should have also tested the canoe flag like room
+//  530 does to prevent the vacuum from reappearing.
+//
+// We fix this by only adding an item to the room if its InvI:owner is zero.
+//  This is initially zero, then set to ego when getting an item, and finally
+//  set to negative one when the item is removed from inventory.
+//
+// Applies to: All versions
+// Responsible method: rm500:init
+// Fixes bug: #11135
+static const uint16 ecoquest2SignatureRoom500Items[] = {
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi test
+	0x78,                               // push1
+	SIG_MAGICDWORD,
+	0x39, 0x0b,                         // pushi 0b
+	0x81, 0x96,                         // lag 96
+	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 11 ]
+	0xa5, 0x00,                         // sat 00
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi test
+	0x78,                               // push1
+	0x39, 0x04,                         // pushi 04
+	0x81, 0x96,                         // lag 96
+	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 4 ]
+	0xa5, 0x01,                         // sat 01
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi test
+	0x78,                               // push1
+	0x39, 0x17,                         // pushi 17
+	0x81, 0x96,                         // lag 96
+	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 23 ]
+	0xa5, 0x02,                         // sat 02
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi test
+	SIG_ADDTOOFFSET(+636),
+	0x38, SIG_SELECTOR16(has),          // pushi has
+	0x78,                               // push1
+	0x39, 0x15,                         // pushi 15
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x06,                         // send 06 [ ego has: 21 ]
+	0x18,                               // not
+	0x31, 0x13,                         // bnt 13 [ don't initialize theOrganizer ]
+	SIG_ADDTOOFFSET(+236),
+	0x38, SIG_SELECTOR16(has),          // pushi has
+	0x78,                               // push1
+	0x39, 0x0b,                         // pushi 0b
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x06,                         // send 06 [ ego has: 11 ]
+	0x18,                               // not
+	0x30, SIG_UINT16(0x0058),           // bnt 0058 [ don't initialize paper ]
+	SIG_END
+};
+
+static const uint16 ecoquest2PatchRoom500Items[] = {
+	0x39, PATCH_SELECTOR8(at),          // pushi at
+	0x3c,                               // dup [ push at, saves 1 byte ]
+	0x78,                               // push1
+	0x39, 0x15,                         // pushi 15
+	0x38, PATCH_GETORIGINALUINT16(+1),  // pushi test
+	0x3c,                               // dup [ push test, saves 2 bytes ]
+	0x3c,                               // dup [ push test, saves 2 bytes ]
+	0x3c,                               // dup [ push test, saves 2 bytes ]
+	0x78,                               // push1
+	0x39, 0x0b,                         // pushi 0b
+	0x81, 0x96,                         // lag 96
+	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 11 ]
+	0xa5, 0x00,                         // sat 00
+	0x78,                               // push1
+	0x39, 0x04,                         // pushi 04
+	0x81, 0x96,                         // lag 96
+	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 4 ]
+	0xa5, 0x01,                         // sat 01
+	0x78,                               // push1
+	0x39, 0x17,                         // pushi 17
+	0x81, 0x96,                         // lag 96
+	0x4a, 0x06,                         // send 06 [ cibolaFlags test: 23 ]
+	0xa5, 0x02,                         // sat 02
+	PATCH_ADDTOOFFSET(+636),
+	0x81, 0x09,                         // lag 09
+	0x4a, 0x06,                         // send 06 [ Inv at: 21 ]
+	0x38, PATCH_SELECTOR16(owner),      // pushi owner
+	0x76,                               // push0
+	0x4a, 0x04,                         // send 04 [ organizer owner? ]
+	0x78,                               // push1
+	0x2f, 0x13,                         // bt 13 [ don't initialize theOrganizer ]
+	PATCH_ADDTOOFFSET(+236),
+	0x39, 0x0b,                         // pushi 0b
+	0x81, 0x09,                         // lag 09
+	0x4a, 0x06,                         // send 06 [ Inv at: 11 ]
+	0x38, PATCH_SELECTOR16(owner),      // pushi owner
+	0x76,                               // push0
+	0x4a, 0x04,                         // send 04 [ password owner? ]
+	0x2f, 0x58,                         // bt 58 [ don't initialize paper ]
+	PATCH_END
+};
+
+// The Ecorder cursor only highlights over one of the four Victoria lilies, even
+//  though they all respond to Ecorder clicks. Each lily has a doit method that
+//  highlights the cursor but three of them never execute because they are
+//  added to the room pic. This removes them from the cast and prevents doit.
+//
+// We fix this by removing the addToPic calls so the lilies remain in the cast.
+//
+// Applies to: All versions
+// Responsible methods: lilly1:init, lilly2:init, lilly3:init
+// Fixes bug: #5552
+static const uint16 ecoquest2SignatureEcorderLily[] = {
+	0x38, SIG_MAGICDWORD,               // pushi addToPic
+	      SIG_SELECTOR16(addToPic),
+	0x76,                               // push0
+	0x54, 0x04,                         // self 04 [ self addToPic: ]
+	SIG_END
+};
+
+static const uint16 ecoquest2PatchEcorderLily[] = {
+	0x32, PATCH_UINT16(0x0003),         // jmp 0003
+	PATCH_END
+};
+
+// Objects that you can hide behind in rooms 530 and 560 all have messages that
+//  are supposed to display when clicking Do after Gonzales leaves camp, but
+//  their doVerb methods are missing a call to super:doVerb. We fix this by
+//  patching the doVerb methods to call super:doVerb instead of doing nothing.
+//
+// Applies to: All versions
+// Responsible methods: crates:doVerb, barrel1-4:doVerb, refuse:doVerb in 530,
+//  bullldozer:doVerb, barrel1-5:doVerb, crates:doVerb in 560
+static const uint16 ecoquest2SignatureCampMessages1[] = {
+	0x30, SIG_UINT16(0x0033),           // bnt 0033 [ end of method ]
+	SIG_ADDTOOFFSET(+10),
+	0x30, SIG_UINT16(0x0026),           // bnt 0026 [ end of method ]
+	SIG_ADDTOOFFSET(+8),
+	0x30, SIG_UINT16(0x001b),           // bnt 001b [ end of method ]
+	0x38, SIG_SELECTOR16(setScript),    // pushi setScript
+	0x39, SIG_MAGICDWORD, 0x03,         // pushi 03
+	0x72, SIG_UINT16(0x00cc),           // lofsa sRunHide
+	SIG_ADDTOOFFSET(+10),
+	0x38, SIG_SELECTOR16(doVerb),       // pushi doVerb
+	SIG_END
+};
+
+static const uint16 ecoquest2PatchCampMessages1[] = {
+	0x30, PATCH_UINT16(0x002a),         // bnt 002a [ super doVerb: verb ]
+	PATCH_ADDTOOFFSET(+10),
+	0x30, PATCH_UINT16(0x001d),         // bnt 001d [ super doVerb: verb ]
+	PATCH_ADDTOOFFSET(+8),
+	0x30, PATCH_UINT16(0x0012),         // bnt 0012 [ super doVerb: verb ]
+	PATCH_END
+};
+
+static const uint16 ecoquest2SignatureCampMessages2[] = {
+	0x30, SIG_UINT16(0x001b),           // bnt 001b [ end of method ]
+	0x38, SIG_SELECTOR16(setScript),    // pushi setScript
+	0x39, SIG_MAGICDWORD, 0x03,         // pushi 03
+	0x72, SIG_UINT16(0x0154),           // lofsa sRunHide
+	SIG_ADDTOOFFSET(+10),
+	0x38, SIG_SELECTOR16(doVerb),       // pushi doVerb
+	SIG_END
+};
+
+static const uint16 ecoquest2PatchCampMessages2[] = {
+	0x30, PATCH_UINT16(0x0012),         // bnt 0012 [ super doVerb: verb ]
+	PATCH_END
+};
+
+//          script, description,                                        signature                          patch
+static const SciScriptPatcherEntry ecoquest2Signatures[] = {
+	{  true,     0, "icon bar tutorial",                            10, ecoquest2SignatureIconBarTutorial, ecoquest2PatchIconBarTutorial },
+	{  true,    10, "disable speed test",                            1, sci11SpeedTestSignature,           sci11SpeedTestPatch},
+	{  true,    50, "initial text not removed on ecorder",           3, ecoquest2SignatureEcorder,         ecoquest2PatchEcorder },
+	{  true,   333, "initial text not removed on ecorder tutorial",  3, ecoquest2SignatureEcorderTutorial, ecoquest2PatchEcorderTutorial },
+	{  true,   500, "room 500 items reappear",                       1, ecoquest2SignatureRoom500Items,    ecoquest2PatchRoom500Items },
+	{  true,   530, "missing camp messages",                         6, ecoquest2SignatureCampMessages1,   ecoquest2PatchCampMessages1 },
+	{  true,   560, "missing camp messages",                         7, ecoquest2SignatureCampMessages2,   ecoquest2PatchCampMessages2 },
+	{  true,   702, "ecorder not highlighting lilies",               3, ecoquest2SignatureEcorderLily,     ecoquest2PatchEcorderLily },
+	{  true,   928, "Narrator lockup fix",                           1, sciNarratorLockupSignature,        sciNarratorLockupPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// Fan-made games
+// Attention: Try to make script patches as specific as possible
+
+// CascadeQuest::autosave in script 994 is called various times to auto-save.
+//  It uses a fixed slot (999) for this purpose. This doesn't work in ScummVM,
+//  because we do not let scripts save directly into specific slots, but
+//  instead use virtual slots / detect scripts wanting to create a new slot.
+// We patch the code to use slot 99 instead. kSaveGame also checks for Cascade
+//  Quest, and if slot 99 is asked for, it will then use the actual slot 0,
+//  which is the official ScummVM auto-save slot.
+//
+// Responsible method: CascadeQuest::autosave
+// Fixes bug: #7007
+static const uint16 fanmadeSignatureCascadeQuestFixAutoSaving[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x03e7),        // pushi 3E7 (999d) -> save game slot 999
+	0x74, SIG_UINT16(0x06f8),        // lofss "AutoSave"
+	0x89, 0x1e,                      // lsg global[1e]
+	0x43, 0x2d, 0x08,                // callk SaveGame
+	SIG_END
+};
+
+static const uint16 fanmadePatchCascadeQuestFixAutoSaving[] = {
+	0x38, PATCH_UINT16((SAVEGAMEID_OFFICIALRANGE_START - 1)), // fix slot
+	PATCH_END
+};
+
+// EventHandler::handleEvent in Demo Quest has a bug, and it jumps to the
+// wrong address when an incorrect word is typed, therefore leading to an
+// 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: #5120
+static const uint16 fanmadeSignatureDemoQuestInfiniteLoop[] = {
+	0x38, SIG_UINT16(0x004c),        // pushi 004c
+	0x39, 0x00,                      // pushi 00
+	0x87, 0x01,                      // lap param[1]
+	0x4b, 0x04,                      // send 04
+	SIG_MAGICDWORD,
+	0x18,                            // not
+	0x30, SIG_UINT16(0x002f),        // bnt 002f  [06a5]    --> jmp ffbc  [0664] --> BUG! infinite loop
+	SIG_END
+};
+
+static const uint16 fanmadePatchDemoQuestInfiniteLoop[] = {
+	PATCH_ADDTOOFFSET(+10),
+	0x30, PATCH_UINT16(0x0032),      // bnt 0032  [06a8] --> pushi 004c
+	PATCH_END
+};
+
+// This patch is for a bug that first appeared in the LSL3 volume dialog and was
+//  then copied into the templates included with SCI Studio and SCI Companion,
+//  causing it to appear in fan games. See larry3SignatureVolumeSlider.
+//
+// Applies to: Fan games built with the SCI Studio / SCI Companion SCI0 template
+// Responsible method: TheMenuBar:handleEvent
+static const uint16 fangameSignatureVolumeSlider1[] = {
+	0x39, SIG_SELECTOR8(doit),       // pushi doit
+	SIG_ADDTOOFFSET(+1),             // push1 [ opcode 79 instead of 78 in some games ]
+	SIG_ADDTOOFFSET(+1),             // push2 [ opcode 7b instead of 7a in some games ]
+	SIG_MAGICDWORD,
+	0x39, 0x08,                      // pushi 08 [ volume ]
+	0x8d, 0x03,                      // lst 03   [ uninitialized variable ]
+	0x43, 0x31, 0x04,                // callk DoSound 04 [ set volume and return previous ]
+	SIG_END
+};
+
+static const uint16 fangamePatchVolumeSlider1[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x39, 0x01,                      // pushi 01
+	0x38, PATCH_UINT16(0x0008),      // pushi 0008 [ volume ]
+	0x43, 0x31, 0x02,                // callk DoSound 02 [ return volume ]
+	PATCH_END
+};
+
+static const uint16 fangameSignatureVolumeSlider2[] = {
+	0x38, SIG_SELECTOR16(doit),      // pushi doit
+	0x39, 0x01,                      // pushi 01
+	0x39, 0x02,                      // pushi 02
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x0008),        // pushi 0808 [ volume ]
+	0x8d, 0x03,                      // lst 03     [ uninitialized variable ]
+	0x43, 0x31, 0x04,                // callk DoSound 04 [ set volume and return previous ]
+	SIG_END
+};
+
+static const uint16 fangamePatchVolumeSlider2[] = {
+	PATCH_ADDTOOFFSET(+5),
+	0x39, 0x01,                      // pushi 01
+	PATCH_ADDTOOFFSET(+3),
+	0x33, 0x00,                      // jmp 00
+	0x43, 0x31, 0x02,                // callk DoSound 02 [ return volume ]
+	PATCH_END
+};
+
+// Fan games based on the SCI Studio template reset their volume to 15 (max) in
+//  the init method of their game object in script 0. As with most SCI32 games,
+//  we patch this out so that the volume stored in ScummVM is used.
+// 
+// Applies to: Fan games built with the SCI Studio / SCI Companion SCI0 template
+// Responsible method: Template:init (the Game object in script 0)
+// Fixes bug: #13795
+static const uint16 fangameSignatureVolumeReset1[] = {
+	0x35, 0x0f,                      // ldi 0f
+	SIG_ADDTOOFFSET(+1), 0x1d,       // sag 1d   [ sag or sal depending on compiler ] 
+	SIG_ADDTOOFFSET(+1),             // push2    [ opcode 7b instead of 7a in some games ]
+	0x39, 0x08,                      // pushi 08 [ volume ]
+	SIG_ADDTOOFFSET(+1),             // lsg 1d   [ lsg or lsl depending on compiler ]
+	SIG_MAGICDWORD, 0x1d,      
+	0x43, 0x31, 0x04,                // callk DoSound 04
+	SIG_END
+};
+
+static const uint16 fangamePatchVolumeReset1[] = {
+	0x33, 0x0a,                      // jmp 0a
+	PATCH_END
+};
+
+static const uint16 fangameSignatureVolumeReset2[] = {
+	0x34, SIG_UINT16(0x000f),        // ldi 0f
+	0xa1, 0x1d,                      // sag 1d
+	0x39, 0x02,                      // pushi 02
+	0x38, SIG_UINT16(0x0008),        // pushi 0008 [ volume ]
+	0x89, SIG_MAGICDWORD, 0x1d,      // lsg 1d
+	0x43, 0x31, 0x04,                // callk DoSound 04
+	SIG_END
+};
+
+static const uint16 fangamePatchVolumeReset2[] = {
+	0x33, 0x0d,                      // jmp 0d
+	PATCH_END
+};
+
+//          script, description,                                      signature                                  patch
+static const SciScriptPatcherEntry fanmadeSignatures[] = {
+	{  true,     0, "SCI Template: disable volume reset",          1, fangameSignatureVolumeReset1,              fangamePatchVolumeReset1 },
+	{  true,     0, "SCI Template: disable volume reset",          1, fangameSignatureVolumeReset2,              fangamePatchVolumeReset2 },
+	{  true,   994, "Cascade Quest: fix auto-saving",              1, fanmadeSignatureCascadeQuestFixAutoSaving, fanmadePatchCascadeQuestFixAutoSaving },
+	{  true,   997, "SCI Template: fix volume slider",             1, fangameSignatureVolumeSlider1,             fangamePatchVolumeSlider1 },
+	{  true,   997, "SCI Template: fix volume slider",             1, fangameSignatureVolumeSlider2,             fangamePatchVolumeSlider2 },
+	{  true,   999, "Demo Quest: infinite loop on typo",           1, fanmadeSignatureDemoQuestInfiniteLoop,     fanmadePatchDemoQuestInfiniteLoop },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+
+// WORKAROUND
+// Freddy Pharkas intro screen
+// Sierra used inner loops for the scaling of the 2 title views.
+// Those inner loops don't call kGameIsRestarting, which is why
+// we do not update the screen and we also do not throttle.
+//
+// This patch fixes this and makes it work.
+// Applies to at least: English PC-CD
+// Responsible method: sTownScript::changeState(1), sTownScript::changeState(3) (script 110)
+static const uint16 freddypharkasSignatureIntroScaling[] = {
+	0x38, SIG_ADDTOOFFSET(+2),       // pushi (setLoop) (009b for PC CD)
+	0x78,                            // push1
+	SIG_ADDTOOFFSET(+1),             // push0 for first code, push1 for second code
+	0x38, SIG_ADDTOOFFSET(+2),       // pushi (setStep) (0143 for PC CD)
+	0x7a,                            // push2
+	0x39, 0x05,                      // pushi 05
+	0x3c,                            // dup
+	0x72, SIG_ADDTOOFFSET(+2),       // lofsa (view)
+	SIG_MAGICDWORD,
+	0x4a, 0x1e,                      // send 1e
+	0x35, 0x0a,                      // ldi 0a
+	0xa3, 0x02,                      // sal local[2]
+	// start of inner loop
+	0x8b, 0x02,                      // lsl local[2]
+	SIG_ADDTOOFFSET(+43),            // skip almost all of inner loop
+	0xa3, 0x02,                      // sal local[2]
+	0x33, 0xcf,                      // jmp [inner loop start]
+	SIG_END
+};
+
+static const uint16 freddypharkasPatchIntroScaling[] = {
+	// remove setLoop(), objects in heap are already prepared, saves 5 bytes
+	0x38,
+	PATCH_GETORIGINALUINT16(+6),     // pushi (setStep)
+	0x7a,                            // push2
+	0x39, 0x05,                      // pushi 05
+	0x3c,                            // dup
+	0x72,
+	PATCH_GETORIGINALUINT16(+13),    // lofsa (view)
+	0x4a, 0x18,                      // send 18 - adjusted
+	0x35, 0x0a,                      // ldi 0a
+	0xa3, 0x02,                      // sal local[2]
+	// start of new inner loop
+	0x78,                            // push1
+	0x76,                            // push0
+	0x43, 0x2c, 0x02,                // callk GameIsRestarting 02 (add this to trigger our speed throttler)
+	PATCH_ADDTOOFFSET(+47),          // skip almost all of inner loop
+	0x33, 0xca,                      // jmp [inner loop start]
+	PATCH_END
+};
+
+// In script 235, rm235::init and sEnterFrom500 disable icon 7+8 of iconbar (CD
+//  only). When picking up the canister after placing it down, the scripts will
+//  disable all the other icons. This results in IconBar::disable doing endless
+//  loops even in sierra sci because there is no enabled icon left. We remove
+//  the disabling of icon 8 (which is help). This fixes the issue.
+// Applies to at least: English PC-CD
+// Responsible method: rm235::init and sEnterFrom500::changeState
+// Fixes bug: #5245
+static const uint16 freddypharkasSignatureCanisterHang[] = {
+	0x38, SIG_SELECTOR16(disable),   // pushi disable
+	0x7a,                            // push2
+	SIG_MAGICDWORD,
+	0x39, 0x07,                      // pushi 07
+	0x39, 0x08,                      // pushi 08
+	0x81, 0x45,                      // lag global[45]
+	0x4a, 0x08,                      // send 08 (call IconBar::disable(7, 8))
+	SIG_END
+};
+
+static const uint16 freddypharkasPatchCanisterHang[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x78,                            // push1
+	PATCH_ADDTOOFFSET(+2),
+	0x33, 0x00,                      // jmp 0 (waste 2 bytes)
+	PATCH_ADDTOOFFSET(+3),
+	0x06,                            // send 06 (call IconBar::disable(7))
+	PATCH_END
+};
+
+// In script 215, lowerLadder::doit and highLadder::doit actually process
+//   keyboard presses when the ladder is on the screen in that room. They
+//   strangely also call kGetEvent. Because the main User::doit also calls
+//   kGetEvent, it's pure luck, where the event will hit. It's the same issue
+//   as in QfG1VGA. If you turn DOSBox to max cycles and click around for 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.
+// Applies to at least: English PC-CD, German Floppy, English Mac
+// Responsible method: lowerLadder::doit and highLadder::doit
+// Fixes bug: #5060
+static const uint16 freddypharkasSignatureLadderEvent[] = {
+	0x39, SIG_MAGICDWORD,
+	SIG_SELECTOR8(new),              // pushi new
+	0x76,                            // push0
+	0x38, SIG_SELECTOR16(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(localize),  // pushi localize
+	0x76,                            // push0
+	0x4a, 0x04,                      // send 04 (call curEvent::localize)
+	SIG_END
+};
+
+static const uint16 freddypharkasPatchLadderEvent[] = {
+	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)
+	PATCH_ADDTOOFFSET(+2),
+	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.
+// Applies to at least: English Mac
+// Responsible method: publicfpInv::drawInvWindow in script 15
+static const uint16 freddypharkasSignatureMacInventory[] = {
+	SIG_MAGICDWORD,
+	0x39, 0x23,                      // pushi 23
+	0x39, 0x74,                      // pushi 74
+	0x78,                            // push1
+	0x38, SIG_UINT16(0x0174),        // pushi 0174 (on mac it's actually 0x01, 0x74)
+	0x85, 0x15,                      // lat temp[15]
+	SIG_END
+};
+
+static const uint16 freddypharkasPatchMacInventory[] = {
+	0x39, 0x02,                      // pushi 02 (now matches the DOS version)
+	PATCH_ADDTOOFFSET(+23),
+	0x39, 0x04,                      // pushi 04 (now matches the DOS version)
+	PATCH_END
+};
+
+// WORKAROUND
+// FPFP Mac has an easter egg with a script bug that accidentally works in
+//  Sierra's interpreter. Clicking Talk on a small part of the mine in room 270
+//  triggers it. The script macThing plays macSound and waits for it to finish,
+//  but macSound:loop is set to -1, indicating that it should loop forever.
+//  ScummVM loops the sound and so macThing never advances to the next state and
+//  the user never regains control. Sierra's interpreter cues the script after
+//  the first play and doesn't loop the sound, despite macSound:loop.
+//
+// We work around this by setting macSound:loop correctly on the heap so that it
+//  only plays once and macThing proceeds.
+//
+// This buggy script didn't break in the original because the Mac interpreter
+//  didn't support looping sounds. It always played sounds just once and then
+//  signaled when they were complete and ignored the value of the loop property.
+//  This was most apparent in the KQ6 Mac port. All the room music, which was
+//  designed to loop, stopped abruptly after a minute in a room and then
+//  jarringly returned when changing rooms.
+//
+// Applies to: Mac Floppy
+// Responsible method: Heap in script 270
+// Fixes bug #7065
+static const uint16 freddypharkasSignatureMacEasterEggHang[] = {
+	SIG_MAGICDWORD,                 // macSound
+	SIG_UINT16(0x0b89),             // number = 2953
+	SIG_UINT16(0x007f),             // vol = 127
+	SIG_UINT16(0x0000),             // priority = 0
+	SIG_UINT16(0xffff),             // loop = -1 [ loop sound forever ]
+	SIG_END
+};
+
+static const uint16 freddypharkasPatchMacEasterEggHang[] = {
+	PATCH_ADDTOOFFSET(+6),
+	PATCH_UINT16(0x0001),           // loop = 1 [ play sound once ]
+	PATCH_END
+};
+
+// WORKAROUND
+// FPFP Mac's easter egg has a view that relies on a bug in the Mac interpreter.
+//  Sierra's interpreter draws views one pixel higher than their y coordinate.
+//  KQ6 Mac has this bug too. Compared to their original PC versions, views
+//  appear higher relative to their background. This is a problem for views that
+//  require precise placement to blend in with those backgrounds.
+//
+// The Mac easter egg adds such a view. View 275 contains a hand in the lake
+//  holding a Macintosh computer. Because this feature was developed against the
+//  Mac interpreter, the y coordinate that achieved the water effect is really
+//  off by one. In our interpreter, which doesn't have this bug, the view
+//  appears one pixel lower than intended and doesn't match the background.
+//
+// We fix this by adjusting macView:y to compensate for Sierra's off-by-one bug
+//  so that view 275 matches the lake background as in the original.
+//
+// Applies to: Mac Floppy
+// Responsible method: Heap in script 270
+static const uint16 freddypharkasSignatureMacEasterEggView[] = {
+	SIG_MAGICDWORD,                 // macView
+	SIG_UINT16(0x061e),             // name = $061e [ macView ]
+	SIG_UINT16(0x00cd),             // x = 205
+	SIG_UINT16(0x0065),             // y = 101
+	SIG_END
+};
+
+static const uint16 freddypharkasPatchMacEasterEggView[] = {
+	PATCH_ADDTOOFFSET(+4),
+	PATCH_UINT16(0x0064),           // y = 100
+	PATCH_END
+};
+
+// FPFP Mac is missing view 844 of Hop Singh leaving town, breaking the scene.
+//  This occurs when going to the desert (room 200) after the restaurant closes
+//  but before act 3 ends. This would also crash the original so we just disable
+//  this minor optional scene.
+//
+// Applies to: Mac Floppy
+// Responsible method: rm200:init
+// Fixes bug #10954
+static const uint16 freddypharkasSignatureMacHopSingh[] = {
+	0x89, 0x77,                     // lsg 77
+	0x35, 0x13,                     // ldi 13
+	0x1a,                           // eq? [ did restaurant just close? ]
+	0x31, 0x46,                     // bnt 46 [ skip hop singh scene ]
+	SIG_ADDTOOFFSET(+0x41),
+	SIG_MAGICDWORD,
+	0x72, 0x01, 0xd0,               // lofsa hopSingh [ hard-coded big endian for mac ]
+	0x4a, 0x20,                     // send 20 [ hopSingh init: ... setScript: sLeaveTown ]
+	SIG_END
+};
+
+static const uint16 freddypharkasPatchMacHopSingh[] = {
+	0x33, 0x4b,                     // jmp 4b [ always skip hop singh scene ]
+	PATCH_END
+};
+
+// At the start of act 4 the church key is removed from inventory but reappears
+//  in the church door. The door script attempts to prevent this by not drawing
+//  the key in act 4 but the verb handler is missing this check. Looking at the
+//  door in act 4 still brings up the inset with the key. Sierra fixed this in
+//  Mac but forgot to include the fix in the CD version a year later.
+//
+// We fix this by replacing a duplicate inventory check with an act 4 check so
+//  that the key no longer appears in the inset and can't be picked up again.
+//
+// Applies to: PC Floppy, PC CD
+// Responsible method: inDoorInset:init
+// Fixes bug #10975
+static const uint16 freddypharkasSignatureChurchKey[] = {
+	SIG_MAGICDWORD,
+	0x76,                           // push0
+	0x59, 0x01,                     // &rest 01
+	0x57, SIG_ADDTOOFFSET(+1), 0x04,// super Inset 04 [ super: init &rest ]
+	0x38, SIG_SELECTOR16(has),      // pushi has
+	0x78,                           // push1
+	0x39, 0x06,                     // pushi 06
+	0x81, 0x00,                     // lag 00
+	0x4a, 0x06,                     // send 06 [ ego has: 6 (church key) ]
+	SIG_END
+};
+
+static const uint16 freddypharkasPatchChurchKey[] = {
+	PATCH_ADDTOOFFSET(+6),
+	0x89, 0x78,                     // lsg 78 [ act number ]
+	0x35, 0x04,                     // ldi 04
+	0x20,                           // ge?
+	0x33, 0x03,                     // jmp 03
+	PATCH_END
+};
+
+// After leaving the desk letter in the grave, the letter reappears in the desk.
+//  The desk script only checks if the letter is in inventory. Sierra started to
+//  fix this in the CD version by setting a new flag but forgot to check it.
+//
+// We fix this by testing Letter's owner, if -1 then it is in the grave.
+//
+// Applies to: All versions
+// Responsible method: deskDrawer:doVerb(1)
+// Fixes bug #10975
+static const uint16 freddypharkasSignatureDeskLetter[] = {
+	SIG_MAGICDWORD,
+	0x30, SIG_UINT16(0x0055),       // bnt 0055
+	0x38, SIG_SELECTOR16(has),      // pushi has
+	0x78,                           // push1
+	0x39, 0x1f,                     // pushi 1f
+	0x81, 0x00,                     // lag 00
+	0x4a, 0x06,                     // send 06 [ ego has: 31 (Letter) ]
+	0x18,                           // not
+	0x31, 0x1f,                     // bnt 1f
+	0x78,                           // push1
+	0x39, 0x31,                     // pushi 31
+	0x45, 0x02, 0x02,               // callb proc0_2 02 [ is flag 49 set? ]
+	0x31, 0x17,                     // bnt 17
+	0x38, SIG_ADDTOOFFSET(+2),      // pushi stopUpd
+	0x76,                           // push0
+	0x81, 0x00,                     // lag 00
+	0x4a, 0x04,                     // send 04 [ ego stopUpd: (optimization) ]
+	0x38, SIG_ADDTOOFFSET(+2),      // pushi setInset
+	0x78,                           // push1
+	0x72, SIG_UINT16(0x0522),       // lofsa inLetterInset
+	0x36,                           // push
+	0x81, 0x02,                     // lag 02
+	0x4a, 0x06,                     // send 06  [ rm610 setInset: inLetterInset ]
+	0x32, SIG_UINT16(0x008f),       // jmp 008f [ end of method ]
+	0x78,                           // push1
+	0x39, 0x31,                     // pushi 31
+	0x45, 0x02, 0x02,               // callb proc0_2 02 [ is flag 49 set? ]
+	0x31, 0x11,                     // bnt 11 [ drawer is closed ]
+	SIG_END
+};
+
+static const uint16 freddypharkasPatchDeskLetter[] = {
+	0x31, 0x56,                     // bnt 56
+	0x78,                           // push1
+	0x39, 0x31,                     // pushi 31
+	0x45, 0x02, 0x02,               // callb proc0_2 02 [ is flag 49 set? ]
+	0x31, 0x3e,                     // bnt 3e  [ drawer is closed ]
+	0x38, PATCH_SELECTOR16(has),    // pushi has
+	0x78,                           // push1
+	0x39, 0x1f,                     // pushi 1f
+	0x81, 0x00,                     // lag 00
+	0x4a, 0x06,                     // send 06 [ ego has: 31 (Letter) ]
+	0x2f, 0x21,                     // bt 21   [ drawer is open and empty ]
+	0x39, PATCH_SELECTOR8(at),      // pushi at
+	0x78,                           // push1
+	0x39, 0x1f,                     // pushi 1f
+	0x81, 0x09,                     // lag 09
+	0x4a, 0x06,                     // send 06 [ fpInv at: 31 (Letter) ]
+	0x38, PATCH_SELECTOR16(owner),  // pushi owner
+	0x76,                           // push0
+	0x4a, 0x04,                     // send 04 [ Letter owner? ]
+	0x39, 0xff,                     // pushi ff
+	0x1a,                           // eq?
+	0x2f, 0x0d,                     // bt 0d   [ drawer is open and empty ]
+	0x38, PATCH_GETORIGINALUINT16(+33), // pushi setInset
+	0x78,                           // push1
+	0x74, PATCH_UINT16(0x0522),     // lofss inLetterInset
+	0x81, 0x02,                     // lag 02
+	0x4a, 0x06,                     // send 06 [ rm610 setInset: inLetterInset ]
+	0x3a,                           // toss
+	0x48,                           // ret
+	PATCH_END
+};
+
+//          script, description,                                      signature                                patch
+static const SciScriptPatcherEntry freddypharkasSignatures[] = {
+	{  true,    15, "Mac: broken inventory",                       1, freddypharkasSignatureMacInventory,      freddypharkasPatchMacInventory },
+	{  true,    28, "disable speed test",                          1, sci11SpeedTestSignature,                 sci11SpeedTestPatch },
+	{  true,   110, "intro scaling workaround",                    2, freddypharkasSignatureIntroScaling,      freddypharkasPatchIntroScaling },
+	{  false,  200, "Mac: skip broken hop singh scene",            1, freddypharkasSignatureMacHopSingh,       freddypharkasPatchMacHopSingh },
+	{  true,   235, "CD: canister pickup hang",                    3, freddypharkasSignatureCanisterHang,      freddypharkasPatchCanisterHang },
+	{  true,   270, "Mac: easter egg hang",                        1, freddypharkasSignatureMacEasterEggHang,  freddypharkasPatchMacEasterEggHang },
+	{  true,   270, "Mac: easter egg view",                        1, freddypharkasSignatureMacEasterEggView,  freddypharkasPatchMacEasterEggView },
+	{  true,   310, "church key reappears",                        1, freddypharkasSignatureChurchKey,         freddypharkasPatchChurchKey },
+	{  true,   320, "ladder event issue",                          2, freddypharkasSignatureLadderEvent,       freddypharkasPatchLadderEvent },
+	{  true,   610, "desk letter reappears",                       1, freddypharkasSignatureDeskLetter,        freddypharkasPatchDeskLetter },
+	{  true,   928, "Narrator lockup fix",                         1, sciNarratorLockupSignature,              sciNarratorLockupPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+
+// During Bridge, Declarer_Second_NT:think performs a bitwise or against an
+//  object due to a script typo. This operation is supposed to be against
+//  (bridgeHand:highCard):rank but instead it's against bridgeHand:highCard.
+//  ThirdSeat_Trump:think has a correct version of this. Declarer_Second_NT must
+//  have just been missing the word "rank" in the original script.
+//
+// We fix this by inserting the missing rank code. To make room we remove the
+//  call to self:checkFinCard. It's called immediately before this patch and its
+//  result is stored in local1 so we just use that. Hoyle5 also has this bug.
+//
+// Applies to at least: English PC
+// Responsible method: Declarer_Second_NT:think
+// Fixes bug #11163
+static const uint16 hoyle4SignatureBridgeArithmetic[] = {
+	0x36,                               // push [ bridgeHand:highCard ]
+	0x34, SIG_UINT16(0x0f00),           // ldi 0f00
+	0x14,                               // or [ error: bridgeHand:highCard is an object ]
+	0x36,                               // push
+	0x63, 0x42,                         // pToa pard
+	0x4a, 0x08,                         // send 08 [ pard hasCard: theSuitLead (bridgeHand:highCard | 0f00) ]
+	SIG_MAGICDWORD,
+	0x2f, 0x1d,                         // bt 1d
+	0x83, 0x03,                         // lal 03
+	0x2f, 0x19,                         // bt 19
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi rank
+	0x76,                               // push0
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi checkFinCard
+	0x78,                               // push1
+	0x67, 0x48,                         // pTos theSuitLead
+	0x54, 0x06,                         // self 06 [ self checkFinCard: theSuitLead ]
+	SIG_END
+};
+
+static const uint16 hoyle4PatchBridgeArithmetic[] = {
+	0x38, PATCH_GETORIGINALUINT16(+17), // pushi rank
+	0x76,                               // push0
+	0x4a, 0x04,                         // send 04 [ bridgeHand:highCard rank? ]
+	0x36,                               // push
+	0x34, PATCH_UINT16(0x0f00),         // ldi 0f00
+	0x14,                               // or
+	0x36,                               // push
+	0x63, 0x42,                         // pToa pard
+	0x4a, 0x08,                         // send 08 [ pard hasCard: theSuitLead ((bridgeHand:highCard):rank | 0f00) ]
+	0x2f, 0x17,                         // bt 17
+	0x83, 0x03,                         // lal 03
+	0x2f, 0x13,                         // bt 13
+	0x38, PATCH_GETORIGINALUINT16(+17), // pushi rank
+	0x76,                               // push0
+	0x83, 0x01,                         // lal 01 [ set to "self checkFinCard: theSuitLead" earlier ]
+	PATCH_END
+};
+
+// In Crazy Eights, playing an eight plays a transition sound effect that's
+//  abruptly interrupted at modern CPU speeds. The timing only worked in the
+//  original on slow CPUs where the interpreter couldn't complete the transition
+//  animation and deal the next card fast enough.
+//
+// We fix this by waiting on the transition sound instead of the animation.
+//
+// Applies to at least: English PC
+// Responsible method: transition:init
+// Fixes bug #10790
+static const uint16 hoyle4SignatureCrazyEightsSound[] = {
+	0x80, SIG_UINT16(0x0129),           // lag 0129
+	0x4a, 0x06,                         // send 06 [ song setLoop: 1 ]
+	0x39, SIG_SELECTOR8(play),          // pushi play
+	0x78,                               // push1
+	0x39, SIG_MAGICDWORD, 0x6f,         // pushi 6f
+	0x80, SIG_UINT16(0x0129),           // lag 0129
+	0x4a, 0x06,                         // send 06 [ song play: 111 ]
+	SIG_ADDTOOFFSET(+57),
+	0x7c,                               // pushSelf [ animation caller ]
+	SIG_END
+};
+
+static const uint16 hoyle4PatchCrazyEightsSound[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x33, 0x00,                         // jmp 00
+	PATCH_ADDTOOFFSET(+2),
+	0x7a,                               // push2
+	PATCH_ADDTOOFFSET(+2),
+	0x7c,                               // pushSelf
+	0x4a, 0x0e,                         // send 0e [ song setLoop: 1 play: 111 self ]
+	0x33, 0x00,                         // jmp 00
+	PATCH_ADDTOOFFSET(+57),
+	0x76,                               // push0 [ no animation caller ]
+	PATCH_END
+};
+
+// In Gin Rummy, sound 404 plays when undercutting the computer but it gets
+//  interrupted. layEmOut:changeState sets a half-second delay, which is long
+//  enough for the undercut sound when the computer wins, but not this one.
+//
+// We fix this by increasing the delay to a full second when playing sound 404.
+//
+// Applies to: All versions
+// Responsible method: layEmOut:changeState(11)
+static const uint16 hoyle4SignatureGinUndercutSound[] = {
+	0x30, SIG_UINT16(0x0027),          // bnt 0027
+	SIG_ADDTOOFFSET(+11),
+	0x30, SIG_UINT16(0x000e),          // bnt 000e
+	SIG_ADDTOOFFSET(+11),
+	0x32, SIG_UINT16(0x000b),          // jmp 000b
+	0x39, SIG_SELECTOR8(play),         // pushi play
+	0x78,                              // push1
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x0194),          // pushi 0194
+	0x80, SIG_UINT16(0x012a),          // lag 012a
+	0x4a, 0x06,                        // send 06 [ sound play: 404 ]
+	0x35, 0x1e,                        // ldi 1e
+	0x65, 0x20,                        // aTop ticks [ ticks = 30 ]
+	0x32, SIG_UINT16(0x000c),          // jmp 000c [ toss, ret ]
+	SIG_END
+};
+
+static const uint16 hoyle4PatchGinUndercutSound[] = {
+	0x30, PATCH_UINT16(0x002a),        // bnt 002a
+	PATCH_ADDTOOFFSET(+11),
+	0x30, PATCH_UINT16(0x000d),        // bnt 000d
+	PATCH_ADDTOOFFSET(+11),
+	0x33, 0x0f,                        // jmp 0f
+	0x39, PATCH_SELECTOR8(play),       // pushi play
+	0x78,                              // push1
+	0x38, PATCH_UINT16(0x0194),        // pushi 0194
+	0x80, PATCH_UINT16(0x012a),        // lag 012a
+	0x4a, 0x06,                        // send 06 [ sound play: 404 ]
+	0x35, 0x3c,                        // ldi 3c
+	0x33, 0x02,                        // jmp 02 [ ticks = 60 ]
+	0x35, 0x1e,                        // ldi 1e
+	0x65, 0x20,                        // aTop ticks [ ticks = 30 ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                         patch
+static const SciScriptPatcherEntry hoyle4Signatures[] = {
+	{  true,   100, "crazy eights sound",                          1, hoyle4SignatureCrazyEightsSound,  hoyle4PatchCrazyEightsSound },
+	{  true,   400, "gin undercut sound",                          1, hoyle4SignatureGinUndercutSound,  hoyle4PatchGinUndercutSound },
+	{  true,   733, "bridge arithmetic against object",            1, hoyle4SignatureBridgeArithmetic,  hoyle4PatchBridgeArithmetic },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#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, we replace this with a call to kScummVMSleep for the requested
+// number of ticks.
+// Applies to at least: English Demo, English PC, English Mac
+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, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, $2
+	0x48,                                     // ret
+	PATCH_END
+};
+
+// While playing Old Maid (room 200), a repeated typo in the game script
+// means that `setScale` is called accidentally instead of `setScaler`.
+// In SSCI this did not do much because the first argument happened to be
+// smaller than the y-position of `ego`, but in ScummVM the first argument is
+// larger and so a debug message "y value less than vanishingY" is displayed.
+// This is the same issue as with LSL6 hires.
+static const uint16 hoyle5SetScaleSignature[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(setScale), // pushi setScale ($14b)
+	0x38, SIG_UINT16(0x05),         // pushi 5
+	0x51, 0x2c,                     // class Scaler
+	SIG_END
+};
+
+static const uint16 hoyle5PatchSetScale[] = {
+	0x38, PATCH_SELECTOR16(setScaler), // pushi setScaler ($14f)
+	PATCH_END
+};
+
+// There are two derived collections of Hoyle Classic Games:
+// 1) The Hoyle Children's Collection, which includes the following games:
+// - Crazy Eights (script 100)
+// - Old Maid (script 200)
+// - Checkers (script 1200)
+// 2) Hoyle Bridge, which includes the following games:
+// - Bridge (script 700)
+// In these two collections, the scripts for the other games have been removed.
+// Choosing any other game than the above results in a "No script found" error.
+// The original game did not show the game selection screen, as there were
+// direct shortcuts to each game.
+// We do show the game selection screen for Children's Collection, thus we
+// disable all the games which are not included in this version:
+// - Hearts (script 300)
+// - Gin Rummy (script 400)
+// - Cribbage (script 500)
+// - Klondike / Solitaire (script 600)
+// - Bridge (script 700)
+// - Poker (script 1100)
+// - Backgammon (script 1300)
+static const uint16 hoyle5SignatureHearts[] = {
+	SIG_MAGICDWORD,
+	0x38, 0x8e, 0x00,      // pushi 008e
+	0x76,                  // push0
+	0x38, 0xf0, 0x02,      // pushi 02f0
+	0x76,                  // push0
+	0x72, 0xdc, 0x03,      // lofsa chooseHearts
+	0x4a, 0x08, 0x00,      // send  0008
+	SIG_END
+};
+
+static const uint16 hoyle5SignatureGinRummy[] = {
+	SIG_MAGICDWORD,
+	0x38, 0x8e, 0x00,      // pushi 008e
+	0x76,                  // push0
+	0x38, 0xf0, 0x02,      // pushi 02f0
+	0x76,                  // push0
+	0x72, 0xbc, 0x02,      // lofsa chooseGinRummy
+	0x4a, 0x08, 0x00,      // send  0008
+	SIG_END
+};
+
+static const uint16 hoyle5SignatureCribbage[] = {
+	SIG_MAGICDWORD,
+	0x38, 0x8e, 0x00,      // pushi 008e
+	0x76,                  // push0
+	0x38, 0xf0, 0x02,      // pushi 02f0
+	0x76,                  // push0
+	0x72, 0x4c, 0x03,      // lofsa chooseCribbage
+	0x4a, 0x08, 0x00,      // send  0008
+	SIG_END
+};
+
+static const uint16 hoyle5SignatureKlondike[] = {
+	SIG_MAGICDWORD,
+	0x38, 0x8e, 0x00,      // pushi 008e
+	0x76,                  // push0
+	0x38, 0xf0, 0x02,      // pushi 02f0
+	0x76,                  // push0
+	0x72, 0xfc, 0x04,      // lofsa chooseKlondike
+	0x4a, 0x08, 0x00,      // send  0008
+	SIG_END
+};
+
+static const uint16 hoyle5SignatureBridge[] = {
+	SIG_MAGICDWORD,
+	0x38, 0x8e, 0x00,      // pushi 008e
+	0x76,                  // push0
+	0x38, 0xf0, 0x02,      // pushi 02f0
+	0x76,                  // push0
+	0x72, 0x6c, 0x04,      // lofsa chooseBridge
+	0x4a, 0x08, 0x00,      // send  0008
+	SIG_END
+};
+
+static const uint16 hoyle5SignaturePoker[] = {
+	SIG_MAGICDWORD,
+	0x38, 0x8e, 0x00,      // pushi 008e
+	0x76,                  // push0
+	0x38, 0xf0, 0x02,      // pushi 02f0
+	0x76,                  // push0
+	0x72, 0x8c, 0x05,      // lofsa choosePoker
+	0x4a, 0x08, 0x00,      // send  0008
+	SIG_END
+};
+
+static const uint16 hoyle5SignatureBackgammon[] = {
+	SIG_MAGICDWORD,
+	0x38, 0x8e, 0x00,      // pushi 008e
+	0x76,                  // push0
+	0x38, 0xf0, 0x02,      // pushi 02f0
+	0x76,                  // push0
+	0x72, 0xac, 0x06,      // lofsa chooseBackgammon
+	0x4a, 0x08, 0x00,      // send  0008
+	SIG_END
+};
+
+static const uint16 hoyle5PatchDisableGame[] = {
+	0x35, 0x00,                      // ldi 00
+	0x35, 0x00,                      // ldi 00
+	0x35, 0x00,                      // ldi 00
+	0x35, 0x00,                      // ldi 00
+	0x35, 0x00,                      // ldi 00
+	0x35, 0x00,                      // ldi 00
+	0x35, 0x00,                      // ldi 00
+	PATCH_END
+};
+
+// During Bridge, Declarer_Second_NT:think performs a bitwise or against an
+//  object due to a script typo. This script bug is also in Hoyle4, see its
+//  patch notes above for more detail.
+//
+// Applies to at least: English PC
+// Responsible method: Declarer_Second_NT:think
+// Fixes bug #11173
+static const uint16 hoyle5SignatureBridgeArithmetic[] = {
+	0x36,                               // push [ bridgeHand:highCard ]
+	0x34, SIG_UINT16(0x0f00),           // ldi 0f00
+	0x14,                               // or [ error: bridgeHand:highCard is an object ]
+	0x36,                               // push
+	0x63, 0x44,                         // pToa pard
+	0x4a, SIG_UINT16(0x0008),           // send 08 [ pard hasCard: theSuitLead (bridgeHand:highCard | 0f00) ]
+	0x2f, 0x26,                         // bt 26
+	0x7e, SIG_ADDTOOFFSET(+2),          // line
+	SIG_MAGICDWORD,
+	0x83, 0x03,                         // lal 03
+	0x2f, 0x1f,                         // bt 1f
+	0x7e, SIG_ADDTOOFFSET(+2),          // line
+	0x38,                               // pushi rank
+	SIG_END
+};
+
+static const uint16 hoyle5PatchBridgeArithmetic[] = {
+	0x38, PATCH_GETORIGINALUINT16(+24), // pushi rank
+	0x76,                               // push0
+	0x4a, PATCH_UINT16(0x0004),         // send 04 [ bridgeHand:highCard rank? ]
+	0x38, PATCH_UINT16(0x0f00),         // pushi 0f00
+	0x14,                               // or
+	0x36,                               // push
+	0x63, 0x44,                         // pToa pard
+	0x4a, PATCH_UINT16(0x0008),         // send 08 [ pard hasCard: theSuitLead ((bridgeHand:highCard):rank | 0f00) ]
+	0x2f, 0x20,                         // bt 20
+	0x83, 0x03,                         // lal 03
+	0x2f, 0x1c,                         // bt 1c
+	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,   200, "fix setScale calls",                         11, hoyle5SetScaleSignature,          hoyle5PatchSetScale },
+	{  true,   500, "remove kGetTime spin",                        1, hoyle5SignatureSpinLoop,          hoyle5PatchSpinLoop },
+	{  true, 64937, "remove kGetTime spin",                        1, hoyle5SignatureSpinLoop,          hoyle5PatchSpinLoop },
+	{  true,   733, "bridge arithmetic against object",            1, hoyle5SignatureBridgeArithmetic,  hoyle5PatchBridgeArithmetic },
+	{  true, 64990, "increase number of save games (1/2)",         1, sci2NumSavesSignature1,           sci2NumSavesPatch1 },
+	{  true, 64990, "increase number of save games (2/2)",         1, sci2NumSavesSignature2,           sci2NumSavesPatch2 },
+	{  true, 64990, "disable change directory button",             1, sci2ChangeDirSignature,           sci2ChangeDirPatch },
+	{ false,   975, "disable Gin Rummy",                           1, hoyle5SignatureGinRummy,          hoyle5PatchDisableGame },
+	{ false,   975, "disable Cribbage",                            1, hoyle5SignatureCribbage,          hoyle5PatchDisableGame },
+	{ false,   975, "disable Klondike",                            1, hoyle5SignatureKlondike,          hoyle5PatchDisableGame },
+	{ false,   975, "disable Bridge",                              1, hoyle5SignatureBridge,            hoyle5PatchDisableGame },
+	{ false,   975, "disable Poker",                               1, hoyle5SignaturePoker,             hoyle5PatchDisableGame },
+	{ false,   975, "disable Hearts",                              1, hoyle5SignatureHearts,            hoyle5PatchDisableGame },
+	{ false,   975, "disable Backgammon",                          1, hoyle5SignatureBackgammon,        hoyle5PatchDisableGame },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#pragma mark -
+#pragma mark Gabriel Knight 1
+
+// `daySixBeignet::changeState(4)` is called when the cop goes outside. It sets
+// cycles to 220. This is a CPU-speed dependent value and not usually enough
+// time to get to the door, so patch it to 22 seconds.
+//
+// Applies to at least: English PC-CD, German PC-CD, English Mac
+static const uint16 gk1Day6PoliceBeignetSignature1[] = {
+	0x35, 0x04,                    // ldi 4
+	0x1a,                          // eq?
+	0x30, SIG_ADDTOOFFSET(+2),     // bnt [next state check]
+	0x38, SIG_SELECTOR16(dispose), // pushi dispose
+	0x76,                          // push0
+	0x72, SIG_ADDTOOFFSET(+2),     // lofsa deskSarg
+	0x4a, SIG_UINT16(0x04),        // send 4
+	SIG_MAGICDWORD,
+	0x34, SIG_UINT16(0xdc),        // ldi 220
+	0x65, SIG_ADDTOOFFSET(+1),     // aTop cycles ($1a for PC, $1c for Mac)
+	0x32,                          // jmp [end]
+	SIG_END
+};
+
+static const uint16 gk1Day6PoliceBeignetPatch1[] = {
+	PATCH_ADDTOOFFSET(+16),
+	0x34, PATCH_UINT16(0x16),                   // ldi 22
+	0x65, PATCH_GETORIGINALBYTEADJUST(+20, +2), // aTop seconds ($1c for PC, $1e for Mac)
+	PATCH_END
+};
+
+// On day 6 when the cop is outside for the beignet, walking through the
+// swinging door will also reset the puzzle timer so the player has 200 cycles
+// to get through the area before the cop returns. This is a CPU-speed
+// dependent value and not usually enough time to get to the door, so we patch
+// it to 20 seconds instead.
+//
+// Applies to at least: English PC-CD, German PC-CD, English Mac
+// Responsible method: sInGateWithPermission::changeState(0)
+// Fixes bug: #9805
+static const uint16 gk1Day6PoliceBeignetSignature2[] = {
+	0x72, SIG_ADDTOOFFSET(+2),    // lofsa daySixBeignet
+	0x1a,                         // eq?
+	0x31, 0x0d,                   // bnt [skip set cycles]
+	0x38, SIG_SELECTOR16(cycles), // pushi cycles
+	0x78,                         // push1
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0xc8),       // pushi 200
+	0x72,                         // lofsa
+	SIG_END
+};
+
+static const uint16 gk1Day6PoliceBeignetPatch2[] = {
+	PATCH_ADDTOOFFSET(+6),
+	0x38, PATCH_SELECTOR16(seconds), // pushi seconds
+	0x78,                            // push1
+	0x38, PATCH_UINT16(0x14),        // pushi 20
+	PATCH_END
+};
+
+// `sargSleeping::changeState(8)` is called when the cop falls asleep and sets
+// the puzzle timer to 220 cycles. This is CPU-speed dependent and not usually
+// enough time to get to the door, so patch it to 22 seconds instead.
+//
+// Applies to at least: English PC-CD, German PC-CD, English Mac
+static const uint16 gk1Day6PoliceSleepSignature[] = {
+	0x35, 0x08,                // ldi 8
+	0x1a,                      // eq?
+	0x31, SIG_ADDTOOFFSET(+1), // bnt [next state check]
+	SIG_MAGICDWORD,
+	0x34, SIG_UINT16(0xdc),    // ldi 220
+	0x65, SIG_ADDTOOFFSET(+1), // aTop cycles ($1a for PC, $1c for Mac)
+	0x32,                      // jmp [end]
+	SIG_END
+};
+
+static const uint16 gk1Day6PoliceSleepPatch[] = {
+	PATCH_ADDTOOFFSET(+5),
+	0x34, PATCH_UINT16(0x16),                  // ldi 22
+	0x65, PATCH_GETORIGINALBYTEADJUST(+9, +2), // aTop seconds (1c for PC, 1e for Mac)
+	PATCH_END
+};
+
+// The beignet vendor's speed at the police station is CPU dependent, causing
+//  him to zoom to his position in room 230 on modern machines at an unintended
+//  high speed that's inconsistent with the room. Unlike the other actors,
+//  theVendor:moveSpeed is set to 0, which advances his motion on every game
+//  cycle instead of tethering his speed to ticks. On a machine from 1993 this
+//  was much slower which is why his movement sound effect is five seconds long.
+//
+// We fix this by setting theVendor:moveSpeed to a time-based speed that matches
+//  the room scene. This doesn't affect puzzle timing, it's just cosmetic.
+//
+// Applies to: All versions
+// Responsible method: heap in script 231
+// Fixes bug: #11892
+static const uint16 gk1BeignetVendorSpeedSignature[] = {
+	SIG_MAGICDWORD,             // theVendor
+	SIG_UINT16(0x0006),         // xStep = 6
+	SIG_UINT16(0x0302),         // origStep = 770
+	SIG_UINT16(0x0000),         // moveSpeed = 0
+	SIG_END
+};
+
+static const uint16 gk1BeignetVendorSpeedPatch[] = {
+	PATCH_ADDTOOFFSET(+4),
+	PATCH_UINT16(0x0006),       // moveSpeed = 6
+	PATCH_END
+};
+
+// At the start of day 5, when the player already has the veve but still needs
+// to get the drum book, the drum book dialogue with Grace is played twice in
+// a row, and then the veve dialogue gets played again even though it was
+// already played during day 4.
+//
+// The duplicate drum book dialogue happens because it is triggered once in
+// `GetTheVeve::changeState(0)` and then again in `GetTheVeve::changeState(11)`.
+// The re-run of the veve dialogue happens because the game gives the player
+// the drum book in `GetTheVeVe::changeState(1)`, then *after* doing so, checks
+// if the player has the drum book and runs the veve dialogue if so.
+//
+// We fix both of these issues by skipping the has-drum-book check if the player
+// just got the drum book in 'GetTheVeve::changeState(1)'.
+// Doing this causes the game to jump from state 1 to state 12, which bypasses
+// the duplicate drum book dialogue in state 11, as well as the veve dialogue
+// trigger in the has-drum-book check.
+//
+// More notes: The veve newspaper item is inventory 9. The drum book is
+//             inventory 14. The flag for veve research is 36, the flag for drum
+//             research is 73.
+//
+// Special thanks, credits and kudos to sluicebox on IRC, who did a ton of
+// research on this and even found this game bug originally.
+//
+// Applies to at least: English PC-CD, German PC-CD
+static const uint16 gk1Day5DrumBookDialogueSignature[] = {
+	0x31, 0x0b,                         // bnt [skip giving player drum book code]
+	0x38, SIG_SELECTOR16(get),          // pushi get ($200)
+	0x78,                               // push1
+	SIG_MAGICDWORD,
+	0x39, 0x0e,                         // pushi $e
+	0x81, 0x00,                         // lag global[0]
+	0x4a, SIG_UINT16(0x06),             // send 6 - GKEgo::get($e)
+	// end of giving player drum book code
+	0x38, SIG_SELECTOR16(has),          // pushi has ($202)
+	0x78,                               // push1
+	0x39, 0x0e,                         // pushi $e
+	0x81, 0x00,                         // lag global[0]
+	0x4a, SIG_UINT16(0x06),             // send 6 - GKEgo::has($e)
+	0x18,                               // not
+	0x30, SIG_UINT16(0x25),             // bnt [veve newspaper code]
+	SIG_END
+};
+
+static const uint16 gk1Day5DrumBookDialoguePatch[] = {
+	0x31, 0x0d,                         // bnt [skip giving player drum book code] adjusted
+	PATCH_ADDTOOFFSET(+11),             // skip give player drum book original code
+	0x33, 0x0d,                         // jmp [over the check inventory for drum book code]
+	// check inventory for drum book
+	0x38, PATCH_SELECTOR16(has),        // pushi has ($202)
+	0x78,                               // push1
+	0x39, 0x0e,                         // pushi $e
+	0x81, 0x00,                         // lag global[0]
+	0x4a, PATCH_UINT16(0x0006),         // send 6 - GKEgo::has($e)
+	0x2f, 0x23,                         // bt [veve newspaper code] (adjusted, saves 2 bytes)
+	PATCH_END
+};
+
+// When Gabriel goes to the phone, the script softlocks at
+// `startOfDay5::changeState(32)`.
+//
+// Applies to at least: English PC-CD, German PC-CD, English Mac
+static const uint16 gk1Day5PhoneFreezeSignature[] = {
+	0x4a,                             // send ...
+	SIG_MAGICDWORD, SIG_UINT16(0x0c), // ... $c
+	0x35, 0x03,                       // ldi 3
+	0x65, SIG_ADDTOOFFSET(+1),        // aTop cycles
+	0x32, SIG_ADDTOOFFSET(+2),        // jmp [end]
+	0x3c,                             // dup
+	0x35, 0x21,                       // ldi $21
+	SIG_END
+};
+
+static const uint16 gk1Day5PhoneFreezePatch[] = {
+	PATCH_ADDTOOFFSET(+3),                     // send $c
+	0x35, 0x06,                                // ldi 6
+	0x65, PATCH_GETORIGINALBYTEADJUST(+6, +6), // aTop ticks
+	PATCH_END
+};
+
+// When Gabriel is grabbing a vine, his saying "I can't believe I'm doing
+// this..." is cut off. We change it so the scripts wait for the audio.
+//
+// This is not supposed to be applied to the Floppy version.
+//
+// Applies to at least: English PC-CD, German PC-CD, Spanish PC-CD
+// Responsible method: vineSwing::changeState(1)
+// Fixes bug: #9820
+static const uint16 gk1Day9VineSwingSignature[] = {
+	0x38, SIG_UINT16(0x0004),         // pushi $4
+	0x51, 0x17,                       // class CT
+	0x36,                             // push
+	0x39, 0x0b,                       // pushi $b
+	0x78,                             // push1
+	0x7c,                             // pushSelf
+	0x81, 0x00,                       // lag global[$0]
+	0x4a, SIG_UINT16(0x0020),         // send $20
+	0x38, SIG_SELECTOR16(setMotion),  // pushi setMotion
+	0x78,                             // push1
+	0x76,                             // push0
+	0x72, SIG_UINT16(0x0412),         // lofsa guard1
+	0x4a, SIG_UINT16(0x0006),         // send $6
+	0x38, SIG_SELECTOR16(say),        // pushi say
+	0x38, SIG_UINT16(0x0004),         // pushi $4
+	SIG_MAGICDWORD,
+	0x39, 0x07,                       // pushi $7
+	0x39, 0x08,                       // pushi $8
+	0x39, 0x10,                       // pushi $10
+	0x78,                             // push1
+	0x81, 0x5b,                       // lag global[$5b]
+	0x4a, SIG_UINT16(0x000c),         // send $c
+	SIG_END
+};
+
+static const uint16 gk1Day9VineSwingPatch[] = {
+	0x38, PATCH_UINT16(0x0003),         // pushi $3
+	0x51, 0x17,                         // class CT
+	0x36,                               // push
+	0x39, 0x0b,                         // pushi $b
+	0x78,                               // push1
+	0x81, 0x00,                         // lag global[$0]
+	0x4a, PATCH_UINT16(0x001e),         // send $20
+	0x38, PATCH_SELECTOR16(setMotion),  // pushi setMotion
+	0x78,                               // push1
+	0x76,                               // push0
+	0x72, PATCH_UINT16(0x0412),         // lofsa guard1
+	0x4a, PATCH_UINT16(0x0006),         // send $6
+	0x38, PATCH_SELECTOR16(say),        // pushi say
+	0x38, PATCH_UINT16(0x0005),         // pushi $5
+	0x39, 0x07,                         // pushi $7
+	0x39, 0x08,                         // pushi $8
+	0x39, 0x10,                         // pushi $10
+	0x78,                               // push1
+	0x7c,                               // pushSelf
+	0x81, 0x5b,                         // lag global[$5b]
+	0x4a, PATCH_UINT16(0x000e),         // send $c
+	PATCH_END
+};
+
+// The mummies on day 9 move without animating if ego exits to the north before
+//  the first one finishes standing. This also occurs in Sierra's interpreter.
+//
+// The 12 outer rooms of the African mound all take place in room 710, which
+//  reinitializes its contents on each room change. Each room's mummy is guard1
+//  repositioned with a different view. When the mummies come to life,
+//  keyWorks:changeState(6) starts guard1's standing animation after which
+//  state 7 initializes guard1 for chasing ego. Ego however can leave before
+//  guard1 finishes standing, preventing state 7 from occurring. The script for
+//  exiting to the north assumes state 7 has run, otherwise guard1 remains on
+//  the wrong view with no cycler or looper in subsequent rooms.
+//
+// This bug is due to the script rightWay only partially initializing guard1 for
+//  chasing as opposed to wrongWay and backTrack which fully initialize. We fix
+//  this by replacing rightWay's partial initialization with the full version
+//  from keyWorks state 7. There are two versions of this patch due to
+//  significant differences between floppy and CD versions of this script.
+//
+// This patch is not applied to the NRS versions of this script, which address
+//  this bug by disabling control until guard1 finishes standing, giving the
+//  player less time to escape.
+//
+// Applies to: All PC Floppy and CD versions. TODO: Test Mac
+// Responsible method: rightWay:changeState(1)
+// Fixes bug: #10828
+static const uint16 gk1MummyAnimateFloppySignature[] = {
+	0x39, SIG_SELECTOR8(view),          // pushi view [ full guard1 init ]
+	SIG_MAGICDWORD,
+	0x78,                               // push1
+	0x38, SIG_UINT16(0x02c5),           // pushi 709d
+	SIG_ADDTOOFFSET(+674),
+	0x38, SIG_SELECTOR16(setMotion),    // pushi setMotion [ partial guard1 init ]
+	0x38, SIG_UINT16(0x0004),           // pushi 0004
+	0x51, 0x70,                         // class PChase
+	0x36,                               // push
+	0x89, 0x00,                         // lsg global[0]
+	0x39, 0x0f,                         // pushi 0f
+	SIG_END
+};
+
+static const uint16 gk1MummyAnimateFloppyPatch[] = {
+	PATCH_ADDTOOFFSET(+680),
+	0x39, PATCH_SELECTOR8(view),        // pushi view [ waste 6 stack items to be compatible with ]
+	0x76,                               // push0      [  the send instruction in full guard1 init ]
+	0x39, PATCH_SELECTOR8(view),        // pushi view
+	0x76,                               // push0
+	0x39, PATCH_SELECTOR8(view),        // pushi view
+	0x39, 0x00,                         // pushi 00
+	0x32, PATCH_UINT16(0xfd4b),         // jmp -693d [ continue full guard1 init in keyWorks state 7 ]
+	PATCH_END
+};
+
+static const uint16 gk1MummyAnimateCDSignature[] = {
+	0x39, SIG_SELECTOR8(view),          // pushi view [ full guard1 init ]
+	SIG_MAGICDWORD,
+	0x78,                               // push1
+	0x38, SIG_UINT16(0x02c5),           // pushi 709d
+	SIG_ADDTOOFFSET(+750),
+	0x38, SIG_SELECTOR16(setMotion),    // pushi setMotion [ partial guard1 init ]
+	0x38, SIG_UINT16(0x0004),           // pushi 0004
+	0x51, 0x70,                         // class PChase
+	0x36,                               // push
+	0x89, 0x00,                         // lsg global[0]
+	0x39, 0x0f,                         // pushi 0f
+	SIG_END
+};
+
+static const uint16 gk1MummyAnimateCDPatch[] = {
+	PATCH_ADDTOOFFSET(+756),
+	0x39, PATCH_SELECTOR8(view),        // pushi view [ waste 6 stack items to be compatible with ]
+	0x76,                               // push0      [  the send instruction in full guard1 init ]
+	0x39, PATCH_SELECTOR8(view),        // pushi view
+	0x76,                               // push0
+	0x39, PATCH_SELECTOR8(view),        // pushi view
+	0x39, 0x00,                         // pushi 00
+	0x32, PATCH_UINT16(0xfcff),         // jmp -769d [ continue full guard1 init in keyWorks state 7 ]
+	PATCH_END
+};
+
+// In GK1, the `view` selector is used to store view numbers in some cases and
+// object references to Views in other cases. `Interrogation::dispose` compares
+// an object stored in the `view` selector with a number (which is not valid)
+// because its checks are in the wrong order. The check order was fixed in the
+// CD version, so just do what the CD version does.
+//
+// TODO: Check if English Mac is affected too and if this patch applies
+// Applies to at least: English Floppy
+static const uint16 gk1InterrogationBugSignature[] = {
+	SIG_MAGICDWORD,
+	0x65, 0x4c,                      // aTop $4c
+	0x67, 0x50,                      // pTos $50
+	0x34, SIG_UINT16(0x2710),        // ldi $2710
+	0x1e,                            // gt?
+	0x31, 0x08,                      // bnt 8 [05a0]
+	0x67, 0x50,                      // pTos $50
+	0x34, SIG_UINT16(0x2710),        // ldi $2710
+	0x04,                            // sub
+	0x65, 0x50,                      // aTop $50
+	0x63, 0x50,                      // pToa $50
+	0x31, 0x15,                      // bnt $15 [05b9]
+	0x39, SIG_SELECTOR8(view),       // pushi view ($e)
+	0x76,                            // push0
+	0x4a, SIG_UINT16(0x04),          // send 4
+	0xa5, 0x00,                      // sat temp[0]
+	0x38, SIG_SELECTOR16(dispose),   // pushi dispose
+	0x76,                            // push0
+	0x63, 0x50,                      // pToa $50
+	0x4a, SIG_UINT16(0x04),          // send 4
+	0x85, 0x00,                      // lat temp[0]
+	0x65, 0x50,                      // aTop $50
+	SIG_END
+};
+
+static const uint16 gk1InterrogationBugPatch[] = {
+	0x65, 0x4c,                      // aTop $4c
+	0x63, 0x50,                      // pToa $50
+	0x31, 0x15,                      // bnt $15 [05b9]
+	0x39, PATCH_SELECTOR8(view),     // pushi view ($e)
+	0x76,                            // push0
+	0x4a, PATCH_UINT16(0x04),        // send 4
+	0xa5, 0x00,                      // sat temp[0]
+	0x38, PATCH_SELECTOR16(dispose), // pushi dispose
+	0x76,                            // push0
+	0x63, 0x50,                      // pToa $50
+	0x4a, PATCH_UINT16(0x04),        // send 4
+	0x85, 0x00,                      // lat temp[0]
+	0x65, 0x50,                      // aTop $50
+	0x67, 0x50,                      // pTos $50
+	0x34, PATCH_UINT16(0x2710),      // ldi $2710
+	0x1e,                            // gt?
+	0x31, 0x08,                      // bnt 8 [05b9]
+	0x67, 0x50,                      // pTos $50
+	0x34, PATCH_UINT16(0x2710),      // ldi $2710
+	0x04,                            // sub
+	0x65, 0x50,                      // aTop $50
+	PATCH_END
+};
+
+// WORKAROUND: Script needed, because of differences in our pathfinding
+// algorithm.
+// In Madame Cazanoux's house, when Gabriel is leaving, he is placed on
+// the edge of the walkable area initially. This leads to a failure in
+// the pathfinding algorithm, and the pathfinding area is then ignored,
+// so Gabriel goes straight to the door by walking through the wall.
+// This is an edge case, which was apparently acceptable in SSCI. We
+// change the upper border of the walk area slightly, so that Gabriel
+// can be placed inside, and the pathfinding algorithm works correctly.
+//
+// Responsible method: rm280:init
+// Fixes bug: #9770
+static const uint16 gk1CazanouxPathfindingSignature[] = {
+	SIG_MAGICDWORD,
+	0x78,                            // push1 x = 1
+	0x38, SIG_UINT16(0x0090),        // pushi y = 144
+	0x38, SIG_UINT16(0x00f6),        // pushi x = 246
+	0x38, SIG_UINT16(0x0092),        // pushi y = 146
+	0x38, SIG_UINT16(0x00f2),        // pushi x = 242
+	0x39, 0x69,                      // pushi y = 105
+	0x39, 0x7c,                      // pushi x = 124
+	0x39, 0x68,                      // pushi y = 104
+	0x39, 0x56,                      // pushi x = 86
+	0x39, 0x6f,                      // pushi y = 111
+	0x39, 0x45,                      // pushi x = 69
+	0x39, 0x7c,                      // pushi y = 124
+	0x39, 0x2e,                      // pushi x = 46
+	0x38, SIG_UINT16(0x0081),        // pushi y = 129
+	SIG_END
+};
+
+static const uint16 gk1CazanouxPathfindingPatch[] = {
+	PATCH_ADDTOOFFSET(+15),
+	0x39, 0x7c,                      // pushi x = 124
+	0x39, 0x67,                      // pushi y = 103 (was 104)
+	PATCH_END
+};
+
+// GK1 english pc floppy locks up on day 10 in the honfour (room 800) when
+//  using the keycard on an unlocked door's keypad. This is due to mistakenly
+//  calling handsOff instead of handsOn. Sierra fixed this in floppy patch 1.0a
+//  and all other versions.
+//
+// We fix this by changing handsOff to handsOn and passing 0 as the caller
+//  to gkMessager:say since the script disposes itself.
+//
+// Applies to: English PC Floppy only
+// Responsible method: sUnlockDoor:changeState(2)
+// Fixes bug: #10767
+static const uint16 gk1HonfourUnlockDoorSignature[] = {
+	0x7c,                           // pushSelf
+	0x81, 0x5b,                     // lag global[5b]
+	0x4a, SIG_MAGICDWORD,           // send e [ gkMessager:say ... self ]
+	SIG_UINT16(0x000e),
+	0x38, SIG_UINT16(0x0216),       // pushi 0216 [ handsOff ]
+	SIG_END
+};
+
+static const uint16 gk1HonfourUnlockDoorPatch[] = {
+	0x76,                           // push0
+	0x81, 0x5b,                     // lag global[5b]
+	0x4a, PATCH_UINT16(0x000e),     // send e [ gkMessager:say ... 0 ]
+	0x38, PATCH_UINT16(0x0217),     // pushi 0217 [ handsOn ]
+	PATCH_END
+};
+
+// GK1 english pc floppy locks up on day 2 when using the binoculars to view
+//  room 410 when the artist's drawing blows away. This is particularly bad
+//  because when using the binoculars you can't use the mouse to access the
+//  control panel to restore.
+//
+// We fix this as Sierra did in later versions by not allowing the drawing to
+//  blow away when viewing through binoculars. To make room for this patch
+//  we remove initializing juggler:cycleSpeed to 6 as this is redundant.
+//  juggler is a Prop and Prop:cycleSpeed's initial value is 6.
+//
+// Applies to: English PC Floppy
+// Responsible method: neJackson:init
+// Fixes bug: #10797
+static const uint16 gk1Day2BinocularsLockupSignature[] = {
+	SIG_MAGICDWORD,
+	0x30, SIG_UINT16(0x01d6),           // bnt 01d6 [ english pc floppy 1.0 only ]
+	0x38, SIG_SELECTOR16(init),         // pushi init
+	0x76,                               // push0
+	0x38, SIG_SELECTOR16(cycleSpeed),   // pushi cycleSpeed
+	0x78,                               // push1
+	0x39, 0x06,                         // pushi 06
+	0x38, SIG_SELECTOR16(setCycle),     // pushi setCycle
+	0x78,                               // push1
+	0x51, 0x15,                         // class Fwd
+	0x36,                               // push
+	0x72, SIG_UINT16(0x02b0),           // lofsa juggler
+	0x4a, SIG_UINT16(0x0010),           // send 10 [ juggler: init, cycleSpeed: 6, setCycle: Fwd ]
+	0x38, SIG_SELECTOR16(init),         // pushi init
+	0x76,                               // push0
+	0x72, SIG_UINT16(0x0538),           // lofsa easel
+	0x4a, SIG_UINT16(0x0004),           // send 4 [ easel: init ]
+	SIG_END
+};
+
+static const uint16 gk1Day2BinocularsLockupPatch[] = {
+	PATCH_ADDTOOFFSET(+6),
+	0x3c,                               // dup
+	0x76,                               // push0
+	0x38, PATCH_SELECTOR16(setCycle),   // pushi setCycle
+	0x78,                               // push1
+	0x51, 0x15,                         // class Fwd
+	0x36,                               // push
+	0x72, PATCH_UINT16(0x02b0),         // lofsa juggler
+	0x4a, PATCH_UINT16(0x000a),         // send a [ juggler: init, setCycle Fwd ]
+	0x76,                               // push0
+	0x72, PATCH_UINT16(0x0538),         // lofsa easel
+	0x4a, PATCH_UINT16(0x0004),         // send 4 [ easel: init ]
+
+	0x89, 0x0c,                         // lsg global[0c] [ previous room ]
+	0x34, PATCH_UINT16(0x0190),         // ldi 0190 [ overlook ]
+	0x1c,                               // ne?
+	0x31, 0x09,                         // bnt 09 [ drawing doesn't blow away ]
+	PATCH_END
+};
+
+// GK1 english pc floppy has a missing-points bug on day 5 in room 240.
+//  Showing Mosely the veve sketch and Hartridge's notes awards 2 points
+//  but not if you show the notes before the veve.
+//  Sierra fixed this in floppy patch 1.0b and all other versions.
+//
+// We fix this by awarding 2 points when showing the veve second.
+//
+// Applies to: English PC Floppy
+// Responsible method: showMoselyPaper:changeState(5)
+// Fixes bug: #10763
+static const uint16 gk1Day5MoselyVevePointsSignature[] = {
+	0x78,                                   // push1
+	0x39, 0x1b,                             // pushi 1b
+	0x47, 0x0d, 0x00, SIG_UINT16(0x0002),   // calle [export 0 of script 13], 02 [ is flag 1b set? ]
+	0x30, SIG_UINT16(0x001e),               // bnt 001e [ haven't shown notes yet ]
+	0x78,                                   // push1
+	0x39, 0x1a,                             // pushi 1a
+	0x47, 0x0d, 0x01, SIG_UINT16(0x0002),   // calle [export 1 of script 13], 02 [ set flag 1a ]
+	0x38, SIG_UINT16(0x00f2),               // pushi 00f2 [ say ]
+	0x38, SIG_UINT16(0x0005),               // pushi 0005
+	0x39, 0x11,                             // pushi 11 [ noun ]
+	SIG_MAGICDWORD,
+	0x39, 0x10,                             // pushi 10 [ verb ]
+	0x39, 0x38,                             // pushi 38 [ cond ]
+	0x76,                                   // push0
+	0x7c,                                   // pushSelf
+	0x81, 0x5b,                             // lag global[5b] [ GkMessager ]
+	0x4a, SIG_UINT16(0x000e),               // send 000e [ GkMessager:say ]
+	0x32, SIG_UINT16(0x0013),               // jmp 0013
+	0x38, SIG_UINT16(0x00f2),               // pushi 00f2 [ say ]
+	SIG_END
+};
+
+static const uint16 gk1Day5MoselyVevePointsPatch[] = {
+	0x38, PATCH_UINT16(0x00f2),             // pushi 00f2 [ say ]
+	0x39, 0x05,                             // pushi 05
+	0x39, 0x11,                             // pushi 11 [ noun ]
+	0x39, 0x10,                             // pushi 10 [ verb ]
+	0x78,                                   // push1
+	0x39, 0x1b,                             // pushi 1b
+	0x47, 0x0d, 0x00, PATCH_UINT16(0x0002), // calle [export 0 of script 13], 02 [ is flag 1b set? ]
+	0x31, 0x20,                             // bnt 20 [ pushi 37, continue GkMessager:say ]
+	0x38, PATCH_UINT16(0x02fa),             // pushi 02fa [ getPoints ]
+	0x7a,                                   // push2
+	0x38, PATCH_UINT16(0xfc19),             // pushi fc19 [ no flag ]
+	0x7a,                                   // push2 [ 2 points ]
+	0x81, 0x00,                             // lag global[0]
+	0x4a, PATCH_UINT16(0x0008),             // send 8 [ GKEgo:getPoints -999 2 ]
+	0x78,                                   // push1
+	0x39, 0x1a,                             // pushi 1a
+	0x47, 0x0d, 0x01, PATCH_UINT16(0x0002), // calle [export 1 of script 13], 02 [ set flag 1a ]
+	0x39, 0x38,                             // pushi 38 [ cond ]
+	0x33, 0x09,                             // jmp 9 [ continue GkMessager:say ]
+	PATCH_END
+};
+
+// When turning on the museum's air conditioner prior to day 5 in room 260, the
+//  timing is off and speech is interrupted. Some parts of the sequence run at
+//  game speed and others don't, which at high speeds eliminates pauses between
+//  dialogue. Dr. John's "We have air conditioning, you see" speech is cut off
+//  at all speeds.
+//
+// We fix this by setting ego's speed to its default (6) during this sequence
+//  and waiting for the messages to complete before proceeding. flipTheSwitch
+//  restores ego's speed at the end of the script, even though it never sets it.
+//
+// Applies to: All CD versions
+// Responsible method: flipTheSwitch:changeState
+// Fixes bug: #11219
+static const uint16 gk1AirConditionerSpeechSignature[] = {
+	0x30, SIG_UINT16(0x0020),               // bnt 0020 [ state 1 ]
+	SIG_ADDTOOFFSET(+26),
+	0x4a, SIG_UINT16(0x000c),               // send 0c
+	0x32, SIG_UINT16(0x0409),               // jmp 0409 [ end of method ]
+	0x3c,                                   // dup
+	0x35, SIG_MAGICDWORD, 0x01,             // ldi 01
+	0x1a,                                   // eq?
+	0x30, SIG_UINT16(0x0056),               // bnt 0056 [ state 2 ]
+	SIG_ADDTOOFFSET(+24),
+	0x4a, SIG_UINT16(0x001a),               // send 1a [ GKEgo view: 265 ... ]
+	SIG_ADDTOOFFSET(+33),
+	0x4a, SIG_UINT16(0x000c),               // send 0c
+	0x32, SIG_UINT16(0x03c0),               // jmp 03c0 [ end of method ]
+	SIG_ADDTOOFFSET(+620),
+	0x7a,                                   // push2
+	SIG_ADDTOOFFSET(+3),
+	0x7c,                                   // pushSelf
+	0x81, 0x00,                             // lag 00
+	0x4a, SIG_UINT16(0x0014),               // send 14 [ GKEgo ... setCycle: End self ]
+	SIG_ADDTOOFFSET(+8),
+	0x38, SIG_UINT16(0x0004),               // pushi 0004
+	SIG_ADDTOOFFSET(+10),
+	0x4a, SIG_UINT16(0x000c),               // send 0c  [ gkMessager say: 28 8 7 4 ]
+	0x32, SIG_UINT16(0x012f),               // jmp 012f [ end of method ]
+	SIG_ADDTOOFFSET(+3),
+	0x38, SIG_UINT16(0x0004),               // pushi 0004
+	SIG_ADDTOOFFSET(+9),
+	0x4a, SIG_UINT16(0x000c),               // send 0c  [ gkMessager say: 28 8 8 4 ]
+	0x32, SIG_UINT16(0x011a),               // jmp 011a [ end of method ]
+	SIG_ADDTOOFFSET(+6),
+	0x38, SIG_SELECTOR16(stop),             // pushi stop [ stop snake sound ]
+	SIG_END
+};
+
+static const uint16 gk1AirConditionerSpeechPatch[] = {
+	0x30, PATCH_UINT16(0x001c),             // bnt 001c [ state 1 ]
+	PATCH_ADDTOOFFSET(+26),
+	0x33, 0x47,                             // jmp 47 [ send 0c / end of method ]
+	0x3c,                                   // dup
+	0x18,                                   // not
+	0x1a,                                   // eq?
+	0x31, 0x5c,                             // bnt 5c [ state 2 ]
+	0x38, PATCH_SELECTOR16(cycleSpeed),     // pushi cycleSpeed
+	0x78,                                   // push1
+	0x39, 0x06,                             // pushi 06
+	PATCH_ADDTOOFFSET(+24),
+	0x4a, PATCH_UINT16(0x0020),             // send 20 [ GKEgo cycleSpeed: 6 view: 265 ... ]
+	PATCH_ADDTOOFFSET(+659),
+	0x78,                                   // push1
+	PATCH_ADDTOOFFSET(+3),
+	0x80, PATCH_UINT16(0x0000),             // lag 0000
+	0x4a, PATCH_UINT16(0x0012),             // send 12 [ GKEgo ... setCycle: End ]
+	PATCH_ADDTOOFFSET(+8),
+	0x38, PATCH_UINT16(0x0005),             // pushi 0005
+	PATCH_ADDTOOFFSET(+10),
+	0x7c,                                   // pushSelf
+	0x4a, PATCH_UINT16(0x000e),             // send 0e [ gkMessager say: 28 8 7 4 self ]
+	0x33, 0x1b,                             // jmp 1b  [ stop snake sound ]
+	PATCH_ADDTOOFFSET(+3),
+	0x38, PATCH_UINT16(0x0005),             // pushi 0005
+	PATCH_ADDTOOFFSET(+9),
+	0x7c,                                   // pushSelf
+	0x4a, PATCH_UINT16(0x000e),             // send 0e [ gkMessager say: 28 8 8 4 self ]
+	0x33, 0x06,                             // jmp 06  [ stop snake sound ]
+	PATCH_END
+};
+
+// The day 5 snake attack has speed, audio, and graphics problems.
+//  These occur in all versions and also in Sierra's interpreter.
+//
+// Gabriel automatically walks cautiously in the darkened museum while looking
+//  around and saying lines, then a snake drops on him. Depending on the game's
+//  speed setting, the audio for "Why is it so dark in here?" is interrupted as
+//  much as halfway through by the next line, "Dr. John, hello?". The cautious
+//  walk animation runs at game speed, which can be fast, then abruptly changes
+//  to 10 (33%) when the snake drops, which looks off. Ego doesn't even reach
+//  the snake and instead stops short and warps 17 pixels to the right when the
+//  drop animation starts.
+//
+// We fix all of this. Initializing ego's speed to 10 solves the interrupted
+//  speech and inconsistent speed. It feels like this was the intended pacing.
+//  The snake-warping isn't a speed issue, ego's animation frames for this
+//  scene simply fall short of the snake's location. To fix that we start ego
+//  a little farther in the room and increase ego's final position so that he
+//  ends up directly under the snake and transitions to the drop animation
+//  smoothly. Finally, we initialize ego on the room's first cycle instead of
+//  second so that ego doesn't materialize after the room is already displayed.
+//
+// This patch works with pc floppy and cd even though they have different
+//  snakeAttack scripts. Floppy doesn't have speech to interrupt but it
+//  has the same issues.
+//
+// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
+// Responsible method: snakeAttack:changeState
+// Fixes bug: #10793
+static const uint16 gk1Day5SnakeAttackSignature1[] = {
+	0x65, 0x1a,                         // aTop cycles
+	0x32, SIG_ADDTOOFFSET(+2),          // jmp [ end of method ]
+	0x3c,                               // dup
+	0x35, 0x01,                         // ldi 1
+	SIG_MAGICDWORD,
+	0x1a,                               // eq?
+	0x30, SIG_UINT16(0x0048),           // bnt 0048 [ state 2 ]
+	0x35, 0x01,                         // ldi 1 [ free bytes ]
+	0x39, SIG_SELECTOR8(view),          // pushi view
+	0x78,                               // push1
+	0x38, SIG_UINT16(0x0107),           // pushi 0107
+	0x38, SIG_SELECTOR16(setCel),       // pushi setCel
+	0x78,                               // push1
+	0x76,                               // push0
+	0x38, SIG_SELECTOR16(setLoop),      // pushi setLoop
+	0x78,                               // push1
+	0x76,                               // push0
+	0x39, SIG_SELECTOR8(signal),        // pushi signal
+	0x78,                               // push1
+	0x39, SIG_SELECTOR8(signal),        // pushi signal
+	0x76,                               // push0
+	0x81, 0x00,                         // lag global[0]
+	0x4a, SIG_UINT16(0x0004),           // send 4 [ GKEgo:signal? ]
+	SIG_ADDTOOFFSET(+18),
+	0x39, 0x64,                         // pushi 64 [ initial x ]
+	SIG_END
+};
+
+static const uint16 gk1Day5SnakeAttackPatch1[] = {
+	0x39, PATCH_SELECTOR8(view),        // pushi view [ begin initializing ego in state 0 ]
+	0x78,                               // push1
+	0x33, 0x07,                         // jmp 07 [ continue initializing ego in state 0 ]
+	0x3c,                               // dup
+	0x18,                               // not [ acc = 1 ]
+	0x1a,                               // eq?
+	0x65, 0x1a,                         // aTop cycles [ just set cycles to 1 in state 1 ]
+	0x33, 0x48,                         // jmp 47 [ state 2 ]
+	0x38, PATCH_UINT16(0x0107),         // pushi 0107
+	0x39, PATCH_SELECTOR8(cel),         // pushi cel
+	0x78,                               // push1
+	0x76,                               // push0
+	0x38, PATCH_SELECTOR16(setLoop),    // pushi setLoop
+	0x78,                               // push1
+	0x76,                               // push0
+	0x39, PATCH_SELECTOR8(signal),      // pushi signal
+	0x78,                               // push1
+	0x38, PATCH_SELECTOR16(cycleSpeed), // pushi cycleSpeed
+	0x78,                               // push1
+	0x39, 0x0a,                         // pushi 0a
+	PATCH_ADDTOOFFSET(+5),
+	0x4a, PATCH_UINT16(0x000a),         // send a [ GKEgo:signal?, cycleSpeed = a ]
+	PATCH_ADDTOOFFSET(+18),
+	0x39, 0x70,                         // pushi 70 [ new initial x ]
+	PATCH_END
+};
+
+// This just changes ego's second x coordinate but unfortunately that promotes it to 16 bits
+static const uint16 gk1Day5SnakeAttackSignature2[] = {
+	SIG_MAGICDWORD,
+	0x39, 0x7a,                         // pushi 7a [ x for second walking loop ]
+	0x39, 0x7c,                         // pushi 7c
+	0x38, SIG_SELECTOR16(setCycle),     // pushi setCycle
+	0x7a,                               // push2
+	0x51, 0x18,                         // class End
+	0x36,                               // push
+	0x7c,                               // pushSelf
+	0x81, 0x00,                         // lag global[0]
+	0x4a, SIG_UINT16(0x0022),           // send 22
+	0x32, SIG_ADDTOOFFSET(+2),          // jmp [ end of method ]
+	SIG_END
+};
+
+static const uint16 gk1Day5SnakeAttackPatch2[] = {
+	0x38, PATCH_UINT16(0x008b),         // pushi 008b [ new x for second walking loop ]
+	0x39, 0x7c,                         // pushi 7c
+	0x38, PATCH_SELECTOR16(setCycle),   // pushi setCycle
+	0x7a,                               // push2
+	0x51, 0x18,                         // class End
+	0x36,                               // push
+	0x7c,                               // pushSelf
+	0x81, 0x00,                         // lag global[0]
+	0x4a, PATCH_UINT16(0x0022),         // send 22
+	0x3a,                               // toss
+	0x48,                               // ret
+	PATCH_END
+};
+
+// When entering the police station (room 230) sGabeEnters sets ego speed
+//  to 4 for the door animation but fails to restore it to the game speed
+//  by calling GKEgo:normalize. This leaves ego at 75% speed until doing
+//  something that does call normalize.
+//
+// We fix this by calling GKEgo:normalize after Gabriel finishes walking
+//  through the door in sGabeEnters:changeState(4). This replaces setting
+//  GKEgo:ignoreActors to 0 but that's okay because normalize does that.
+//
+// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
+// Responsible method: sGabeEnters:changeState(4)
+// Fixes bug: #10780
+static const uint16 gk1PoliceEgoSpeedFixSignature[] = {
+	0x38, SIG_MAGICDWORD,               // pushi ignoreActors
+	      SIG_SELECTOR16(ignoreActors),
+	0x78,                               // push1
+	0x76,                               // push0
+	0x81, 0x00,                         // lag global[0]
+	0x4a, SIG_UINT16(0x000c),           // send c [ GKEgo: ..., ignoreActors: 0 ]
+	SIG_END
+};
+
+static const uint16 gk1PoliceEgoSpeedFixPatch[] = {
+	0x38, PATCH_SELECTOR16(normalize),  // pushi normalize
+	0x39, 0x00,                         // pushi 00
+	0x81, 0x00,                         // lag global[0]
+	0x4a, PATCH_UINT16(0x000a),         // send a [ GKEgo: ..., normalize ]
+	PATCH_END
+};
+
+// When exiting the drugstore (room 250) egoExits sets ego speed to 15
+//  (slowest) for the door animation but fails to restore it to game
+//  speed by calling GKEgo:normalize. This leaves ego slow until doing
+//  something that does call normalize.
+//
+// We fix this by calling GKEgo:normalize after the door animation.
+//
+// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
+// Responsible method: egoExits:changeState
+// Fixes bug: #10780
+static const uint16 gk1DrugStoreEgoSpeedFixSignature[] = {
+	0x30, SIG_UINT16(0x003f),           // bnt 003f [ state 1 ]
+	SIG_ADDTOOFFSET(+60),
+	SIG_MAGICDWORD,
+	0x32, SIG_UINT16(0x0012),           // jmp 12 [ end of method ]
+	0x3c,                               // dup
+	0x35, 0x01,                         // ldi 1
+	0x1a,                               // eq?
+	0x31, 0x0c,                         // bnt c [ end of method ]
+	0x38, SIG_SELECTOR16(newRoom),      // pushi newRoom
+	0x78,                               // push1
+	0x38, SIG_UINT16(0x00c8),           // pushi 00c8 [ map ]
+	0x81, 0x02,                         // lag global[2]
+	0x4a, SIG_UINT16(0x0006),           // send 6 [ rm250:newRoom = map ]
+	0x3a,                               // toss
+	SIG_END
+};
+
+static const uint16 gk1DrugStoreEgoSpeedFixPatch[] = {
+	0x3a,                               // toss
+	0x31, 0x3d,                         // bnt 3d [ state 1 ]
+	PATCH_ADDTOOFFSET(+60),
+	0x48,                               // ret
+	0x38, PATCH_SELECTOR16(normalize),  // pushi normalize
+	0x76,                               // push0
+	0x81, 0x00,                         // lag global[0]
+	0x4a, PATCH_UINT16(0x0004),         // send 4 [ GKEgo:normalize ]
+	0x38, PATCH_SELECTOR16(newRoom),    // pushi newRoom
+	0x78,                               // push1
+	0x38, PATCH_UINT16(0x00c8),         // pushi 00c8 [ map ]
+	0x81, 0x02,                         // lag global[2]
+	0x4a, PATCH_UINT16(0x0006),         // send 6 [ rm250:newRoom = map ]
+	PATCH_END
+};
+
+// GK1 CD version cuts off Grace's speech when hanging up the phone on day 1.
+//  This is a timing issue that also occurs in the original.
+//
+// startingCartoon:changeState(12) plays Grace's final phone message but doesn't
+//  synchronize it with the script. Instead ego goes through a series of movements
+//  that advance the state while Grace is speaking. Once the sequence is complete
+//  Grace hangs up the phone and starts her next message which interrupts the
+//  previous one. There is no mechanism to make sure that Grace's message has
+//  first completed and so it cut offs the last one or two words. The timing only
+//  worked in the original on slower machines that weren't able to run the
+//  sequence at full speed.
+//
+// We fix this by adding a delay to startingCartoon:changeState(18) so that
+//  Grace's speech has time to complete. This scene occurs before game speed
+//  can be set and it plays at a consistent speed on ScummVM.
+//
+// This patch is only applied to CD versions. Floppies have a different script.
+//
+// Applies to: All CD versions
+// Responsible method: startingCartoon:changeState(18)
+// Fixes bug: #10787
+static const uint16 gk1Day1GracePhoneSignature[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x12,                 // ldi 12
+	0x1a,                       // eq?
+	0x31, 0x2c,                 // bnt 2c
+	SIG_ADDTOOFFSET(+28),
+	0x38, SIG_UINT16(0x0003),   // pushi 0003
+	0x51, 0x69,                 // class Osc
+	0x36,                       // push
+	0x78,                       // push1
+	0x7c,                       // pushSelf
+	0x81, 0x00,                 // lag global[0]
+	0x4a, SIG_UINT16(0x0024),   // send 24 [ GKEgo: ... setCycle: Osc 1 self ]
+	0x32, SIG_ADDTOOFFSET(+2),  // jmp [ end of method ]
+	SIG_END
+};
+
+static const uint16 gk1Day1GracePhonePatch[] = {
+	PATCH_ADDTOOFFSET(+33),
+	0x7a,                       // push2
+	0x51, 0x69,                 // class Osc
+	0x36,                       // push
+	0x78,                       // push1
+	0x81, 0x00,                 // lag global[0]
+	0x4a, PATCH_UINT16(0x0022), // send 22 [ GKEgo: ... setCycle: Osc 1 ]
+
+	// advance to the next state in 6 seconds instead of when Gabriel finishes
+	//  taking a sip of coffee, which takes 2 seconds, giving Grace's speech
+	//  an extra 4 seconds to complete.
+	0x35, 0x06,                 // ldi 06
+	0x65, 0x1c,                 // aTop seconds
+
+	0x3a,                       // toss
+	0x48,                       // ret
+	PATCH_END
+};
+
+// French and Spanish CD versions contain an active debugging hotkey, ALT+N,
+//  which brings up a series of unskippable bug-reporting dialogs and
+//  eventually writes files to disk and crashes non-release builds due to
+//  an uninitialized read. This hotkey is always active and not hidden
+//  behind the game's debug mode flag so we just patch it out.
+//
+// Applies to: French and Spanish PC CD
+// Responsible method: GK:handleEvent
+// Fixes bug: #10781
+static const uint16 gk1SysLoggerHotKeySignature[] = {
+	SIG_MAGICDWORD,
+	0x34, SIG_UINT16(0x3100),       // ldi 3100 [ ALT+N ]
+	0x1a,                           // eq?
+	0x31,                           // bnt
+	SIG_END
+};
+
+static const uint16 gk1SysLoggerHotKeyPatch[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x33,                           // jmp
+	PATCH_END
+};
+
+// After interrogating Gran in room 380, the room is re-initialized incorrectly.
+//  Clicking on objects while seated causes Gabriel to briefly flicker into
+//  standing and other frames. After standing, the knitting basket can be walked
+//  through. These are script bugs which also occur in Sierra's interpreter.
+//
+// Ego is initialized incorrectly by rm380:init when returning from interrogation
+//  (room 50). Several properties are wrong and it's bad luck that it works as
+//  well as it does or Sierra would have noticed. For comparison, the scripts
+//  egoEnters and sitDown do it correctly. rm380:init first initializes ego for
+//  walking and then applies only some of the properties for sitting in the chair.
+//
+// This leaves ego in a walking/sitting state with several problems:
+//  - signal flag kSignalDoesntTurn isn't set
+//  - cycler is set to StopWalk instead of none
+//  - loop/cel is set to 2 0 instead of 0 5
+//
+// rm380:init sets ego's loop/cel to 0 5 (Gabriel sitting) but the unexpected
+//  StopWalk immediately changes this to 2 0 (Gabriel starts talking) which went
+//  unnoticed because those two frames are similar. This is why Gabriel's hand
+//  is slightly raised when returning from interrogation. The flickering is due
+//  to ego attempting to turn to face items while sitting due to kSignalDoesntTurn
+//  not being set.
+//
+// We fix the flickering by passing a second parameter to GKEgo:setLoop which
+//  causes kSignalDoesntTurn to be set, preventing ego from attempting to face
+//  objects being clicked, just as egoEnters and sitDown do. We fix the knitting
+//  basket by adding its obstacle polygon to the room even when returning from
+//  interrogation, which Sierra forgot to do.
+//
+// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
+// Responsible method: rm380:init
+// Fixes bug: #9760, #10707
+static const uint16 gk1GranRoomInitSignature[] = {
+	0x38, SIG_SELECTOR16(setCel),       // pushi setCel
+	0x78,                               // push1
+	0x39, 0x05,                         // pushi 05
+	0x38, SIG_SELECTOR16(setLoop),      // pushi setLoop
+	0x78,                               // push1
+	0x76,                               // push0 [ loop: 0 ]
+	0x38, SIG_SELECTOR16(init),         // pushi init
+	0x76,                               // push0
+	0x38, SIG_SELECTOR16(posn),         // pushi posn
+	SIG_MAGICDWORD,
+	0x7a,                               // push2
+	0x38, SIG_UINT16(0x00af),           // pushi 00af
+	0x39, 0x75,                         // pushi 75
+	0x81, 0x00,                         // lag global[0]
+	0x4a, SIG_UINT16(0x001e),           // send 1e [ GKEgo: ... setCel: 5, setLoop: 0 ... ]
+	0x35, 0x01,                         // ldi 1
+	0xa3, 0x00,                         // sal local[0] [ 1, a non-zero value indicates ego is sitting ]
+	SIG_END
+};
+
+static const uint16 gk1GranRoomInitPatch[] = {
+	0x39, PATCH_SELECTOR8(cel),         // pushi cel [ use cel instead of equivalent setCel to save a byte ]
+	0x78,                               // push1
+	0x39, 0x05,                         // pushi 05
+	0x38, PATCH_SELECTOR16(setLoop),    // pushi setLoop
+	0x7a,                               // push2
+	0x76,                               // push0 [ loop: 0 ]
+	0x78,                               // push1 [ 2nd param tells setLoop to set kSignalDoesntTurn ]
+	0x38, PATCH_SELECTOR16(init),       // pushi init
+	0x76,                               // push0
+	0x38, PATCH_SELECTOR16(posn),       // pushi posn
+	0x7a,                               // push2
+	0x38, PATCH_UINT16(0x00af),         // pushi 00af
+	0x39, 0x75,                         // pushi 75
+	0x81, 0x00,                         // lag global[0]
+	0xa3, 0x00,                         // sal local[0] [ setting a non-zero object instead of 1 saves 2 bytes ]
+	0x4a, PATCH_UINT16(0x0020),         // send 20 [ GKEgo: ... cel: 5, setLoop: 0 1 ... ]
+	0x33, 0x87,                         // jmp -79 [ add knitting basket obstacle to room ]
+	PATCH_END
+};
+
+// After phoning Wolfgang on day 7, Gabriel is placed beyond room 220's obstacle
+//  boundary and can walk through walls and behind the room. This also occurs in
+//  the original. The script inconsistently uses accessible and inaccessible
+//  positions for placing ego next to the phone. We patch all instances to use
+//  the accessible position.
+//
+// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
+// Responsible methods: rm220:init, useThePhone:changeState(0)
+// Fixes bug: #10853
+static const uint16 gk1EgoPhonePositionSignature[] = {
+	SIG_MAGICDWORD,
+	0x39, 0x68,                         // pushi 68 [ x: 104 ]
+	0x39, 0x7e,                         // pushi 7e [ y: 126 ]
+	SIG_END
+};
+
+static const uint16 gk1EgoPhonePositionPatch[] = {
+	0x39, 0x6b,                         // pushi 6b [ x: 107 ]
+	0x39, 0x7c,                         // pushi 7c [ y: 124 ]
+	PATCH_END
+};
+
+// Restarting the game doesn't reset the current inventory item in the icon bar.
+//  The previously selected item can then be used on day 1.
+//
+// Room 93 restarts the game and resets inventory by setting each item's owner
+//  to zero. It makes no attempt to reset the icon bar. We fix this by instead
+//  calling GKEgo:put on each item and passing zero for the new owner, as this
+//  handles updating the icon bar when dropping an item. The "state" property is
+//  no longer cleared for items but that's okay because it's never set or used.
+//
+// Applies to: All versions
+// Responsible method: doTheRestart:changeState(0)
+// Fixes bug: #11222
+static const uint16 gk1RestartInventorySignature[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(owner),            // pushi owner
+	0x78,                                   // push1
+	0x76,                                   // push0
+	0x39, SIG_SELECTOR8(state),             // pushi state
+	0x78,                                   // push1
+	0x76,                                   // push0
+	0x39, SIG_SELECTOR8(at),                // pushi at
+	0x78,                                   // push1
+	0x8b, 0x00,                             // lsl 00
+	0x81, 0x09,                             // lag 09
+	0x4a, SIG_UINT16(0x0006),               // send 06 [ GKInventory at: local0 ]
+	0x4a, SIG_UINT16(0x000c),               // send 0c [ item owner: 0 state: 0 ]
+	SIG_END
+};
+
+static const uint16 gk1RestartInventoryPatch[] = {
+	0x38, PATCH_SELECTOR16(put),            // pushi put
+	0x7a,                                   // push2
+	0x8b, 0x00,                             // lsl 00
+	0x76,                                   // push0
+	0x81, 0x00,                             // lag 00
+	0x4a, PATCH_UINT16(0x0008),             // send 08 [ GKEgo put: local0 0 ]
+	0x33, 0x08,                             // jmp 08
+	PATCH_END
+};
+
+// On day 6 in Jackson Square, if you never gave Madame Lorelei her veil on an
+//  earlier day, then looking at her empty booth says that she's sitting there.
+//  Clicking Operate also says the wrong message. The logic in the booth and
+//  chair doVerb methods doesn't consider that this optional action might not
+//  occur by day 6. We add the missing day check by overwriting a redundant
+//  local variable test.
+//
+// Applies to: All versions
+// Responsible methods: booth:doVerb, chair1:doVerb, chair2:doVerb
+static const uint16 gk1EmptyBoothMessageSignature[] = {
+	SIG_MAGICDWORD,
+	0x30, SIG_UINT16(0x001a),               // bnt 001a [ skip lorelei message ]
+	0x83, 0x01,                             // lal 01   [ always zero ]
+	0x18,                                   // not
+	0x30, SIG_UINT16(0x0014),               // bnt 0014 [ skip lorelei message ]
+	SIG_END
+};
+
+static const uint16 gk1EmptyBoothMessagePatch[] = {
+	0x31, 0x1b,                             // bnt 1b [ skip lorelei message ]
+	0x89, 0x7b,                             // lsg 7b
+	0x35, 0x05,                             // ldi 05
+	0x24,                                   // le?    [ day <= 5 ]
+	0x31, 0x14,                             // bnt 14 [ skip lorelei message ]
+	PATCH_END
+};
+
+// Madame Lorelei has an obscure timer bug that can cause events to repeat and
+//  award duplicate points. When exiting the conversation with her by selecting
+//  "Er...nothing.", fortuneTeller:cue resets the dance timer incorrectly.
+//  loreleiTimer's client is the room. When it fires, nwJackson:cue tests flags
+//  and room conditions before running the sLoreleiDance script, otherwise it
+//  resets the timer for 5 seconds. When fortuneTeller:cue resets the timer it
+//  changes the client to sLoreleiDance, bypassing the checks in nwJackson:cue.
+//  Madame Lorelei can then dance and drop her veil a second time while Gabriel
+//  already has it, among other edge cases.
+//
+// We fix this by setting the room as the client when resetting the timer. This
+//  requires calling dispose first since the timer is already running, which
+//  might have been what led to this script being written differently.
+//
+// Applies to: All versions
+// Responsible method: fortuneTeller:cue
+static const uint16 gk1LoreleiDanceTimerSignature[] = {
+	0x30, SIG_UINT16(0x0005),               // bnt 0005
+	0xc3, SIG_MAGICDWORD, 0x04,             // +al 04
+	0x32, SIG_UINT16(0x001f),               // jmp 001f
+	0x3c,                                   // dup
+	0x35, 0x10,                             // ldi 10 [ "Er...nothing." ]
+	0x1a,                                   // eq?
+	0x30, SIG_UINT16(0x0018),               // bnt 0018
+	0x38, SIG_SELECTOR16(setReal),          // pushi setReal
+	0x7a,                                   // push2
+	0x72, SIG_ADDTOOFFSET(+2),              // lofsa sLoreleiDance
+	0x36,                                   // push
+	SIG_ADDTOOFFSET(+13),
+	0x4a, SIG_UINT16(0x0008),               // send 08 [ loreleiTimer setReal: sLoreleiDance ... ]
+	SIG_END
+};
+
+static const uint16 gk1LoreleiDanceTimerPatch[] = {
+	0x30, PATCH_UINT16(0x0004),             // bnt 0004
+	PATCH_ADDTOOFFSET(+2),
+	0x33, 0x20,                             // jmp 20
+	0x3c,                                   // dup
+	0x35, 0x10,                             // ldi 10 [ "Er...nothing." ]
+	0x1a,                                   // eq?
+	0x31, 0x1a,                             // bnt 1a
+	0x38, PATCH_SELECTOR16(dispose),        // pushi dispose
+	0x76,                                   // push0
+	0x38, PATCH_SELECTOR16(setReal),        // pushi setReal
+	0x7a,                                   // push2
+	0x89, 0x02,                             // lsg 02
+	PATCH_ADDTOOFFSET(+13),
+	0x4a, PATCH_UINT16(0x000c),             // send 0c [ loreleiTimer dispose: setReal: nwJackson ... ]
+	PATCH_END
+};
+
+// When walking between rooms in Jackson Square, the cursor is often initialized
+//  to the wrong view, even though it's really the Walk cursor. This seemingly
+//  random event with many variations is due to a bug in the ExitFeature class.
+//
+// ExitFeature is responsible for swapping the cursor with an Exit cursor when
+//  the mouse is over it and then restoring afterwards. The previous cursor is
+//  stored in ExitFeature:lastCursor. The first problem is that ExitFeature:init
+//  initializes lastCursor to the current cursor even though the mouse hasn't
+//  touched it yet. The second problem is that ExitFeature:dispose restores the
+//  cursor to lastCursor if the current cursor is any Exit cursor, including
+//  ones it's not responsible for. Entering Jackson Square from the cathedral
+//  causes all three ExitFeatures in the room to initialize lastCursor to
+//  theWaitCursor (the shield). When exiting the room, the ExitFeatures are
+//  disposed in the order they were added, which means northExit disposes first.
+//  northExit:lastCursor is still theWaitCursor unless it was moused over.
+//  Exiting to another Jackson Square room will cause northExit:dispose to check
+//  if the cursor is globeCursor, which represents all Exit cursors, and if so
+//  then it will incorrectly restore the cursor to theWaitCursor, preventing
+//  the ExitFeature responsible for the room change from correctly restoring.
+//
+// We fix this by patching ExitFeature:dispose to only restore the cursor if
+//  its view matches the Exit cursor that it's responsible for.
+//
+// Applies to: All versions
+// Responsible method: ExitFeature:dispose
+static const uint16 gk1ExitFeatureCursorSignature[] = {
+	0x89, 0x13,                             // lsg 13 [ current-cursor ]
+	0x7a,                                   // push2
+	0x76,                                   // push0
+	0x78,                                   // push1
+	0x43, 0x02, SIG_UINT16(0x0004),         // callk ScriptID 0 1 [ globeCursor ]
+	0x1a,                                   // eq?
+	0x31, 0x0b,                             // bnt 0b [ skip if current-cursor isn't an exit cursor ]
+	0x38, SIG_SELECTOR16(setCursor),        // pushi setCursor
+	0x78,                                   // push1
+	0x67, SIG_ADDTOOFFSET(+1),              // pTos lastCursor
+	0x81, 0x01,                             // lag 01
+	0x4a, SIG_UINT16(0x0006),               // send 06 [ GK1 setCursor: lastCursor ]
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(delete),            // pushi delete
+	0x78,                                   // push1
+	0x7c,                                   // pushSelf
+	0x81, 0xce,                             // lag ce
+	0x4a, SIG_UINT16(0x0006),               // send 06 [ gk1Exits delete: self ]
+	0x48,                                   // ret
+	SIG_ADDTOOFFSET(+372),
+	0x38, SIG_SELECTOR16(setCursor),        // pushi setCursor
+	0x78,                                   // push1
+	0x67, SIG_ADDTOOFFSET(+1),              // pTos lastCursor
+	0x81, 0x01,                             // lag 01
+	0x4a, SIG_UINT16(0x0006),               // send 06 [ GK1 setCursor: lastCursor ]
+	0x35, 0x01,                             // ldi 01
+	0x65, SIG_ADDTOOFFSET(+1),              // aTop eCursor [ eCursor = 1 ]
+	0x48,                                   // ret
+	SIG_END
+};
+
+static const uint16 gk1ExitFeatureCursorPatch[] = {
+	0x39, PATCH_SELECTOR8(delete),          // pushi delete
+	0x78,                                   // push1
+	0x7c,                                   // pushSelf
+	0x81, 0xce,                             // lag ce
+	0x4a, PATCH_UINT16(0x0006),             // send 06 [ gk1Exits delete: self ]
+	0x39, PATCH_SELECTOR8(view),            // pushi view
+	0x76,                                   // push0
+	0x81, 0x13,                             // lag 13  [ current-cursor ]
+	0x4a, PATCH_UINT16(0x0004),             // send 04 [ current-cursor: view? ]
+	0x67, PATCH_GETORIGINALBYTEADJUST(+17, -2), // pTos cursor
+	0x1a,                                   // eq?     [ current-cursor:view == self:cursor ]
+	0x2e, PATCH_UINT16(0x017e),             // bt 017e [ GK1 setCursor: lastCursor ]
+	0x48,                                   // ret
+	PATCH_END
+};
+
+// The Windows CD version never plays its AVI videos during the bayou ritual,
+//  instead it runs the view-based slide shows for the floppy versions. The
+//  ritual script contains the normal code for playing its AVI and SEQ files
+//  depending on kPlatform, just like every video script in the game, except
+//  that the initial floppy flag test has been replaced with another kPlatform
+//  call which prevents the real platform test from executing.
+//
+// It's unclear if this is a script bug or why it would be intentional, but
+//  the end result is that selecting Windows as the platform excludes videos
+//  from this one scene whereas selecting DOS doesn't, so we patch the platform
+//  tests back to floppy tests like everywhere else and enable the AVI videos.
+//
+// Applies to: All CD versions, though only English versions support Windows
+// Responsible method: roomScript:changeState
+// Fixes bug: #9807
+static const uint16 gk1BayouRitualAviSignature[] = {
+	0x76,                                   // push0
+	0x43, 0x68, SIG_UINT16(0x0000),         // callk Platform
+	SIG_MAGICDWORD,
+	0x36,                                   // push
+	0x35, 0x01,                             // ldi 01 [ DOS ]
+	0x1c,                                   // ne?
+	SIG_END
+};
+
+static const uint16 gk1BayouRitualAviPatch[] = {
+	0x78,                                   // push1
+	0x38, PATCH_UINT16(0x01d6),             // pushi 01d6     [ flag 470 ]
+	0x47, 0x0d, 0x00, PATCH_UINT16(0x0002), // calle proc13_0 [ is floppy flag set? ]
+	PATCH_END
+};
+
+// The comic-book cartoon scenes have timing problems. Many delays are too fast,
+//  instantaneous, or random. As with other GK1 timing bugs, these scripts were
+//  written against CPUs that couldn't run the interpreter at full speed.
+//
+// Most cartoon delays are implemented by setting Script:seconds to one or two.
+//  At slower CPU speeds, Sierra's interpreter lagged enough that it appeared to
+//  deliver the requested durations. But without that lag, the real behavior is
+//  exposed. When Script:seconds is set, the first second is deducted on the
+//  next doit except in some cases when there are stale values from a previous
+//  delay. A one second delay is usually no delay at all. Subsequent seconds
+//  are deducted whenever the seconds value of the system clock changes. This
+//  means that the duration of the 2nd "second" depends on the system clock's
+//  subsecond value when the delay was requested. A script that requests a two
+//  second delay usually gets a random delay between zero and one second.
+//
+// We fix this by replacing all the one and two second cartoon delays with the
+//  equivalent in ticks. This makes the durations match the requested values and
+//  removes the inconsistencies due to subseconds. These correct timings expose
+//  broken animation in one of the bayou cartoon panels due to the script
+//  specifying the wrong view number, so we fix that too.
+//
+// There is still room for improvement in the bayou cartoons. Several delays are
+//  implemented by waiting on disabled messages that instantly cue. All fades
+//  are done by unthrottled inner loops and the scene timing implicitly depends
+//  on those going slowly. This is why several panels only appear for an instant
+//  before the entire screen changes.
+//
+// Applies to: All versions
+// Responsible methods: doTheCloseUp:changeState, roomScript:changeState (480),
+//                      cutToTheHeart:changeState, sCutPanel1:changeState,
+//                      sCutPanel2:changeState, sCutPanel4:changeState
+static const uint16 gk1CartoonTimingPcSignature1[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x01,                         // ldi 01
+	0x65, 0x1c,                         // aTop seconds [ seconds = 1 ]
+	SIG_END
+};
+
+static const uint16 gk1CartoonTimingMacSignature1[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x01,                         // ldi 01
+	0x65, 0x1e,                         // aTop seconds [ seconds = 1 ]
+	SIG_END
+};
+
+static const uint16 gk1CartoonTimingPatch1[] = {
+	0x35, 0x3c,                                // ldi 3c
+	0x65, PATCH_GETORIGINALBYTEADJUST(+3, +4), // aTop ticks [ ticks = 60 ]
+	PATCH_END
+};
+
+static const uint16 gk1CartoonTimingPcSignature2[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x02,                         // ldi 02
+	0x65, 0x1c,                         // aTop seconds [ seconds = 2 ]
+	SIG_END
+};
+
+static const uint16 gk1CartoonTimingMacSignature2[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x02,                         // ldi 02
+	0x65, 0x1e,                         // aTop seconds [ seconds = 2 ]
+	SIG_END
+};
+
+static const uint16 gk1CartoonTimingPatch2[] = {
+	0x35, 0x78,                                // ldi 78
+	0x65, PATCH_GETORIGINALBYTEADJUST(+3, +4), // aTop ticks [ ticks = 120 ]
+	PATCH_END
+};
+
+// During the bayou cartoon when Malia recognizes Gabriel, the third panel's
+//  animation is broken. The script attempts to animate Gabriel's face but it
+//  instead it specifies the wrong view and draws a fragment of Malia's face.
+//  This wasn't noticed because of the broken timing (see above patch notes)
+//  that immediately overwrote the wrong first view with the correct second.
+//  Now that we've fixed the timing, we fix this view as well so that the panel
+//  animates correctly. We know that 6142 is the correct view because the script
+//  attempts to unload it afterwards.
+//
+// Applies to: All versions
+// Responsible method: roomScript:changeState(64)
+static const uint16 gk1BayouCartoonViewSignature[] = {
+	0x39, SIG_SELECTOR8(view),          // pushi view
+	SIG_MAGICDWORD,
+	0x78,                               // push1
+	0x38, SIG_UINT16(0x17fd),           // pushi 17fd [ view 6141: Malia ]
+	SIG_END
+};
+
+static const uint16 gk1BayouCartoonViewPatch[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x38, PATCH_UINT16(0x17fe),         // pushi 17fe [ view 6142: Gabriel ]
+	PATCH_END
+};
+
+// On day 6, an envelope is dropped off in the bookstore after 20 seconds, but
+//  if the game is in the middle of a message sequence then it can lockup.
+//  When a timer expires, bookstore:cue tests a number of properties to make
+//  sure that it's not interrupting anything, but unlike other rooms such as
+//  nwJackson:cue it doesn't test if a message is being said. Looking at Grace
+//  triggers one of many message sequences which can prevent ego from completing
+//  his turn to face the door, leaving dropTheEnvelope stuck in handsOff mode.
+//
+// We fix this by adding a test to bookstore:cue to verify that a message isn't
+//  being said, just like nwJackson:cue. We make room for this by overwriting a
+//  redundant handsOff call. This also prevents the florist script from starting
+//  in the middle of a message, as this could have similar conflicts.
+//
+// Applies to: All versions
+// Responsible method: bookstore:cue
+static const uint16 gk1Day6EnvelopeSignature[] = {
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(state),             // pushi state
+	0x76,                                   // push0
+	0x51, SIG_ADDTOOFFSET(+1),              // class CueObj
+	0x4a, SIG_UINT16(0x0004),               // send 04 [ CueObj state? ]
+	0x18,                                   // not
+	0x31, SIG_ADDTOOFFSET(+1),              // bnt [ reset timer ]
+	0x38, SIG_SELECTOR16(handsOff),         // pushi handsOff
+	0x76,                                   // push0
+	0x81, 0x01,                             // lag 01
+	0x4a, SIG_UINT16(0x0004),               // send 04 [ GK1 handsOff: ]
+	SIG_END
+};
+
+static const uint16 gk1Day6EnvelopePatch[] = {
+	PATCH_ADDTOOFFSET(+8),
+	0x2f, PATCH_GETORIGINALBYTEADJUST(+10, +1), // bt [ reset timer ]
+	0x39, PATCH_SELECTOR8(size),                // pushi size
+	0x76,                                       // push0
+	0x81, 0x54,                                 // lag 54
+	0x4a, PATCH_UINT16(0x0004),                 // send 04 [ talkers size? ]
+	0x2f, PATCH_GETORIGINALBYTEADJUST(+10, -9), // bt [ reset timer ]
+	PATCH_END
+};
+
+// GK1 Mac is missing view 56, which is the close-up of the talisman. Clicking
+//  Look on the talisman from inventory is supposed to display an inset with
+//  view 56 and say a message, but instead this would crash the Mac interpreter.
+//
+// We fix this by skipping the talisman inset when view 56 isn't present in the
+//  Mac version. The default verb handler still says the talisman message.
+//
+// Applies to: Mac Floppy
+// Responsible method: talisman:doVerb
+static const uint16 gk1MacTalismanInsetSignature[] = {
+	0x31, 0x3e,                             // bnt 3e [ super doVerb: verb &rest ]
+	0x39, SIG_SELECTOR8(hide),              // pushi hide
+	0x78,                                   // push1
+	0x78,                                   // push1
+	0x81, 0x09,                             // lag 09
+	0x4a, SIG_UINT16(0x0006),               // send 06 [ GKInventory hide: 1 ]
+	0x39, SIG_SELECTOR8(doit),              // pushi doit
+	0x38, SIG_MAGICDWORD,                   // pushi 0008
+	      SIG_UINT16(0x0008),
+	0x39, 0x38,                             // pushi 38 [ talisman view ]
+	SIG_END
+};
+
+static const uint16 gk1MacTalismanInsetPatch[] = {
+	0x33,                                   // jmp [ super doVerb: verb &rest ]
+	PATCH_END
+};
+
+// In the final scene before the credits the wrong font is used and the 'a' with
+//  an umlaut in "Schattenjager" isn't displayed. endTalker:font is set to 999
+//  which doesn't include decorated characters. Font 40 has the same glyphs as
+//  999 plus the decorated characters, so we use that instead. This patch is
+//  only to be applied to English versions; localized ones have different fonts.
+//
+// Applies to: English CD versions
+// Responsible method: heap in script 670
+static const uint16 gk1EndGameFontSignature[] = {
+	SIG_MAGICDWORD,                     // endTalker
+	SIG_UINT16(0x0002),                 // modeless = 2
+	SIG_UINT16(0x03e7),                 // font = 999
+	SIG_END
+};
+
+static const uint16 gk1EndGameFontPatch[] = {
+	PATCH_ADDTOOFFSET(+2),
+	PATCH_UINT16(0x0028),               // font = 40
+	PATCH_END
+};
+
+// Narrator lockup fix for GK1 CD / Mac, see sciNarratorLockupSignature.
+//  The custom code in these versions overlaps with the generic patch signature
+//  so we enable the correct one based on game version and platform.
+static const uint16 gk1NarratorLockupSignature[] = {
+	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += game time ]
+	0x33, 0x0b,                         // jmp 0b
+	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
+	SIG_MAGICDWORD,
+	0x35, 0x3c,                         // ldi 3c
+	0x02,                               // add
+	0x36,                               // push
+	0x81, 0x58,                         // lag 58 [ game time ]
+	0x02,                               // add
+	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time ]
+	0x35, 0x01,                         // ldi 01 [ true ]
+	0x48,                               // ret
+	SIG_END
+};
+
+static const uint16 gk1NarratorLockupPatch[] = {
+	PATCH_ADDTOOFFSET(+2),
+	0x33, 0x0a,                         // jmp 0a
+	PATCH_ADDTOOFFSET(+5),
+	0x89, 0x58,                         // lsg 58 [ game time ]
+	0x02,                               // add
+	0x65, PATCH_GETORIGINALBYTE(+1),    // aTop ticks [ ticks += 60 + game time ]
+	0x00,                               // bnot
+	0x31, 0xfb,                         // bnt fb [ set ticks to 0 if ticks == -1 ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                         patch
+static const SciScriptPatcherEntry gk1Signatures[] = {
+	{  true,     0, "remove alt+n syslogger hotkey",               1, gk1SysLoggerHotKeySignature,      gk1SysLoggerHotKeyPatch },
+	{  true,    17, "disable video benchmarking",                  1, sci2BenchmarkSignature,           sci2BenchmarkPatch },
+	{  true,    21, "fix ExitFeature cursor restore",              1, gk1ExitFeatureCursorSignature,    gk1ExitFeatureCursorPatch },
+	{  false,   24, "mac: fix missing talisman view",              1, gk1MacTalismanInsetSignature,     gk1MacTalismanInsetPatch },
+	{  true,    51, "fix interrogation bug",                       1, gk1InterrogationBugSignature,     gk1InterrogationBugPatch },
+	{  true,    93, "fix inventory on restart",                    1, gk1RestartInventorySignature,     gk1RestartInventoryPatch },
+	{  true,   210, "fix day 6 envelope lockup",                   2, gk1Day6EnvelopeSignature,         gk1Day6EnvelopePatch },
+	{  true,   211, "fix day 1 grace phone speech timing",         1, gk1Day1GracePhoneSignature,       gk1Day1GracePhonePatch },
+	{  true,   212, "fix day 5 drum book dialogue error",          1, gk1Day5DrumBookDialogueSignature, gk1Day5DrumBookDialoguePatch },
+	{  true,   212, "fix day 5 phone softlock",                    1, gk1Day5PhoneFreezeSignature,      gk1Day5PhoneFreezePatch },
+	{  true,   220, "fix ego phone position",                      2, gk1EgoPhonePositionSignature,     gk1EgoPhonePositionPatch },
+	{  true,   230, "fix day 6 police beignet timer issue (1/2)",  1, gk1Day6PoliceBeignetSignature1,   gk1Day6PoliceBeignetPatch1 },
+	{  true,   230, "fix day 6 police beignet timer issue (2/2)",  1, gk1Day6PoliceBeignetSignature2,   gk1Day6PoliceBeignetPatch2 },
+	{  true,   230, "fix day 6 police sleep timer issue",          1, gk1Day6PoliceSleepSignature,      gk1Day6PoliceSleepPatch },
+	{  true,   230, "fix police station ego speed",                1, gk1PoliceEgoSpeedFixSignature,    gk1PoliceEgoSpeedFixPatch },
+	{  true,   231, "fix beignet vendor speed",                    1, gk1BeignetVendorSpeedSignature,   gk1BeignetVendorSpeedPatch },
+	{  true,   240, "fix day 5 mosely veve missing points",        1, gk1Day5MoselyVevePointsSignature, gk1Day5MoselyVevePointsPatch },
+	{  true,   250, "fix ego speed when exiting drug store",       1, gk1DrugStoreEgoSpeedFixSignature, gk1DrugStoreEgoSpeedFixPatch },
+	{  true,   260, "fix air conditioner speech timing",           1, gk1AirConditionerSpeechSignature, gk1AirConditionerSpeechPatch },
+	{  true,   260, "fix day 5 snake attack (1/2)",                1, gk1Day5SnakeAttackSignature1,     gk1Day5SnakeAttackPatch1 },
+	{  true,   260, "fix day 5 snake attack (2/2)",                1, gk1Day5SnakeAttackSignature2,     gk1Day5SnakeAttackPatch2 },
+	{  true,   280, "fix pathfinding in Madame Cazanoux's house",  1, gk1CazanouxPathfindingSignature,  gk1CazanouxPathfindingPatch },
+	{  true,   380, "fix Gran's room obstacles and ego flicker",   1, gk1GranRoomInitSignature,         gk1GranRoomInitPatch },
+	{  true,   410, "fix day 2 binoculars lockup",                 1, gk1Day2BinocularsLockupSignature, gk1Day2BinocularsLockupPatch },
+	{  true,   420, "fix day 6 empty booth message",               6, gk1EmptyBoothMessageSignature,    gk1EmptyBoothMessagePatch },
+	{  true,   420, "fix lorelei dance timer",                     1, gk1LoreleiDanceTimerSignature,    gk1LoreleiDanceTimerPatch },
+	{ false,   471, "pc: fix cartoon timing",                      4, gk1CartoonTimingPcSignature1,     gk1CartoonTimingPatch1 },
+	{ false,   471, "pc: fix cartoon timing",                      3, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
+	{ false,   471, "mac: fix cartoon timing",                     4, gk1CartoonTimingMacSignature1,    gk1CartoonTimingPatch1 },
+	{ false,   471, "mac: fix cartoon timing",                     3, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
+	{ false,   480, "pc: fix cartoon timing",                     10, gk1CartoonTimingPcSignature1,     gk1CartoonTimingPatch1 },
+	{ false,   480, "pc: fix cartoon timing",                      7, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
+	{ false,   480, "mac: fix cartoon timing",                    10, gk1CartoonTimingMacSignature1,    gk1CartoonTimingPatch1 },
+	{ false,   480, "mac: fix cartoon timing",                     7, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
+	{  true,   480, "fix bayou cartoon view",                      1, gk1BayouCartoonViewSignature,     gk1BayouCartoonViewPatch },
+	{  true,   480, "win: play day 6 bayou ritual avi videos",     3, gk1BayouRitualAviSignature,       gk1BayouRitualAviPatch },
+	{ false,   720, "pc: fix cartoon timing",                      2, gk1CartoonTimingPcSignature1,     gk1CartoonTimingPatch1 },
+	{ false,   720, "pc: fix cartoon timing",                      6, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
+	{ false,   720, "mac: fix cartoon timing",                     2, gk1CartoonTimingMacSignature1,    gk1CartoonTimingPatch1 },
+	{ false,   720, "mac: fix cartoon timing",                     6, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
+	{ false,   891, "pc: fix cartoon timing",                      1, gk1CartoonTimingPcSignature1,     gk1CartoonTimingPatch1 },
+	{ false,   891, "mac: fix cartoon timing",                     1, gk1CartoonTimingMacSignature1,    gk1CartoonTimingPatch1 },
+	{ false,   892, "pc: fix cartoon timing",                      1, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
+	{ false,   892, "mac: fix cartoon timing",                     1, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
+	{ false,   894, "pc: fix cartoon timing",                      1, gk1CartoonTimingPcSignature2,     gk1CartoonTimingPatch2 },
+	{ false,   894, "mac: fix cartoon timing",                     1, gk1CartoonTimingMacSignature2,    gk1CartoonTimingPatch2 },
+	{ false,   670, "fix end game font",                           1, gk1EndGameFontSignature,          gk1EndGameFontPatch },
+	{  true,   710, "fix day 9 vine swing speech playing",         1, gk1Day9VineSwingSignature,        gk1Day9VineSwingPatch },
+	{  true,   710, "fix day 9 mummy animation (floppy)",          1, gk1MummyAnimateFloppySignature,   gk1MummyAnimateFloppyPatch },
+	{  true,   710, "fix day 9 mummy animation (cd)",              1, gk1MummyAnimateCDSignature,       gk1MummyAnimateCDPatch },
+	{  true,   800, "fix day 10 honfour unlock door lockup",       1, gk1HonfourUnlockDoorSignature,    gk1HonfourUnlockDoorPatch },
+	{ false, 64928, "floppy: Narrator lockup fix",                 1, sciNarratorLockupSignature,       sciNarratorLockupPatch },
+	{ false, 64928, "cd/mac: Narrator lockup fix",                 1, gk1NarratorLockupSignature,       gk1NarratorLockupPatch },
+	{  true, 64990, "increase number of save games (1/2)",         1, sci2NumSavesSignature1,           sci2NumSavesPatch1 },
+	{  true, 64990, "increase number of save games (2/2)",         1, sci2NumSavesSignature2,           sci2NumSavesPatch2 },
+	{  true, 64990, "disable change directory button",             1, sci2ChangeDirSignature,           sci2ChangeDirPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#pragma mark -
+#pragma mark Gabriel Knight 2
+
+// GK2 uses a kGetTime spin loop to delay for half a second while displaying
+//  the "bad" cursor when clicking an item on something it can't be used on.
+//  This leaves ScummVM unresponsive without displaying the cursor.
+//
+// We fix this by replacing the spin loop with a call to kScummVMSleep.
+//
+// Applies to: All versions
+// Responsible method: GKHotCursor:flashBad
+static const uint16 gk2FlashBadCursorSignature[] = {
+	0x8d, SIG_MAGICDWORD, 0x00,     // lst 00
+	0x76,                           // push0
+	0x43, 0x79, SIG_UINT16(0x0000), // callk GetTime 00
+	0x1e,                           // gt?
+	0x31, 0x02,                     // bnt 02 [ exit loop ]
+	0x33, 0xf4,                     // jmp f4 [ continue loop ]
+	SIG_END
+};
+
+static const uint16 gk2FlashBadCursorPatch[] = {
+	0x78,                           // push1
+	0x39, 0x1e,                     // pushi 1e [ half a second ]
+	0x43, kScummVMSleepId,          // callk ScummVMSleep 02
+	      PATCH_UINT16(0x0002),
+	0x32, PATCH_UINT16(0x0002),     // jmp 0002 [ exit loop ]
+	PATCH_END
+};
+
+// GK2's inventory scrolls smoothly when the mouse is held down in the original
+//  due to an inner loop in ScrollButton:track, but this causes slow scrolling
+//  in our interpreter since we throttle kFrameOut. The script's inner loop is
+//  itself throttled by ScrollButton:moveDelay, which is set to 25 and limits
+//  event processing to every 25th iteration. Removing this delay results in
+//  smooth scrolling as in the original.
+//
+// Applies to: All versions
+// Responsible method: ScrollButton:track
+static const uint16 gk2InventoryScrollSpeedSignature[] = {
+	SIG_MAGICDWORD,
+	0x63, 0x9c,                 // pToa moveDelay [ 25 ]
+	0xa5, 0x02,                 // sat 02
+	SIG_END
+};
+
+static const uint16 gk2InventoryScrollSpeedPatch[] = {
+	0x35, 0x01,                 // ldi 01
+	PATCH_END
+};
+
+// The down scroll button in GK2 jumps up a pixel on mousedown because there is
+//  a send to scrollSelections using an immediate value 1, which means to scroll
+//  up by 1 pixel. This patch fixes the send to scrollSelections by passing the
+//  button's delta instead of 1. The Italian version's vocab.997 is missing the
+//  scrollSelections selector so this patch avoids referencing it. Two versions
+//  are necessary to accommodate scripts compiled with and without line numbers.
+//
+// Applies to: All versions
+// Responsible method: ScrollButon:track
+// Fixes bug: #9648
+static const uint16 gk2InventoryScrollDirSignature1[] = {
+	SIG_MAGICDWORD,
+	0x78,                               // push1
+	0x63, 0x98,                         // pToa client
+	0x4a, SIG_UINT16(0x0006),           // send 06 [ client scrollSelections: 1 ]
+	0x7e,                               // line
+	SIG_END
+};
+
+static const uint16 gk2InventoryScrollDirPatch1[] = {
+	0x66, PATCH_UINT16(0x009a),         // pTos delta
+	0x62, PATCH_UINT16(0x0098),         // pToa client
+	0x4a, PATCH_UINT16(0x0006),         // send 06 [ client scrollSelections: delta ]
+	PATCH_END
+};
+
+static const uint16 gk2InventoryScrollDirSignature2[] = {
+	0x78,                               // push1
+	0x63, 0x98,                         // pToa client
+	0x4a, SIG_MAGICDWORD,               // send 06 [ client scrollSelections: 1 ]
+	      SIG_UINT16(0x0006),
+	0x35, 0x02,                         // ldi 02
+	0x65, 0x56,                         // aTop cel
+	SIG_END
+};
+
+static const uint16 gk2InventoryScrollDirPatch2[] = {
+	0x67, 0x9a,                         // pTos delta
+	0x63, 0x98,                         // pToa client
+	0x4a, PATCH_UINT16(0x0006),         // send 06 [ client scrollSelections: delta ]
+	0x7a,                               // push2
+	0x69, 0x56,                         // sTop cel
+	PATCH_END
+};
+
+// The init code 'GK2::init' that runs when GK2 starts up unconditionally resets
+// the music volume to 63, but the game should always use the volume stored in
+// ScummVM.
+// Applies to: All versions
+// Fixes bug: #9700
+static const uint16 gk2VolumeResetSignature[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x3f, // ldi $3f
+	0xa1, 0x4c, // sag global[$4c] (music volume)
+	SIG_END
+};
+
+static const uint16 gk2VolumeResetPatch[] = {
+	0x33, 0x02,  // jmp 2 [past volume changes]
+	PATCH_END
+};
+
+// GK2 has custom video benchmarking code that needs to be disabled in a local
+//  procedure called from GK2:init. It sets the game's detailLevel and returns
+//  a value which is assigned to GK2:speedRating and never used. The maximum
+//  detailLevel the game recognizes is six so we just set it to that.
+//
+// Applies to: All versions
+// Responsible method: GK2:init
+static const uint16 gk2BenchmarkSignature[] = {
+	0x76,                       // push0
+	0x40, SIG_ADDTOOFFSET(+2),  // call speed test proc
+	      SIG_MAGICDWORD,
+		  SIG_UINT16(0x0000),
+	0x65, 0x28,                 // aTop speedRating
+	SIG_END
+};
+
+static const uint16 gk2BenchmarkPatch[] = {
+	0x35, 0x06,                 // ldi 06
+	0x65, 0x18,                 // aTop _detailLevel
+	0x33, 0x02,                 // jmp 02
+	PATCH_END
+};
+
+// GK2 has a complex sound bug which causes seemingly random lockups when
+//  changing rooms in many areas including the Herrenchiemse Museum, the Hunt
+//  Club, and St. Georg Church. This also occurs in the original.
+//
+// SoundManager continuously plays an array of sounds provided to its play
+//  method. Sounds play in a random order with a random delay of five to ten
+//  seconds in between. SoundManager is attached to soundRegion and survives
+//  room changes. Rooms that set a new playlist call play on initialization.
+//  The problem is that SoundManager:play doesn't clear its delay timer. If play
+//  is called during a delay then the timer continues and expires during the
+//  next sound. This is noticeable throughout the game when background music is
+//  randomly interrupted by different music. Many room scripts change rooms by
+//  calling SoundManager:fade in handsOff mode and proceeding once they've been
+//  cued. If a stray SoundManager timer expires while a script is waiting for
+//  fade to complete then SoundManager:cue will play the next sound, overwrite
+//  gk2Music:client with itself, and the waiting script will never cue.
+//
+// We fix this by clearing SoundManager's timer state in SoundManager:play.
+//  This prevents the delay timer from ever running while music is playing.
+//  Note that this bug is unrelated to lockups when the music volume slider
+//  is set to its lowest value. We fix that in Sci::Audio32::fadeChannel().
+//
+// Applies to: All versions
+// Responsible method: SoundManager:play
+static const uint16 gk2SoundManagerLockupSignature1[] = {
+	0x7e, SIG_ADDTOOFFSET(+2),          // line
+	0x7e, SIG_ADDTOOFFSET(+2),          // line
+	SIG_MAGICDWORD,
+	0x35, 0x00,                         // ldi 00
+	0x65, 0x34,                         // aTop cleanup
+	SIG_END
+};
+
+static const uint16 gk2SoundManagerLockupPatch1[] = {
+	0x35, 0x00,                         // ldi 00
+	0x64, PATCH_UINT16(0x001e),         // aTop seconds
+	0x64, PATCH_UINT16(0x0012),         // aTop scratch
+	PATCH_END
+};
+
+static const uint16 gk2SoundManagerLockupSignature2[] = {
+	0x87, SIG_MAGICDWORD, 0x00,         // lap 00
+	0x18,                               // not
+	0x31, 0x10,                         // bnt 10 [ skip debug message ]
+	0x78,                               // push1
+	0x72,                               // lofsa "WARNING: 0 args passed to SoundManager!"
+	SIG_END
+};
+
+static const uint16 gk2SoundManagerLockupPatch2[] = {
+	0x35, 0x00,                         // ldi 00
+	0x65, 0x1e,                         // aTop seconds
+	0x65, 0x12,                         // aTop scratch
+	0x32, PATCH_UINT16(0x0014),         // jmp 0014 [ skip debug message ]
+	PATCH_END
+};
+
+// Clicking on Frau Miller in room 810 after exhausting her topics and then
+//  clicking on anything else can lockup or crash the game. rm810:newRoom fades
+//  the music before transitioning to room 8110, which takes several seconds.
+//  The game doesn't disable input during this period and if the player begins
+//  another action then rm810:cue can unexpectedly interrupt it. If Grace is
+//  walking then the room will reload in a handsOff state. Other edge cases
+//  include setting the room number to zero and subsequently crashing.
+//
+// We fix this by calling handsOff so that the player can't interrupt the Frau
+//  Miller room transition while waiting for the music to fade, which is
+//  consistent with the exit to the map.
+//
+// Applies to: All versions
+// Responsible method: rm810:newRoom
+static const uint16 gk2FrauMillerLockupSignature[] = {
+	SIG_MAGICDWORD,
+	0x39, 0x03,                         // pushi 03
+	0x8f, 0x01,                         // lsp 01
+	0x38, SIG_UINT16(0x1fae),           // pushi 1fae
+	0x38, SIG_UINT16(0x0320),           // pushi 0320
+	0x46, SIG_UINT16(0xfde7),           // calle proc64999_5 [ OneOf newRoomNumber 8110 800 ]
+	      SIG_UINT16(0x0005),
+	      SIG_UINT16(0x0006),
+	0x31,                               // bnt [ don't fade music ]
+	SIG_END
+};
+
+static const uint16 gk2FrauMillerLockupPatch[] = {
+	0x8f, 0x01,                         // lsp 01
+	0x34, PATCH_UINT16(0x1fae),         // ldi 1fae
+	0x24,                               // le? [ newRoomNumber <= 8110 ]
+	0x31, PATCH_GETORIGINALBYTEADJUST(+18, +11), // bnt [ don't fade music ]
+	0x38, PATCH_SELECTOR16(handsOff),   // pushi handsOff
+	0x39, 0x00,                         // pushi 00
+	0x80, PATCH_UINT16(0x0001),         // lag 0001
+	0x4a, PATCH_UINT16(0x0004),         // send 04 [ GK2 handsOff: ]
+	PATCH_END
+};
+
+// GK2 1.0 contains a deadend bug in chapter 3. Exhausting Leber's topics before
+//  reading Grace's letter prevents returning to the police station to ask about
+//  the Black Wolf, which is necessary to complete the chapter.
+//
+// We fix this as Sierra did by adding a flag 218 test so that the police
+//  station doesn't close before Leber has been asked about the Black Wolf.
+//
+// Applies to: English PC 1.0
+// Responsible method: rm3210:dispose
+static const uint16 gk2PoliceStationDeadendSignature[] = {
+	0x78,                               // push1
+	0x38, SIG_UINT16(0x00dd),           // pushi 00dd
+	0x47, 0x0b, 0x00, SIG_MAGICDWORD,   // calle proc11_0 [ is flag 221 set? ]
+	      SIG_UINT16(0x002),
+	0x31, 0x51,                         // bnt 51 [ skip closing police station ]
+	SIG_END
+};
+
+static const uint16 gk2PoliceStationDeadendPatch[] = {
+	0x80, PATCH_UINT16(0x00a3),         // lag 00a3 [ flags 208-223 ]
+	0x39, 0x24,                         // pushi 24
+	0x12,                               // and
+	0x39, 0x24,                         // pushi 24
+	0x1a,                               // eq? [ are flags 218 and 221 set? ]
+	PATCH_END
+};
+
+// In chapter 3, Xaver can be asked about the Black Wolf before learning about
+//  the Black Wolf from Grace's letter. The tBlackWolf topic in room 4320 is
+//  missing the readyFlagNum value of 514 that the other tBlackWolf topics in
+//  chapter 3 have, so we set it.
+//
+// Applies to: All versions
+// Responsible method: heap in script 4320
+static const uint16 gk2XaverBlackWolfSignature[] = {
+	SIG_MAGICDWORD,             // tBlackWolf
+	SIG_UINT16(0x010e),         // sceneNum = 270
+	SIG_UINT16(0x00f0),         // flagNum = 240
+	SIG_UINT16(0x0000),         // readyFlagNum = 0
+	SIG_END
+};
+
+static const uint16 gk2XaverBlackWolfkPatch[] = {
+	PATCH_ADDTOOFFSET(+4),
+	PATCH_UINT16(0x0202),       // readyFlagNum = 514
+	PATCH_END
+};
+
+// Chapter 4 has a bug in many versions of GK2 that is effectively a deadend.
+//  Asking Georg about "Ludwig's letter to the Conductor" is required to finish
+//  the chapter. This topic becomes available after looking at the "Ludwig and
+//  Wagner" plaque in Herrenchiemsee and then clicking again to read it aloud.
+//  The problem is that the rest of the game only cares about looking at the
+//  plaque. If Herrenchiemsee is completed without reading the plaque then the
+//  Hint feature claims everything is done and the player appears to be stuck.
+//
+// We fix this as Sierra did by making Georg's letter topic available upon just
+//  looking at the plaque, which is consistent with the rest of the scripts.
+//  Although Sierra advertised this fix in the readme for GK2PAT 1.11, the patch
+//  file seems to be missing, but appears in later versions and the GOG release.
+//
+// Applies to: English PC 1.0, 1.1, 1.11 Patch, Mac
+// Responsible method: Heap in script 8520
+static const uint16 gk2GeorgLetterTopicSignature[] = {
+	SIG_MAGICDWORD,             // tLtr2Conductor
+	SIG_UINT16(0x0211),         // sceneNum = 529
+	SIG_UINT16(0x012a),         // flagNum = 298
+	SIG_UINT16(0x0283),         // readyFlagNum = 643
+	SIG_END
+};
+
+static const uint16 gk2GeorgLetterTopicPatch[] = {
+	PATCH_ADDTOOFFSET(+4),
+	PATCH_UINT16(0x026f),       // readyFlagNum = 623
+	PATCH_END
+};
+
+// In early versions of GK2, clicking on the holy water basket after using the
+//  holy water locks up the game. The script is supposed to test the flag that's
+//  set when getting the water but some code mistakenly tests inventory instead.
+//  We fix this as Sierra did by replacing the inventory tests with flag tests.
+//
+// Applies to: English PC 1.0, Mac
+// Responsible methods: waterBasket:handleEvent, waterBasket:doVerb
+static const uint16 gk2HolyWaterLockupSignature[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(has),  // pushi has
+	0x78,                       // push1
+	0x39, 0x3e,                 // pushi 3e
+	0x81, 0x00,                 // lag 00
+	0x4a, SIG_UINT16(0x0006),   // send 06 [ GraceEgo has: 62 (invBottleOfWater) ]
+	SIG_END
+};
+
+static const uint16 gk2HolyWaterLockupPatch[] = {
+	0x38, PATCH_UINT16(0x0001), // pushi 0001
+	0x38, PATCH_UINT16(0x0476), // pushi 0476
+	0x47, 0x0b, 0x00,           // calle proc11_0 [ is flag 1142 set? ]
+	      PATCH_UINT16(0x0002),
+	PATCH_END
+};
+
+// In early versions of GK2, Neuschwanstein castle can flash when clicking the
+//  Hint button even after completing everything. The Hint script tests too many
+//  flags including one whose value is random since it toggles back and forth
+//  between two tape messages. We remove these flag tests as Sierra did.
+//
+// Applies to: English PC 1.0, Mac
+// Responsible method: local procedure #0 in script 800
+static const uint16 gk2NeuschwansteinHintSignature1[] = {
+	SIG_MAGICDWORD,
+	0x78,                       // push1
+	0x38, SIG_UINT16(0x024d),   // pushi 024d
+	0x47, 0x0b, 0x00,           // calle proc11_0 [ is flag 589 set? ]
+	SIG_UINT16(0x0002),
+	SIG_END
+};
+
+static const uint16 gk2NeuschwansteinHintSignature2[] = {
+	SIG_MAGICDWORD,
+	0x78,                       // push1
+	0x38, SIG_UINT16(0x024e),   // pushi 024e
+	0x47, 0x0b, 0x00,           // calle proc11_0 [ is flag 590 set? ]
+	SIG_UINT16(0x0002),
+	SIG_END
+};
+
+static const uint16 gk2NeuschwansteinHintSignature3[] = {
+	SIG_MAGICDWORD,
+	0x78,                       // push1
+	0x38, SIG_UINT16(0x0250),   // pushi 0250
+	0x47, 0x0b, 0x00,           // calle proc11_0 [ is flag 592 set? ]
+	SIG_UINT16(0x0002),
+	SIG_END
+};
+
+static const uint16 gk2NeuschwansteinHintPatch[] = {
+	0x35, 0x01,                 // ldi 01
+	0x33, 0x05,                 // jmp 05
+	PATCH_END
+};
+
+// Clicking an inventory item on the Wagner paintings in rooms 8616 and 8617
+//  causes a missing message error. The paintings only have responses for the
+//  "Do" verb but painting:doVerb passes the incoming verb to gk2Messager:say
+//  without any filtering. We fix this by always playing the "Do" message.
+//
+// Applies to: All versions
+// Responsible methods: painting:doVerb in scripts 8616 and 8617
+static const uint16 gk2WagnerPaintingMessageSignature[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(say),  // pushi say
+	0x38, SIG_UINT16(0x0006),   // pushi 0006
+	0x67, SIG_ADDTOOFFSET(+1),  // pTos noun
+	0x8f, 0x01,                 // lsp 01 [ verb ]
+	SIG_END
+};
+
+static const uint16 gk2WagnerPaintingMessagePatch[] = {
+	PATCH_ADDTOOFFSET(+8),
+	0x39, 0x3e,                 // pushi 3e [ "Do" verb ]
+	PATCH_END
+};
+
+// The game-over rooms 665 and 666 draw a pic over everything by setting the
+//  default plane's priority to 202, but this is already inventoryBorderPlane's
+//  priority. In our interpreter this causes a border fragment to be drawn above
+//  the pics. This worked by luck in Sierra's interpreter because it sorts on
+//  memory ID when planes have the same priority. In ScummVM the renderer
+//  guarantees a sort order based on the creation order of the planes. The
+//  default plane is created first and drawn before inventoryBorderPlane.
+//
+// We fix this by increasing the plane priority in the game-over rooms.
+//
+// Applies to: All versions
+// Responsible methods: gabeNews:init, uDie:init
+// Fixes bug: #11298
+static const uint16 gk2GameOverPrioritySignature[] = {
+	0x39, SIG_SELECTOR8(priority),  // pushi priority
+	SIG_MAGICDWORD,
+	0x78,                           // push1
+	0x38, SIG_UINT16(0x00ca),       // pushi 00ca
+	0x81, 0x03,                     // lag 03
+	0x4a, SIG_UINT16(0x0012),       // send 12 [ Plane ... priority: 202 ]
+	SIG_END
+};
+
+static const uint16 gk2GameOverPriorityPatch[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x38, PATCH_UINT16(0x00cb),     // pushi 00cb [ priority: 203 ]
+	PATCH_END
+};
+
+// GK2 fans have created patches that add subtitles to the entire game. There
+//  are at least English and Spanish patch sets. Sierra added the subtitle
+//  feature solely for the Portuguese version. The fan patches include these
+//  subtitle scripts, replace the Portuguese resources and embedded script
+//  strings, and configure Sierra's interpreter to use the Portuguese language
+//  through RESOURCE.CFG. This sets GK2:printLang which the scripts test for
+//  Portuguese in order to activate subtitles.
+//
+// The subtitle patches are compatible with ScummVM except for the requirement
+//  that GK2:printLang equals Portuguese (351) since we don't use RESOURCE.CFG.
+//  We fix this by patching the GK2:printLang tests to always activate subtitles
+//  when a sync resource is present for synchronizing text to video playback.
+//
+// Applies to: PC versions with a subtitle fan-patch applied
+// Responsible methods: Any that test GK2:printLang for Portuguese
+// Fixes bugs: #9677, #11282
+static const uint16 gk2SubtitleCompatibilitySignature[] = {
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(printLang), // pushi printLang
+	0x76,                           // push0
+	0x81, 0x01,                     // lag 01
+	0x4a, SIG_UINT16(0x0004),       // send 04 [ GK2 printLang? ]
+	SIG_END
+};
+
+static const uint16 gk2SubtitleCompatibilityPatch[] = {
+	0x34, PATCH_UINT16(0x015f),     // ldi 015f [ K_LANG_PORTUGUESE ]
+	0x33, 0x03,                     // jmp 03
+	PATCH_END
+};
+
+//          script, description,                                              signature                         patch
+static const SciScriptPatcherEntry gk2Signatures[] = {
+	{  true,     0, "disable volume reset on startup",                     1, gk2VolumeResetSignature,           gk2VolumeResetPatch },
+	{  true,     0, "disable video benchmarking",                          1, gk2BenchmarkSignature,             gk2BenchmarkPatch },
+	{  true,    23, "fix inventory scroll speed",                          2, gk2InventoryScrollSpeedSignature,  gk2InventoryScrollSpeedPatch },
+	{  true,    23, "fix inventory scroll direction",                      1, gk2InventoryScrollDirSignature1,   gk2InventoryScrollDirPatch1 },
+	{  true,    23, "fix inventory scroll direction (no line numbers)",    1, gk2InventoryScrollDirSignature2,   gk2InventoryScrollDirPatch2 },
+	{  true,    37, "fix sound manager lockup",                            1, gk2SoundManagerLockupSignature1,   gk2SoundManagerLockupPatch1 },
+	{  true,    37, "fix sound manager lockup (no line numbers)",          1, gk2SoundManagerLockupSignature2,   gk2SoundManagerLockupPatch2 },
+	{  true,   665, "fix game-over priority",                              1, gk2GameOverPrioritySignature,      gk2GameOverPriorityPatch },
+	{  true,   666, "fix game-over priority",                              1, gk2GameOverPrioritySignature,      gk2GameOverPriorityPatch },
+	{  true,   800, "fix neuschwanstein hint (1/3)",                       1, gk2NeuschwansteinHintSignature1,   gk2NeuschwansteinHintPatch },
+	{  true,   800, "fix neuschwanstein hint (2/3)",                       1, gk2NeuschwansteinHintSignature2,   gk2NeuschwansteinHintPatch },
+	{  true,   800, "fix neuschwanstein hint (3/3)",                       1, gk2NeuschwansteinHintSignature3,   gk2NeuschwansteinHintPatch },
+	{  true,   810, "fix frau miller lockup",                              1, gk2FrauMillerLockupSignature,      gk2FrauMillerLockupPatch },
+	{  true,  1020, "fix holy water lockup",                               2, gk2HolyWaterLockupSignature,       gk2HolyWaterLockupPatch },
+	{  true,  3210, "fix police station deadend",                          1, gk2PoliceStationDeadendSignature,  gk2PoliceStationDeadendPatch },
+	{  true,  4320, "fix xaver black wolf topic",                          1, gk2XaverBlackWolfSignature,        gk2XaverBlackWolfkPatch },
+	{  true,  8520, "fix georg letter topic",                              1, gk2GeorgLetterTopicSignature,      gk2GeorgLetterTopicPatch },
+	{  true,  8616, "fix wagner painting message",                         2, gk2WagnerPaintingMessageSignature, gk2WagnerPaintingMessagePatch },
+	{  true,  8617, "fix wagner painting message",                         2, gk2WagnerPaintingMessageSignature, gk2WagnerPaintingMessagePatch },
+	{  true, 64928, "Narrator lockup fix",                                 1, sciNarratorLockupSignature,        sciNarratorLockupPatch },
+	{  true, 64928, "Narrator lockup fix",                                 1, sciNarratorLockupLineSignature,    sciNarratorLockupLinePatch },
+	{  true, 64962, "flash bad cursor spin loop",                          1, gk2FlashBadCursorSignature,        gk2FlashBadCursorPatch },
+	{  true, 64990, "increase number of save games (1/2)",                 1, sci2NumSavesSignature1,            sci2NumSavesPatch1 },
+	{  true, 64990, "increase number of save games (2/2)",                 1, sci2NumSavesSignature2,            sci2NumSavesPatch2 },
+	{  true, 64990, "disable change directory button",                     1, sci2ChangeDirSignature,            sci2ChangeDirPatch },
+	{ false,     0, "subtitle patch compatibility",                        3, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+	{ false,    11, "subtitle patch compatibility",                        7, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+	{ false,    12, "subtitle patch compatibility",                        5, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+	{ false,    91, "subtitle patch compatibility",                        7, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+	{ false,   200, "subtitle patch compatibility",                        1, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+	{ false,  1300, "subtitle patch compatibility",                        1, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+	{ false, 64924, "subtitle patch compatibility",                        1, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#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
+};
+
+// At the pier in Honolulu, room 23, "climb down" causes ego to bypass boarding
+//  procedure, walk through the air, climb down the hatch, and get stuck in the
+//  submarine without triggering a room change. There is no "climb up" command.
+//
+// Boarding requires asking the officer permission. comeAboardScript gives him
+//  the orders, runs downTheHatchScript, and changes to room 31 when finished.
+//  downTheHatchScript only walks ego to the hatch and runs the climb animation.
+//  "climb down" simply runs downTheHatchScript and nothing else, leaving the
+//  room in a broken state by running this intermediate script out of context.
+//
+// We patch "climb down" to respond with the message for other hatch commands.
+//
+// Applies to: All versions
+// Responsible method: hatch:handleEvent
+// Fixes bug #11039
+static const uint16 icemanClimbDownHatchSignature[] = {
+	0x7a,                               // push2
+	SIG_MAGICDWORD,
+	0x39, 0x17,                         // pushi 17
+	0x39, 0x18,                         // pushi 18
+	0x47, 0xff, 0x00, 0x04,             // calle proc255_0 04 [ "You must follow proper boarding procedure." ]
+	0x32, SIG_UINT16(0x0021),           // jmp 0021 [ end of method ]
+	SIG_ADDTOOFFSET(+22),
+	0x39, SIG_SELECTOR8(setScript),     // pushi setScript
+	0x78,                               // push1
+	0x72, SIG_UINT16(0xfc24),           // lofsa downTheHatchScript
+	SIG_END
+};
+
+static const uint16 icemanClimbDownHatchPatch[] = {
+	PATCH_ADDTOOFFSET(+34),
+	0x33, 0xdc,                         // jmp dc [ "You must follow proper boarding procedure." ]
+	PATCH_END
+};
+
+//         script, description,                                       signature                                      patch
+static const SciScriptPatcherEntry icemanSignatures[] = {
+	{ true,    23, "climb down hatch",                             1, icemanClimbDownHatchSignature,                 icemanClimbDownHatchPatch },
+	{ true,    99, "disable speed test",                           1, sci01SpeedTestLocalSignature,                  sci01SpeedTestLocalPatch },
+	{ true,   314, "destroyer timer (1/2)",                        1, icemanDestroyerTimer1Signature,                icemanDestroyerTimer1Patch },
+	{ true,   391, "destroyer timer (2/2)",                        1, icemanDestroyerTimer2Signature,                icemanDestroyerTimer2Patch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// Island of Dr. Brain
+
+// Narrator lockup fix, see sciNarratorLockupSignature.
+//  Island of Dr. Brain contains an early version of Narrator with the lockup
+//  bug so it requires its own patch.
+static const uint16 islandBrainNarratorLockupSignature[] = {
+	0x67, SIG_ADDTOOFFSET(+1),          // pTos ticks
+	SIG_MAGICDWORD,
+	0x35, 0x3c,                         // ldi 3c
+	0x02,                               // add
+	0x36,                               // push
+	0x89, 0x56,                         // lsg 56 [ game time ]
+	0x76,                               // push0
+	0x43, 0x42, 0x00,                   // callk GetTime 00
+	0x02,                               // add
+	0x02,                               // add
+	0x65, SIG_ADDTOOFFSET(+1),          // aTop ticks [ ticks += 60 + game time + GetTime ]
+	0x35, 0x01,                         // ldi 01 [ true ]
+	0x48,                               // ret
+	SIG_END
+};
+
+static const uint16 islandBrainNarratorLockupPatch[] = {
+	0x76,                               // push0
+	0x43, 0x42, 0x00,                   // callk GetTime 00
+	0x39, 0x3c,                         // pushi 3c
+	0x02,                               // add
+	0x67, PATCH_GETORIGINALBYTE(+1),    // pTos ticks
+	0x02,                               // add
+	0x89, 0x56,                         // lsg 56 [ game time ]
+	0x02,                               // add
+	0x65, PATCH_GETORIGINALBYTE(+1),    // aTop ticks [ ticks = GetTime + 60 + game time + ticks ]
+	0x00,                               // bnot
+	0x31, 0xfb,                         // bnt fb [ set ticks to 0 if ticks == -1 ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                                 patch
+static const SciScriptPatcherEntry islandBrainSignatures[] = {
+	{  true,   928, "Narrator lockup fix",                         1, islandBrainNarratorLockupSignature,       islandBrainNarratorLockupPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// Jones In The Fast Lane
+
+//          script, description,                                      signature                         patch
+static const SciScriptPatcherEntry jonesSignatures[] = {
+	{  true,   764, "disable speed test",                          1, sci01SpeedTestLocalSignature,     sci01SpeedTestLocalPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// King's Quest 1
+
+// In the demo, the leprechaun dance runs awkwardly fast on modern computers.
+//  The demo script increases the speed from the default (5 or 6) to fastest (1)
+//  for this scene only. This appears to be an attempt to speed up the dance and
+//  also compensate for the original interpreter significantly slowing down.
+//  On a machine from the demo's era, the interpreter was unable to keep up with
+//  all of the animating dancers. As each dancer disappeared the lag decreased
+//  and the dance got noticeably faster. On modern computers the dancers cause
+//  no lag and the real game's scripts don't adjust the speed at all, so we just
+//  lower the temporary dance speed to one that matches the demo and the dance
+//  music duration.
+//
+// Applies to: PC Demo only
+// Responsible method: danceFever:changeState(0)
+// Fixes bug: #9825
+static const uint16 kq1SignatureDemoDanceSpeed[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x01,                         // ldi 01
+	0xa1, 0x03,                         // sag 03 [ gameSpeed = 1 (fastest) ]
+	SIG_END
+};
+
+static const uint16 kq1PatchDemoDanceSpeed[] = {
+	0x35, 0x04,                         // ldi 04
+	PATCH_END
+};
+
+//          script, description,                                      signature                         patch
+static const SciScriptPatcherEntry kq1Signatures[] = {
+	{  true,    77, "demo: dance speed",                           1, kq1SignatureDemoDanceSpeed,       kq1PatchDemoDanceSpeed },
+	{  true,    99, "demo: disable speed test",                    1, sci01SpeedTestGlobalSignature,    sci01SpeedTestGlobalPatch },
+	{  true,   777, "disable speed test",                          1, sci01SpeedTestGlobalSignature,    sci01SpeedTestGlobalPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// In KQ4 1.000.111, falling down the lower stairs in room 90 sends a message to
+//  a non-object, which also crashes the original. It appears that the fragment
+//  of code which instantiated the Sound object was accidentally deleted from
+//  the script. This line was intact in the previous version and in later
+//  versions it was rewritten to use a new local Sound object. We fix this by
+//  jumping from the broken code into the sound code in fallingToDeath, which
+//  correctly plays the same sound.
+//
+// Applies to: PC 1.000.111
+// Responsible method: fallingDown:changeState(0)
+static const uint16 kq4SignatureFallDownStairs[] = {
+	SIG_MAGICDWORD,
+	0x83, 0x01,                      // lal 01  [ not set, zero ]
+	0x4a, 0x10,                      // send 10 [ local1 number: 51 loop: 1 play: ]
+	SIG_ADDTOOFFSET(+0x0108),
+	0x38, SIG_SELECTOR16(new),       // pushi new
+	0x76,                            // push0
+	0x51, 0x31,                      // class Sound
+	0x4a, 0x04,                      // send 04  [ Sound new: ]
+	0x4a, 0x10,                      // send 10  [ sound number: 51 loop: 1 play: ]
+	0x32, SIG_UINT16(0x0040),        // jmp 0040 [ end of method ]
+	SIG_END
+};
+
+static const uint16 kq4PatchFallDownStairs[] = {
+	0x32, PATCH_UINT16(0x0109),      // jmp 0109
+	PATCH_ADDTOOFFSET(+0x0111),
+	0xa2, PATCH_UINT16(0x0001),      // sal 0001 [ local1 = the new sound ]
+	0x4a, 0x10,                      // send 10  [ local1 number: 51 loop: 1 play: ]
+	PATCH_END
+};
+
+// KQ4 1.003.006 is missing view 653 and crashes room 24 outside the waterfall.
+//  In the original this only occurred at high CPU speeds. View 653 animates the
+//  river's current, which was first added in this version, but it's only loaded
+//  when the game's speed test detects a fast machine. Sierra later released a
+//  KQ4FIX patch with the missing view and included it in subsequent versions.
+//  We fix this by not initializing view 653 when it's not present.
+//
+// Applies to: PC and Atari ST 1.003.006
+// Responsible method: Room24:init
+static const uint16 kq4SignatureMissingWaterfallView[] = {
+	0x39, SIG_SELECTOR8(new),       // pushi new
+	0x76,                           // push0
+	0x51, SIG_ADDTOOFFSET(+1),      // class Prop
+	0x4a, 0x04,                     // send 04 [ Prop new: ]
+	0xa3, 0x0c,                     // sal 0c  [ local12 = new Prop ]
+	SIG_ADDTOOFFSET(+14),
+	0x39, SIG_SELECTOR8(view),      // pushi view
+	SIG_MAGICDWORD,
+	0x78,                           // push1
+	0x38, SIG_UINT16(0x028d),       // pusi 028d
+	SIG_ADDTOOFFSET(+83),
+	0x83, 0x0d,                     // lal 0d
+	0x4a, 0x34,                     // send 34 [ local13 ... view: 653 ... ]
+	SIG_END
+};
+
+static const uint16 kq4PatchMissingWaterfallView[] = {
+	0x33, 0x72,                     // jmp 72 [ skip missing view (local12 and local13) ]
+	PATCH_END
+};
+
+// KQ4 1.003.006 draws pics incorrectly when riding the unicorn at night.
+//  The riding scene takes place within room 333 which simulates room changes by
+//  drawing each pic in the sequence. This version of KQ4 introduced overlays
+//  for drawing night instead of using alternate pics, but Sierra forgot to
+//  update this script. Instead of drawing the base pic followed by the night
+//  overlay, this script only draws the overlay as if it were a complete pic.
+//  This paints the screen almost entirely white except for the night sky.
+//
+// There are too many outdated Rm:drawPic calls in script 333 with too many
+//  differences to reasonably patch each with the new logic and additional
+//  Rm:overlay call. Instead we patch Rm:drawPic to detect and handle these
+//  attempts. Rm:drawPic and Rm:overlay do similar work, so we patch Rm:overlay
+//  to handle both and rewrite Rm:drawPic to call Rm:overlay appropriately. When
+//  Rm:drawPic is called with a night overlay (100-129) it now calls Rm:overlay
+//  twice to draw the associated base pic first and then the night overlay.
+//
+// Applies to: PC and Atari ST 1.003.006
+// Responsible methods: Rm:drawPic and Rm:overlay
+static const uint16 kq4SignatureUnicornNightRide[] = {
+	// Rm:drawPic
+	0x87, 0x01,                     // lap 01
+	0x65, 0x22,                     // aTop curPic [ curPic = picNumber ]
+	0x35, 0xff,                     // ldi ff
+	0xa1, 0x39,                     // sag 39 [ global57 = -1 ]
+	0x7a,                           // push2
+	0x8f, 0x01,                     // lsp 01
+	0x8f, 0x00,                     // lsp 00
+	0x35, 0x02,                     // ldi 02
+	0x1a,                           // eq?
+	0x30, SIG_UINT16(0x0005),       // bnt 0005
+	0x87, 0x02,                     // lap 02
+	0x32, SIG_UINT16(0x000f),       // jmp 000f
+	0x67, 0x14,                     // pTos style
+	0x35, 0xff,                     // ldi ff
+	0x1c,                           // ne?
+	0x30, SIG_UINT16(0x0005),       // bnt 0005
+	0x63, 0x14,                     // pToa style
+	0x32, SIG_UINT16(0x0002),       // jmp 0002
+	0x81, 0x11,                     // lag 11
+	0x36,                           // push
+	SIG_MAGICDWORD,
+	0x43, 0x08, 0x04,               // callk DrawPic 04
+	0x48,                           // ret
+	// Rm:overlay
+	SIG_ADDTOOFFSET(+16),
+	0x87, 0x02,                     // lap 02
+	SIG_ADDTOOFFSET(+11),
+	0x63, 0x14,                     // pToa style
+	SIG_ADDTOOFFSET(+3),
+	0x81, 0x11,                     // lag 11
+	0x36,                           // push
+	0x78,                           // push1
+	SIG_END
+};
+
+static const uint16 kq4PatchUnicornNightRide[] = {
+	// Rm:drawPic
+	0x76,                           // push0
+	0xa9, 0x1a,                     // ssg 1a [ global26 = 0, draw pic normally ]
+	0x38, PATCH_SELECTOR16(overlay),// pushi overlay
+	0x8f, 0x01,                     // lsp 01 [ picNumber ]
+	0x35, 0x64,                     // ldi 64
+	0x04,                           // sub
+	0x65, 0x22,                     // aTop curPic [ curPic = picNumber - 100 ]
+	0x39, 0x1e,                     // pushi 1e
+	0x28,                           // uge?   [ 30 >= (picNumber - 100) ]
+	0x31, 0x09,                     // bnt 09 [ jump if this is a correct drawPic call]
+	0x78,                           // push1
+	0x60,                           // pprev
+	0x54, 0x06,                     // self 06 [ self overlay: (picNumber - 100) ]
+	0x78,                           // push1
+	0xa9, 0x1a,                     // ssg 1a [ global26 = 1, draw pic as overlay ]
+	0x33, 0x11,                     // jmp 11 [ self overlay: &rest, ret ]
+	0x76,                           // push0
+	0x59, 0x01,                     // &rest 01
+	0x54, 0x04,                     // self 04 [ self overlay: &rest ]
+	0x87, 0x01,                     // lap 01
+	0x65, 0x22,                     // aTop curPic [ curPic = picNumber ]
+	0x35, 0xff,                     // ldi ff
+	0xa1, 0x39,                     // sag 39 [ global57 = -1 ]
+	0x78,                           // push1
+	0xa9, 0x1a,                     // ssg 1a [ global26 = 1, its original value ]
+	0x48,                           // ret
+	// Rm:overlay
+	PATCH_ADDTOOFFSET(+16),
+	0x8f, 0x02,                     // lsp 02
+	PATCH_ADDTOOFFSET(+11),
+	0x67, 0x14,                     // pTos style
+	PATCH_ADDTOOFFSET(+3),
+	0x89, 0x11,                     // lsg 11
+	0x89, 0x1a,                     // lsg 1a [ always 1 unless cleared in drawPic ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                                 patch
+static const SciScriptPatcherEntry kq4Signatures[] = {
+	{ false,    24, "missing waterfall view",                      1, kq4SignatureMissingWaterfallView,         kq4PatchMissingWaterfallView },
+	{  true,    90, "fall down stairs",                            1, kq4SignatureFallDownStairs,               kq4PatchFallDownStairs },
+	{  true,    98, "disable speed test",                          1, sci0EarlySpeedTestSignature,              sci0EarlySpeedTestPatch },
+	{  true,    99, "disable speed test",                          1, sci0EarlySpeedTestSignature,              sci0EarlySpeedTestPatch },
+	{  true,   994, "ride unicorn at night",                       1, kq4SignatureUnicornNightRide,             kq4PatchUnicornNightRide },
+	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
+//  master volume. This makes SSCI set the volume to max. We fix the procedure,
+//  so volume won't get modified in those cases.
+//
+// Applies to at least: PC CD
+// Responsible method: export 29 in script 0
+// Fixes bug: #5209
+static const uint16 kq5SignatureCdHarpyVolume[] = {
+	SIG_MAGICDWORD,
+	0x80, SIG_UINT16(0x0191),        // lag global[191h]
+	0x18,                            // not
+	0x30, SIG_UINT16(0x002c),        // bnt [jump further] (jumping, if global[191h] is 1)
+	0x35, 0x01,                      // ldi 01
+	0xa0, SIG_UINT16(0x0191),        // sag global[191h] (setting to 1)
+	0x38, SIG_UINT16(0x017b),        // pushi 017b
+	0x76,                            // push0
+	0x81, 0x01,                      // lag global[1]
+	0x4a, 0x04,                      // send 04 - read KQ5::masterVolume
+	0xa5, 0x03,                      // sat temp[3] (store volume)
+	0x38, SIG_UINT16(0x017b),        // 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
+};
+
+static const uint16 kq5PatchCdHarpyVolume[] = {
+	0x38, PATCH_UINT16(0x022f),      // 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)
+	0x80, PATCH_UINT16(0x0191),      // lag global[191h]
+	// saving 1 byte due optimization
+	0x2e, PATCH_UINT16(0x0023),      // bt [jump further] (jumping, if global[191h] is 1)
+	0x35, 0x01,                      // ldi 01
+	0xa0, PATCH_UINT16(0x0191),      // sag global[191h] (setting to 1)
+	0x38, PATCH_UINT16(0x017b),      // pushi 017b
+	0x76,                            // push0
+	0x81, 0x01,                      // lag global[1]
+	0x4a, 0x04,                      // send 04 - read KQ5::masterVolume
+	0xa5, 0x03,                      // sat temp[3] (store volume)
+	// saving 8 bytes due removing of duplicate code
+	0x39, 0x04,                      // pushi 04 (saving 1 byte due swapping)
+	0x22,                            // lt? (because we switched values)
+	PATCH_END
+};
+
+// The witchCage object in script 200 is broken and claims to have 12
+// properties instead of the 8 it should have because it is a Cage.
+// Additionally its top,left,bottom,right properties are set to 0 rather
+// than the right values. We fix the object by setting the right values.
+// If they are all zero, this causes an impossible position check in
+// witch::cantBeHere and an infinite loop when entering room 22.
+//
+// This bug is accidentally not triggered in SSCI because the invalid number
+// of variables effectively hides witchCage::doit, causing this position check
+// to be bypassed entirely.
+// See also the warning+comment in Object::initBaseObject
+//
+// Applies to at least: PC CD, English PC floppy
+// Responsible method: heap in script 200
+// Fixes bug: #4964
+static const uint16 kq5SignatureWitchCageInit[] = {
+	SIG_UINT16(0x0000),         // top
+	SIG_UINT16(0x0000),         // left
+	SIG_UINT16(0x0000),         // bottom
+	SIG_UINT16(0x0000),         // right
+	SIG_UINT16(0x0000),         // extra property #1
+	SIG_MAGICDWORD,
+	SIG_UINT16(0x007a),         // extra property #2
+	SIG_UINT16(0x00c8),         // extra property #3
+	SIG_UINT16(0x00a3),         // extra property #4
+	SIG_END
+};
+
+static const uint16 kq5PatchWitchCageInit[] = {
+	PATCH_UINT16(0x0000),       // top
+	PATCH_UINT16(0x007a),       // left
+	PATCH_UINT16(0x00c8),       // bottom
+	PATCH_UINT16(0x00a3),       // right
+	PATCH_END
+};
+
+// The multilingual releases of KQ5 hang right at the end during the magic
+// battle with Mordack. It seems additional code was added to wait for signals,
+// but the signals are never set and thus the game hangs. We disable that code,
+// so that the battle works again. This also happened in the original
+// interpreter. We must not change similar code, that happens before.
+//
+// Applies to at least: French PC floppy, German PC floppy, Spanish PC floppy
+// Responsible method: stingScript::changeState, dragonScript::changeState, snakeScript::changeState
+static const uint16 kq5SignatureMultilingualEndingGlitch[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x57,                      // lsg global[57h]
+	0x35, 0x00,                      // ldi 0
+	0x1a,                            // eq?
+	0x18,                            // not
+	0x30, SIG_UINT16(0x0011),        // bnt [skip signal check]
+	SIG_ADDTOOFFSET(+8),             // skip globalSound::prevSignal get code
+	0x36,                            // push
+	0x35, 0x0a,                      // ldi 0Ah
+	SIG_END
+};
+
+static const uint16 kq5PatchMultilingualEndingGlitch[] = {
+	PATCH_ADDTOOFFSET(+6),
+	0x32,                            // jmp (replace bnt)
+	PATCH_END
+};
+
+// In the final battle, the DOS version uses signals in the music to handle
+// timing, while in the Windows version another method is used and the GM
+// tracks do not contain these signals. The original kq5 interpreter used
+// global[400] to distinguish between Windows (1) and DOS (0) versions.
+//
+// We replace the global[400] checks with a fixed true. This is toggled with
+// enablePatch() below when alternative Windows GM MIDI tracks are used.
+//
+// Global[400] is also used to determine which cursor type to use: color view
+// resources for DOS or old black and white cursor resources for Windows.
+// We set this depending on if the user has used the "windows_cursors" option
+// in the Windows version. That doesn't affect this patch since it removes
+// global[400] from the code.
+//
+// Applies to at least: Win CD
+// Responsible method: mordOneScript::changeState(1), dragonScript::changeState(1),
+//                     fireScript::changeState() in script 124
+// Fixes bug: #6251
+static const uint16 kq5SignatureWinGMSignals[] = {
+	SIG_MAGICDWORD,
+	0x80, SIG_UINT16(0x0190),        // lag global[400]
+	0x18,                            // not
+	0x30, SIG_UINT16(0x001b),        // bnt 0x001b
+	0x89, 0x57,                      // lsg global[87]
+	SIG_END
+};
+
+static const uint16 kq5PatchWinGMSignals[] = {
+	0x34, PATCH_UINT16(0x0001),      // ldi 0x0001
+	PATCH_END
+};
+
+// During the introduction at Crispin's house in later floppy versions, Graham's
+//  initial message immediately disappears. This is another KQ5 sound regression
+//  caused by a broken signal that a script depends on.
+//
+// Sound 80's first signal is supposed to be set after 781 ticks to trigger the
+//  second message in room 109, but starting in the French version the sound
+//  changed to set this signal on the first tick. This causes the first message
+//  to miss the signal and display for too long until the second signal occurs
+//  and closes the first message and immediately closes the second.
+//
+// We fix this by replacing the first signal wait with a 13 second delay.
+//  781 ticks / 60 = 13 seconds and 1 tick. All subsequent signals in sound 80
+//  are correct. Sierra noticed this bug in the German Amiga Floppy version, but
+//  instead of fixing the broken sound, they peppered this script with similar
+//  delays except for the one place that needed it. This covers up that the
+//  wrong signals are still triggering messages with unintentional timings, but
+//  the results are acceptable. Due to this messy history, and that it involves
+//  multiple versions of multiple resources, we only enable this patch on game
+//  versions known to disappear Graham's message.
+//
+// Applies to: French PC Floppy, Italian PC Floppy, English Mac Floppy,
+//             English Amiga Floppy
+// Responsible method: a2s5Script:changeState(2)
+// Fixes bug: #11543
+static const uint16 kq5SignatureCrispinIntroSignal[] = {
+	SIG_MAGICDWORD,
+	0x36,                            // push
+	0x35, 0x0a,                      // ldi 0a
+	0x22,                            // lt? [ globalMusic:prevSignal < 10 ]
+	0x30, SIG_UINT16(0x0002),        // bnt 0002
+	0x6d, 0x0a,                      // dpToa state
+	0x35, 0x01,                      // ldi 01
+	0x65, 0x10,                      // aTop cycles
+	SIG_END
+};
+
+static const uint16 kq5PatchCrispinIntroSignal[] = {
+	0x38, PATCH_SELECTOR16(seconds), // pushi seconds
+	0x78,                            // push1
+	0x39, 0x0d,                      // pushi 0d
+	0x54, 0x06,                      // self 06 [ self seconds: 13 ]
+	0x32, PATCH_UINT16(0x0002),      // jmp 0002
+	PATCH_END
+};
+
+// Clicking Look or Do on the bandit's campfire in room 216 of the PC-98 version
+//  crashes the game or displays the wrong message after attempting to process
+//  hundreds of uninitialized parameters. The script has four calle instructions
+//  with frame size operands that don't match the number of parameters passed on
+//  the stack. The first real parameter, 216, is interpreted as the parameter
+//  count and chaos ensues.
+//
+// We fix this by setting the correct frame size. These instructions are correct
+//  in the later FM-Towns version so this appears to be a compiler bug.
+//
+// Applies to: Japanese PC-98
+// Responsible methods: fire:handleEvent, fireRing:handleEvent
+static const uint16 kq5SignaturePc98CampfireMessages[] = {
+	0x35, SIG_ADDTOOFFSET(+1),       // ldi
+	SIG_MAGICDWORD,
+	0x36,                            // push
+	0x46, SIG_UINT16(0x02f7),        // calle proc759_0 [ print message, 1 parameter ]
+	      SIG_UINT16(0x0000), 0x02,
+	SIG_END
+};
+
+static const uint16 kq5PatchPc98CampfireMessages[] = {
+	PATCH_ADDTOOFFSET(+8),
+	0x04,                            // calle proc759_0 [ print message, 2 parameters ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                  patch
+static const SciScriptPatcherEntry kq5Signatures[] = {
+	{  true,     0, "CD: harpy volume change",                     1, kq5SignatureCdHarpyVolume,            kq5PatchCdHarpyVolume },
+	{  true,     0, "timer rollover",                              1, sciSignatureTimerRollover,            sciPatchTimerRollover },
+	{  true,    99, "disable speed test",                          1, sci01SpeedTestLocalSignature,         sci01SpeedTestLocalPatch },
+	{  true,    99, "disable speed test",                          1, sci11SpeedTestSignature,              sci11SpeedTestPatch },
+	{ false,   109, "Crispin intro signal",                        1, kq5SignatureCrispinIntroSignal,       kq5PatchCrispinIntroSignal },
+	{  true,   124, "Multilingual: Ending glitching out",          3, kq5SignatureMultilingualEndingGlitch, kq5PatchMultilingualEndingGlitch },
+	{ false,   124, "Win: GM Music signal checks",                 4, kq5SignatureWinGMSignals,             kq5PatchWinGMSignals },
+	{  true,   200, "CD: witch cage init",                         1, kq5SignatureWitchCageInit,            kq5PatchWitchCageInit },
+	{  true,   216, "PC-98: campfire messages",                    4, kq5SignaturePc98CampfireMessages,     kq5PatchPc98CampfireMessages },
+	{  true,   973, "timer rollover",                              1, sciSignatureTimerRollover,            sciPatchTimerRollover },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// In the garden (room 480), when giving the milk bottle to one of the babies,
+// script 481 starts a looping a baby cry sound (cryMusic). However, that
+// particular sound has an overridden check() method that explicitly restarts
+// the sound, even if it's set to be looped. Thus the same sound is played
+// twice, squelching all other sounds.
+//
+// We just rip out the unnecessary check() method, 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.
+//
+// Applies to at least: PC-CD
+// Responsible method: cryMusic::check in script 481
+// Fixes bug: #4955
+static const uint16 kq6SignatureDuplicateBabyCry[] = {
+	SIG_MAGICDWORD,
+	0x83, 0x00,                      // lal local[0]
+	0x31, 0x1e,                      // bnt 1e [07f4]
+	0x78,                            // push1
+	0x39, 0x04,                      // pushi 04
+	0x43, 0x75, 0x02,                // callk DoAudio[75], 02
+	SIG_END
+};
+
+static const uint16 kq6PatchDuplicateBabyCry[] = {
+	0x48,                            // ret
+	PATCH_END
+};
+
+// 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 in script 907
+// Fixes bug: #5681
+static const uint16 kq6SignatureInventoryStackFix[] = {
+	0x67, 0x30,                         // pTos state
+	0x34, SIG_UINT16(0x2000),           // 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(0xdfff),           // ldi dfff
+	0x12,                               // and
+	0x65, 0x30,                         // aTop state
+	0x38, SIG_SELECTOR16(show),         // pushi show (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)
+};
+
+static 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(0x2000),         // ldi 2000
+	0x12,                               // and
+	0x2f, 0x02,                         // bt [not first refresh] - saves 3 bytes in total
+	0x65, 0x1e,                         // aTop curIcon
+	0x00,                               // bnot (neg, either 2000 or 0000 in acc, this will create dfff or ffff) - saves 2 bytes
+	0x12,                               // and
+	0x65, 0x30,                         // aTop state
+	0x38, PATCH_GETORIGINALUINT16(+22), // pushi show
+	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, PATCH_GETORIGINALBYTEADJUST(+39, +6), // bnt [menu exit code] (0x0e for pc, 0x0d for mac)
+	0x34, PATCH_UINT16(0x2000),         // ldi 2000
+	0x12,                               // and
+	0x2f, 0x05,                         // bt [to ret]
+	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
+};
+
+// The "Drink Me" bottle code doesn't repaint the AddToPics elements to the
+//  screen, when Alexander returns back from the effect of the bottle.
+//  It's pretty strange that Sierra didn't find this bug, because it occurs
+//  when drinking the bottle right on the screen, where the bottle is found.
+// This bug also occurs in Sierra SCI.
+//
+// Applies to at least: PC-CD, English PC floppy, German PC floppy, English Mac
+// Responsible method: drinkMeScript::changeState in script 87
+// Fixes bug: #5252
+static const uint16 kq6SignatureDrinkMeFix[] = {
+	SIG_MAGICDWORD,
+	0x3c,                               // dup
+	0x35, 0x0f,                         // ldi 0f
+	0x1a,                               // eq?
+	0x30, SIG_UINT16(0x00a4),           // bnt [skip to next check]
+	SIG_ADDTOOFFSET(+161),
+	0x32, SIG_UINT16(0x007f),           // jmp [return]
+	0x3c,                               // dup
+	0x35, 0x10,                         // ldi 10
+	0x1a,                               // eq?
+	0x31, 0x07,                         // bnt [skip to next check]
+	0x35, 0x03,                         // ldi 03
+	0x65, 0x1a,                         // aTop (cycles)
+	0x32, SIG_UINT16(0x0072),           // jmp [return]
+	0x3c,                               // dup
+	0x35, 0x11,                         // ldi 11
+	0x1a,                               // eq?
+	0x31, 0x13,                         // bnt [skip to next check]
+	SIG_ADDTOOFFSET(+20),
+	0x35, 0x12,                         // ldi 12
+	SIG_ADDTOOFFSET(+23),
+	0x35, 0x13,                         // ldi 13
+	SIG_END
+};
+
+static const uint16 kq6PatchDrinkMeFix[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x30, PATCH_UINT16(0x00b1),         // bnt 00b1 [ check for 11h code ]
+	PATCH_ADDTOOFFSET(+161),
+	0x39, PATCH_SELECTOR8(doit),        // pushi doit
+	0x76,                               // push0
+	0x81, 0x0a,                         // lag global[0a]
+	0x4a, 0x04,                         // send 04 (call addToPics::doit)
+	0x3a,                               // toss
+	0x48,                               // ret
+	PATCH_ADDTOOFFSET(+8),              // skip to check 11h code
+	0x35, 0x10,                         // ldi 10 (instead of 11)
+	PATCH_ADDTOOFFSET(+23),             // skip to check 12h code
+	0x35, 0x11,                         // ldi 11 (instead of 12)
+	PATCH_ADDTOOFFSET(+23),             // skip to check 13h code
+	0x35, 0x12,                         // ldi 12 (instead of 13)
+	PATCH_END
+};
+
+// KQ6 Mac is missing pic 981 and crashes when drinking the "Drink Me" bottle.
+//  This also crashed the original. Pic 981 is a black background and it's only
+//  used in this scene. Pic 98 is also a black background and used when the game
+//  starts and everywhere else. We restore this scene by switching to pic 98.
+//
+// This patch is only enabled on Mac as the script is the same in all versions.
+//  The pics have different palettes and applying it to PC would disable the
+//  palette cycling between red and black during this scene. KQ6 Mac didn't do
+//  these palette cycling effects as it didn't include any palette resources.
+//
+// Applies to: English Mac
+// Responsible method: drinkMeScript:changeState(0)
+static const uint16 kq6SignatureMacDrinkMePic[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x03d5),           // pushi 981d
+	0x39, 0x09,                         // pushi 09
+	0x43, 0x08, 0x04,                   // callk DrawPic 04
+	SIG_END
+};
+
+static const uint16 kq6PatchMacDrinkMePic[] = {
+	0x38, PATCH_UINT16(0x0062),         // pushi 98d
+	PATCH_END
+};
+
+// Looking at the ribbon in inventory says that there's a hair even after it's
+//  been removed. This occurs after the hair has been put in the skull or is on
+//  a different inventory page than the ribbon.
+//
+// The ribbon's Look handler has incorrect logic for determining if it contains
+//  a hair. It fails to test flag 143 which is set when getting the hair and so
+//  it displays the wrong message. The Do handler tests all the necessary flags.
+//  This bug probably would have been noticed except that both verb handlers
+//  also test inventory for hair, which is redundant as testing flags is enough,
+//  but it causes the right message some of the time. Testing inventory is wrong
+//  because possessing the hair is temporary, which is why the bug emerges after
+//  it's used, and it's broken because testing inventory across pages doesn't
+//  work in KQ6. ego:has returns false for any item on another page when the
+//  inventory window is open. As inventory increases the ribbon and hair end up
+//  on different pages and ribbon:doVerb can no longer see it.
+//
+// We fix the message by changing ribbon:doVerb(1) to test flag 143 like doVerb(5).
+//  This requires overwriting one of the redundant inventory tests.
+//
+// Beauty's clothes also have a hair and clothes:doVerb(1) has similar issues
+//  but it happens to work. Those items are always on the same page due to their
+//  low item numbers and the clothes are removed from inventory before the hair.
+//
+// Applies to: PC CD, PC Floppy, Mac Floppy
+// Responsible method: ribbon:doVerb(1) in script 907
+// Fixes bug: #10801
+static const uint16 kq6SignatureLookRibbonFix[] = {
+	0x30, SIG_ADDTOOFFSET(+2),          // bnt [ verb != Look ]
+	0x38, SIG_SELECTOR16(has),          // pushi has
+	0x78,                               // push1
+	0x39, 0x04,                         // pushi 04
+	0x81, SIG_MAGICDWORD, 0x00,         // lag global[0]
+	0x4a, 0x06,                         // send 6 [ ego:has 4 (beauty's hair) ]
+	0x2e,                               // bt [ continue hair tests ]
+	SIG_END
+};
+
+static const uint16 kq6PatchLookRibbonFix[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x78,                               // push1
+	0x38, PATCH_UINT16(0x008f),         // pushi 008f
+	0x46, PATCH_UINT16(0x0391),         // calle [export 0 of script 13], 02 [ is flag 8f set? ]
+	      PATCH_UINT16(0x0000), 0x02,
+	PATCH_END
+};
+
+// During the common Game Over cutscene, the CD audio for "Tickets, only" gets
+//  cut off. This only worked in the original interpreter at slow CPU speeds.
+//  modeLessScript sets a 4 second timer for the message to complete. This is
+//  enough time, but actor animations also cue modeLessScript, and they complete
+//  in 2 seconds unless the interpreter can't keep up due to a slow CPU.
+//
+// We fix this by ignoring the cue from deathCartoonScr if CD audio is enabled
+//  and the audio timeout hasn't completed. This does not change scene duration
+//  or actor delays or when messages start. Text-only mode is unaffected.
+//
+// Applies to: PC CD
+// Responsible method: modeLessScript:changeState
+static const uint16 kq6CDSignatureTicketsOnlyAudioTiming[] = {
+	0x31, 0x2b,                         // bnt 2b [ state 1 ]
+	SIG_ADDTOOFFSET(+38),
+	SIG_MAGICDWORD,
+	0x65, 0x1c,                         // aTop seconds
+	0x32, SIG_UINT16(0x0051),           // jmp 0051 [ end of method ]
+	0x3c,                               // dup
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	0x31, 0x0c,                         // bnt 0c [ state 2 ]
+	0x81, 0x19,                         // lag 19 [ dialog ]
+	0x30, SIG_UINT16(0x0046),           // bnt 0046
+	0x39, SIG_SELECTOR8(dispose),       // pushi dispose
+	0x76,                               // push0
+	0x4a, 0x04,                         // send 04 [ dialog dispose: ]
+	0x33, 0x3f,                         // jmp 3f
+	SIG_ADDTOOFFSET(+44),
+	0x65, 0x1c,                         // aTop seconds
+	SIG_ADDTOOFFSET(+8),
+	0x81, 0x19,                         // lag 19 [ dialog ]
+	SIG_END
+};
+
+static const uint16 kq6CDPatchTicketsOnlyAudioTiming[] = {
+	0x31, 0x28,                         // bnt 28 [ state 1 ]
+	PATCH_ADDTOOFFSET(+38),
+	0x33, 0x41,                         // jmp 41 [ aTop seconds, end of method ]
+	0x3c,                               // dup
+	0x18,                               // not [ acc = 1 ]
+	0x1a,                               // eq?
+	0x31, 0x10,                         // bnt 10 [ state 2 ]
+	0x81, 0x5a,                         // lag 5a [ mode ]
+	0x7a,                               // push2  [ audio ]
+	0x12,                               // and    [ is audio enabled? ]
+	0x31, 0x40,                         // bnt 40 [ if no audio then dispose dialog normally ]
+	0x63, 0x1c,                         // pToa seconds
+	0x2f, 0x04,                         // bt 04  [ ignore cue from deathCartoonScr if audio is playing ]
+	0x6b, 0x1a,                         // ipToa cycles [ cycles = 1 ]
+	0x33, 0x38,                         // jmp 38 [ dispose dialog normally ]
+	0x6d, 0x14,                         // dpToa state [ state = 0 so that state 1 can repeat ]
+	PATCH_END
+};
+
+// KQ6 CD introduced a bug in the wallflower dance in room 480. The dance is
+//  supposed to last until the music ends but in Text mode it stops after only
+//  three seconds once the user gains control. This isn't usually enough time
+//  to get the hole in the wall. This bug also occurs in Sierra's interpreter.
+//
+// wallFlowerDance was changed in the CD version for Speech mode but broke Text.
+//  In Text mode, changeState(9) creates a dialog with Print, which blocks, and
+//  then sets ticks to 12. Meanwhile, wallFlowerDance:handleEvent cues if an
+//  event is received in state 9. A mouse click starts a 12 tick race which
+//  handleEvent wins, cueing before the countdown expires, and so the countdown
+//  expires on state 10, skipping ahead to the three second fadeout. Closing the
+//  dialog with the keyboard works because Dialog claims keyboard events when
+//  blocking, preventing wallFlowerDance:handleEvent from receiving and cueing.
+//
+// We fix this by setting the Print dialog to modeless as it was in the floppy
+//  version and removing the countdown. wallFlowerDance:handleEvent now receives
+//  all events and is the only one responsible for advancing state 9 to 10 in
+//  Text mode. This patch does not affect audio modes Speech and Both.
+//
+// Applies to: PC CD
+// Responsible method: wallFlowerDance:changeState(9) in script 480
+// Fixes bug: #10811
+static const uint16 kq6CDSignatureWallFlowerDanceFix[] = {
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(init),          // pushi init
+	0x76,                               // push0
+	0x51, 0x15,                         // class Print [ Print: ... init ]
+	0x4a, 0x24,                         // send 24
+	0x35, 0x0c,                         // ldi 0c
+	0x65, 0x20,                         // aTop ticks
+	0x32, SIG_UINT16(0x00d0),           // jmp 00d0 [ end of method ]
+	SIG_END
+};
+
+static const uint16 kq6CDPatchWallFlowerDanceFix[] = {
+	0x38, PATCH_SELECTOR16(modeless),   // pushi modeless
+	0x78,                               // push1
+	0x78,                               // push1
+	0x39, PATCH_SELECTOR8(init),        // pushi init
+	0x76,                               // push0
+	0x51, 0x15,                         // class Print [ Print: ... modeless: 1, init ]
+	0x4a, 0x2a,                         // send 2a
+	0x3a,                               // toss
+	0x48,                               // ret
+	PATCH_END
+};
+
+// Attempting to pick a second head of frozen lettuce accidentally succeeds or
+//  fails depending on the time of day in real life.
+//
+// Upon picking the lettuce it starts to melt. After 150 seconds it's half
+//  melted, after 300 seconds it's a puddle, and after 450 seconds it disappears
+//  from inventory. When trying to pick a second head while one is inventory,
+//  lettuce:doVerb attempts to figure out if the lettuce is melted enough to
+//  replace or if it should say that Alexander already has frozen lettuce.
+//  The script's logic is:
+//
+//    if (kGetTime(1) - global157) < 150 then don't replace lettuce
+//
+// The first problem is that this code is outdated. Global 157 is never set, but
+//  presumably it was the original timer implementation before lettuceTimer.
+//  This code is supposed to test an elapsed time period, but since global 157
+//  is always zero, instead it's an accidental test of the current clock time.
+//  The second problem is that this is a signed comparison and kGetTime(1) is
+//  unsigned with the hour as the upper four bits. When the current clock time
+//  is between 8:00 and 12:59 (am or pm) then kGetTime(1) appears negative and
+//  the lettuce can never be replaced. During the other 14 hours of the day the
+//  lettuce can always be replaced, even if it's frozen.
+//
+// We fix this by replacing the time test with the correct frozen lettuce test.
+//
+// Applies to: All versions
+// Responsible method: lettuce:doVerb
+static const uint16 kq6SignatureSecondLettuceFix[] = {
+	0x31, 0x12,                         // bnt 12 [ skip message if clock hour < 8 (unintentional) ]
+	0x38, SIG_SELECTOR16(say),          // pushi say
+	SIG_ADDTOOFFSET(+15),
+	0x78,                               // push1
+	0x78,                               // push1
+	0x43, 0x42, 0x02,                   // callk GetTime 02
+	0x36,                               // push
+	0x81, 0x9d,                         // lag 9d [ always zero ]
+	0x04,                               // sub
+	0x36,                               // push
+	SIG_MAGICDWORD,
+	0x34, SIG_UINT16(0x012c),           // ldi 012c
+	0x22,                               // lt? [ (kGetTime(1) - global157) < 300 ]
+	0x31, 0x0a,                         // bnt 0a [ pick lettuce ]
+	0x78,                               // push1
+	0x7c,                               // pushSelf
+	0x46, SIG_UINT16(0x01e3),           // calle 01e3 ... [ pick lettuce ]
+	SIG_END
+};
+
+static const uint16 kq6PatchSecondLettuceFix[] = {
+	0x33, 0x12,                         // jmp 12 [ skip to correct lettuce logic ]
+	PATCH_ADDTOOFFSET(+18),
+	0x39, PATCH_SELECTOR8(at),          // pushi at
+	0x78,                               // push1
+	0x39, 0x15,                         // pushi 15
+	0x81, 0x09,                         // lag 09
+	0x4a, 0x06,                         // send 06 [ KqInv at: 21 ]
+	0x39, PATCH_SELECTOR8(message),     // pushi message
+	0x76,                               // push0
+	0x4a, 0x04,                         // send 04  [ lettuce message? ]
+	0x39, 0x34,                         // pushi 34 [ frozen ]
+	0x1a,                               // eq?      [ is lettuce frozen? ]
+	0x2f, 0xdb,                         // bt db    [ "Alexander already has a frozen head of lettuce." ]
+	0x33, 0x05,                         // jmp 05   [ pick lettuce ]
+	PATCH_END
+};
+
+// In room 300 at the bottom of the logic cliffs, clicking Walk while Alexander
+//  randomly wobbles on lower steps causes him to float around the room. Scripts
+//  attempt to prevent this by ignoring Walk when ego:view is 301 and ego:loop
+//  is 3, which is wobbling animation, but this is incomplete because egoWobbles
+//  also animates with view 3011. The rest of the cliff rooms directly test if
+//  egoWobbles is running and so they don't have this bug. egoWobbles isn't
+//  exported so room 300 is left testing ego's state.
+//
+// We fix this by adding the missing test for view 3011 so that the Walk verb is
+//  successfully ignored whenever egoWobbles is running.
+//
+// Applies to: All versions
+// Responsible methods: beach:doVerb, WalkFeature:doVerb
+static const uint16 kq6SignatureCliffStepFloatFix[] = {
+	0x36,                               // push
+	0x34, SIG_UINT16(0x012d),           // ldi 012d
+	0x1a,                               // eq?      [ ego:view == 301 ]
+	0x31, 0x12,                         // bnt 12   [ not wobbling ]
+	0x39, 0x03,                         // pushi 03 [ loop ]
+	0x76,                               // push0
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x04,                         // send 04  [ ego loop? ]
+	0x36,                               // push
+	0x35, SIG_MAGICDWORD, 0x03,         // ldi 03
+	0x1a,                               // eq?      [ ego:loop == 3 ]
+	0x31, 0x05,                         // bnt 05   [ not wobbling ]
+	0x35, 0x00,                         // ldi 00
+	0x32, SIG_ADDTOOFFSET(+2),          // jmp      [ end of method ]
+	0x76,                               // push0    [ y ]
+	0x76,                               // push0
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x04,                         // send 04  [ ego y? ]
+	0x36,                               // push
+	0x35, 0x26,                         // ldi 26
+	0x22,                               // lt?      [ ego:y < 38 ]
+	SIG_ADDTOOFFSET(+17),
+	0x32,                               // jmp      [ end of method ]
+	SIG_END
+};
+
+static const uint16 kq6PatchCliffStepFloatFix[] = {
+	0x38, PATCH_UINT16(0x0bc3),         // pushi 0bc3
+	0x1a,                               // eq?      [ ego:view == 3011 ]
+	0x2f, 0x12,                         // bt 12    [ wobbling ]
+	0x60,                               // pprev
+	0x34, PATCH_UINT16(0x012d),         // ldi 012d
+	0x1a,                               // eq?      [ ego:view == 301 ]
+	0x31, 0x0d,                         // bnt 0d   [ not wobbling ]
+	0x39, 0x03,                         // pushi 03
+	0x3c,                               // dup      [ loop ]
+	0x76,                               // push0
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x04,                         // send 04  [ ego loop? ]
+	0x1a,                               // eq?      [ ego:loop == 3 ]
+	0x31, 0x02,                         // bnt 02   [ not wobbling ]
+	0x33, 0x1a,                         // jmp 1a   [ end of method ]
+	0x76,                               // push0    [ y ]
+	0x76,                               // push0
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x04,                         // send 04  [ ego y? ]
+	0x39, 0x26,                         // pushi 26
+	0x20,                               // ge?      [ 38 >= ego:y ]
+	PATCH_END
+};
+
+// Similar to the patched bug above, clicking an item on the beach in room 300
+//  while wobbling on the bottom step causes Alexander to float around the room.
+//  The doVerb methods for the flower and the feather incorrectly test ego:y
+//  using a less than comparison instead of less than or equals to, which is
+//  what the rest of the methods in this script do.
+//
+// Applies to: All versions
+// Responsible methods: stench:doVerb, feather:doVerb
+static const uint16 kq6SignatureCliffItemFloatFix[] = {
+	SIG_MAGICDWORD,
+	0x36,                               // push
+	0x35, 0x69,                         // ldi 69
+	0x22,                               // lt?
+	SIG_END
+};
+
+static const uint16 kq6PatchCliffItemFloatFix[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x24,                               // le?
+	PATCH_END
+};
+
+// After casting the Make Rain spell, collecting the baby's tears a second time
+//  awards a duplicate point. The script getBabyTears is missing a flag check to
+//  prevent this. The falling water from Beast's fountain doesn't have this bug
+//  because it tests flag 14 before awarding its point. Flag 14 is set when the
+//  Druids catch Alexander. We add the missing flag check.
+//
+// Applies to: All versions
+// Responsible method: getBabyTears:changeState(4)
+static const uint16 kq6SignatureDuplicateBabyTearsPoint[] = {
+	0x31, 0x0f,                         // bnt 0f [ state 4 ]
+	SIG_ADDTOOFFSET(+12),
+	0x32, SIG_ADDTOOFFSET(+2),          // jmp [ end of method ]
+	0x3c,                               // dup
+	0x35, 0x04,                         // ldi 04
+	0x1a,                               // eq?
+	0x30, SIG_UINT16(0x0040),           // bnt 0040
+	0x89, 0xa1,                         // lsg a1
+	0x35, SIG_MAGICDWORD, 0x04,         // ldi 04
+	0x14,                               // or
+	0xa1, 0xa1,                         // sag a1
+	0x38, SIG_SELECTOR16(givePoints),   // pushi givePoints
+	0x78,                               // push1
+	0x78,                               // push1
+	0x81, 0x01,                         // lag 01
+	0x4a, 0x06,                         // send 06 [ Kq6 givePoints: 1 ]
+	SIG_ADDTOOFFSET(+45),
+	0x32,                               // jmp [ end of method ]
+	SIG_END
+};
+
+static const uint16 kq6PatchDuplicateBabyTearsPoint[] = {
+	0x31, 0x0c,                         // bnt 0c [ state 4 ]
+	PATCH_ADDTOOFFSET(+12),
+	0x3c,                               // dup
+	0x35, 0x04,                         // ldi 04
+	0x1a,                               // eq?
+	0x31, 0x44,                         // bnt 44
+	0x81, 0xa1,                         // lag a1
+	0x14,                               // or
+	0xa1, 0xa1,                         // sag a1
+	0x81, 0x89,                         // lag 89 [ flags ]
+	0x7a,                               // push2  [ flag 14 ]
+	0x12,                               // and    [ has storm occurred? ]
+	0x2f, 0x09,                         // bt 09  [ skip point ]
+	PATCH_ADDTOOFFSET(+54),
+	0x48,                               // ret    [ prevent toss, stack is empty ]
+	0x00,                               // bnot
+	0x00,                               // bnot
+	PATCH_END
+};
+
+// Clicking the lamp on the Baby Tears when the lamp already contains the sacred
+//  water awards the tears even if the babies aren't crying, allowing the puzzle
+//  to be bypassed. The script tests for the sacred water, even though the water
+//  shouldn't affect this sequence, and its only function is to skip the crying
+//  test which is always necessary. We fix this by disabling the water test.
+//
+// Applies to: All versions
+// Responsible method: Brat:doVerb
+static const uint16 kq6SignatureGetBabyTears[] = {
+	SIG_MAGICDWORD,
+	0x89, 0xa1,                         // lsg a1 [ lamp flags ]
+	0x35, 0x02,                         // ldi 02 [ sacred water ]
+	0x12,                               // and    [ is sacred water in lamp? ]
+	SIG_END
+};
+
+static const uint16 kq6PatchGetBabyTears[] = {
+	0x39, 0x00,                         // pushi 00 [ disable sacred water test ]
+	PATCH_END
+};
+
+// KQ6 truncates messages longer than 400 characters in the CD and Mac versions.
+//  This is most prominent when reading Cassima's letter to Alexander. When the
+//  Messager class was upgraded to support audio, a 400 character buffer was
+//  added to read messages into, but KQ6 has messages as long as 602 characters.
+//  This limitation is in other games with this same Messager class. LB2, for
+//  example, has the same class but no messages beyond 400 characters.
+//
+// We fix this by increasing the temporary variables in Messager:sayNext from
+//  202 to 303 to accommodate the longest message. This patch implicitly depends
+//  on the Audio+Subtitle patches below, as they coincidentally alter sayNext
+//  in a way that this patch would otherwise have to. The CD version uses
+//  temp201, which we would normally have to patch to temp302 since we're
+//  expanding the buffer before it, but the Audio+Subtitle patches happen to
+//  remove or disable all use of this variable.
+//
+// Applies to: PC CD, Macintosh
+// Responsible method: Messager:sayNext
+// Fixes bug: #10682
+static const uint16 kq6SignatureTruncatedMessagesFix[] = {
+	SIG_MAGICDWORD,
+	0x3f, 0xca,                         // link ca
+	0x87, 0x00,                         // lap 00
+	0x31, 0x18,                         // bnt 18
+	0x39, 0x07,                         // pushi 07
+	0x76,                               // push0
+	0x8f, 0x01,                         // lsp 01
+	0x8f, 0x02,                         // lsp 02
+	0x8f, 0x03,                         // lsp 03
+	0x8f, 0x04,                         // lsp 04
+	0x8f, 0x05,                         // lsp 05
+	0x5b, 0x04, 0x01,                   // lea 04 01
+	0x36,                               // push
+	0x43, 0x7c, 0x0e,                   // callk Message 0e
+	0xa5, 0x00,                         // sat 00
+	0x33, 0x0b,                         // jmp 0b
+	SIG_ADDTOOFFSET(+9),
+	0xa5, 0x00,                         // sat 00
+	SIG_END
+};
+
+static const uint16 kq6PatchTruncatedMessagesFix[] = {
+	0x3e, PATCH_UINT16(0x012f),         // link 012f
+	0x87, 0x00,                         // lap 00
+	0x31, 0x17,                         // bnt 17
+	0x39, 0x07,                         // pushi 07
+	0x76,                               // push0
+	0x8f, 0x01,                         // lsp 01
+	0x8f, 0x02,                         // lsp 02
+	0x8f, 0x03,                         // lsp 03
+	0x8f, 0x04,                         // lsp 04
+	0x8f, 0x05,                         // lsp 05
+	0x5b, 0x04, 0x01,                   // lea 04 01
+	0x36,                               // push
+	0x43, 0x7c, 0x0e,                   // callk Message 0e
+	0x32, PATCH_UINT16(0x0009),         // jmp 0009
+	PATCH_END
+};
+
+// WORKAROUND
+//
+// Dangling Participle and Rotten Tomato are inventory items that can talk, but
+//  their mouths are animated by inner loops that call kDrawCel with unthrottled
+//  inner inner loops that spin to create a delay between frames. This prevents
+//  updating the screen and responding to input. We replace the spin loops with
+//  calls to kScummVMSleep for 5 ticks so that the speed is reasonable, the
+//  screen updates, and the game is responsive.
+//
+// Applies to: All versions
+// Responsible method: participle:doVerb, tomato:doVerb
+static const uint16 kq6SignatureTalkingInventory[] = {
+	0x35, 0x00,                         // ldi 00
+	0xa5, 0x01,                         // sat 01
+	0x8d, 0x01,                         // lst 01
+	SIG_MAGICDWORD,
+	0x34, SIG_UINT16(0x1b58),           // ldi 1b58
+	0x22,                               // lt? [ temp1 < 7000 ]
+	SIG_END
+};
+
+static const uint16 kq6PatchTalkingInventory[] = {
+	PATCH_ADDTOOFFSET(+2),
+	0x78,                               // push1
+	0x39, 0x05,                         // pushi 05
+	0x43, kScummVMSleepId, 0x02,        // callk kScummVMSleep 02 [ 5 ticks ]
+	0x35, 0x00,                         // ldi 00 [ exit loop ]
+	PATCH_END
+};
+
+// Exiting the pawnshop while the Genie's eye is glinting locks up the game.
+//  Unlike the bookstore, the pawnshop script fails to dispose the "eye" object
+//  if it's in the middle of animating, causing the door animation in the next
+//  room to loop forever. Sierra added a simple workaround in later versions to
+//  prevent this: the eye no longer glints when ego is close the pawnshop exit.
+//  We apply this same workaround to vulnerable versions.
+//
+// Applies to: English, French, and German PC Floppy, English Mac Floppy,
+//             English PC CD 1.000.000
+// Responsible method: genieBrowseScr:changeState(3)
+static const uint16 kq6SignaturePawnshopGenieEye[] = {
+	0x39, 0x03,                         // pushi 03
+	SIG_MAGICDWORD,
+	0x7a,                               // push2
+	0x76,                               // push0
+	0x7a,                               // push2
+	0x43, 0x3c, 0x04,                   // callk Random [ Random 0 2 ]
+	0x36,                               // push
+	0x76,                               // push0
+	0x78,                               // push1
+	0x46, SIG_UINT16(0x03e7),           // calle proc999_5 [ OneOf (Random 0 2) 0 1 ]
+	      SIG_UINT16(0x0005), 0x06,
+	SIG_END
+};
+
+static const uint16 kq6PatchPawnshopGenieEye[] = {
+	0x39, 0x43,                         // pushi 43
+	0x78,                               // push1 [ x ]
+	0x76,                               // push0
+	0x81, 0x00,                         // lag 00
+	0x4a, 0x04,                         // send 04 [ ego x? ]
+	0x22,                               // lt?     [ 67 < ego:x ]
+	0x31, 0x06,                         // bnt 06  [ skip glint ]
+	0x7a,                               // push2
+	0x76,                               // push0
+	0x7a,                               // push2
+	0x43, 0x3c, 0x04,                   // callk Random [ Random 0 2 ]
+	PATCH_END
+};
+
+// During the wedding close-up with the Vizier and the Genie in room 740,
+//  clicking almost any of the wrong lamps on the Genie results in the wrong
+//  message sequence. Alexander says "I have this lamp, 'princess'" twice
+//  instead of the Genie responding after the first message. The script passes
+//  the wrong sequence number in the second message tuple.
+//
+// Applies to: All versions
+// Responsible method: genieHead:doVerb
+static const uint16 kq6SignatureWeddingGenieLampMessage[] = {
+	0x39, SIG_SELECTOR8(add),           // pushi add
+	0x39, 0x05,                         // pushi 05
+	0x67, SIG_ADDTOOFFSET(+1),          // pTos modNum
+	0x67, SIG_ADDTOOFFSET(+1),          // pTos noun
+	SIG_MAGICDWORD,
+	0x39, 0x39,                         // pushi 39 [ verb ]
+	0x76,                               // push0    [ cond ]
+	0x78,                               // push1    [ wrong seq ]
+	SIG_END
+};
+
+static const uint16 kq6PatchWeddingGenieLampMessage[] = {
+	PATCH_ADDTOOFFSET(+11),
+	0x7a,                               // push2 [ correct seq ]
+	PATCH_END
+};
+
+// Clicking Look on the first catacombs room (405) or the dead-end room (407)
+//  while in text-mode breaks the CD and Spanish versions. The message boxes
+//  never leave the screen, even after restarting. The doVerb methods in these
+//  rooms are missing the necessary "return true" statements that were added to
+//  all other rooms in the CD version. In earlier versions, Messager:say always
+//  set the accumulator to non-zero and these statements weren't necessary.
+//
+// Applies to: PC CD, Spanish PC Floppy
+// Responsible methods: rm405:doVerb(1), rm407:doVerb(1)
+static const uint16 kq6SignatureRoom405LookMessage[] = {
+	0x33, 0x1f,                         // jmp 1f
+	SIG_ADDTOOFFSET(+18),
+	0x33, 0x0b,                         // jmp 0b
+	SIG_ADDTOOFFSET(+8),
+	SIG_MAGICDWORD,
+	0x57, 0x93, 0x06,                   // super LabRoom 06 [ super doVerb: param1 &rest ]
+	0x3a,                               // toss
+	0x48,                               // ret
+	SIG_END
+};
+
+static const uint16 kq6PatchRoom405LookMessage[] = {
+	0x14,                               // or [ acc |= 1  ]
+	0x48,                               // ret
+	PATCH_ADDTOOFFSET(+18),
+	0x14,                               // or [ acc |= 1  ]
+	0x48,                               // ret
+	PATCH_END
+};
+
+static const uint16 kq6SignatureRoom407LookMessage[] = {
+	0x33, 0x0b,                         // jmp 0b
+	SIG_ADDTOOFFSET(+8),
+	SIG_MAGICDWORD,
+	0x57, 0x93, 0x06,                   // super LabRoom 06 [ super doVerb: param1 &rest ]
+	0x3a,                               // toss
+	0x48,                               // ret
+	SIG_END
+};
+
+static const uint16 kq6PatchRoom407LookMessage[] = {
+	0x14,                               // or [ acc |= 1  ]
+	0x48,                               // ret
+	PATCH_END
+};
+
+// After lighting the torch in the dark catacombs room and then re-entering,
+//  using items such as a book results in a message that the room is too dark.
+//  rm406:scriptCheck tests for darkness with a local variable that is set when
+//  lighting the torch instead of a persistent global. We could change the
+//  darkness test but it turns out that this method is never called in the dark.
+//  KQ6Room:setScript only calls scriptCheck when ego:view is 900 and that is
+//  only true once the torch is lit.
+//
+// We fix this by patching rm406:scriptCheck to always allow items since the
+//  condition it tries to prevent can never occur.
+//
+// Applies to: All versions
+// Responsible method: rm406:scriptCheck
+static const uint16 kq6SignatureDarkRoomInventory[] = {
+	0x3f, 0x01,                         // link 01
+	0x35, 0x00,                         // ldi 00
+	0xa5, 0x00,                         // sat temp0
+	0x8b, SIG_MAGICDWORD, 0x01,         // lsl 01
+	0x35, 0x64,                         // ldi 64
+	0x22,                               // lt? [ has lightItUp not run yet? ]
+	SIG_END
+};
+
+static const uint16 kq6PatchDarkRoomInventory[] = {
+	0x35, 0x01,                         // ldi 01
+	0x48,                               // ret [ return true, allow items ]
+	PATCH_END
+};
+
+// The Girl In The Tower theme plays from a CD audio track during the credits.
+//  In ScummVM this requires an actual CD, or a mounted CD image, or extracting
+//  the audio to a "track1" file ahead of time. If the track can't be played
+//  then there is silence for the entire credits, but the game includes a 5 MB
+//  Audio version to fall back on when CD audio is unavailable. The script plays
+//  this when the CD audio driver fails to load, though this never occurs in our
+//  our implementation and doesn't address a missing track.
+//
+// We ensure that the credits theme always plays by patching the script to also
+//  fall back on the Audio version when CD audio playback fails.
+//
+// Applies to: PC CD
+// Responsible method: sCredits:init
+static const uint16 kq6CDSignatureGirlInTheTowerPlayback[] = {
+	SIG_MAGICDWORD,
+	0x39, 0x05,                         // pushi 05
+	0x39, 0x0a,                         // pushi 0a   [ kSciAudioCD ]
+	0x7a,                               // push2      [ play ]
+	0x7a,                               // push2      [ track ]
+	0x76,                               // push0      [ start ]
+	0x38, SIG_UINT16(0x00ec),           // pushi 00ec [ end ]
+	0x43, 0x75, 0x0a,                   // callk DoAudio 0a
+	0x33,                               // jmp [ skip Audio version ]
+	SIG_END
+};
+
+static const uint16 kq6CDPatchGirlInTheTowerPlayback[] = {
+	PATCH_ADDTOOFFSET(+13),
+	0x2f,                               // bt [ skip Audio version if CD audio succeeded ]
+	PATCH_END
+};
+
+// Audio + subtitles support - SHARED! - used for King's Quest 6 and Laura Bow 2.
+//  This patch gets enabled when the user selects "both" in the ScummVM
+//  "Speech + Subtitles" menu. We currently use global[98d] to hold a kMemory
+//  pointer.
+// Applies to at least: KQ6 PC-CD, LB2 PC-CD
+// Patched method: Messager::sayNext / lb2Messager::sayNext (always use text branch)
+static const uint16 kq6laurabow2CDSignatureAudioTextSupport1[] = {
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x02,                         // ldi 02
+	0x12,                               // and
+	SIG_MAGICDWORD,
+	0x31, 0x13,                         // bnt [audio call]
+	0x38, SIG_SELECTOR16(modNum),       // pushi modNum
+	SIG_END
+};
+
+static const uint16 kq6laurabow2CDPatchAudioTextSupport1[] = {
+	PATCH_ADDTOOFFSET(+5),
+	0x33, 0x13,                         // jmp [audio call]
+	PATCH_END
+};
+
+// Applies to at least: KQ6 PC-CD, LB2 PC-CD
+// Patched method: Messager::sayNext / lb2Messager::sayNext (allocate audio memory)
+static const uint16 kq6laurabow2CDSignatureAudioTextSupport2[] = {
+	0x7a,                               // push2
+	0x78,                               // push1
+	0x39, 0x0c,                         // pushi 0c
+	0x43, SIG_MAGICDWORD, 0x72, 0x04,   // callk Memory
+	0xa5, 0xc9,                         // sat temp[c9]
+	SIG_END
+};
+
+static const uint16 kq6laurabow2CDPatchAudioTextSupport2[] = {
+	PATCH_ADDTOOFFSET(+7),
+	0xa1, 0x62,                         // sag global[62] (global[98d])
+	PATCH_END
+};
+
+// Applies to at least: KQ6 PC-CD, LB2 PC-CD
+// Patched method: Messager::sayNext / lb2Messager::sayNext (release audio memory)
+static const uint16 kq6laurabow2CDSignatureAudioTextSupport3[] = {
+	0x7a,                               // push2
+	0x39, 0x03,                         // pushi 03
+	SIG_MAGICDWORD,
+	0x8d, 0xc9,                         // lst temp[c9]
+	0x43, 0x72, 0x04,                   // callk Memory
+	SIG_END
+};
+
+static const uint16 kq6laurabow2CDPatchAudioTextSupport3[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x89, 0x62,                         // lsg global[62] (global[98d])
+	PATCH_END
+};
+
+// startText call gets acc = 0 for text-only and acc = 2 for audio+text
+// Applies to at least: KQ6 PC-CD, LB2 PC-CD
+// Patched method: Narrator::say (use audio memory)
+static const uint16 kq6laurabow2CDSignatureAudioTextSupport4[] = {
+	// set caller property code
+	0x31, 0x08,                         // bnt [set acc to 0 for caller]
+	0x87, 0x02,                         // lap param[2]
+	0x31, 0x04,                         // bnt [set acc to 0 for caller]
+	0x87, 0x02,                         // lap param[2]
+	0x33, 0x02,                         // jmp [set caller]
+	0x35, 0x00,                         // ldi 00
+	0x65, 0x68,                         // aTop caller
+	// call startText + startAudio code
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x01,                         // ldi 01
+	0x12,                               // and
+	0x31, 0x08,                         // bnt [skip code]
+	0x38, SIG_SELECTOR16(startText),    // pushi startText
+	0x78,                               // push1
+	0x8f, 0x01,                         // lsp param[1]
+	0x54, 0x06,                         // self 06
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x02,                         // ldi 02
+	0x12,                               // and
+	0x31, 0x08,                         // bnt [skip code]
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(startAudio),   // pushi startAudio
+	0x78,                               // push1
+	0x8f, 0x01,                         // lsp param[1]
+	0x54, 0x06,                         // self 06
+	SIG_END
+};
+
+static const uint16 kq6laurabow2CDPatchAudioTextSupport4[] = {
+	0x31, 0x02,                         // bnt [set caller]
+	0x87, 0x02,                         // lap param[2]
+	0x65, 0x68,                         // aTop caller
+	0x81, 0x5a,                         // lag global[5a]
+	0x78,                               // push1
+	0x12,                               // and
+	0x31, 0x11,                         // bnt [skip startText code]
+	0x81, 0x5a,                         // lag global[5a]
+	0x7a,                               // push2
+	0x12,                               // and
+	0x33, 0x03,                         // jmp 3 [skip unused bytes]
+	PATCH_ADDTOOFFSET(+22),
+	0x89, 0x62,                         // lsg global[62] (global[98d])
+	PATCH_END
+};
+
+// Applies to at least: KQ6 PC-CD, LB2 PC-CD
+// Patched method: Talker::display/Narrator::say (remove reset saved mouse cursor code)
+//  code would screw over mouse cursor
+static const uint16 kq6laurabow2CDSignatureAudioTextSupport5[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x00,                         // ldi 00
+	0x65, 0x82,                         // aTop saveCursor
+	SIG_END
+};
+
+static const uint16 kq6laurabow2CDPatchAudioTextSupport5[] = {
+	0x18, 0x18, 0x18, 0x18,             // (waste bytes)
+	PATCH_END
+};
+
+// Additional patch specifically for King's Quest 6
+//  Fixes text window placement, when in "dual" mode
+// Applies to at least: PC-CD
+// Patched method: Kq6Talker::init
+static const uint16 kq6CDSignatureAudioTextSupport1[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x02,                         // ldi 02
+	0x1a,                               // eq?
+	0x31, SIG_ADDTOOFFSET(+1),          // bnt [jump-to-text-code]
+	0x78,                               // push1
+	SIG_END
+};
+
+static const uint16 kq6CDPatchAudioTextSupport1[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x12,                               // and
+	PATCH_END
+};
+
+// Additional patch specifically for King's Quest 6
+//  Fixes low-res portrait staying on screen for hi-res mode
+// Applies to at least: PC-CD
+// Patched method: Talker::startText
+//  this method is called by Narrator::say and acc is 0 for text-only and 2 for dual mode (audio+text)
+static const uint16 kq6CDSignatureAudioTextSupport2[] = {
+	SIG_MAGICDWORD,
+	0x3f, 0x01,                         // link 01
+	0x63, 0x8a,                         // pToa viewInPrint
+	0x18,                               // not
+	0x31, 0x06,                         // bnt [skip following code]
+	0x38, SIG_UINT16(0x00e1),           // pushi 00e1
+	0x76,                               // push0
+	0x54, 0x04,                         // self 04
+	SIG_END
+};
+
+static const uint16 kq6CDPatchAudioTextSupport2[] = {
+	PATCH_ADDTOOFFSET(+2),
+	0x67, 0x8a,                         // pTos viewInPrint
+	0x14,                               // or
+	0x2f,                               // bt [skip following code]
+	PATCH_END
+};
+
+// Additional patch specifically for King's Quest 6
+//  Fixes special windows, used for example in...
+//   The Pawn shop (room 280), when the man in a robe complains about no more
+//    mints.
+//   Room 300 at the cliffs (aka copy protection), when Alexander falls down
+//    the cliffs (closes automatically, but too late).
+//   Room 210, when Alexander gives the ring to the nightingale (these need a
+//    mouse click).
+//
+//  We have to change even more code because the game uses PODialog class for
+//   text windows and myDialog class for audio. Both are saved to
+//   KQ6Print::dialog.
+//
+//  Changing KQ6Print::dialog is disabled for now, because it has side-effects
+//   (breaking game over screens).
+//
+//  Original comment:
+//  Sadly PODialog is created during KQ6Print::addText, myDialog is set during
+//   KQ6Print::showSelf, which is called much later and KQ6Print::addText
+//   requires KQ6Print::dialog to be set, which means we have to set it before
+//   calling addText for audio mode, otherwise the user would have to click to
+//   get those windows disposed.
+//
+// Applies to at least: PC-CD
+// Patched method: KQ6Print::say
+static const uint16 kq6CDSignatureAudioTextSupport3[] = {
+	0x31, 0x6e,                         // bnt [to text code]
+	SIG_ADDTOOFFSET(+85),
+	SIG_MAGICDWORD,
+	0x8f, 0x01,                         // lsp param[1]
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	0x31, 0x0c,                         // bnt [code to set property repressText to 1]
+	0x38,                               // pushi (selector addText)
+	SIG_ADDTOOFFSET(+9),                // skip addText-calling code
+	0x33, 0x10,                         // jmp [to ret]
+	0x35, 0x01,                         // ldi 01
+	0x65, 0x2e,                         // aTop repressText
+	0x33, 0x0a,                         // jmp [to ret]
+	SIG_END
+};
+
+static const uint16 kq6CDPatchAudioTextSupport3[] = {
+	0x31, 0x68,                         // bnt (adjust branch to reuse audio mode addText-calling code)
+	PATCH_ADDTOOFFSET(+85),             // (right at the MAGIC_DWORD)
+	// check, if text is supposed to be shown. If yes, skip the follow-up check (param[1])
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x01,                         // ldi 01
+	0x12,                               // and
+	0x2f, 0x07,                         // bt [skip over param check]
+	// original code, checks param[1]
+	0x8f, 0x01,                         // lsp param[1]
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	0x31, 0x10,                         // bnt [code to set property repressText to 1], adjusted
+	// waste 5 bytes instead of using myDialog class for now
+	// setting myDialog class all the time causes game over screens to misbehave (bug #9771)
+	0x34, PATCH_UINT16(0x0000),         // ldi 0 (waste 3 bytes)
+	0x35, 0x00,                         // ldi 0 (waste 2 bytes)
+	// use myDialog class, so that text box automatically disappears (this is not done for text only mode, like in the original)
+	//0x72, 0x0e, 0x00,                   // lofsa myDialog
+	//0x65, 0x12,                         // aTop dialog
+	// followed by original addText-calling code
+	0x38,
+	PATCH_GETORIGINALUINT16(+95),       // pushi (addText)
+	0x78,                               // push1
+	0x8f, 0x02,                         // lsp param[2]
+	0x59, 0x03,                         // &rest 03
+	0x54, 0x06,                         // self 06
+	0x48,                               // ret
+
+	0x35, 0x01,                         // ldi 01
+	0x65, 0x2e,                         // aTop repressText
+	0x48,                               // ret
+	PATCH_END
+};
+
+// Additional patch specifically for King's Quest 6
+//  Fixes text-window size for hires portraits mode
+//   Otherwise at least at the end some text-windows will be way too small
+// Applies to at least: PC-CD
+// Patched method: Talker::init
+static const uint16 kq6CDSignatureAudioTextSupport4[] = {
+	SIG_MAGICDWORD,
+	0x63, 0x94,                         // pToa raving
+	0x31, 0x0a,                         // bnt [no rave code]
+	0x35, 0x00,                         // ldi 00
+	SIG_ADDTOOFFSET(+6),                // skip reset of bust, eyes and mouth
+	0x33, 0x24,                         // jmp [to super class code]
+	SIG_END
+};
+
+static const uint16 kq6CDPatchAudioTextSupport4[] = {
+	PATCH_ADDTOOFFSET(+12),
+	0x33, PATCH_GETORIGINALBYTEADJUST(+13, -6), // (adjust jump to also include setSize call)
+	PATCH_END
+};
+
+//  Fixes text window placement, when dual mode is active (Guards in room 220)
+// Applies to at least: PC-CD
+// Patched method: tlkGateGuard1::init & tlkGateGuard2::init
+static const uint16 kq6CDSignatureAudioTextSupportGuards[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	SIG_END                             // followed by bnt for Guard1 and bt for Guard2
+};
+
+static const uint16 kq6CDPatchAudioTextSupportGuards[] = {
+	PATCH_ADDTOOFFSET(+2),
+	0x35, 0x02,                         // ldi 02
+	0x1c,                               // ne?
+	PATCH_END
+};
+
+//  Fixes text window placement, when portrait+text is shown (Stepmother in room 250)
+// Applies to at least: PC-CD
+// Patched method: tlkStepmother::init
+static const uint16 kq6CDSignatureAudioTextSupportStepmother[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x02,                         // ldi 02
+	0x12,                               // and
+	0x31,                               // bnt [jump-for-text-code]
+	SIG_END
+};
+
+static const uint16 kq6CDPatchAudioTextSupportJumpAlways[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x1a,                               // eq?
+	PATCH_END
+};
+
+//  Fixes "Girl In The Tower" to get played in dual mode as well
+//  Also changes credits to use CD audio for dual mode.
+//
+// Applies to at least: PC-CD
+// Patched method: rm740::cue (script 740), sCredits::init (script 52)
+static const uint16 kq6CDSignatureAudioTextSupportGirlInTheTower[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x02,                         // ldi 02
+	0x1a,                               // eq?
+	0x31,                               // bnt [jump-for-text-code]
+	SIG_END
+};
+
+static const uint16 kq6CDPatchAudioTextSupportGirlInTheTower[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x12,                               // and
+	PATCH_END
+};
+
+//  Fixes dual mode for scenes with Azure and Ariel (room 370)
+//   Effectively same patch as the one for fixing "Girl In The Tower"
+// Applies to at least: PC-CD
+// Patched methods: rm370::init, caughtAtGateCD::changeState, caughtAtGateTXT::changeState, toLabyrinth::changeState
+// Fixes bug: #6750
+static const uint16 kq6CDSignatureAudioTextSupportAzureAriel[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x02,                         // ldi 02
+	0x1a,                               // eq?
+	0x31,                               // bnt [jump-for-text-code]
+	SIG_END
+};
+
+static const uint16 kq6CDPatchAudioTextSupportAzureAriel[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x12,                               // and
+	PATCH_END
+};
+
+// Fixes Alexander's yell in dual mode when the Minotaur knocks him into the
+//  fiery pit in room 440.
+//
+// Applies to: PC-CD
+// Patched method: hornSwaggled:changeState
+static const uint16 kq6CDSignatureAudioTextSupportMinotaurLair[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x02,                         // ldi 02
+	0x1a,                               // eq?
+	SIG_ADDTOOFFSET(+41),
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x02,                         // ldi 02
+	0x1c,                               // ne?
+	SIG_END
+};
+
+static const uint16 kq6CDPatchAudioTextSupportMinotaurLair[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x12,                               // and
+	PATCH_ADDTOOFFSET(+43),
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	PATCH_END
+};
+
+// Additional patch specifically for King's Quest 6
+//  Adds another button state for the text/audio button. We currently use the "speech" view for "dual" mode.
+// View 947, loop 9, cel 0+1 -> "text"
+// View 947, loop 8, cel 0+1 -> "speech"
+// View 947, loop 12, cel 0+1 -> "dual" (this view is injected by us into the game)
+// Applies to at least: PC-CD
+// Patched method: iconTextSwitch::show, iconTextSwitch::doit
+static const uint16 kq6CDSignatureAudioTextMenuSupport[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x02,                         // ldi 02
+	0x1a,                               // eq?
+	0x31, 0x06,                         // bnt [set text view]
+	0x35, 0x08,                         // ldi 08
+	0x65, 0x14,                         // aTop loop
+	0x33, 0x04,                         // jmp [skip over text view]
+	0x35, 0x09,                         // ldi 09
+	0x65, 0x14,                         // aTop loop
+	SIG_ADDTOOFFSET(+102),              // skip to iconTextSwitch::doit code
+	0x89, 0x5a,                         // lsg global[5a]
+	0x3c,                               // dup
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	0x31, 0x06,                         // bnt [set text mode]
+	0x35, 0x02,                         // ldi 02
+	0xa1, 0x5a,                         // sag global[5a]
+	0x33, 0x0a,                         // jmp [skip over text mode code]
+	0x3c,                               // dup
+	0x35, 0x02,                         // ldi 02
+	0x1a,                               // eq?
+	0x31, 0x04,                         // bnt [skip over text ode code]
+	0x35, 0x01,                         // ldi 01
+	0xa1, 0x5a,                         // sag global[5a]
+	0x3a,                               // toss
+	0x67, 0x14,                         // pTos loop
+	0x35, 0x09,                         // ldi 09
+	0x1a,                               // eq?
+	0x31, 0x04,                         // bnt [set text view]
+	0x35, 0x08,                         // ldi 08
+	0x33, 0x02,                         // jmp [skip text view]
+	0x35, 0x09,                         // ldi 09
+	0x65, 0x14,                         // aTop loop
+	SIG_END
+};
+
+static const uint16 kq6CDPatchAudioTextMenuSupport[] = {
+	PATCH_ADDTOOFFSET(+13),
+	0x33, 0x79,                         // jmp [to new text+dual code]
+	PATCH_ADDTOOFFSET(+104),            // seek to iconTextSwitch::doit
+	0x81, 0x5a,                         // lag global[5a]
+	0x78,                               // push1
+	0x02,                               // add
+	0xa1, 0x5a,                         // sag global[5a]
+	0x36,                               // push
+	0x35, 0x03,                         // ldi 03
+	0x1e,                               // gt?
+	0x31, 0x03,                         // bnt [skip over]
+	0x78,                               // push1
+	0xa9, 0x5a,                         // ssg global[5a]
+	0x33, 0x17,                         // jmp [iconTextSwitch::show call]
+	// additional code for iconTextSwitch::show
+	0x89, 0x5a,                         // lsg global[5a]
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	0x31, 0x04,                         // bnt [dual mode]
+	0x35, 0x09,                         // ldi 09
+	0x33, 0x02,                         // jmp [skip over dual mode]
+	0x35, 0x0c,                         // ldi 0c (view 947, loop 12, cel 0+1 is our "dual" view, injected by view.cpp)
+	0x65, 0x14,                         // aTop loop
+	0x32, PATCH_UINT16(0xff75),         // jmp [back to iconTextSwitch::show]
+	PATCH_END
+};
+
+// When caught by guard dogs in the castle, sometimes their music doesn't stop.
+//  Sound 710 continues playing in the dungeon and afterwards, drowning out the
+//  real room music. This script bug also occurs in the original. It's a
+//  regression in the CD version and subsequent localized floppy versions.
+//
+// When changing rooms, CastleRoom:newRoom fades out sound 710 if it's already
+//  playing, which it detects by testing if globalSound2:prevSignal != -1.
+//  This worked in the original floppy versions but the CD version introduced a
+//  newer Sound class with different behavior. prevSignal is no longer reset to
+//  0 by every Sound:play. This prevents CastleRoom:newRoom from detecting and
+//  stopping the music when globalSound2:prevSignal is -1 from an earlier sound.
+//
+// We fix this by testing globalSound2:handle instead of prevSignal. handle is
+//  always set while a sound is being played and always cleared afterwards. This
+//  is the same bug as in LB2CD's Act 5 finale music, and the same fix.
+//
+// Applies to: PC CD, Italian PC Floppy, Spanish PC Floppy
+// Responsible method: CastleRoom:newRoom
+// Fixes bug: #11746
+static const uint16 kq6SignatureGuardDogMusic[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x00ac),           // pushi prevSignal [ hard-coded for affected versions ]
+	0x76,                               // push0
+	0x81, 0x67,                         // lag 67  [ globalSound2 ]
+	0x4a, 0x04,                         // send 04 [ globalSound2 prevSignal? ]
+	0x36,                               // push
+	0x35, 0xff,                         // ldi ff
+	SIG_END
+};
+
+static const uint16 kq6PatchGuardDogMusic[] = {
+	0x38, PATCH_SELECTOR16(handle),     // pushi handle
+	PATCH_ADDTOOFFSET(+6),
+	0x35, 0x00,                         // ldi 00
+	PATCH_END
+};
+
+// Quickly clicking on certain Features multiple times can lockup and crash the
+//  the game. Examples: giving the rose to Beauty and looking at the peephole in
+//  the passage outside of Cassima's room. This also occurs in the original.
+//
+// The bug is in the Feature and CueObj classes but only a few Features are
+//  vulnerable. Factors include approach properties (coordinates, dist), the
+//  surrounding obstacles, and timing. Clicking on a Feature causes ego to walk
+//  towards it, turn towards it, wait three cycles, and then call doVerb. CueObj
+//  handles most of this sequence. However, if ego is already close to the
+//  Feature, then CueObj is advanced to its final state to immediately call
+//  doVerb. The problem is that this doesn't take into account that ego might be
+//  in the middle of turning. If a second click occurs while ego is turning from
+//  the first click, doVerb will be called immediately, CueObj will be reset to
+//  its initial state, and then ego's turn will complete and CueObj will proceed
+//  to call doVerb again. If doVerb runs a hands-off script then it will be
+//  interrupted and restarted at which point the game breaks in various ways.
+//
+// We fix this by removing a simple line that resets CueObj to its initial state
+//  after it calls Feature:doVerb. Nothing depends on this; every caller resets
+//  CueObj:state explicitly. But without this line, a stray cue from ego turning
+//  will advance CueObj from its final state (three) to an unused state (four)
+//  where it will have no effect. Although this buggy Feature script is in other
+//  games, so far it's only known to cause problems in KQ6.
+//
+// Applies to: All versions
+// Responsible method: CueObj:changeState(3)
+static const uint16 kq6SignatureFeatureEventHandling[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x00,                         // ldi 00
+	0x65, 0x14,                         // atop state [ state = 0 ]
+	SIG_END
+};
+
+static const uint16 kq6PatchFeatureEventHandling[] = {
+	0x33, 0x02,                         // jmp 02 [ don't reset CueObj state ]
+	PATCH_END
+};
+
+// KQ6 Mac sets a three second delay before playing its QuickTime opening movie
+//  in order to sync it with the music, but setting Script:seconds produces
+//  inconsistent delays. (See GK1 cartoon timing patches.) Converting the delay
+//  from seconds to ticks results in consistent timing in sync with the movie.
+//
+// Applies to: English Mac only
+// Responsible method: showMovie:changeState(2)
+static const uint16 kq6MacSignatureMacOpeningMovieDelay[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x03,                         // ldi 03
+	0x65, 0x1c,                         // aTop seconds [ seconds = 3 ]
+	0x33, 0x24,                         // jmp 24       [ end of method ]
+	SIG_END
+};
+
+static const uint16 kq6MacPatchMacOpeningMovieDelay[] = {
+	0x34, PATCH_UINT16(0x00b4),         // ldi 00b4
+	0x64, PATCH_UINT16(0x0020),         // aTop ticks [ ticks = 180 ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                                 patch
+static const SciScriptPatcherEntry kq6Signatures[] = {
+	{  true,    52, "CD: Girl In The Tower playback",                 1, kq6CDSignatureGirlInTheTowerPlayback,     kq6CDPatchGirlInTheTowerPlayback },
+	{  true,    80, "fix guard dog music",                            1, kq6SignatureGuardDogMusic,                kq6PatchGuardDogMusic },
+	{  true,    87, "fix Drink Me bottle",                            1, kq6SignatureDrinkMeFix,                   kq6PatchDrinkMeFix },
+	{ false,    87, "Mac: Drink Me pic",                              1, kq6SignatureMacDrinkMePic,                kq6PatchMacDrinkMePic },
+	{  true,    99, "disable speed test",                             1, sci11SpeedTestSignature,                  sci11SpeedTestPatch },
+	{  true,   105, "Mac: opening movie delay",                       1, kq6MacSignatureMacOpeningMovieDelay,      kq6MacPatchMacOpeningMovieDelay },
+	{  true,   281, "fix pawnshop genie eye",                         1, kq6SignaturePawnshopGenieEye,             kq6PatchPawnshopGenieEye },
+	{  true,   300, "fix floating off steps",                         2, kq6SignatureCliffStepFloatFix,            kq6PatchCliffStepFloatFix },
+	{  true,   300, "fix floating off steps",                         2, kq6SignatureCliffItemFloatFix,            kq6PatchCliffItemFloatFix },
+	{  true,   405, "fix catacombs room message",                     1, kq6SignatureRoom405LookMessage,           kq6PatchRoom405LookMessage },
+	{  true,   406, "fix catacombs dark room inventory",              1, kq6SignatureDarkRoomInventory,            kq6PatchDarkRoomInventory },
+	{  true,   407, "fix catacombs room message",                     1, kq6SignatureRoom407LookMessage,           kq6PatchRoom407LookMessage },
+	{  true,   480, "CD: fix wallflower dance",                       1, kq6CDSignatureWallFlowerDanceFix,         kq6CDPatchWallFlowerDanceFix },
+	{  true,   480, "fix picking second lettuce",                     1, kq6SignatureSecondLettuceFix,             kq6PatchSecondLettuceFix },
+	{  true,   480, "fix getting baby tears",                         1, kq6SignatureGetBabyTears,                 kq6PatchGetBabyTears },
+	{  true,   481, "fix duplicate baby cry",                         1, kq6SignatureDuplicateBabyCry,             kq6PatchDuplicateBabyCry },
+	{  true,   481, "fix duplicate baby tears point",                 1, kq6SignatureDuplicateBabyTearsPoint,      kq6PatchDuplicateBabyTearsPoint },
+	{  true,   640, "fix 'Tickets Only' audio timing",                1, kq6CDSignatureTicketsOnlyAudioTiming,     kq6CDPatchTicketsOnlyAudioTiming },
+	{  true,   745, "fix wedding genie lamp message",                 1, kq6SignatureWeddingGenieLampMessage,      kq6PatchWeddingGenieLampMessage },
+	{  true,   907, "fix inventory stack leak",                       1, kq6SignatureInventoryStackFix,            kq6PatchInventoryStackFix },
+	{  true,   907, "fix hair detection for ribbon's look msg",       1, kq6SignatureLookRibbonFix,                kq6PatchLookRibbonFix },
+	{  true,   907, "talking inventory workaround",                   4, kq6SignatureTalkingInventory,             kq6PatchTalkingInventory },
+	{  true,   924, "CD/Mac: fix truncated messages",                 1, kq6SignatureTruncatedMessagesFix,         kq6PatchTruncatedMessagesFix },
+	{  true,   928, "Narrator lockup fix",                            1, sciNarratorLockupSignature,               sciNarratorLockupPatch },
+	{  true,   950, "fix Feature event handling",                     1, kq6SignatureFeatureEventHandling,         kq6PatchFeatureEventHandling },
+	// King's Quest 6 and Laura Bow 2 share basic patches for audio + text support
+	// *** King's Quest 6 audio + text support ***
+	{ false,   924, "CD: audio + text support KQ6&LB2 1",             1, kq6laurabow2CDSignatureAudioTextSupport1,     kq6laurabow2CDPatchAudioTextSupport1 },
+	{ false,   924, "CD: audio + text support KQ6&LB2 2",             1, kq6laurabow2CDSignatureAudioTextSupport2,     kq6laurabow2CDPatchAudioTextSupport2 },
+	{ false,   924, "CD: audio + text support KQ6&LB2 3",             1, kq6laurabow2CDSignatureAudioTextSupport3,     kq6laurabow2CDPatchAudioTextSupport3 },
+	{ false,   928, "CD: audio + text support KQ6&LB2 4",             1, kq6laurabow2CDSignatureAudioTextSupport4,     kq6laurabow2CDPatchAudioTextSupport4 },
+	{ false,   928, "CD: audio + text support KQ6&LB2 5",             2, kq6laurabow2CDSignatureAudioTextSupport5,     kq6laurabow2CDPatchAudioTextSupport5 },
+	{ false,   909, "CD: audio + text support KQ6 1",                 2, kq6CDSignatureAudioTextSupport1,              kq6CDPatchAudioTextSupport1 },
+	{ false,   928, "CD: audio + text support KQ6 2",                 1, kq6CDSignatureAudioTextSupport2,              kq6CDPatchAudioTextSupport2 },
+	{ false,   104, "CD: audio + text support KQ6 3",                 1, kq6CDSignatureAudioTextSupport3,              kq6CDPatchAudioTextSupport3 },
+	{ false,   928, "CD: audio + text support KQ6 4",                 1, kq6CDSignatureAudioTextSupport4,              kq6CDPatchAudioTextSupport4 },
+	{ false,  1009, "CD: audio + text support KQ6 Guards",            2, kq6CDSignatureAudioTextSupportGuards,         kq6CDPatchAudioTextSupportGuards },
+	{ false,  1027, "CD: audio + text support KQ6 Stepmother",        1, kq6CDSignatureAudioTextSupportStepmother,     kq6CDPatchAudioTextSupportJumpAlways },
+	{ false,    52, "CD: audio + text support KQ6 Girl In The Tower", 1, kq6CDSignatureAudioTextSupportGirlInTheTower, kq6CDPatchAudioTextSupportGirlInTheTower },
+	{ false,   740, "CD: audio + text support KQ6 Girl In The Tower", 1, kq6CDSignatureAudioTextSupportGirlInTheTower, kq6CDPatchAudioTextSupportGirlInTheTower },
+	{ false,   370, "CD: audio + text support KQ6 Azure & Ariel",     6, kq6CDSignatureAudioTextSupportAzureAriel,     kq6CDPatchAudioTextSupportAzureAriel },
+	{ false,   441, "CD: audio + text support KQ6 Minotaur lair",     1, kq6CDSignatureAudioTextSupportMinotaurLair,   kq6CDPatchAudioTextSupportMinotaurLair },
+	{ false,   903, "CD: audio + text support KQ6 menu",              1, kq6CDSignatureAudioTextMenuSupport,           kq6CDPatchAudioTextMenuSupport },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#ifdef ENABLE_SCI32
+#pragma mark -
+#pragma mark Kings Quest 7
+
+// KQ7's subtitles were left unfinished in the shipped game, so there are
+// several problems when enabling them from the ScummVM launcher:
+//
+// 1. `kqMessager::findTalker` tries to determine which class to use for
+//    displaying subtitles using the talker number of each message, but the
+//    talker data is often bogus (e.g. princess messages normally use talker 7,
+//    but talker 99 (which is for the narrator) is used for her messages at the
+//    start of chapter 2), so it can't be used.
+// 2. Some display classes render subtitles at the top or middle of the game
+//    area, blocking the view of what is on the screen.
+// 3. In some areas, the colors of the subtitles are changed arbitrarily (e.g.
+//    pink/purple at the start of chapter 2).
+//
+// To work around these problems, we always use KQTalker, force the text area to
+// the bottom of the game area, and force it to always use black & white, which
+// are guaranteed to not be changed by game scripts.
+//
+// We make 2 changes to KQNarrator::init and one to Narrator::say.
+//
+// Applies to at least: PC CD 1.4 English, 1.51 English, 1.51 German, 2.00 English
+static const uint16 kq7SubtitleFixSignature1[] = {
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(fore), // pushi fore ($25)
+	0x78,                      // push1
+	0x39, 0x06,                // pushi 6 - sets fore to 6
+	0x39, SIG_SELECTOR8(back), // pushi back ($26)
+	0x78,                      // push1
+	0x78,                      // push1 - sets back to 1
+	0x39, SIG_SELECTOR8(font), // pushi font ($2a)
+	0x78,                      // push1
+	0x89, 0x16,                // lsg global[$16] - sets font to global[$16]
+	0x7a,                      // push2 (y)
+	0x78,                      // push1
+	0x76,                      // push0 - sets y to 0
+	0x54, SIG_UINT16(0x0018),  // self $18
+	SIG_END
+};
+
+static const uint16 kq7SubtitleFixPatch1[] = {
+	0x33, 0x12, // jmp [skip special init code]
+	PATCH_END
+};
+
+// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English
+static const uint16 kq7SubtitleFixSignature2[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x5a,                         // lsg global[$5a]
+	0x35, 0x02,                         // ldi 2
+	0x12,                               // and
+	0x31, 0x1e,                         // bnt [skip audio volume code]
+	0x38, SIG_SELECTOR16(masterVolume), // pushi masterVolume (0212h for 2.00, 0219h for 1.51)
+	0x76,                               // push0
+	0x81, 0x01,                         // lag global[1]
+	0x4a, SIG_UINT16(0x0004),           // send 4
+	0x65, 0x32,                         // aTop curVolume
+	0x38, SIG_SELECTOR16(masterVolume), // pushi masterVolume (0212h for 2.00, 0219h for 1.51)
+	0x78,                               // push1
+	0x67, 0x32,                         // pTos curVolume
+	0x35, 0x02,                         // ldi 2
+	0x06,                               // mul
+	0x36,                               // push
+	0x35, 0x03,                         // ldi 3
+	0x08,                               // div
+	0x36,                               // push
+	0x81, 0x01,                         // lag global[1]
+	0x4a, SIG_UINT16(0x0006),           // send 6
+	// end of volume code
+	0x35, 0x01,                         // ldi 1
+	0x65, 0x28,                         // aTop initialized
+	SIG_END
+};
+
+static const uint16 kq7SubtitleFixPatch2[] = {
+	PATCH_ADDTOOFFSET(+5),    // skip to bnt
+	0x31, 0x1b,               // bnt [skip audio volume code]
+	PATCH_ADDTOOFFSET(+15),   // right after "aTop curVolume / pushi masterVolume / push1"
+	0x7a,                     // push2
+	0x06,                     // mul (saves 3 bytes in total)
+	0x36,                     // push
+	0x35, 0x03,               // ldi 3
+	0x08,                     // div
+	0x36,                     // push
+	0x81, 0x01,               // lag global[1]
+	0x4a, PATCH_UINT16(0x06), // send 6
+	// end of volume code
+	0x35, 0x76,               // ldi 118
+	0x65, 0x16,               // aTop y
+	0x78,                     // push1 (saves 1 byte)
+	0x69, 0x28,               // sTop initialized
+	PATCH_END
+};
+
+// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English
+static const uint16 kq7SubtitleFixSignature3[] = {
+	SIG_MAGICDWORD,
+	0x63, 0x28,                 // pToa initialized
+	0x18,                       // not
+	0x31, 0x07,                 // bnt [skip init code]
+	0x38, SIG_SELECTOR16(init), // pushi init ($8e for 2.00, $93 for 1.51)
+	0x76,                       // push0
+	0x54, SIG_UINT16(0x0004),   // self 4
+	// end of init code
+	0x8f, 0x00,                 // lsp param[0]
+	0x35, 0x01,                 // ldi 1
+	0x1e,                       // gt?
+	0x31, 0x08,                 // bnt [set acc to 0]
+	0x87, 0x02,                 // lap param[2]
+	0x31, 0x04,                 // bnt [set acc to 0]
+	0x87, 0x02,                 // lap param[2]
+	0x33, 0x02,                 // jmp [over set acc to 0 code]
+	0x35, 0x00,                 // ldi 00
+	0x65, 0x18,                 // aTop caller
+	SIG_END
+};
+
+static const uint16 kq7SubtitleFixPatch3[] = {
+	PATCH_ADDTOOFFSET(+2),              // skip over "pToa initialized code"
+	0x2f, 0x0c,                         // bt [skip init code] - saved 1 byte
+	0x38, PATCH_GETORIGINALUINT16(+6),  // pushi init
+	0x76,                               // push0
+	0x54, PATCH_UINT16(0x0004),         // self 4
+	// additionally set background color here (5 bytes)
+	0x34, PATCH_UINT16(0x00ff),         // ldi 255
+	0x65, 0x2e,                         // aTop back
+	// end of init code
+	0x8f, 0x00,                         // lsp param[0]
+	0x35, 0x01,                         // ldi 1 (this may get optimized to get another byte)
+	0x1e,                               // gt?
+	0x31, 0x04,                         // bnt [set acc to 0]
+	0x87, 0x02,                         // lap param[2]
+	0x2f, 0x02,                         // bt [over set acc to 0 code]
+	PATCH_END
+};
+
+// KQ7 has custom video benchmarking code that needs to be disabled in a subroutine
+// that is called by KQ7CD::init; see sci2BenchmarkSignature
+static const uint16 kq7BenchmarkSignature[] = {
+	0x38, SIG_SELECTOR16(new), // pushi new
+	0x76,                      // push0
+	0x51, SIG_ADDTOOFFSET(+1), // class Actor
+	0x4a, SIG_UINT16(0x0004),  // send 4
+	0xa5, 0x00,                // sat temp[0]
+	0x39, SIG_SELECTOR8(view), // pushi view ($e)
+	SIG_MAGICDWORD,
+	0x78,                      // push1
+	0x38, SIG_UINT16(0xfdd4),  // pushi 64980
+	SIG_END
+};
+
+static const uint16 kq7BenchmarkPatch[] = {
+	0x34, PATCH_UINT16(10000), // ldi 10000
+	0x48,                      // ret
+	PATCH_END
+};
+
+// When attempting to use an inventory item on an object that does not interact
+// with that item, the game briefly displays an X cursor. It does this by
+// spinning for 90000 cycles, which makes the duration dependent on CPU speed,
+// maxes out the CPU for no reason, and keeps the engine from polling for
+// events (which may make the window appear nonresponsive to the OS).
+//
+// We replace the loop with a call to kScummVMSleep.
+//
+// Applies to at least: KQ7 English 2.00b
+// Responsible method: KQ7CD::pragmaFail in script 0
+static const uint16 kq7PragmaFailSpinSignature[] = {
+	0x35, 0x00,               // ldi 0
+	0xa5, 0x02,               // sat temp[2]
+	SIG_MAGICDWORD,
+	0x8d, 0x02,               // lst temp[2]
+	0x35, 0x03,               // ldi 3
+	0x22,                     // lt?
+	SIG_END
+};
+
+static const uint16 kq7PragmaFailSpinPatch[] = {
+	0x78,                                     // push1
+	0x39, 0x12,                               // pushi 18 (~300ms)
+	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, 2
+	0x35, 0x00,                               // ldi 0 [ exit loop ]
+	PATCH_END
+};
+
+// Room 6100 creates an extra ambrosia, usually floating in upper left of the
+//  screen, due to an off by one error. The script's local arrays contain four
+//  ambrosia coordinates but the loop that accesses them iterates five times.
+//
+// Applies to: All versions
+// Responsible method: rm6100:init
+// Fixes bug #9790
+static const uint16 kq7ExtraAmbrosiaSignature[] = {
+	SIG_MAGICDWORD,
+	0x8d, 0x00,                 // lst 00
+	0x35, 0x04,                 // ldi 04
+	0x24,                       // le?
+	SIG_END
+};
+
+static const uint16 kq7ExtraAmbrosiaPatch[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x22,                       // lt?
+	PATCH_END
+};
+
+// In KQ7 1.4, after giving the statue to the snake oil salesman, the curtain is
+//  drawn on top of ego when walking in front of the wagon. The script doesn't
+//  dispose of the salesman and this leaves his final cel stuck on the screen.
+//  We add the missing call to snakeSalesman:dispose.
+//
+// Applies to: English PC 1.4
+// Responsible method: giveStatue:changeState
+// Fixes bug: #10221
+static const uint16 kq7SnakeOilSalesmanSignature[] = {
+	0x38, SIG_SELECTOR16(setHeading),   // pushi setHeading
+	SIG_ADDTOOFFSET(+0x281),
+	0x72, SIG_UINT16(0x15b4),           // lofsa snakeSalesman
+	SIG_ADDTOOFFSET(+0x3f),
+	0x3c,                               // dup
+	0x35, SIG_MAGICDWORD, 0x0c,         // ldi 0c
+	0x1a,                               // eq?
+	0x30, SIG_UINT16(0x0010),           // bnt 0010 [ state 13 ]
+	0x38, SIG_SELECTOR16(setHeading),   // pushi setHeading
+	0x7a,                               // pushi2
+	0x38, SIG_UINT16(0x00b4),           // pushi 00b4
+	0x7c,                               // pushSelf
+	0x81, 0x00,                         // lag 00
+	0x4a, SIG_UINT16(0x0008),           // send 08  [ KQEgo setHeading: 180 self ]
+	0x32, SIG_UINT16(0x0017),           // jmp 0017 [ end of method ]
+	SIG_END
+};
+
+static const uint16 kq7SnakeOilSalesmanPatch[] = {
+	PATCH_ADDTOOFFSET(+0x02cd),
+	0x38, PATCH_SELECTOR16(dispose),    // pushi dispose
+	0x76,                               // push0
+	0x72, PATCH_UINT16(0x15b4),         // lofsa snakeSalesman
+	0x4a, PATCH_UINT16(0x0004),         // send 04  [ snakeSalesman: dispose ]
+	0x32, PATCH_UINT16(0xfd26),         // jmp fd26 [ KQEgo setHeading and end of method ]
+	PATCH_END
+};
+
+// In KQ7 1.65c, when Chicken Petite appears in room 5300 after leaving the
+//  china shop, the script sends a message to a non-object. Several script and
+//  export numbers changed from the previous version, but chickenCartoon2 wasn't
+//  updated to call ScriptID with the new values. Instead, the stale values
+//  return a procedure address instead of the chickenTimerScript object.
+//
+// We fix this by using chickenTimerScript's correct script and export numbers.
+//
+// Applies to: English PC 1.65c, French PC 1.65c, probably German 1.65c
+// Responsible method: chickenCartoon2:changeState(9)
+// Fixes bug: #11575
+static const uint16 kq7ChickenCartoonSignature[] = {
+	0x38, SIG_MAGICDWORD, SIG_UINT16(0x14b4), // pushi 14b4
+	0x39, 0x03,                               // pushi 03
+	0x43, 0x02, SIG_UINT16(0x0004),           // callk ScriptID [ ScriptID 5300 3 ]
+	SIG_ADDTOOFFSET(+0x037b),
+	// this part of the signature matches 1.65c while excluding earlier versions
+	0x38, SIG_UINT16(0x14b5),                 // pushi 14b5
+	0x39, 0x03,                               // pushi 03
+	0x43, 0x02, SIG_UINT16(0x0004),           // callk ScriptID [ ScriptID 5301 3 ]
+	SIG_END
+};
+
+static const uint16 kq7ChickenCartoonPatch[] = {
+	0x38, PATCH_UINT16(0x14b6),               // pushi 14b6 [ script 5302 ]
+	0x39, 0x16,                               // pushi 16   [ export 22   ]
+	PATCH_END
+};
+
+// KQ7 allows a maximum of 10 save games but English version 2.00 introduced a
+//  script bug which removed the check that enforces this. We add the missing
+//  check so that the game doesn't break. Sierra later released English version
+//  2.00b whose only change was to fix this.
+//
+// Applies to: English PC 2.00
+// Responsible method: startBut:doVerb
+static const uint16 kq7TooManySavesSignature[] = {
+	0x47, 0x15, 0x00, SIG_UINT16(0x0000),   // calle proc21_0 [ get save count ]
+	0xa5, 0x00,                             // sat 00 [ unused ]
+	SIG_MAGICDWORD,
+	0x35, 0x00,                             // ldi 00
+	0x31, 0x16,                             // bnt 16 [ allow save ]
+	SIG_END
+};
+
+static const uint16 kq7TooManySavesPatch[] = {
+	PATCH_ADDTOOFFSET(+5),
+	0x36,                                   // push
+	0x35, 0x0a,                             // ldi 0a
+	0x20,                                   // ge? [ save count >= 10 ]
+	PATCH_END
+};
+
+// During the chapter one opening cartoon, clicking the skip-scene button too
+//  quickly breaks the game. openingCartoon sets a 20 tick timer in state 0 and
+//  initializes ego in state 1. If skip-scene is clicked during this window then
+//  KQEgo:init is never called, Valanice never appears, and clicking eventually
+//  crashes the game. This also happens in Sierra's interpreter.
+//
+// We fix this by adding code to the skip-scene handler in openingCartoon to
+//  call KQEgo:init if the script was in state 0 when skip-scene was clicked.
+//  We make room by overwriting an unnecessary state check.
+//
+// Applies to: All versions
+// Responsible method: openingCartoon:changeState
+static const uint16 kq7OpeningCartoonSignature[] = {
+	SIG_MAGICDWORD,
+	0x18,                                   // not
+	0x30, SIG_UINT16(0x0544),               // bnt 05444 [ skip if skip-scene clicked ]
+	SIG_ADDTOOFFSET(+0x0541),
+	0x32, SIG_ADDTOOFFSET(+2),              // jmp [ ret ]
+	0x87, 0x01,                             // lap 01
+	0x65, 0x16,                             // aTop state
+	0x36,                                   // push
+	0x3c,                                   // dup
+	0x35, 0x00,                             // ldi 00
+	0x1a,                                   // eq? [ is state 0? always true ]
+	0x30, SIG_ADDTOOFFSET(+2),              // bnt [ toss, ret ]
+	SIG_END
+};
+
+static const uint16 kq7OpeningCartoonPatch[] = {
+	PATCH_ADDTOOFFSET(+1),
+	0x30, PATCH_UINT16(0x0542),             // bnt 0542 [ skip if skip-scene clicked ]
+	PATCH_ADDTOOFFSET(+0x0541),
+	0x48,                                   // ret
+	0x63, 0x22,                             // pToa ticks [ non-zero if we were in state 0 ]
+	0x31, 0x09,                             // bnt 09     [ skip ego init if state > 0 ]
+	0x38, PATCH_SELECTOR16(init),           // pushi init
+	0x76,                                   // push0
+	0x81, 0x00,                             // lag 00
+	0x4a, PATCH_UINT16(0x0004),             // send 0004 [ KQEgo init: ]
+	0x36,                                   // push [ to satisfy toss ]
+	PATCH_END
+};
+
+// In chapter one, moving the top gem in the statue all the way to the right and
+//  exiting the puzzle shows the gems in the wrong position. The script that
+//  determines which cel to display duplicates a chunk of code for every gem
+//  combination but the final copy is missing an entire switch block.
+//
+// We fix this by patching a branch so that one of the many copies of the
+//  missing code is executed for the buggy gem combination.
+//
+// Applies to: All versions
+// Responsible method: collar:init
+static const uint16 kq7StatueGemCelSignature[] = {
+	0x30, SIG_UINT16(0x003b),               // bnt 003b [ incomplete code ]
+	SIG_ADDTOOFFSET(+0x07),
+	0x88, SIG_UINT16(0x0148),               // lsg 0148
+	SIG_ADDTOOFFSET(+0x2e),
+	0xa3, SIG_MAGICDWORD, 0x06,             // sal 06
+	0x3a,                                   // toss
+	0x3a,                                   // toss
+	0x3a,                                   // toss
+	SIG_END
+};
+
+static const uint16 kq7StatueGemCelPatch[] = {
+	0x30, PATCH_UINT16(0x0007),             // bnt 0007 [ copy of missing code ]
+	PATCH_END
+};
+
+// KQ7 fails to reset most of its global variables when starting a new game. The
+//  script implicitly relies on initial values from the heap. Starting a new
+//  game after returning to the main menu causes the previous game's state to
+//  persist and create various glitches. A simple example is on the first screen
+//  of chapter 1: if a new game is started after playing a later chapter, the
+//  top gem in the statue will be in its solved position. nameGameRoom:init does
+//  reset some globals, but only those whose initial heap values weren't zero.
+//
+// We fix this by writing our own loop to reset all global variables correctly
+//  when starting a new game. We do this by combining the existing loops that
+//  reset flag globals to zero and inventory indexes to -1. All other game
+//  globals are now reset to zero, except for the two objects which must remain.
+//  We also restore a global which must contain the result of kMemoryInfo 0, and
+//  initialize global372 to -1 which Sierra forgot to do. After our reset loop,
+//  nameGameRoom:init proceeds with its initialization of non-zero globals.
+//
+// Applies to: All versions
+// Responsible method: nameGameRoom:init
+static const uint16 kq7InitGameGlobalsSignature[] = {
+	SIG_MAGICDWORD,
+	0x34, SIG_UINT16(0x04d2),               // ldi 04d2
+	0xa1, 0x65,                             // sag 65 [ redundant write of unused global ]
+	SIG_ADDTOOFFSET(+0x30),
+	0x35, 0xff,                             // ldi ff
+	0xa0, SIG_UINT16(0x0149),               // sag 0149 [ global329 = -1 ]
+	0x35, 0xff,                             // ldi ff
+	0xa0, SIG_UINT16(0x014a),               // sag 014a [ global330 = -1 ]
+	// loop: set all inventory indexes to -1
+	0x35, 0x00,                             // ldi 00
+	0xa5, 0x00,                             // sat 00 [ temp0 = 0 ]
+	0x8d, 0x00,                             // lst 00
+	0x35, 0x10,                             // ldi 10
+	0x22,                                   // lt?    [ temp0 < 16 ]
+	0x31, 0x12,                             // bnt 12
+	0x39, 0xff,                             // pushi ff
+	0x85, 0x00,                             // lat 00
+	0xb0, SIG_UINT16(0x0151),               // sagi 0151 [ global337[temp0] = -1 ]
+	0x39, 0xff,                             // pushi ff
+	0x85, 0x00,                             // lat 00
+	0xb0, SIG_UINT16(0x0161),               // sagi 0161 [ global353[temp0] = -1 ]
+	0xc5, 0x00,                             // +at 00 [ ++temp0 ]
+	0x33, 0xe7,                             // jmp e7 [ iterate ]
+	// loop: set all flag globals to 0
+	0x35, 0x24,                             // ldi 24
+	0xa5, 0x02,                             // sat 02 [ temp2 = 36 ]
+	0x35, 0x00,                             // ldi 00
+	0xa5, 0x00,                             // sat 00 [ temp0 = 0 ]
+	0x8d, 0x00,                             // lst 00
+	0x85, 0x02,                             // lst 02
+	0x22,                                   // lt?    [ temp0 < temp2 (36) ]
+	0x31, 0x09,                             // bnt 09
+	0x76,                                   // push0
+	0x85, 0x00,                             // lat 00
+	0xb1, 0x7f,                             // sagi 7f [ global127[temp0] = 0 ]
+	0xc5, 0x00,                             // +at 00 [ ++temp0 ]
+	0x33, 0xf0,                             // jmp f0 [ iterate ]
+	SIG_END
+};
+
+static const uint16 kq7InitGameGlobalsPatch[] = {
+	0x34, PATCH_UINT16(0x007f),             // ldi 007f
+	0x33, 0x43,                             // jmp 43 [ init loop ]
+	PATCH_ADDTOOFFSET(+0x35),
+	0xa0, PATCH_UINT16(0x014a),             // sag 014a [ global330 = -1 ]
+	0xa0, PATCH_UINT16(0x0174),             // sag 0174 [ global372 = -1 (reset chicken little) ]
+	0x34, PATCH_UINT16(0x7fe8),             // ldi 7fe8
+	0xa0, PATCH_UINT16(0x0142),             // sag 0142 [ global332 = kMemoryInfo 0 result ]
+	0x33, 0x2c,                             // jmp 2c   [ continue room init ]
+	// init loop
+	0xa5, 0x00,                             // sat 00 [ temp0 = 127 ]
+	// loop condition
+	0x38, PATCH_UINT16(0x017b),             // pushi 017b
+	0x1a,                                   // eq?    [ global == 379 ]
+	0x2f, 0xb5,                             // bt b5  [ exit loop and init specific globals ]
+	// skip kqResponseCode, it can't be reset
+	0x60,                                   // pprev
+	0x34, PATCH_UINT16(0x0136),             // ldi 0136
+	0x1a,                                   // eq?    [ global == 310 ]
+	0x2f, 0x19,                             // bt 19  [ skip reset ]
+	// skip theUseObjCursor, it can't be reset
+	0x8d, 0x00,                             // lst 00
+	0x34, PATCH_UINT16(0x014c),             // ldi 014c
+	0x1a,                                   // eq?    [ global == 332 ]
+	0x2f, 0x11,                             // bt 11  [ skip reset ]
+	// reset globals 337 through 368 to -1, all others to 0
+	0x39, 0x20,                             // pushi 20
+	0x38, PATCH_UINT16(0x0170),             // pushi 0170
+	0x85, 0x00,                             // lat 00
+	0x04,                                   // sub    [ 368 - temp0 ]
+	0x28,                                   // uge?   [ 32 u>= (368 - temp0) ]
+	0x31, 0x01,                             // bnt 01 [ skip if global not in -1 range ]
+	0x16,                                   // neg    [ acc = -1 ]
+	0x36,                                   // push   [ 0 or -1 ]
+	0x85, 0x00,                             // lat 00
+	0xb1, 0x00,                             // sagi 00 [ global[temp0] = 0 or -1 ]
+	0xc5, 0x00,                             // +at 00  [ ++temp0 ]
+	0x33, 0xd6,                             // jmp d6  [ iterate ]
+	PATCH_END
+};
+
+// KQ7 doesn't reset the chapter 6 volcano timers when exiting to the main menu
+//  without saving. The volcano can then erupt on the main menu or in a new game
+//  in the wrong chapter. The quit menu has several copies of the code that
+//  resets the game for the main menu but only one of them stops the timers.
+//
+// We fix this by patching the incomplete code to jump to the complete version.
+//
+// Applies to: PC 2.00 and 2.00b
+// Responsible method: chapInset:dispose
+static const uint16 kq7StopTimersSignature[] = {
+	0x38, SIG_SELECTOR16(eachElementDo),    // pushi eachElementDo [ start of complete reset ]
+	SIG_ADDTOOFFSET(+0xbf),
+	0x38, SIG_SELECTOR16(eachElementDo),    // pushi eachElementDo [ start of incomplete reset ]
+	SIG_ADDTOOFFSET(+0x49),
+	0x33, SIG_MAGICDWORD, 0x2f,             // jmp 2f
+	0x38, SIG_SELECTOR16(eachElementDo),    // pushi eachElementDo [ start of incomplete reset ]
+	SIG_END
+};
+
+static const uint16 kq7StopTimersPatch[] = {
+	PATCH_ADDTOOFFSET(+0xc2),
+	0x32, PATCH_UINT16(0xff3b),             // jmp ff3b [ jump to complete reset ]
+	PATCH_ADDTOOFFSET(+0x4b),
+	0x32, PATCH_UINT16(0xfeed),             // jmp feed [ jump to complete reset ]
+	PATCH_END
+};
+
+// The wooden nickel can't be given to the Faux Shop owner in early versions of
+//  KQ7 because the script doesn't register the hotspot. This was fixed in later
+//  versions. We add the missing shopOwner:addRespondVerb call.
+//
+// Applies to: PC 1.4 and PC 1.51 English/German/French
+// Responsible method: rm5000:init
+static const uint16 kq7FauxShopWoodenNickelSignature[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(ignoreActors),     // pushi ignoreActors
+	0x78,                                   // push1
+	0x78,                                   // push1
+	SIG_ADDTOOFFSET(+13),
+	0x34, SIG_UINT16(0x1000),               // ldi 1000 [ signal ]
+	SIG_ADDTOOFFSET(+2),
+	0x38, SIG_SELECTOR16(setCel),           // pushi setCel
+	0x78,                                   // push1
+	0x39, 0x09,                             // pushi 09
+	0x38, SIG_SELECTOR16(init),             // pushi init
+	0x76,                                   // push0
+	SIG_END
+};
+
+static const uint16 kq7FauxShopWoodenNickelPatch[] = {
+	0x39, PATCH_SELECTOR8(cel),             // pushi cel
+	0x78,                                   // push1
+	0x39, 0x09,                             // pushi 09
+	PATCH_ADDTOOFFSET(+13),
+	0x34, PATCH_UINT16(0x5000),             // ldi 5000 [ signal | ignoreActors flag ]
+	PATCH_ADDTOOFFSET(+2),
+	0x38, PATCH_SELECTOR16(init),           // pushi init
+	0x76,                                   // push0
+	0x38, PATCH_SELECTOR16(addRespondVerb), // pushi addRespondVerb
+	0x78,                                   // push1
+	0x39, 0x3b,                             // pushi 3b [ wooden nickel ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                                 patch
+static const SciScriptPatcherEntry kq7Signatures[] = {
+	{  true,     0, "disable video benchmarking",                  1, kq7BenchmarkSignature,                    kq7BenchmarkPatch },
+	{  true,     0, "remove hardcoded spin loop",                  1, kq7PragmaFailSpinSignature,               kq7PragmaFailSpinPatch },
+	{  true,    20, "fix initializing game globals",               1, kq7InitGameGlobalsSignature,              kq7InitGameGlobalsPatch },
+	{  true,    25, "fix stopping timers",                         1, kq7StopTimersSignature,                   kq7StopTimersPatch },
+	{  true,    30, "fix allowing too many saves",                 1, kq7TooManySavesSignature,                 kq7TooManySavesPatch },
+	{  true,  1250, "fix opening cartoon",                         1, kq7OpeningCartoonSignature,               kq7OpeningCartoonPatch },
+	{  true,  1250, "fix statue gem cel",                          1, kq7StatueGemCelSignature,                 kq7StatueGemCelPatch },
+	{  true,  5000, "fix wooden nickel in faux shop",              1, kq7FauxShopWoodenNickelSignature,         kq7FauxShopWoodenNickelPatch },
+	{  true,  5300, "fix snake oil salesman disposal",             1, kq7SnakeOilSalesmanSignature,             kq7SnakeOilSalesmanPatch },
+	{  true,  5301, "fix chicken cartoon",                         1, kq7ChickenCartoonSignature,               kq7ChickenCartoonPatch },
+	{  true,  6100, "fix extra ambrosia",                          1, kq7ExtraAmbrosiaSignature,                kq7ExtraAmbrosiaPatch },
+	{  true,    31, "enable subtitles (1/3)",                      1, kq7SubtitleFixSignature1,                 kq7SubtitleFixPatch1 },
+	{  true, 64928, "enable subtitles (2/3)",                      1, kq7SubtitleFixSignature2,                 kq7SubtitleFixPatch2 },
+	{  true, 64928, "enable subtitles (3/3)",                      1, kq7SubtitleFixSignature3,                 kq7SubtitleFixPatch3 },
+	{  true, 64928, "Narrator lockup fix",                         1, sciNarratorLockupSignature,               sciNarratorLockupPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#pragma mark -
+#pragma mark Lighthouse
+
+// When going to room 5 (sierra logo & menu room) from room 380 (the credits
+// room), the game tries to clear flags from 0 (global[116] bit 0) to 1423
+// (global[204] bit 15), but global[201] is not a flag global (it holds a
+// reference to theInvisCursor). This patch stops clearing after flag 1359
+// (global[200] bit 15). Hopefully that is good enough to not break the game.
+// Applies to at least: English 1.0c & 2.0a
+static const uint16 lighthouseFlagResetSignature[] = {
+	SIG_MAGICDWORD,
+	0x34, SIG_UINT16(0x58f), // ldi 1423
+	0x24,                    // le?
+	SIG_END
+};
+
+static const uint16 lighthouseFlagResetPatch[] = {
+	0x34, PATCH_UINT16(0x54f), // ldi 1359
+	PATCH_END
+};
+
+// When doing a system check on the portal computer in the lighthouse, the game
+// counts up to 1024MB, one megabyte at a time. In SSCI, this count speed would
+// be video speed dependent, but with our frame rate throttler, it takes 17
+// seconds. So, replace this slowness with a much faster POST that is more
+// accurate to the original game.
+// Applies to at least: US English 1.0c
+static const uint16 lighthouseMemoryCountSignature[] = {
+	SIG_MAGICDWORD,
+	0x8d, 0x02,             // lst temp[2]
+	0x35, 0x0a,             // ldi 10
+	0x24,                   // le?
+	0x31, 0x3b,             // bnt [to second digit overflow]
+	SIG_ADDTOOFFSET(+4),    // ldi, sat
+	0x8d, 0x03,             // lst temp[3]
+	0x35, 0x0a,             // ldi 10
+	SIG_END
+};
+
+static const uint16 lighthouseMemoryCountPatch[] = {
+	PATCH_ADDTOOFFSET(+2), // lst temp[2]
+	0x35, 0x02,            // ldi 2
+	PATCH_ADDTOOFFSET(+9), // le?, bnt, ldi, sat, lst
+	0x35, 0x02,            // ldi 2
+	PATCH_END
+};
+
+// In Lighthouse version 2.0, entering the submarine while the compass is out
+//  causes a message to be sent to a non-object. The PanelProps ppCompass and
+//  ppCompassFace are missing initialization code. Room 212 disposes of compass
+//  objects, but since they weren't correctly initialized, Feature:dispose
+//  attempts to remove them from a nonexistent Set in global 105.
+//
+// We fix this by patching the init methods of both compass objects to jump to
+//  ppOptions:init where there is a copy of the missing initialization code.
+//  This is effectively what Sierra did in their LITE2FIX patch.
+//
+// Applies to: Version 2.0
+// Responsible methods: ppCompass:init, ppCompassFace:init
+static const uint16 lighthouseCompassSignature[] = {
+	// ppCompass:init
+	0x4a, SIG_MAGICDWORD,               // send 10
+	      SIG_UINT16(0x0010),
+	0x48,                               // ret
+	0x00, 0x00,                         // unused padding
+	SIG_ADDTOOFFSET(+0x00fa),
+	// ppCompassFace:init
+	0x39, SIG_SELECTOR8(init),          // pushi init
+	0x76,                               // push0
+	0x59, 0x01,                         // &rest 01
+	0x57, 0x81, SIG_UINT16(0x0004),     // super 04 [ PanelProp init: 1 &rest ]
+	0x48,                               // ret
+	SIG_ADDTOOFFSET(+0x0b84),
+	// ppOptions:init
+	0x39, SIG_SELECTOR8(init),          // pushi init
+	0x76,                               // push0
+	0x59, 0x01,                         // &rest 01
+	0x57, 0x81, SIG_UINT16(0x0004),     // super 04 [ PanelProp init: 1 &rest ]
+	0x62, SIG_UINT16(0x01b6),           // pToa approachX
+	0x31, 0x16,                         // bnt 16
+	SIG_ADDTOOFFSET(+0x11),
+	0x35, 0x00,                         // ldi 00
+	0x64, SIG_UINT16(0x01b6),           // aTop approachX
+	0x48,                               // ret
+	SIG_END
+};
+
+static const uint16 lighthouseCompassPatch[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x32, PATCH_UINT16(0x0c91),         // jmp 0c91 [ ppCompass:init => ppOptions:init ]
+	PATCH_ADDTOOFFSET(+0x00fa),
+	0x32, PATCH_UINT16(0x0b8b),         // jmp 0b8b [ ppCompassFace:init => ppOptions:init ]
+	PATCH_END
+};
+
+// The script for opening the underwater safe has a timing bug that relies on
+//  the original interpreter being too slow to play the robot video at the
+//  specified frame rate. In ScummVM this causes the submarine arm animation to
+//  be out of sync with the safe door, repeat itself, and end on the wrong cel.
+//
+// openSafe:changeState(0) starts two animations: robot 596 (the safe door) and
+//  view 595 (the submarine arm). State 1 cues when the robot completes and
+//  resets the view's cel on the assumption that the view's cycler has already
+//  completed. But the robot is 50 frames at 2 ticks per frame (100 ticks) while
+//  the view is 39 ticks at 6 ticks per frame (234 ticks) so the robot should
+//  complete first. This worked in the original interpreter because it wasn't
+//  fast enough to run this scene at 2 ticks per frame and because Lighthouse's
+//  RobotPlayer script has a bug in its time calculations that amplifies delays
+//  when the specified frame rate can't be achieved. This combination caused the
+//  the robot to animate slower than specified and complete after the view.
+//
+// We fix this by lowering the robot's specified frame rate to the effective
+//  frame rate from the original.
+//
+// Applies to: All versions
+// Responsible Method: openSafe:changeState(0)
+// Fixes bug: #10226
+static const uint16 lighthouseOpenSafeSpeedSignature[] = {
+	0x39, SIG_SELECTOR8(init),             // pushi init
+	SIG_MAGICDWORD,
+	0x3c,                                  // dup
+	0x38, SIG_UINT16(0x0254),              // pushi 0254 [ view 585 ]
+	SIG_ADDTOOFFSET(+10),
+	0x38, SIG_SELECTOR16(start),           // pushi start
+	0x7a,                                  // push2
+	0x78,                                  // push1
+	0x39, 0x1e,                            // pushi 1e [ 30 frames per second (100 ticks) ]
+	SIG_END
+};
+
+static const uint16 lighthouseOpenSafeSpeedPatch[] = {
+	PATCH_ADDTOOFFSET(+21),
+	0x39, 0x0a,                            // pushi 0a [ 10 frames per second (300 ticks) ]
+	PATCH_END
+};
+
+// At the top of the roost tower there can be up to three mechanical birds, but
+//  they can appear and disappear inconsistently depending on which direction
+//  the player was facing before turning. rm510:changeScene has two bugs that
+//  set the wrong scene/pic links on the exit cursors once Birdman has appeared:
+//
+// 1. When facing the ladder (scene 504) and there are 3 birds, exitRight:curPic
+//    is set to 7506 (no birds) instead of 7504 (left and broken center bird).
+// 2. When facing right of the perch and there are no birds (scene 502), there
+//    is no code to handle the bird count being 0, and so exitLeft:curPic is set
+//    to 4511 (left and broken center bird) instead of 501 (no birds).
+//
+// We fix this by setting the correct scene/pic view when facing the ladder and
+//  adding the missing bird count test when facing right of the perch.
+//
+// Applies to: All versions
+// Responsible method: rm510:changeScene
+// Fixes bug: #10265
+static const uint16 lighthouseRoostBirdPicSignature1[] = {
+	0x3c,                                  // dup
+	0x35, 0x03,                            // ldi 03
+	0x1a,                                  // eq? [ bird count == 3 ]
+	0x31, 0x14,                            // bnt 14
+	0x38, SIG_SELECTOR16(newPic),          // pushi newPic
+	SIG_MAGICDWORD,
+	0x7a,                                  // push2
+	0x38, SIG_UINT16(0x1d52),              // pushi 1d52 [ no birds ]
+	0x39, 0x04,                            // pushi 04
+	0x7a,                                  // push2
+	0x78,                                  // push1
+	0x39, 0x04,                            // pushi 04
+	0x43, 0x02, SIG_UINT16(0x0004),        // callk ScriptID 04 [ exitRight ]
+	0x4a, SIG_UINT16(0x0008),              // send 08 [ exitRight newPic: 7506 4 ]
+	SIG_END
+};
+
+static const uint16 lighthouseRoostBirdPicPatch1[] = {
+	PATCH_ADDTOOFFSET(+10),
+	0x38, PATCH_UINT16(0x1d50),            // pushi 1d50 [ left bird + broken bird ]
+	PATCH_END
+};
+
+static const uint16 lighthouseRoostBirdPicSignature2[] = {
+	SIG_MAGICDWORD,
+	0x3c,                                  // dup
+	0x34, SIG_UINT16(0x01f6),              // ldi 01f6
+	0x1a,                                  // eq? [ is scene 502? ]
+	0x31, 0x68,                            // bnt 68
+	0x78,                                  // push1
+	0x38, SIG_UINT16(0x0182),              // pushi 0182 [ flag 386 ]
+	0x45, 0x05, SIG_UINT16(0x0002),        // callb proc5_2 [ has birdman attacked? ]
+	0x31, 0x33,                            // bnt 33 [ no birds to the left ]
+	0x89, 0xd1,                            // lsg d1 [ bird count ]
+	0x35, 0x01,                            // ldi 01
+	0x1a,                                  // eq?
+	SIG_END
+};
+
+static const uint16 lighthouseRoostBirdPicPatch2[] = {
+	PATCH_ADDTOOFFSET(+7),
+	0x89, 0x8c,                            // lsg 8c   [ flag global ]
+	0x34, PATCH_UINT16(0x2000),            // ldi 2000 [ flag 386 ]
+	0x12,                                  // and      [ is flag 386 set? ]
+	0x31, 0x35,                            // bnt 35   [ no birds to left ]
+	0x81, 0xd1,                            // lag d1   [ bird count ]
+	0x31, 0x31,                            // bnt 31   [ no birds to left if bird count == 0 ]
+	0x39, 0x01,                            // pushi 01
+	PATCH_END
+};
+
+//          script, description,                                      signature                         patch
+static const SciScriptPatcherEntry lighthouseSignatures[] = {
+	{  true,     5, "fix bad globals clear after credits",         1, lighthouseFlagResetSignature,     lighthouseFlagResetPatch },
+	{  true,     9, "fix compass in submarine",                    1, lighthouseCompassSignature,       lighthouseCompassPatch },
+	{  true,   360, "fix slow computer memory counter",            1, lighthouseMemoryCountSignature,   lighthouseMemoryCountPatch },
+	{  true,   510, "fix roost bird pic",                          1, lighthouseRoostBirdPicSignature1, lighthouseRoostBirdPicPatch1 },
+	{  true,   510, "fix roost bird pic",                          1, lighthouseRoostBirdPicSignature2, lighthouseRoostBirdPicPatch2 },
+	{  true,   700, "fix open safe speed",                         1, lighthouseOpenSafeSpeedSignature, lighthouseOpenSafeSpeedPatch },
+	{  true, 64928, "Narrator lockup fix",                         1, sciNarratorLockupSignature,       sciNarratorLockupPatch },
+	{  true, 64990, "increase number of save games (1/2)",         1, sci2NumSavesSignature1,           sci2NumSavesPatch1 },
+	{  true, 64990, "increase number of save games (2/2)",         1, sci2NumSavesSignature2,           sci2NumSavesPatch2 },
+	{  true, 64990, "disable change directory button",             1, sci2ChangeDirSignature,           sci2ChangeDirPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#endif
+
+// ===========================================================================
+// When Robin hands out the scroll to Marion and then types his name using the
+// hand code, the German version's script contains a typo (likely a copy/paste
+// error), and the local procedure that shows each letter is called twice. The
+// The procedure expects a letter arg and returns no value, so the first call
+// takes its letter and feeds an undefined value to the second call. Thus the
+// kStrCat() within the procedure reads a random pointer and crashes.
+//
+// We patch all of the 5 doubled local calls (one for each letter typed from
+// "R", "O", "B", "I", "N") to be the same as the English version.
+// Applies to at least: German floppy
+// Responsible method: giveScroll::changeState(19,21,23,25,27) in script 210
+// Fixes bug: #5264
+static const uint16 longbowSignatureShowHandCode[] = {
+	0x78,                            // push1 (1 call arg)
+									 //
+	0x78,                            // push1 (1 call arg)
+	0x72, SIG_ADDTOOFFSET(+2),       // lofsa (letter that was typed)
+	0x36,                            // push
+	0x40, SIG_ADDTOOFFSET(+2), 0x02, // call [localproc], 02
+									 //
+	0x36,                            // push (the result is an arg for the next call)
+	0x40, SIG_ADDTOOFFSET(+2), SIG_MAGICDWORD, 0x02, // call [localproc], 02
+									 //
+	0x38, SIG_SELECTOR16(setMotion), // pushi setMotion (0x11c in Longbow German)
+	0x39, SIG_SELECTOR8(x),          // pushi x (0x04 in Longbow German)
+	0x51, 0x1e,                      // class MoveTo
+	SIG_END
+};
+
+static 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 untouched
+	// The following will remove the first push & call
+	0x32, PATCH_UINT16(0x0002),      // jmp 02 [to the second push & call]
+	0x35, 0x00,                      // ldi 0 (waste 2 bytes)
+	PATCH_END
+};
+
+// When walking through the forest, arithmetic errors may occur at "random".
+// The scripts try to add a value and a pointer to the object "berryBush".
+//
+// This is caused by a local variable overflow.
+//
+// The scripts create berry bush objects dynamically. The array storage for
+// those bushes may hold a total of 8 bushes. But sometimes 10 bushes
+// are created. This overwrites 2 additional locals in script 225 and
+// those locals are used normally for value lookups.
+//
+// Changing the total of bushes could cause all sorts of other issues,
+// that's why I rather patched the code, that uses the locals for a lookup.
+// Which means it doesn't matter anymore when those locals are overwritten.
+//
+// Applies to at least: English PC floppy, German PC floppy, English Amiga floppy
+// Responsible method: export 2 of script 225
+// Fixes bug: #6751
+static const uint16 longbowSignatureBerryBushFix[] = {
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x03,                      // ldi 03h
+	0x1a,                            // eq?
+	0x2e, SIG_UINT16(0x002d),        // bt [process code]
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x04,                      // ldi 04h
+	0x1a,                            // eq?
+	0x2e, SIG_UINT16(0x0025),        // bt [process code]
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x05,                      // ldi 05h
+	0x1a,                            // eq?
+	0x2e, SIG_UINT16(0x001d),        // bt [process code]
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x06,                      // ldi 06h
+	0x1a,                            // eq?
+	0x2e, SIG_UINT16(0x0015),        // bt [process code]
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x18,                      // ldi 18h
+	0x1a,                            // eq?
+	0x2e, SIG_UINT16(0x000d),        // bt [process code]
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x19,                      // ldi 19h
+	0x1a,                            // eq?
+	0x2e, SIG_UINT16(0x0005),        // bt [process code]
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x1a,                      // ldi 1Ah
+	0x1a,                            // eq?
+	// jump location for the "bt" instructions
+	0x30, SIG_UINT16(0x0011),        // bnt [skip over follow up code, to offset 0c35]
+	// 55 bytes until here
+	0x85, 0x00,                      // lat temp[0]
+	SIG_MAGICDWORD,
+	0x9a, SIG_UINT16(0x0110),        // lsli local[110h] -> 110h points normally to 110h / 2Bh
+	// 5 bytes
+	0x7a,                            // push2
+	SIG_END
+};
+
+static const uint16 longbowPatchBerryBushFix[] = {
+	PATCH_ADDTOOFFSET(+4),           // keep: lsg global[70h], ldi 03h
+	0x22,                            // lt? (global < 03h)
+	0x2f, 0x42,                      // bt [skip over all the code directly]
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x06,                      // ldi 06h
+	0x24,                            // le? (global <= 06h)
+	0x2f, 0x0e,                      // bt [to kRandom code]
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x18,                      // ldi 18h
+	0x22,                            // lt? (global < 18h)
+	0x2f, 0x34,                      // bt [skip over all the code directly]
+	0x89, 0x70,                      // lsg global[70h]
+	0x35, 0x1a,                      // ldi 1Ah
+	0x24,                            // le? (global <= 1Ah)
+	0x31, 0x2d,                      // bnt [skip over all the code directly]
+	// 28 bytes, 27 bytes saved
+	// kRandom code
+	0x85, 0x00,                      // lat temp[0]
+	0x2f, 0x05,                      // bt [skip over case 0]
+	// temp[0] == 0
+	0x38, PATCH_UINT16(0x0110),      // pushi 0110h - that's what's normally at local[110h]
+	0x33, 0x18,                      // jmp [kRandom call]
+	// check temp[0] further
+	0x78,                            // push1
+	0x1a,                            // eq?
+	0x31, 0x05,                      // bnt [skip over case 1]
+	// temp[0] == 1
+	0x38, PATCH_UINT16(0x002b),      // pushi 002Bh - that's what's normally at local[111h]
+	0x33, 0x0f,                      // jmp [kRandom call]
+	// temp[0] >= 2
+	0x8d, 0x00,                      // lst temp[0]
+	0x35, 0x02,                      // ldi 02
+	0x04,                            // sub
+	0x9a, PATCH_UINT16(0x0112),      // lsli local[112h] -> look up value in 2nd table
+	                                 // this may not be needed at all and was just added for safety reasons
+	// waste 9 spare bytes
+	0x35, 0x00,                      // ldi 00
+	0x35, 0x00,                      // ldi 00
+	0x34, PATCH_UINT16(0x0000),      // ldi 0000
+	PATCH_END
+};
+
+// The camp (room 150) has a bug that can prevent the outlaws from ever rescuing
+//  the boys at sunset on day 5 or 6. The rescue occurs when entering camp as an
+//  abbey monk after leaving town exactly 3 times but this assumes that the
+//  counter can't exceed this. Wearing a different disguise can increment the
+//  counter beyond 3 at which point sunset can never occur.
+//
+// We fix this by patching the counter tests to greater than or equals. This
+//  makes them consistent with the other scripts that test this global variable.
+//
+// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
+// Responsible method: local procedure #3 in script 150
+// Fixes bug: #10839
+static const uint16 longbowSignatureCampSunsetFix[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x8e,                     // lsg global[8e] [ times left town ]
+	0x35, 0x03,                     // ldi 03
+	0x1a,                           // eq?
+	SIG_END
+};
+
+static const uint16 longbowPatchCampSunsetFix[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x20,                        	// ge?
+	PATCH_END
+};
+
+// The town map (room 260) has a bug that can send Robin to the wrong room.
+//  Loading the map from town on day 5 or 6 automatically sends Robin to camp
+//  (room 150) after leaving town more than twice. The intent is to start the
+//  sunset scene where the outlaws rescue the boys, but the map doesn't test the
+//  correct sunset conditions and can load an empty camp, even on the wrong day.
+//
+// We fix this by changing the map's logic to match the camp's by requiring the
+//  abbey monk disguise to be worn and the rescue flag to not be set.
+//
+// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
+// Responsible method: rm260:init
+// Fixes bug: #10839
+static const uint16 longbowSignatureTownMapSunsetFix[] = {
+	SIG_MAGICDWORD,
+	0x39, 0x05,                     // pushi 05
+	0x81, 0x82,                     // lag global[82] [ day ]
+	0x24,                           // le?
+	0x30, SIG_UINT16(0x0089),       // bnt 0089 [ no sunset if day < 5 ]
+	0x60,                           // pprev
+	0x35, 0x06,                     // ldi 06
+	0x24,                           // le?
+	0x30, SIG_UINT16(0x0082),       // bnt 0082 [ no sunset if day > 6 ]
+	0x89, 0x8e,                     // lsg global[8e]
+	0x35, 0x01,                     // ldi 01
+	SIG_END
+};
+
+static const uint16 longbowPatchTownMapSunsetFix[] = {
+	0x89, 0x7e,                     // lsg global[7e] [ current disguise ]
+	0x35, 0x05,                     // ldi 05 [ abbey monk ]
+	0x1c,                           // ne?
+	0x2f, 0x06,                     // bt 06 [ no sunset if disguise != abbey monk ]
+	0x78,                           // push1
+	0x39, 0x38,                     // pushi 38
+	0x45, 0x05, 0x02,               // callb [export 5 of script 0], 02 [ is rescue flag set? ]
+	0x2e, PATCH_UINT16(0x0081),     // bt 0081 [ no sunset if rescue flag is set ]
+	0x81, 0x8e,                     // lag global[8e]
+	0x78,                           // push1 [ save a byte ]
+	PATCH_END
+};
+
+// Ending day 5 or 6 by choosing to attack the castle fails to set the rescue
+//  flag which tells the next day what to do. This flag is set when rescuing
+//  the boys yourself and when the outlaws rescue them at sunset. Without this
+//  flag, the sunset rescue can repeat the next day and break the game.
+//
+// We fix this by setting the flag when returning the boys to their mother in
+//  room 250 after the attack.
+//
+// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
+// Responsible method: boysSaved:changeState(0)
+// Fixes bug: #10839
+static const uint16 longbowSignatureRescueFlagFix[] = {
+	0x3c,                           // dup
+	0x35, 0x00,                     // ldi 00
+	0x1a,                           // eq?
+	0x30, SIG_MAGICDWORD,           // bnt 0003 [ state 1 ]
+	      SIG_UINT16(0x0003),
+	0x32, SIG_UINT16(0x025b),       // jmp 025b [ end of method ]
+	SIG_END
+};
+
+static const uint16 longbowPatchRescueFlagFix[] = {
+	0x2f, 0x08,                     // bt 08 [ state 1 ]
+	0x78,                           // push1
+	0x39, 0x38,                     // pushi 38
+	0x45, 0x06, 0x02,               // callb [export 6 of script 0], 02 [ set rescue flag ]
+	0x3a,                           // toss
+	0x48,                           // ret
+	PATCH_END
+};
+
+// On day 7, Tuck can appear at camp to say that the widow wants to see you when
+//  she really doesn't. This scene is only supposed to occur if you haven't
+//  received the net but the script only tests if the net is currently in
+//  inventory, which it isn't if you've already used it or are in disguise.
+//
+// We fix this by testing the net's owner instead of inventory. If net:owner is
+//  non-zero then it's in inventory or in your cave or has been used.
+//
+// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
+// Responsible method: local procedure #3 in script 150
+// Fixes bug: #10847
+static const uint16 longbowSignatureTuckNetFix[] = {
+	SIG_MAGICDWORD,
+	0x30, SIG_UINT16(0x03a2),       // bnt 03a2 [ end of method ]
+	0x38, SIG_SELECTOR16(has),      // pushi has
+	0x78,                           // push1
+	0x39, 0x04,                     // pushi 04
+	0x81, 0x00,                     // lag global[0]
+	0x4a, 0x06,                     // send 6 [ ego: has 4 ]
+	0x18,                           // not
+	0x30, SIG_UINT16(0x0394),       // bnt 0394 [ end of method if net not in inventory ]
+	0x78,                           // push1
+	0x39, 0x47,                     // pushi 47
+	0x45, 0x05, 0x02,               // callb [export 5 of script 0], 02 [ is flag 47 set? ]
+	0x18,                           // not
+	0x30, SIG_UINT16(0x038a),       // bnt 038a [ end of method ]
+	SIG_ADDTOOFFSET(+60),
+	0x32, SIG_UINT16(0x034b),       // jmp 034b [ end of method ]
+	SIG_END
+};
+
+static const uint16 longbowPatchTuckNetFix[] = {
+	0x31, 0x55,                     // bnt 55 [ skip scene, save a byte ]
+	0x39, PATCH_SELECTOR8(at),      // pushi at
+	0x78,                           // push1
+	0x39, 0x04,                     // pushi 04
+	0x81, 0x09,                     // lag global[9]
+	0x4a, 0x06,                     // send 6 [ Inv: at 4 ]
+	0x38, PATCH_SELECTOR16(owner),  // pushi owner
+	0x76,                           // push0
+	0x4a, 0x04,                     // send 4 [ net: owner? ]
+	0x2f, 0x44,                     // bt 44 [ skip scene if net:owner != 0 ]
+	0x78,                           // push1
+	0x39, 0x47,                     // pushi 47
+	0x45, 0x05, 0x02,               // callb [export 5 of script 0], 02 [ is flag 47 set? ]
+	0x2f, 0x3c,                     // bt 3c [ skip scene, save 2 bytes ]
+	PATCH_END
+};
+
+// On day 9, room 350 outside the cobbler's hut is initialized incorrectly if
+//  disguised as a monk. The entrance to the hut is broken and several minor
+//  messages are incorrect. This is due to the room's script assuming that the
+//  only disguises that day are yeoman and merchant. A monk disguise causes some
+//  tests to pass and others to fail, leaving the room in an inconsistent state.
+//
+// We fix this by changing the yeoman disguise tests in the script to include
+//  the monk disguises. The disguise global is set to 4 for yeoman and 5 or 6
+//  for monk disguises so we patch the tests to be greater than or equals to.
+//
+// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
+// Responsible methods: rm350:init, lobbsHut:doVerb, lobbsDoor:doVerb,
+//                      lobbsCover:doVerb, tailorDoor:doVerb
+// Fixes bug: #10834
+static const uint16 longbowSignatureCobblerHut[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x7e,                     // lsg global[7e] [ current disguise ]
+	0x35, 0x04,                     // ldi 04 [ yeoman ]
+	0x1a,                           // eq?    [ is current disguise yeoman? ]
+	SIG_END
+};
+
+static const uint16 longbowPatchCobblerHut[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x20,                           // ge? [ is current disguise yeoman or monk? ]
+	PATCH_END
+};
+
+// The Amiga version of room 530 adds a broken fDrunk:onMe method which prevents
+//  messages when clicking on the drunk on the floor of the pub and causes a
+//  signature mismatch on every click in the room. fDrunk:onMe passes an Event
+//  object as an integer x coordinate and an uninitialized parameter as a y
+//  coordinate to kOnControl. This is a signature mismatch and would cause onMe
+//  to return false on every click and prevent hit testing from dispatching
+//  events to fDrunk. It's unclear why Sierra added this method to this one
+//  Feature in the room. Even if it worked, Feature:onMe already does this.
+//
+// We fix this by replacing fDrunk:onMe's contents with a call to super:onMe
+//  which calls kOnControl correctly and does proper hit testing, making its
+//  behavior consistent with the DOS version, which doesn't override onMe.
+//
+// Applies to: English Amiga Floppy
+// Responsible method: fDrunk:onMe
+// Fixes bug: #9688
+static const uint16 longbowSignatureAmigaPubFix[] = {
+	SIG_MAGICDWORD,
+	0x67, 0x20,                     // pTos onMeCheck
+	0x39, 0x03,                     // pushi 03
+	0x39, 0x04,                     // pushi 04
+	0x8f, 0x01,                     // lsp param[1]
+	0x8f, 0x02,                     // lsp param[2]
+	0x43, 0x4e, 0x06,               // callk OnControl, 6
+	SIG_END
+};
+
+static const uint16 longbowPatchAmigaPubFix[] = {
+	0x38, PATCH_UINT16(0x00c4),     // pushi 00c4 [ onMe, hard-coded for amiga ]
+	0x76,                           // push0
+	0x59, 0x01,                     // &rest 1
+	0x57, 0x2c, 0x04,               // super Feature, 4 [ super: onMe &rest ]
+	0x48,                           // ret
+	PATCH_END
+};
+
+// WORKAROUND: Script needed, because of differences in our pathfinding
+// algorithm
+// When the guards kick Robin out of archery room 320 the game locks up due to
+//  pathfinding algorithm differences. Ours sends ego in the wrong direction,
+//  colliding with a guard, and preventing the script from continuing.
+//
+// Applies to: English PC Floppy, German PC Floppy, English Amiga Floppy
+// Responsible method: takeHimOut:changeState(1)
+// Fixes bug: #10896
+static const uint16 longbowSignatureArcherPathfinding[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x00c8),       // pushi 00c8 [ y = 200 ]
+	0x7c,                           // pushSelf
+	0x81, 0x00,                     // lag 00
+	0x4a, 0x0c,                     // send 0c [ ego setMotion: PolyPath (ego x?) 200 self ]
+	SIG_END
+};
+
+static const uint16 longbowPatchArcherPathfinding[] = {
+	0x38, PATCH_UINT16(0x00c4),     // pushi 00c4 [ y = 196 ]
+	PATCH_END
+};
+
+// Longbow 1.0 has two random but common game-breaking bugs: Green Man's riddle
+//  scene never ends and the Sheriff's men catch Robin too quickly when sweeping
+//  the forest. Both are due to reusing an uninitialized global variable.
+//
+// Global 137 is used by the abbey hedge maze to store ego's cel during room
+//  transitions. Exiting the maze leaves this as a random value between 0 and 5.
+//  The forest sweep also uses this global but as a counter it expects to start
+//  at 0. It increments as Robin changes rooms during a sweep until it reaches a
+//  a maximum and he is caught. This is usually 7 but in some rooms it's only 3.
+//  A high initial value can make this sequence impossible. rm180:doit also
+//  tests the sweep counter and doesn't allow scripts to respond to a hand code
+//  when greater than 2. This breaks the riddle scene after the first answer.
+//
+// We fix this by clearing global 137 at the start of days 1-7 and 11 so that
+//  stale hedge maze values from days 5/6 and 10 don't affect the day 7 riddles
+//  or the sweeps on days 9 and 12. Ideally we could just clear this at the
+//  start of each day but there's no day initialization script. Instead we add
+//  our day-specific code to Robin's cave (room 140), similar to Sierra's patch
+//  and later versions.
+//
+// Applies to: English PC Floppy 1.0
+// Responsible method: localproc_001a in script 140
+// Fixes bug #5036
+static const uint16 longbowSignatureGreenManForestSweepFix[] = {
+	0x89, SIG_MAGICDWORD, 0x82,     // lsg 82 [ day ]
+	0x35, 0x01,                     // ldi 01
+	0x1a,                           // eq?
+	0x30, SIG_UINT16(0x0019),       // bnt 0019 [ skip horn init ]
+	0x38, SIG_SELECTOR16(has),      // pushi has
+	0x78,                           // push1
+	0x78,                           // push1
+	0x81, 0x00,                     // lag 00
+	0x4a, 0x06,                     // send 06 [ ego has: 1 ]
+	0x18,                           // not
+	0x30, SIG_UINT16(0x000c),       // bnt 000c [ skip horn init ]
+	0x39, SIG_SELECTOR8(init),      // pushi init
+	0x76,                           // push0
+	0x38, SIG_ADDTOOFFSET(+2),      // pushi stopUpd
+	0x76,                           // push0
+	0x72, SIG_UINT16(0x19b2),       // lofsa horn
+	0x4a, 0x08,                     // send 08 [ horn init: stopUpd: ]
+	0x89, 0x7e,                     // lsg 7e
+	0x35, 0x00,                     // ldi 00
+	0x1a,                           // eq?
+	0x2e, SIG_UINT16(0005),         // bt 0005
+	SIG_ADDTOOFFSET(+19),
+	0x39, SIG_SELECTOR8(init),      // push init
+	0x76,                           // push0
+	0x38, SIG_ADDTOOFFSET(+2),      // pushi stopUpd
+	0x76,                           // push0
+	0x72, SIG_UINT16(0x1912),       // lofsa bow
+	SIG_END
+};
+
+static const uint16 longbowPatchGreenManForestSweepFix[] = {
+	0x39, 0x07,                     // pushi 07
+	0x81, 0x82,                     // lag 82 [ day ]
+	0x22,                           // lt?
+	0x31, 0x06,                     // bnt 06
+	0x60,                           // pprev  [ day ]
+	0x35, 0x0b,                     // ldi 0b
+	0x1c,                           // ne?
+	0x2f, 0x02,                     // bt 02
+	0xa1, 0x89,                     // sag 89 [ sweep-count = 0 if day <= 7 or day == 11 ]
+	0x81, 0x82,                     // lag 82 [ day ]
+	0x78,                           // push1
+	0x1a,                           // eq?
+	0x31, 0x10,                     // bnt 10 [ skip horn init ]
+	0x38, PATCH_SELECTOR16(has),    // pushi has
+	0x78,                           // push1
+	0x78,                           // push1
+	0x81, 0x00,                     // lag 00
+	0x4a, 0x06,                     // send 06 [ ego has: 1 ]
+	0x2f, 0x05,                     // bt 05 [ skip horn init ]
+	0x72, PATCH_UINT16(0x19b2),     // lofsa horn
+	0x33, 0x1a,                     // jmp 1c [ continue horn init ]
+	0x81, 0x7e,                     // lag 7e
+	0x31, 0x08,                     // bnt 08
+	PATCH_ADDTOOFFSET(+19),
+	0x72, PATCH_UINT16(0x1912),     // lofsa bow
+	0x39, PATCH_SELECTOR8(init),    // push init
+	0x76,                           // push0
+	0x38, PATCH_GETORIGINALUINT16(+25), // pushi stopUpd
+	0x76,                           // push0
+	PATCH_END
+};
+
+// After rescuing Fulk in the Amiga version, rescueOfFulk stores the boat speed
+//  in a temporary variable during one state and expects it to still be there in
+//  a later state, which only worked by accident in Sierra's interpreter. This
+//  Amiga tweak was made so that on slower machines the boat would animate after
+//  Fulk and Robin leave the screen. We fix this by using the script's register
+//  property for storage instead of a temporary variable.
+//
+// Applies to: English Amiga Floppy
+// Responsible method: rescueOfFulk:changeState
+// Fixes bug: #11137
+static const uint16 longbowSignatureAmigaFulkRescue[] = {
+	SIG_MAGICDWORD,
+	0xa5, 0x00,                     // sat 00
+	0x89, 0x57,                     // lsg 87
+	SIG_ADDTOOFFSET(+10),
+	0x8d, 0x00,                     // lst 00
+	SIG_ADDTOOFFSET(+635),
+	0x8d, 0x00,                     // lst 00
+	SIG_END
+};
+
+static const uint16 longbowPatchAmigaFulkRescue[] = {
+	0x65, 0x1a,                     // aTop register
+	PATCH_ADDTOOFFSET(+12),
+	0x67, 0x1a,                     // pTos register
+	PATCH_ADDTOOFFSET(+635),
+	0x67, 0x1a,                     // pTos register
+	PATCH_END
+};
+
+// The Amiga version has an unusual speed test which takes 10 seconds to run in
+//  ScummVM, causing the test to assume a slow machine speed and reduce details
+//  throughout the game. We disable the speed test and its long delay before the
+//  the Sierra logo so that the fastest machine speed is used.
+//
+// Applies to: English Amiga Floppy
+// Responsible method: speedScript:changeState
+static const uint16 longbowSignatureAmigaSpeedTest[] = {
+	// state 1
+	0x32, SIG_UINT16(0x0164),       // jmp 0164 [ end of method ]
+	SIG_ADDTOOFFSET(+0xe9),
+	// state 2
+	SIG_MAGICDWORD,
+	0x35, 0x02,                     // ldi 02   [ fastest machine speed ]
+	0x32, SIG_UINT16(0x000f),       // jmp 000f [ set machine speed ]
+	SIG_END
+};
+
+static const uint16 longbowPatchAmigaSpeedTest[] = {
+	0x32, PATCH_UINT16(0x00e9),     // jmp 00e9 [ skip test, use fastest machine speed ]
+	PATCH_END
+};
+
+// The Amiga version introduced a script bug that prevents setting the flag when
+//  saving the peasant woman on day one. To get a perfect score, Robin must give
+//  the woman money as she walks away, but this causes the rest of the game to
+//  behave as if she was left to die. The script savedTheWoman was altered to
+//  set flag 173 in a later state than before, but this was a mistake because
+//  giveWomanBucks interrupts savedTheWoman and completes the scene. The Amiga
+//  script also allows exiting to the map before flag 173 is set.
+//
+// We fix this by setting flag 173 as soon as savedTheWoman enables input, just
+//  like in the PC versions. We make room by overwriting an Amiga-only test of
+//  the machine's speed. This is unnecessary as we disable the speed test above.
+//
+// Applies to: English Amiga Floppy
+// Responsible method: savedTheWoman:changeState(13)
+static const uint16 longbowSignatureAmigaPeasantWoman[] = {
+	0x89, SIG_MAGICDWORD, 0x57,     // lsg 87 [ machine speed, always 2 ]
+	0x35, 0x01,                     // ldi 01
+	0x20,                           // ge?    [ machine speed >= 1 ]
+	0x30, SIG_UINT16(0x0012),       // bnt 0012
+	SIG_END
+};
+
+static const uint16 longbowPatchAmigaPeasantWoman[] = {
+	0x39, 0x01,                     // pushi 01
+	0x38, PATCH_UINT16(0x00ad),     // pushi 00ad    [ flag 173 ]
+	0x45, 0x06, 0x02,               // callb proc0_6 [ set saved-woman flag ]
+	PATCH_END
+};
+
+// When Robin is sentenced to death, King Richard and Robin discuss Marian's
+//  death even if she is alive and just finished testifying at the trial.
+//
+// At the end of the game, troub:init calculates which ending to use based on
+//  the ransom raised, the number of outlaws left, interactions with others, and
+//  whether or not Marian lived. These calculations are complex and the worst of
+//  the four endings is to be hung. Room 422 handles this ending, but unlike the
+//  other trial scripts, it doesn't test any flags. Instead it always displays
+//  messages that begin with Marian's death even though this ending is possible
+//  when Marian is alive.
+//
+// We fix this by skipping the messages that discuss Marian's death if she is
+//  alive. We make room for this by overwriting redundant code that disables the
+//  icon bar. The icon bar is already disabled by the previous room, and even if
+//  it weren't, the subsequent call to HandsOff would have disabled it.
+//
+// Applies to: All versions
+// Responsible method: hanging:init
+static const uint16 longbowSignatureMarianMessagesFix[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(disable),  // pushi disable
+	0x39, 0x08,                     // pushi 08
+	0x76,                           // push0
+	0x78,                           // push1
+	0x7a,                           // push2
+	0x39, 0x03,                     // pushi 03
+	0x39, 0x04,                     // pushi 04
+	0x39, 0x05,                     // pushi 05
+	0x39, 0x06,                     // pushi 06
+	0x39, 0x07,                     // pushi 07
+	0x81, 0x45,                     // lag 45
+	0x4a, 0x14,                     // send 14 [ IconBar disable: 1 2 3 4 5 6 7 ]
+	SIG_END
+};
+
+static const uint16 longbowPatchMarianMessagesFix[] = {
+	0x76,                           // push0
+	0x39, 0x3e,                     // pushi 3e      [ flag 62 ]
+	0x45, 0x05, 0x02,               // callb proc0_5 [ is Marian alive? ]
+	0x31, 0x0e,                     // bnt 0e
+	0x38, PATCH_UINT16(0x0093),     // pushi 0093
+	0xab, 0x0a,                     // ssl 0a [ start message sequence at 147 ]
+	0x76,                           // push0
+	0xab, 0x0c,                     // ssl 0c [ stop sequence after first message ]
+	0x33, 0x04,                     // jmp 04
+	PATCH_END
+};
+
+// In the abbey hedge maze, the music stops if the interpreter loads the next
+//  maze room in under half a second. ScummVM can achieve this on fast machines.
+//  When changing maze rooms, the old room sets the music to slowly fade to zero
+//  without waiting. The new room then sets the music to fade back in to full
+//  volume (127). This has no noticeable effect since the second fade reverts
+//  the first almost instantly, but if the new room loads before the fade timer
+//  has lowered the volume at all then kDoSoundFade ignores the second fade
+//  because the volume is already at the target. The first fade then proceeds to
+//  lower the volume to zero and stop the sound, after which it never resumes.
+//
+// We fix this by patching HedgeRow:dispose to only fade out the music when
+//  exiting the maze. This doesn't change the music since the fades canceled
+//  each other out when changing maze rooms. There is already a nearby check for
+//  exiting the maze so this patch re-orders the instructions.
+//
+// Applies to: All versions
+// Responsible method: HedgeRow:dispose
+// Fixes bug: #13674
+static const uint16 longbowSignatureHedgeMazeMusic[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(fade),     // pushi fade
+	0x39, 0x04,                     // pushi 04
+	0x76,                           // push0
+	0x39, 0x1e,                     // pushi 1e
+	0x39, 0x08,                     // pushi 08
+	0x78,                           // push1
+	0x81, 0x64,                     // lag 64
+	0x4a, 0x0c,                     // send 0c [ rgnMusic fade: 0 30 8 1 ]
+	0x38, SIG_SELECTOR16(enable),   // pushi enable
+	0x78,                           // push1
+	0x39, 0x05,                     // pushi 05
+	0x81, 0x45,                     // lag 45
+	0x4a, 0x06,                     // send 06 [ IconBar enable: 5 ]
+	0x89, 0x0d,                     // lsg 0d  [ new room ]
+	0x35, 0x55,                     // ldi 55  [ max maze room ]
+	0x1e,                           // gt?     [ exiting hedge maze? ]
+	0x30, SIG_UINT16(0x0020),       // bnt 0020
+	SIG_END
+};
+
+static const uint16 longbowPatchHedgeMazeMusic[] = {
+	0x38, PATCH_SELECTOR16(enable), // pushi enable
+	0x78,                           // push1
+	0x39, 0x05,                     // pushi 05
+	0x81, 0x45,                     // lag 45
+	0x4a, 0x06,                     // send 06 [ IconBar enable: 5 ]
+	0x89, 0x0d,                     // lsg 0d  [ new room ]
+	0x35, 0x55,                     // ldi 55  [ max maze room ]
+	0x1e,                           // gt?     [ exiting hedge maze? ]
+	0x30, PATCH_UINT16(0x002f),     // bnt 002f
+	0x38, PATCH_SELECTOR16(fade),   // pushi fade
+	0x39, 0x04,                     // pushi 04
+	0x76,                           // push0
+	0x39, 0x1e,                     // pushi 1e
+	0x39, 0x08,                     // pushi 08
+	0x78,                           // push1
+	0x81, 0x64,                     // lag 64
+	0x4a, 0x0c,                     // send 0c [ rgnMusic fade: 0 30 8 1 ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                                patch
+static const SciScriptPatcherEntry longbowSignatures[] = {
+	{  true,    29, "amiga day 1 peasant woman",                   1, longbowSignatureAmigaPeasantWoman,       longbowPatchAmigaPeasantWoman},
+	{  true,   140, "green man riddles and forest sweep fix",      1, longbowSignatureGreenManForestSweepFix,  longbowPatchGreenManForestSweepFix },
+	{  true,   150, "day 5/6 camp sunset fix",                     2, longbowSignatureCampSunsetFix,           longbowPatchCampSunsetFix },
+	{  true,   150, "day 7 tuck net fix",                          1, longbowSignatureTuckNetFix,              longbowPatchTuckNetFix },
+	{  true,   210, "hand code crash",                             5, longbowSignatureShowHandCode,            longbowPatchShowHandCode },
+	{  true,   225, "arithmetic berry bush fix",                   1, longbowSignatureBerryBushFix,            longbowPatchBerryBushFix },
+	{  true,   250, "day 5/6 rescue flag fix",                     1, longbowSignatureRescueFlagFix,           longbowPatchRescueFlagFix },
+	{  true,   260, "day 5/6 town map sunset fix",                 1, longbowSignatureTownMapSunsetFix,        longbowPatchTownMapSunsetFix },
+	{  true,   320, "day 8 archer pathfinding workaround",         1, longbowSignatureArcherPathfinding,       longbowPatchArcherPathfinding },
+	{  true,   350, "day 9 cobbler hut fix",                      10, longbowSignatureCobblerHut,              longbowPatchCobblerHut },
+	{  true,   422, "marian messages fix",                         1, longbowSignatureMarianMessagesFix,       longbowPatchMarianMessagesFix },
+	{  true,   490, "hedge maze music",                            1, longbowSignatureHedgeMazeMusic,          longbowPatchHedgeMazeMusic },
+	{  true,   530, "amiga pub fix",                               1, longbowSignatureAmigaPubFix,             longbowPatchAmigaPubFix },
+	{  true,   600, "amiga fulk rescue fix",                       1, longbowSignatureAmigaFulkRescue,         longbowPatchAmigaFulkRescue },
+	{  true,   803, "amiga speed test",                            1, longbowSignatureAmigaSpeedTest,          longbowPatchAmigaSpeedTest },
+	{  true,   803, "disable speed test",                          1, sci01SpeedTestLocalSignature,            sci01SpeedTestLocalPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// Leisure Suit Larry 1 (Spanish)
+//
+// It seems originally the Spanish version of Larry 1 used some beta code at
+// least for the man wearing a barrel, who walks around in front of the casino.
+// The script inside the resource files even uses a class, that does not exist
+// inside those resource files, which causes a hard error.
+// The patch files included with the Spanish version (300.scr,300.tex, 927.scr)
+// add this class, but at least inside ScummVM a write to a non-existent selector
+// happens right after the player tries to buy an apple from that man.
+//
+// In the original English releases (2.0+2.1) this was handled differently.
+// Which is why this script patch changes that code to work just like in the English release.
+//
+// Attention: for at least some release of this game, view 302 (man wearing a barrel) is fully
+//            broken! Which also causes a crash. The original interpreter crashes as well.
+//            The only way to fix this is to dump that view from another release of Larry 1
+//            and then use the view patch file on this release.
+//
+// Applies to at least: Spanish floppy
+// Responsible method: sBuyApple::changeScript(2)
+// Fixes bug: #10240
+static const uint16 larry1SignatureBuyApple[] = {
+	// end of state 0
+	0x35, 0x01,                      // ldi 01
+	0x65, 0x10,                      // aTop cycles
+	0x32, SIG_UINT16(0x0248),        // jmp [ret]
+	0x3c,                            // dup
+	0x35, 0x01,                      // ldi 01
+	0x1a,                            // eq?
+	0x30, SIG_UINT16(0x0007),        // bnt [step 2 check]
+	// state 1 code
+	0x35, 0x01,                      // ldi 01
+	0x65, 0x10,                      // aTop cycles
+	0x32, SIG_UINT16(0x023a),        // jmp [ret]
+	0x3c,                            // dup
+	0x35, 0x02,                      // ldi 02
+	0x1a,                            // eq?
+	0x30, SIG_UINT16(0x0036),        // bnt [step 3 check]
+	// state 2 code
+	0x35, 0x02,                      // ldi 02
+	0x38, SIG_UINT16(0x0091),        // pushi setCycle
+	0x78,                            // push1
+	0x51, 0x18,                      // class Walk
+	0x36,                            // push
+	0x38, SIG_UINT16(0x0126),        // pushi setAvoider
+	0x78,                            // push1
+	0x51, SIG_ADDTOOFFSET(+1),       // class PAvoider (original 0x25, w/ patch file 0x6d)
+	0x36,                            // push
+	0x38, SIG_UINT16(0x0116),        // pushi setMotion
+	SIG_MAGICDWORD,
+	0x39, 0x04,                      // pushi 04
+	0x51, 0x24,                      // class PolyPath
+	0x36,                            // push
+	0x39, 0x04,                      // pushi 04
+	0x76,                            // push0
+	0x72, SIG_UINT16(0x0f4e),        // lofsa aAppleMan
+	0x4a, 0x04,                      // send 04
+	0x36,                            // push
+	0x35, 0x1d,                      // ldi 1Dh
+	0x02,                            // add
+	0x36,                            // push
+	0x39, 0x03,                      // pushi 03
+	0x76,                            // push0
+	0x72, SIG_UINT16(0x0f4e),        // lofsa aAppleMan
+	0x4a, 0x04,                      // send 04
+	0x36,                            // push
+	0x7c,                            // pushSelf
+	0x81, 0x00,                      // lag global[0]
+	0x4a, 0x18,                      // send 18h
+	0x32, SIG_UINT16(0x01fd),        // jmp [ret]
+	SIG_END
+};
+
+static const uint16 larry1PatchBuyApple[] = {
+	PATCH_ADDTOOFFSET(+11),
+	0x2f, 0xf3,                        // bt [jump to end of step 1 code], saves 8 bytes
+	0x3c,                              // dup
+	0x35, 0x02,                        // ldi 02
+	0x1a,                              // eq?
+	0x31, 0x3f,                        // bnt [step 3 check]
+	0x38, PATCH_UINT16(0x00e1),        // pushi distanceTo
+	0x78,                              // push1
+	0x72, PATCH_UINT16(0x0f4e),        // lofsa sAppleMan
+	0x36,                              // push
+	0x81, 0x00,                        // lag global[0]
+	0x4a, 0x06,                        // send 06
+	0x36,                              // push
+	0x35, 0x1e,                        // ldi 1Eh
+	0x1e,                              // gt?
+	0x31, 0xdb,                        // bnt [jump to end of step 1 code]
+	0x38, PATCH_SELECTOR16(setCycle),  // pushi setCycle
+	0x78,                              // push1
+	0x51, 0x18,                        // class Walk
+	0x36,                              // push
+	0x38, PATCH_SELECTOR16(setMotion), // pushi setMotion
+	0x39, 0x04,                        // pushi 04
+	0x51, 0x24,                        // class PolyPath
+	0x36,                              // push
+	0x39, 0x04,                        // pushi 04
+	0x76,                              // push0
+	0x72, PATCH_UINT16(0x0f4e),        // lofsa aAppleMan
+	0x4a, 0x04,                        // send 04
+	0x36,                              // push
+	0x35, 0x1d,                        // ldi 1Dh
+	0x02,                              // add
+	0x36,                              // push
+	0x39, 0x03,                        // pushi 03
+	0x76,                              // push0
+	0x72, PATCH_UINT16(0x0f4e),        // lofsa aAppleMan
+	0x4a, 0x04,                        // send 04
+	0x36,                              // push
+	0x7c,                              // pushSelf
+	0x81, 0x00,                        // lag global[0]
+	0x4a, 0x12,                        // send 12h
+	PATCH_END
+};
+
+//          script, description,                               signature                patch
+static const SciScriptPatcherEntry larry1Signatures[] = {
+	{  true,   300, "Spanish: buy apple from barrel man",    1, larry1SignatureBuyApple, larry1PatchBuyApple },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// Leisure Suit Larry 2
+
+// On the plane, Larry is able to wear the parachute. This grants 4 points.
+// In early versions of LSL2, it was possible to get "unlimited" points by
+//  simply wearing it multiple times.
+// They fixed it in later versions by remembering, if the parachute was already
+//  used before.
+// But instead of adding it properly, it seems they hacked the script / forgot
+//  to replace script 0 as well, which holds information about how many global
+//  variables are allocated at the start of the game.
+// The script tries to read an out-of-bounds global variable, which somewhat
+//  "worked" in SSCI, but ScummVM/SCI doesn't allow that.
+// That's why those points weren't granted here at all.
+// We patch to use global[5a], which seems to be unused in the whole game.
+// Applies to at least: English floppy
+// Responsible method: rm63Script::handleEvent
+// Fixes bug: #6346
+static const uint16 larry2SignatureWearParachutePoints[] = {
+	0x35, 0x01,                      // ldi 01
+	0xa1, SIG_MAGICDWORD, 0x8e,      // sag global[8e]
+	0x80, SIG_UINT16(0x01e0),        // lag global[1e0]
+	0x18,                            // not
+	0x30, SIG_UINT16(0x000f),        // bnt [don't give points]
+	0x35, 0x01,                      // ldi 01
+	0xa0, 0xe0, 0x01,                // sag global[1e0]
+	SIG_END
+};
+
+static const uint16 larry2PatchWearParachutePoints[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x80, PATCH_UINT16(0x005a),      // lag global[5a]
+	PATCH_ADDTOOFFSET(+6),
+	0xa0, PATCH_UINT16(0x005a),      // sag global[5a]
+	PATCH_END
+};
+
+// When buying a lottery ticket, the message box "Processing..." is displayed
+//  three times with no delay between the messages. In the original, each was
+//  visibly erased before the next because the interpreter drew directly to the
+//  screen. This created the necessary flicker effect indicating that the three
+//  identical messages were separate. In ScummVM there is no flicker because the
+//  window is updated with the screen buffer when processing events or between
+//  game cycles. The result is a single message box that appears to not respond
+//  to Enter or clicks until the third one dismisses it.
+//
+// We fix this by adding a brief delay in the "Processing..." loop with a call
+//  to kScummVMSleep so that the screen is redrawn between message boxes and the
+//  intended effect occurs as in the original. This patch is broken up into two
+//  parts because different versions have different instructions in the loop.
+//
+// Applies to: All versions
+// Responsible method: rm114Script:changeState(15)
+static const uint16 larry2SignatureLotteryTicketMessages1[] = {
+	0x35, 0x00,                      // ldi 00
+	0xa5, 0x00,                      // sat 00 [ temp0 = 0 ]
+	0x8d, 0x00,                      // lst 00 [ start loop ]
+	SIG_MAGICDWORD,
+	0x35, 0x03,                      // ldi 03
+	0x22,                            // lt?    [ temp0 < 3 ]
+	0x30, SIG_ADDTOOFFSET(+1), 0x00, // bnt    [ exit loop ]
+	SIG_END
+};
+
+static const uint16 larry2PatchLotteryTicketMessages1[] = {
+	0xa5, 0x00,                      // sat 00 [ temp0 = 0 (acc already 0) ]
+	0x7a,                            // push2  [ start loop ]
+	0x20,                            // ge?    [ 2 >= temp0 ]
+	0x31, PATCH_GETORIGINALBYTEADJUST(+10, +6), // bnt [ exit loop ]
+	0x78,                            // push1
+	0x39, 0x02,                      // pushi 02
+	0x43, kScummVMSleepId, 0x02,     // callk kScummVMSleep 02 [ 2 ticks ]
+	PATCH_END
+};
+
+static const uint16 larry2SignatureLotteryTicketMessages2[] = {
+	0x47, 0xff, SIG_MAGICDWORD, 0x00, 0x0c, // calle proc255_0 0c [ Print "Processing..." ]
+	0xc5, 0x00,                             // +at 00 [ temp0++, acc = temp0 ]
+	0x32, SIG_ADDTOOFFSET(+1), 0xff,        // jmp    [ continue loop ]
+	SIG_END
+};
+
+static const uint16 larry2PatchLotteryTicketMessages2[] = {
+	PATCH_ADDTOOFFSET(+6),
+	0x32, PATCH_GETORIGINALBYTEADJUST(+7, -2), 0xff, // jmp [ continue loop ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                              patch
+static const SciScriptPatcherEntry larry2Signatures[] = {
+	{  true,    63, "plane: no points for wearing parachute",      1, larry2SignatureWearParachutePoints,    larry2PatchWearParachutePoints },
+	{  true,    99, "disable speed test",                          1, sci0EarlySpeedTestSignature,           sci0EarlySpeedTestPatch },
+	{  true,    99, "disable speed test",                          1, sci01SpeedTestGlobalSignature,         sci01SpeedTestGlobalPatch },
+	{  true,   114, "lottery ticket messages (1/2)",               1, larry2SignatureLotteryTicketMessages1, larry2PatchLotteryTicketMessages1 },
+	{  true,   114, "lottery ticket messages (2/2)",               1, larry2SignatureLotteryTicketMessages2, larry2PatchLotteryTicketMessages2 },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// Leisure Suit Larry 3
+
+// Disable the LSL3 speed test by always setting the machine speed to 40 (PC AT)
+//  so that all graphics are enabled and the weight room behaves reasonably.
+//  40 is the minimum value that enables everything such as incrementing the
+//  score and the lighting effects in rooms 390, 430, and 431. The weight room
+//  (room 380) uses the machine speed to calculate how many exercises are
+//  required and the results would be much too high (in the thousands) if the
+//  speed test were to run unthrottled at modern speeds.
+//
+// Applies to: All versions
+// Responsible method: rm290:doit
+// Fixes bug: #11967
+static const uint16 larry3PatchSpeedTest[] = {
+	0x34, PATCH_UINT16(0x0028),         // ldi 0028
+	0xa1, PATCH_GETORIGINALBYTE(+1),    // sag [ machine-speed = 40 ]
+	0x18,                               // not [ always skip initialization ]
+	PATCH_END
+};
+
+// The LSL3 volume dialog initialize its slider to the current volume by calling
+//  kDoSoundMasterVolume, but it passes an uninitialized variable as an extra
+//  parameter. This changes the volume instead of just querying it, leaving the
+//  slider out of sync with the abruptly changed volume.
+//
+// We remove the uninitialized parameter so that this code correctly queries the
+//  volume instead of setting it. This was fixed in later versions but the buggy
+//  one was used as the basis for SCI Studio's template script, which is also
+//  included with SCI Companion, and so this bug lives on in fan games.
+//
+// Applies to: English PC, English Amiga, English Atari ST
+// Responsible method: TheMenuBar:handleEvent
+static const uint16 larry3SignatureVolumeSlider[] = {
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(doit),       // pushi doit
+	0x78,                            // push1
+	0x7a,                            // push2
+	0x39, 0x08,                      // pushi 08 [ volume ]
+	0x8d, 0x01,                      // lst 01   [ uninitialized variable ]
+	0x43, 0x31, 0x04,                // callk DoSound 04 [ set volume and return previous ]
+	SIG_END
+};
+
+static const uint16 larry3PatchVolumeSlider[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x39, 0x01,                      // pushi 01
+	0x38, PATCH_UINT16(0x0008),      // pushi 0008 [ volume ]
+	0x43, 0x31, 0x02,                // callk DoSound 02 [ return volume ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                      patch
+static const SciScriptPatcherEntry larry3Signatures[] = {
+	{  true,   290, "disable speed test",                          1, sci01SpeedTestGlobalSignature, larry3PatchSpeedTest },
+	{  true,   997, "fix volume slider",                           1, larry3SignatureVolumeSlider,   larry3PatchVolumeSlider },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// Leisure Suit Larry 5
+// In Miami the player can call the green card telephone number and get
+//  green card including limo at the same time in the English 1.000 PC release.
+// This results later in a broken game in case the player doesn't read
+//  the second telephone number for the actual limousine service, because
+//  in that case it's impossible for the player to get back to the airport.
+//
+// We disable the code, that is responsible to make the limo arrive.
+//
+// This bug was fixed in the European (dual language) versions of the game.
+//
+// Applies to at least: English PC floppy (1.000)
+// Responsible method: sPhone::changeState(40)
+static const uint16 larry5SignatureGreenCardLimoBug[] = {
+	0x7a,                               // push2
+	SIG_MAGICDWORD,
+	0x39, 0x07,                         // pushi 07
+	0x39, 0x0c,                         // pushi 0Ch
+	0x45, 0x0a, 0x04,                   // callb [export 10 of script 0], 04
+	0x78,                               // push1
+	0x39, 0x26,                         // pushi 26h (limo arrived flag)
+	0x45, 0x07, 0x02,                   // callb [export 7 of script 0], 02 (sets flag)
+	SIG_END
+};
+
+static const uint16 larry5PatchGreenCardLimoBug[] = {
+	PATCH_ADDTOOFFSET(+8),
+	0x34, PATCH_UINT16(0x0000),         // ldi 0000 (dummy)
+	0x34, PATCH_UINT16(0x0000),         // ldi 0000 (dummy)
+	PATCH_END
+};
+
+// In one of the conversations near the end (to be exact - room 380 and the text
+//  about using champagne on Reverse Biaz - only used when you actually did that
+//  in the game), the German text is too large, causing the textbox to get too large.
+// Because of that the talking head of Patti is drawn over the textbox. A translation oversight.
+// Applies to at least: German floppy
+// Responsible method: none, position of talker object on screen needs to get modified
+static const uint16 larry5SignatureGermanEndingPattiTalker[] = {
+	SIG_MAGICDWORD,
+	SIG_UINT16(0x006e),                 // object pattiTalker::x (110)
+	SIG_UINT16(0x00b4),                 // object pattiTalker::y (180)
+	SIG_ADDTOOFFSET(+469),              // verify that it's really the German version
+	0x59, 0x6f, 0x75,                   // (object name) "You"
+	0x23, 0x47, 0x44, 0x75,             // "#GDu"
+	SIG_END
+};
+
+static const uint16 larry5PatchGermanEndingPattiTalker[] = {
+	PATCH_UINT16(0x005a),               // object pattiTalker::x (90)
+	PATCH_END
+};
+
+//          script, description,                                      signature                               patch
+static const SciScriptPatcherEntry larry5Signatures[] = {
+	{  true,   280, "English-only: fix green card limo bug",       1, larry5SignatureGreenCardLimoBug,        larry5PatchGreenCardLimoBug },
+	{  true,   380, "German-only: Enlarge Patti Textbox",          1, larry5SignatureGermanEndingPattiTalker, larry5PatchGermanEndingPattiTalker },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// 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).
+// Applies to at least: German PC-CD
+// Responsible method: unknown
+static const uint16 larry6SignatureDeathDialog[] = {
+	SIG_MAGICDWORD,
+	0x3e, SIG_UINT16(0x0133),        // link 0133 (offset 0x20)
+	0x35, 0xff,                      // ldi ff
+	0xa3, 0x00,                      // sal local[0]
+	SIG_ADDTOOFFSET(+680),           // ...
+	0x8f, 0x01,                      // lsp param[1] (offset 0x2cf)
+	0x7a,                            // push2
+	0x5a, SIG_UINT16(0x0004), SIG_UINT16(0x010e), // lea temp[010e]
+	0x36,                            // push
+	0x43, 0x7c, 0x0e,                // callk Message[7c], 0e
+	SIG_ADDTOOFFSET(+90),            // ...
+	0x38, SIG_UINT16(0x00d6),        // pushi 00d6 (offset 0x335)
+	0x78,                            // push1
+	0x5a, SIG_UINT16(0x0004), SIG_UINT16(0x010e), // lea temp[010e]
+	0x36,                            // push
+	SIG_ADDTOOFFSET(+76),            // ...
+	0x38, SIG_UINT16(0x00cd),        // pushi 00cd (offset 0x38b)
+	0x39, 0x03,                      // pushi 03
+	0x5a, SIG_UINT16(0x0004), SIG_UINT16(0x010e), // lea temp[010e]
+	0x36,
+	SIG_END
+};
+
+static const uint16 larry6PatchDeathDialog[] = {
+	0x3e, 0x00, 0x02,                                 // link 0200
+	PATCH_ADDTOOFFSET(+687),
+	0x5a, PATCH_UINT16(0x0004), PATCH_UINT16(0x0140), // lea temp[0140]
+	PATCH_ADDTOOFFSET(+98),
+	0x5a, PATCH_UINT16(0x0004), PATCH_UINT16(0x0140), // lea temp[0140]
+	PATCH_ADDTOOFFSET(+82),
+	0x5a, PATCH_UINT16(0x0004), PATCH_UINT16(0x0140), // lea temp[0140]
+	PATCH_END
+};
+
+//          script, description,                                      signature                   patch
+static const SciScriptPatcherEntry larry6Signatures[] = {
+	{  true,    82, "death dialog memory corruption",              1, larry6SignatureDeathDialog, larry6PatchDeathDialog },
+	{  true,    99, "disable speed test",                          1, sci11SpeedTestSignature,    sci11SpeedTestPatch },
+	{  true,   928, "Narrator lockup fix",                         1, sciNarratorLockupSignature, sciNarratorLockupPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#ifdef ENABLE_SCI32
+#pragma mark -
+#pragma mark Leisure Suit Larry 6 Hires
+
+// When entering room 270 (diving board) from room 230, a typo in the game
+// script means that `setScale` is called accidentally instead of `setScaler`.
+// In SSCI this did not do much because the first argument happened to be
+// smaller than the y-position of `ego`, but in ScummVM the first argument is
+// larger and so a debug message "y value less than vanishingY" is displayed.
+static const uint16 larry6HiresSetScaleSignature[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(setScale), // pushi setScale ($14b)
+	0x38, SIG_UINT16(0x0005),       // pushi 5
+	0x51, 0x2c,                     // class Scaler
+	SIG_END
+};
+
+static const uint16 larry6HiresSetScalePatch[] = {
+	0x38, PATCH_SELECTOR16(setScaler), // pushi setScaler ($14f)
+	PATCH_END
+};
+
+// The init code that runs when LSL6hires starts up unconditionally resets the
+// master music volume to 12 (and the volume dial to 11), but the game should
+// always use the volume stored in ScummVM. Mac version initializes to 5.
+//
+// Applies to at least: English CD, Mac CD
+// Responsible method: initCode:init
+// Fixes bug: #9700
+static const uint16 larry6HiresVolumeResetSignature[] = {
+	SIG_MAGICDWORD,
+	0x4a, SIG_UINT16(0x0006),           // send 06 [ LSL6 masterVolume: ... ]
+	0x35, SIG_ADDTOOFFSET(+1),          // ldi 0b on PC, 05 on Mac
+	0xa1, 0xc2,                         // sag c2
+	SIG_END
+};
+
+static const uint16 larry6HiresVolumeResetPatch[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x33, 0x02,                         // jmp 02 [ skip volume change ]
+	PATCH_END
+};
+
+// Mac version stores the master music volume in an additional global which it
+//  sets the volume to on every restore. We disable this code so that the
+//  current ScummVM volume is used.
+//
+// Applies to: Mac CD only
+// Responsible method: LSL6:replay
+static const uint16 larry6HiresMacVolumeRestoreSignature[] = {
+	0x7a,                               // push2
+	SIG_MAGICDWORD,
+	0x76,                               // push0
+	0x88, SIG_UINT16(0x0103),           // lsg 0103
+	0x43, 0x40, SIG_UINT16(0x0004),     // callk DoSound 04 [ kDoSound MasterVolume global259 ]
+	SIG_END
+};
+
+static const uint16 larry6HiresMacVolumeRestorePatch[] = {
+	0x33, 0x07,                         // jmp 07 [ skip volume change ]
+	PATCH_END
+};
+
+// Filling the whale oil lamp with cellulite locks up the game when the PATCHES
+//  directory is missing. The patch files for script 330 override a very broken
+//  version in the resource volumes that always goes into an infinite loop.
+//  Unfortunately, the Leisure Suit Larry Collection CD includes a RESOURCE.CFG
+//  with an incorrect path to the PATCHES directory. Sierra's fix was to issue a
+//  save file with a full oil lamp that was compatible with the broken scripts.
+//  This shouldn't affect ScummVM since we don't use RESOURCE.CFG, but something
+//  about the way the collection was packaged causes players to continue to miss
+//  this directory and not realize until it's too late. The lockup occurs late
+//  in the game and adding the missing patch files invalidates all saves. 
+//
+// We don't generally fix "bugs" that are consequences of not providing all of
+//  the game's data files, but this is a severe case that keeps coming up.
+//  Fortunately, the script bug is simple, so we might as well just patch it and
+//  allow the player to proceed.
+//
+// We mitigate this by patching fillLampScr:changeState(2) to increment its
+//  register property. This is the counter that's supposed to animate the lamp
+//  but instead register is never incremented and the loop never ends.
+//
+// Applies to: English PC CD when PATCHES is missing (TODO: check localizations)
+// Responsible method: fillLampScr:changeState(2)
+// Fixes bug: #10484
+static const uint16 larry6HiresWhaleOilLampSignature[] = {
+	0x39, SIG_SELECTOR8(loop),          // pushi loop
+	0x78,                               // push1
+	0x78,                               // push1
+	0x39, SIG_MAGICDWORD,               // pushi cel
+	      SIG_SELECTOR8(cel),
+	0x78,                               // push1
+	0x67, 0x26,                         // pTos register
+	0x81, 0x00,                         // lag 00
+	0x4a, SIG_UINT16(0x000c),           // send 0c [ ego loop: 1 cel: register ]
+	SIG_END
+};
+
+static const uint16 larry6HiresWhaleOilLampPatch[] = {
+	PATCH_ADDTOOFFSET(+7),
+	0x6f,                               // ipTos register [ increment register ]
+	PATCH_END
+};
+
+// When attempting to take the guard's weapons, missleDeathScr calculates an
+//  excessively long delay in game cycles based on the initial speed test. The
+//  script attempts to use this delay as a backup if the user quickly dismisses
+//  the "Without thinking twice..." message so that it doesn't get stuck. We
+//  patch the speed test to use the best value so that all details are enabled,
+//  but we also throttle game cycles, and this results in a 30+ second delay.
+//
+// We fix this incompatibility by patching the delay down to 60 cycles, but this
+//  exposes a real script bug. The backup delay is always active and interrupts
+//  the message audio if the delay lasts less than six seconds. The script
+//  attempts to prevent this by polling the message's audio position, but it
+//  passes the wrong audio tuple. We also fix the tuple and now the delay works.
+//
+// Applies to: All versions
+// Responsible method: missleDeathScr:changeState(3), missleDeathScr:doit
+// Fixes bug: #13501
+static const uint16 larry6HiresGuardDelaySignature1[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x57,                         // lsg 57 [ how-fast ]
+	0x35, 0x4b,                         // ldi 4b
+	0x06,                               // mul
+	0x65, 0x26,                         // aTop register [ register = how-fast * 75 ]
+	SIG_END
+};
+
+static const uint16 larry6HiresGuardDelayPatch1[] = {
+	0x35, 0x3c,                         // ldi 3c [ 60 cycles ]
+	0x32, PATCH_UINT16(0x0000),         // jmp 0000
+	PATCH_END
+};
+
+static const uint16 larry6HiresGuardDelaySignature2[] = {
+	SIG_MAGICDWORD,
+	0x39, 0x06,                         // pushi 06
+	0x3c,                               // dup [ kDoAudioPosition ]
+	0x38, SIG_UINT16(0x0352),           // pushi 0352
+	0x39, 0x03,                         // pushi 03 [ noun ]
+	0x39, 0x05,                         // pushi 05 [ verb ]
+	0x76,                               // push0    [ cond ]
+	0x76,                               // push0    [ seq  ]
+	SIG_END
+};
+
+static const uint16 larry6HiresGuardDelayPatch2[] = {
+	PATCH_ADDTOOFFSET(+6),
+	0x39, 0x04,                         // pushi 04 [ correct noun ]
+	PATCH_ADDTOOFFSET(+3),
+	0x78,                               // push1    [ correct seq  ]
+	PATCH_END
+};
+
+// When using the phone with text enabled, dialing certain combinations crashes.
+//  This is due to a bug introduced when script 610 was altered for the hi-res
+//  version. The showTitle property of the phone's talker is only supposed to be
+//  set when talking to someone with a name, but now showTitle is never cleared.
+//  The operator is the one voice without a name, so talking to someone else
+//  first leaves these properties out of sync. Talking to the operator in this
+//  state causes Print:addTitle to attempt to duplicate the null name string.
+//
+// We fix this by clearing the phone talker's showTitle property when the name
+//  property is cleared. This keeps both properties in sync as before.
+//
+// Applies to: All versions
+// Responsible method: Export 2 of script 610
+// Fixes bug: #13554
+static const uint16 larry6HiresPhoneOperatorSignature[] = {
+	0x39, SIG_SELECTOR8(name),          // pushi name
+	0x76,                               // push0
+	0x72, SIG_ADDTOOFFSET(+2),          // lofsa talker
+	0x4a, SIG_UINT16(0x0004),           // send 04 [ talker name? ]
+	0x31, SIG_MAGICDWORD, 0x1a,         // bnt 1a  [ skip if no name ]
+	0x38, SIG_SELECTOR16(dispose),      // pushi dispose
+	0x76,                               // push0
+	0x39, SIG_SELECTOR8(name),          // pushi name
+	0x76,                               // push0
+	0x72, SIG_ADDTOOFFSET(+2),          // lofsa talker
+	0x4a, SIG_UINT16(0x0004),           // send 04 [ talker name? ]
+	0x4a, SIG_UINT16(0x0004),           // send 04 [ name dispose: ]
+	0x39, SIG_SELECTOR8(name),          // pushi name
+	0x78,                               // push1
+	0x76,                               // push0
+	0x72, SIG_ADDTOOFFSET(+2),          // lofsa talker
+	0x4a, SIG_UINT16(0x0006),           // send 06 [ talker name: 0 ]
+	SIG_END
+};
+
+static const uint16 larry6HiresPhoneOperatorPatch[] = {
+	PATCH_ADDTOOFFSET(+15),
+	0x4a, PATCH_UINT16(0x0004),         // send 04 [ name dispose: ]
+	0x38, PATCH_SELECTOR16(showTitle),  // pushi showTitle
+	0x78,                               // push1
+	0x76,                               // push0
+	0x33, 0x02,                         // jmp 02
+	PATCH_ADDTOOFFSET(+9),
+	0x4a, PATCH_UINT16(0x000c),         // send 0c [ talker showTitle: 0 name: 0 ]
+	PATCH_END
+};
+
+//          script, description,                                      signature                             patch
+static const SciScriptPatcherEntry larry6HiresSignatures[] = {
+	{  true,     0, "disable mac volume restore",                  1, larry6HiresMacVolumeRestoreSignature, larry6HiresMacVolumeRestorePatch },
+	{  true,    71, "disable volume reset on startup (1/2)",       1, sci2VolumeResetSignature,             sci2VolumeResetPatch },
+	{  true,    71, "disable volume reset on startup (2/2)",       1, larry6HiresVolumeResetSignature,      larry6HiresVolumeResetPatch },
+	{  true,    71, "disable video benchmarking",                  1, sci2BenchmarkSignature,               sci2BenchmarkPatch },
+	{  true,   270, "fix incorrect setScale call",                 1, larry6HiresSetScaleSignature,         larry6HiresSetScalePatch },
+	{  true,   330, "fix whale oil lamp lockup",                   1, larry6HiresWhaleOilLampSignature,     larry6HiresWhaleOilLampPatch },
+	{  true,   610, "phone operator crash",                        1, larry6HiresPhoneOperatorSignature,    larry6HiresPhoneOperatorPatch },
+	{  true,   850, "guard delay (1/2)",                           1, larry6HiresGuardDelaySignature1,      larry6HiresGuardDelayPatch1 },
+	{  true,   850, "guard delay (2/2)",                           1, larry6HiresGuardDelaySignature2,      larry6HiresGuardDelayPatch2 },
+	{  true, 64928, "Narrator lockup fix",                         1, sciNarratorLockupSignature,           sciNarratorLockupPatch },
+	{  true, 64990, "increase number of save games (1/2)",         1, sci2NumSavesSignature1,               sci2NumSavesPatch1 },
+	{  true, 64990, "increase number of save games (2/2)",         1, sci2NumSavesSignature2,               sci2NumSavesPatch2 },
+	{  true, 64990, "disable change directory button",             1, sci2ChangeDirSignature,               sci2ChangeDirPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#pragma mark -
+#pragma mark Leisure Suit Larry 7
+
+// The init code that runs when LSL7 starts up unconditionally resets the audio
+// volumes to defaults, but the game should always use the volume stored in
+// ScummVM. This patch is basically identical to the patch for Torin, except
+// that they left line numbers in the LSL7 scripts and changed the music volume.
+// Applies to at least: English CD
+static const uint16 larry7VolumeResetSignature1[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x41,                         // ldi $41
+	0xa1, 0xe3,                         // sag global[$e3] (music volume)
+	0x7e, SIG_ADDTOOFFSET(+2),          // (line whatever)
+	0x35, 0x3c,                         // ldi $3c
+	0xa1, 0xe4,                         // sag global[$e4] (sfx volume)
+	0x7e, SIG_ADDTOOFFSET(+2),          // (line whatever)
+	0x35, 0x64,                         // ldi $64
+	0xa1, 0xe5,                         // sag global[$e5] (speech volume)
+	SIG_END
+};
+
+static const uint16 larry7VolumeResetPatch1[] = {
+	0x33, 0x10,                         // jmp [past volume resets]
+	PATCH_END
+};
+
+// The init code that runs when LSL7 starts up unconditionally resets the
+// audio volumes to values stored in larry7.prf, but the game should always use
+// the volume stored in ScummVM. This patch is basically identical to the patch
+// for Torin, except that they left line numbers in the LSL7 scripts.
+// Applies to at least: English CD
+static const uint16 larry7VolumeResetSignature2[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(readWord),     // pushi readWord
+	0x76,                               // push0
+	SIG_ADDTOOFFSET(+6),                // ...
+	0xa1, 0xe3,                         // sag global[$e3] (music volume)
+	SIG_ADDTOOFFSET(+3),                // (line whatever)
+	SIG_ADDTOOFFSET(+10),               // ...
+	0xa1, 0xe4,                         // sag global[$e4] (sfx volume)
+	SIG_ADDTOOFFSET(+3),                // (line whatever)
+	SIG_ADDTOOFFSET(+10),               // ...
+	0xa1, 0xe5,                         // sag global[$e5] (speech volume)
+	SIG_END
+};
+
+static const uint16 larry7VolumeResetPatch2[] = {
+	PATCH_ADDTOOFFSET(+10),
+	0x18, 0x18,                         // (waste bytes)
+	PATCH_ADDTOOFFSET(+3),              // (line whatever)
+	PATCH_ADDTOOFFSET(+10),             // ...
+	0x18, 0x18,                         // (waste bytes)
+	PATCH_ADDTOOFFSET(+3),              // (line whatever)
+	PATCH_ADDTOOFFSET(+10),             // ...
+	0x18, 0x18,                         // (waste bytes)
+	PATCH_END
+};
+
+// In room 540 of Leisure Suit Larry 7, when using the cheese maker,
+// `soMakeCheese::changeState(6)` incorrectly pushes `self` as the end cel
+// instead of a cel number to the End cycler. In SSCI, this bad argument would
+// get corrected down to the final cel in the loop by `CycleCueList::init`, but
+// because ScummVM currently always sorts numbers higher than objects, the
+// comparison fails and the cel number is not corrected, so the cycler never
+// calls back and the game softlocks.
+// Here, we fix the call so a proper cel number is given for the second argument
+// instead of a bogus object pointer.
+//
+// Applies to at least: English PC-CD, German PC-CD
+static const uint16 larry7MakeCheeseCyclerSignature[] = {
+	0x38, SIG_UINT16(0x04), // pushi 4
+	0x51, 0xc4,             // class End
+	0x36,                   // push
+	SIG_MAGICDWORD,
+	0x7c,                   // pushSelf
+	0x39, 0x04,             // pushi 4
+	0x7c,                   // pushSelf
+	SIG_END
+};
+
+static const uint16 larry7MakeCheeseCyclerPatch[] = {
+	0x39, 0x04, // pushi 4 - save 1 byte
+	0x51, 0xc4, // class End
+	0x36,       // push
+	0x7c,       // pushSelf
+	0x39, 0x04, // pushi 4
+	0x39, 0x10, // pushi $10 (last cel of view 54007, loop 0)
+	PATCH_END
+};
+
+// During the cheese maker cutscene, `soMakeCheese::changeState(2)` sets the
+// priority of ego to 500 to draw him over the cheese maker, but this is also
+// above the guillotine (view 54000, cel 7, priority 400), so ego gets
+// incorrectly drawn on top of the guillotine as well. The cheese maker has a
+// priority of 373, so use priority 374 instead of 500.
+// Applies to at least: English PC-CD, German PC-CD
+// Responsible method: soMakeCheese::changeState(2) in script 540
+static const uint16 larry7MakeCheesePrioritySignature[] = {
+	0x38, SIG_SELECTOR16(setPri),    // pushi setPri
+	SIG_MAGICDWORD,
+	0x78,                            // push1
+	0x38, SIG_UINT16(0x01f4),        // pushi 500
+	SIG_END
+};
+
+static const uint16 larry7MakeCheesePriorityPatch[] = {
+	PATCH_ADDTOOFFSET(+4),           // pushi setPri, push1
+	0x38, PATCH_UINT16(0x0176),      // pushi 374
+	PATCH_END
+};
+
+// LSL7 tries to reset the message type twice at startup, first with a default
+// value in script 0, then with a stored value from larry7.prf (if that file
+// exists) or the same default value (if it does not) in script 64000. Since
+// message type sync relies on the game only setting this value once at startup,
+// we must stop the second attempt or the value from ScummVM will be
+// overwritten.
+// Applies to at least: English CD
+static const uint16 larry7MessageTypeResetSignature[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x02, // ldi 2
+	0xa1, 0x5a, // sag global[$5a]
+	SIG_END
+};
+
+static const uint16 larry7MessageTypeResetPatch[] = {
+	0x33, 0x02, // jmp [past reset]
+	PATCH_END
+};
+
+// LSL7 Russian by Softclub can crash when Peggy catches Larry in room 551 after
+//  Jamie receives the polyester. This is a script bug that exists in every
+//  version of the game, but the Softclub release happens to have a sync
+//  resource with an internal value that exposes the problem.
+//
+// When talking to Peggy on the deck in room 261, MouthSync:oSpecialSync is set
+//  to coHandleLaugh to handle Peggy's laugh animation, but the script fails to
+//  clear this property. The only other place that uses this feature is room 256
+//  where oSpecialSync is correctly cleared. MouthSync:doit cues oSpecialSync
+//  whenever a sync resource has a cue value >= 8.  After talking to Peggy, any
+//  sync with a cue value of 9 causes coHandleLaugh to draw Peggy laughing in
+//  the wrong room and crash the game due to an invalid plane. In the English
+//  version this never came up because no other syncs contain a 9, but two of
+//  Peggy's Russian syncs in room 551 contain a 9 cue.
+//
+// We fix this by clearing MouthSync:oSpecialSync when exiting room 261. This
+//  also fixes script 261 never unloading. This patch applies to all PC versions
+//  but not Mac, since Mac scripts were compiled without debugging instructions.
+//  There is no need for a Mac patch since that version is only in English.
+//
+// Applies to: All PC versions
+// Responsible method: ro261:dispose
+// Fixes bug: #13209
+static const uint16 larry7PeggySyncHandlerSignature[] = {
+	0x7d, SIG_ADDTOOFFSET(+7),              // file "261.sc"
+	0x7e, SIG_ADDTOOFFSET(+2),              // line
+	0x35, SIG_MAGICDWORD, 0x00,             // ldi 00
+	0xa0, SIG_UINT16(0x0155),               // sag 0155 [ global341 = 0 ]
+	SIG_END
+};
+
+static const uint16 larry7PeggySyncHandlerPatch[] = {
+	0x38, PATCH_SELECTOR16(oSpecialSync),   // pushi oSpecialSync
+	0x39, 0x01,                             // pushi 01
+	0x76,                                   // push0
+	0x51, 0x27,                             // class MouthSync
+	0x4a, PATCH_UINT16(0x0006),             // send 06 [ MouthSync oSpecialSync: 0 ]
+	PATCH_END
+};
+
+//          script, description,                                signature                           patch
+static const SciScriptPatcherEntry larry7Signatures[] = {
+	{  true,     0, "disable message type reset on startup", 1, larry7MessageTypeResetSignature,    larry7MessageTypeResetPatch },
+	{  true,   261, "fix peggy sync handler",                1, larry7PeggySyncHandlerSignature,    larry7PeggySyncHandlerPatch },
+	{  true,   540, "fix make cheese cutscene (cycler)",     1, larry7MakeCheeseCyclerSignature,    larry7MakeCheeseCyclerPatch },
+	{  true,   540, "fix make cheese cutscene (priority)",   1, larry7MakeCheesePrioritySignature,  larry7MakeCheesePriorityPatch },
+	{  true, 64000, "disable volume reset on startup (1/2)", 1, larry7VolumeResetSignature1,        larry7VolumeResetPatch1 },
+	{  true, 64000, "disable volume reset on startup (2/2)", 1, larry7VolumeResetSignature2,        larry7VolumeResetPatch2 },
+	{  true, 64866, "increase number of save games",         1, torinLarry7NumSavesSignature,       torinLarry7NumSavesPatch },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+#endif
+
+// ===========================================================================
+// Laura Bow 1 - Colonel's Bequest
+//
+// This is basically just a broken easter egg in Colonel's Bequest.
+// A plane can show up in room 4, but that only happens really rarely.
+// Anyway the Sierra developer seems to have just entered the wrong loop,
+// which is why the statue view is used instead (loop 0).
+// We fix it to use the correct loop.
+//
+// This is only broken in the PC version. It was fixed for Amiga + Atari ST.
+//
+// Credits to OmerMor, for finding it.
+//
+// Applies to at least: English PC Floppy
+// Responsible method: room4::init
+static const uint16 laurabow1SignatureEasterEggViewFix[] = {
+	0x78,                               // push1
+	0x76,                               // push0
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(setLoop),      // pushi setLoop
+	0x78,                               // push1
+	0x39, 0x03,                         // pushi 3 (loop 3, view only has 3 loops)
+	SIG_END
+};
+
+static const uint16 laurabow1PatchEasterEggViewFix[] = {
+	PATCH_ADDTOOFFSET(+7),
+	0x02,                               // (change loop to 2)
+	PATCH_END
+};
+
+// When oiling the armor or opening the visor of the armor, the scripts first
+//  check if Laura/ego is near the armor and if she is not, they will move her
+//  to the armor. After that, further code is executed.
+//
+// The current location is checked by a ego::inRect() call.
+//
+// The given rect for the inRect call inside openVisor::changeState was made
+//  larger for Atari ST/Amiga versions. We change the PC version to use the
+//  same rect.
+//
+// Additionally, the coordinate that Laura is moved to (152, 107) may not be
+//  reachable depending on where Laura was when "use oil on helmet of armor"
+//  or "open visor of armor" got entered. Bad coordinates such as (82, 110),
+//  cause collisions and effectively an endless loop, effectively freezing the
+//  game. The user is only able to restore a previous game.
+//
+//  We change the destination coordinate to (152, 110), which seems to be
+//   reachable all the time.
+//
+// The following patch fixes the rect for the PC version of the game.
+//
+// Applies to at least: English PC Floppy
+// Responsible method: openVisor::changeState (script 37)
+// Fixes bug: #7119
+static const uint16 laurabow1SignatureArmorOpenVisorFix[] = {
+	0x39, 0x04,                         // pushi 04
+	SIG_MAGICDWORD,
+	0x39, 0x6a,                         // pushi 6a (106d)
+	0x38, SIG_UINT16(0x0096),           // pushi 0096 (150d)
+	0x39, 0x6c,                         // pushi 6c (108d)
+	0x38, SIG_UINT16(0x0098),           // pushi 0098 (152d)
+	SIG_END
+};
+
+static const uint16 laurabow1PatchArmorOpenVisorFix[] = {
+	PATCH_ADDTOOFFSET(+2),
+	0x39, 0x68,                         // pushi 68 (104d)   (-2)
+	0x38, PATCH_UINT16(0x0094),         // pushi 0094 (148d) (-2)
+	0x39, 0x6f,                         // pushi 6f (111d)   (+3)
+	0x38, PATCH_UINT16(0x009a),         // pushi 009a (154d) (+2)
+	PATCH_END
+};
+
+// This here fixes the destination coordinate (exact details are above).
+//
+// Applies to at least: English PC Floppy, English Atari ST Floppy, English Amiga Floppy
+// Responsible method: openVisor::changeState, oiling::changeState (script 37)
+// Fixes bug: #7119
+static const uint16 laurabow1SignatureArmorMoveToFix[] = {
+	SIG_MAGICDWORD,
+	0x36,                               // push
+	0x39, 0x6b,                         // pushi 6B (107d)
+	0x38, SIG_UINT16(0x0098),           // pushi 98 (152d)
+	0x7c,                               // pushSelf
+	0x81, 0x00,                         // lag global[0]
+	SIG_END
+};
+
+static const uint16 laurabow1PatchArmorMoveToFix[] = {
+	PATCH_ADDTOOFFSET(+1),
+	0x39, 0x6e,                         // pushi 6E (110d) - adjust x, so that no collision can occur anymore
+	PATCH_END
+};
+
+// When oiling the left arm of the armor that holds the axe, pressing 'E' to
+//  exit the screen leaves input disabled in the PC version. The local procedure
+//  that restores room 37 enables directional control but not input when the axe
+//  arm is is oiled. Sierra fixed this in the Amiga and Atari ST versions by
+//  adding a call to User:canInput(1) so that the procedure always enables both.
+//
+// We also fix this by enabling both control and input, but we do it by calling
+//  the HandsOn procedure instead, which this procedure already does in every
+//  case except the buggy one when the axe arm is being oiled. We simply patch
+//  out the tests that prevent HandsOn from being called when it's needed.
+//
+// Applies to: English PC Floppy
+// Responsible method: 3rd subroutine in script 37, called by Room37:handleEvent
+// Fixes bug: #7154
+static const uint16 laurabow1SignatureArmorOilingArmFix[] = {
+	SIG_MAGICDWORD,
+	0x72, SIG_UINT16(0x18f3),           // lofsa valve [ included offset so that only PC version is patched ]
+	0x4a, 0x04,                         // send 04 [ valve hide: ]
+	0x8b, 0x34,                         // lsl 34  [ oil-target ]
+	0x35, 0x02,                         // ldi 02  [ left arm ]
+	0x1c,                               // ne?
+	0x30, SIG_UINT16(0x0014),           // bnt 0014 [ skip HandsOn if oiled left arm ]
+	SIG_ADDTOOFFSET(+0x10),             // [ more oil-target tests: left elbow, axe ]
+	0x76,                               // push0
+	0x45, 0x04, 0x00,                   // callb proc0_4 [ HandsOn ]
+	0x48,                               // ret
+	SIG_END
+};
+
+static const uint16 laurabow1PatchArmorOilingArmFix[] = {
+	PATCH_ADDTOOFFSET(+5),
+	0x33, 0x16,                         // jmp 16 [ always call HandsOn ]
+	PATCH_END
+};
+
+// Jeeves lights the chapel candles (room 58) in act 2 but they don't stay
+//  lit when re-entering until the next act. This is due to Room58:init
+//  incorrectly testing the global variable that tracks Jeeves' act 2 state.
+//
+// We fix this by changing the test from if global[155] equals 11, which it
+//  never does, to if it's greater than 11. The global is set to 12 in
+//  lightCandles:changeState(11) and it continues to increment as Jeeves'
+//  chore sequence progresses, ending with 17.
+//
+// Applies to: DOS, Amiga, Atari ST
+// Responsible method: Room58:init
+// Fixes bug: #10743
+static const uint16 laurabow1SignatureChapelCandlesPersistence[] = {
+	SIG_MAGICDWORD,
+	0x89, 0x9b,                         // lsg global[155] [ Jeeves' act 2 state ]
+	0x35, 0x0b,                         // ldi b
+	0x1a,                               // eq?
+	SIG_END
+};
+
+static const uint16 laurabow1PatchChapelCandlesPersistence[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x1e,                               // gt?
+	PATCH_END
+};
+
+// LB1 DOS doesn't acknowledge Lillian's presence in room 44 when she's sitting
+//  on the bed in act 4. Look, talk, etc respond that she's not there.
+//  This is due to not setting global[195] which tracks who is in the room.
+//  We fix this by setting the global as Amiga and Atari ST versions do.
+//
+// Applies to: DOS only
+// Responsible method: Room44:init
+// Fixes bug: #10742
+static const uint16 laurabow1SignatureLillianBedFix[] = {
+	SIG_MAGICDWORD,
+	0x72, SIG_UINT16(0x10f8),           // lofsa suit2 [ only matches DOS version ]
+	0x4a, 0x14,                         // send 14
+	SIG_ADDTOOFFSET(+8),
+	0x89, 0x76,                         // lsg global[118]
+	0x35, 0x02,                         // ldi 2
+	0x12,                               // and
+	0x30, SIG_UINT16(0x000d),           // bnt d [ haven't seen Lillian in study ]
+	0x35, 0x01,                         // ldi 1
+	SIG_END
+};
+
+static const uint16 laurabow1PatchLillianBedFix[] = {
+	PATCH_ADDTOOFFSET(+13),
+	0x81, 0x76,                         // lag global[118]
+	0x7a,                               // push2
+	0x12,                               // and
+	0x31, 0x0f,                         // bnt f [ haven't seen Lillian in study ]
+	0x35, 0x20,                         // ldi 20 [ Lillian ]
+	0xa1, 0xc3,                         // sag global[195] [ set Lillian as in the room ]
+	PATCH_END
+};
+
+// Entering Laura's bedroom resets the cursor position to the upper right corner
+//  of the screen as if the game were starting. Room44:init calls kSetCursor to
+//  initialize the game because it's the first room where the user has control,
+//  but this part of the script is missing the startup test and so it happens
+//  every time. We fix this by adding the missing startup test.
+//
+// Applies to: All versions
+// Responsible method: Room44:init
+static const uint16 laurabow1SignatureRoom44CursorFix[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x00,                         // ldi 00
+	0xa1, 0xbe,                         // sag be [ global190 = 0 ]
+	0x39, SIG_SELECTOR8(init),          // pushi init
+	0x76,                               // push0
+	0x57, 0x37, 0x04,                   // super Rm 04 [ super init: ]
+	SIG_ADDTOOFFSET(+10),
+	0x43, 0x28, 0x08,                   // callk SetCursor 08 [ SetCursor 997 1 300 0 ]
+	SIG_ADDTOOFFSET(+439),
+	0x89, 0xa5,                         // lsg a5
+	0x35, 0x00,                         // ldi 00
+	0x1a,                               // eq?
+	0x30,                               // bnt
+	SIG_END
+};
+
+static const uint16 laurabow1PatchRoom44CursorFix[] = {
+	0x39, PATCH_SELECTOR8(init),        // pushi init
+	0x76,                               // push0
+	0x57, 0x37, 0x04,                   // super Rm 04 [ super init: ]
+	0x81, 0xcb,                         // lag cb [ global203 == 0 when game is starting ]
+	0x2f, 0x0d,                         // bt 0d  [ skip SetCursor if game already started ]
+	PATCH_ADDTOOFFSET(+452),
+	0x76,                               // push0
+	0xa9, 0xbe,                         // ssg be [ global190 = 0 ]
+	0x81, 0xa5,                         // lag a5
+	0x2e,                               // bt
+	PATCH_END
+};
+
+// When you tell Lilly about Gertie in room 35, Lilly will then walk to the
+// left and off the screen. If Laura (ego) is in the way, the whole game will
+// basically block and you won't be able to do anything except saving or
+// restoring the game.
+//
+// If this happened already, the player can enter "send Lillian ignoreActors 1"
+// inside the debugger to fix this situation.
+//
+// This issue is very difficult to solve, because Lilly also walks diagonally
+// after walking to the left right under the kitchen table. This means that
+// even if we added a few more rectangle checks, there could still be spots,
+// where the game would block.
+//
+// Also the mover "PathOut" is used for Lillian instead of the regular
+// "MoveTo", which would avoid other actors by itself.
+//
+// So instead we set Lilly to ignore other actors during that cutscene, which
+// is the least invasive solution.
+//
+// Applies to at least: English PC Floppy, English Amiga Floppy, English Atari ST Floppy
+// Responsible method: goSee::changeState(1) in script 236
+// Fixes bug: (happened during GOG Let's Play)
+static const uint16 laurabow1SignatureTellLillyAboutGerieBlockingFix1[] = {
+	0x7a,                               // puah2
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x00c1),           // pushi 00C1h
+	0x38, SIG_UINT16(0x008f),           // pushi 008Fh
+	0x38, SIG_SELECTOR16(ignoreActors), // pushi ignoreActors
+	0x78,                               // push1
+	0x76,                               // push0
+	SIG_END
+};
+
+static const uint16 laurabow1PatchTellLillyAboutGertieBlockingFix1[] = {
+	PATCH_ADDTOOFFSET(+11),             // skip over until push0
+	0x78,                               // push1 (change push0 to push1)
+	PATCH_END
+};
+
+// a second patch to call Lillian::ignoreActors(1) on goSee::changeState(9) in script 236
+static const uint16 laurabow1SignatureTellLillyAboutGerieBlockingFix2[] = {
+	0x3c,                               // dup
+	0x35, 0x09,                         // ldi 09
+	0x1a,                               // eq?
+	0x30, SIG_UINT16(0x003f),           // bnt [ret]
+	0x39, SIG_ADDTOOFFSET(+1),          // pushi view
+	0x78,                               // push1
+	0x38, SIG_UINT16(0x0203),           // pushi 203h (515d)
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi posn
+	0x7a,                               // push2
+	0x38, SIG_UINT16(0x00c9),           // pushi C9h (201d)
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x0084),           // pushi 84h (132d)
+	0x72, SIG_ADDTOOFFSET(+2),          // lofsa Lillian (different offsets for different platforms)
+	0x4a, 0x0e,                         // send 0Eh
+	SIG_END
+};
+
+static const uint16 laurabow1PatchTellLillyAboutGertieBlockingFix2[] = {
+	0x38, PATCH_SELECTOR16(ignoreActors), // pushi ignoreActors
+	0x78,                                 // push1
+	0x76,                                 // push0
+	0x33, 0x00,                           // ldi 00 (waste 2 bytes)
+	PATCH_ADDTOOFFSET(+19),               // skip over until send
+	0x4a, 0x14,                           // send 14h
+	PATCH_END
+};
+
+// LB1 contains over 20 commands which lockup the game if entered while ego is
+//  colliding with an obstacle. Opening and moving closets in room 43 are prime
+//  examples. They are all symptoms of a global bug.
+
+// Every cycle, CB1:doit checks to see if ego appears to be walking and blocked,
+//  and if so it stops ego's motion and sets ego's view to 11 (standing). If ego
+//  has just collided with an obstacle but is still displaying view 1 (walking)
+//  when a command is entered which disables input and sets ego's motion without
+//  setting an avoider then CB1:doit will stop that new motion at the start of
+//  the next cycle and lockup the game. This occurs in part because CB1:doit
+//  tests potentially stale values that the new motion hasn't yet had a chance
+//  to set. Scripts which set an avoider aren't vulnerable because CB1:doit
+//  won't stop ego if one is set. Other SCI games don't have this kind of code
+//  in their Game's doit and so they don't have this bug.
+
+// We fix this by clearing the kSignalHitObstacle flag whenever Act:setMotion is
+//  called with a new motion. This causes CB1:doit's subsequent call to
+//  ego:isBlocked to return false, instead of a stale true value, preventing
+//  CB1:doit from stopping the new motion before it's had a chance to start.
+//  Should the new motion actually be blocked then the interpreter will then set
+//  the flag when processing the motion as usual. This patch closes the short
+//  window during which this value is stale and CB1:doit tests it.
+
+// Applies to: DOS, Amiga, Atari ST and occurs in Sierra's interpreter.
+// Responsible method: Act:setMotion
+// Fixes bug: #10733
+static const uint16 laurabow1SignatureObstacleCollisionLockupsFix[] = {
+	SIG_MAGICDWORD,
+	0x30, SIG_UINT16(0x002f),           // bnt 2f
+	0x38, SIG_UINT16(0x00a3),           // pushi a3 [ startUpd ]
+	0x76,                               // push0
+	0x54, 0x04,                         // self 4
+	0x7a,                               // push2 [ -info- ]
+	0x76,                               // push0
+	0x87, 0x01,                         // lap param[1]
+	0x4a, 0x04,                         // send 4
+	0x36,                               // push
+	0x34, SIG_UINT16(0x8000),           // ldi 8000
+	0x12,                               // and
+	0x30, SIG_UINT16(0x000a),           // bnt a
+	0x39, 0x56,                         // pushi 56 [ new ]
+	0x76,                               // push0
+	0x87, 0x01,                         // lap param[1]
+	0x4a, 0x04,                         // send 4
+	0x32, SIG_UINT16(0x0002),           // jmp 2
+	0x87, 0x01,                         // lap param[1]
+	0x65, 0x4c,                         // aTop mover
+	0x39, 0x57,                         // pushi 57 [ init ]
+	0x78,                               // push1
+	0x7c,                               // pushSelf
+	0x59, 0x02,                         // &rest 2
+	0x63, 0x4c,                         // pToa mover
+	0x4a, 0x06,                         // send 6
+	0x32, SIG_UINT16(0x0004),           // jmp 4
+	0x35, 0x00,                         // ldi 0
+	SIG_END
+};
+
+static const uint16 laurabow1PatchObstacleCollisionLockupsFix[] = {
+	0x31, 0x32,                         // bnt 32 [ save 1 byte ]
+
+	0x63, 0x1c,                         // pToa signal
+	0x38, PATCH_UINT16(0xfbff),         // pushi fbff
+	0x12,                               // and
+	0x65, 0x1c,                         // aTop signal [ clear kSignalHitObstacle (0400) ]
+
+	0x38, PATCH_UINT16(0x00a3),         // pushi a3 [ startUpd ]
+	0x76,                               // push0
+	0x54, 0x04,                         // self 4
+	0x7a,                               // push2 [ -info- ]
+	0x76,                               // push0
+	0x87, 0x01,                         // lap param[1]
+	0x4a, 0x04,                         // send 4
+	0x38, PATCH_UINT16(0x8000),         // pushi 8000 [ save 1 byte ]
+	0x12,                               // and
+	0x31, 0x09,                         // bnt 9 [ save 1 byte ]
+	0x39, 0x56,                         // pushi 56 [ new ]
+	0x76,                               // push0
+	0x87, 0x01,                         // lap param[1]
+	0x4a, 0x04,                         // send 4
+	0x33, 0x02,                         // jmp 2 [ save 1 byte ]
+	0x87, 0x01,                         // lap param[1]
+	0x65, 0x4c,                         // aTop mover
+	0x39, 0x57,                         // pushi 57 [ init ]
+	0x78,                               // push1
+	0x7c,                               // pushSelf
+	0x59, 0x02,                         // &rest 2
+	0x63, 0x4c,                         // pToa mover
+	0x4a, 0x06,                         // send 6
+	0x48,                               // ret  [ save 4 bytes ]
+	PATCH_END
+};
+
+// Laura can get stuck walking up the attic stairs diagonally in room 47 and
+//  lockup the game. This also occurs in the original. Room47:doit loads the
+//  attic when ego is on control $10 at the base of the stairs and facing north.
+//  Room47:handleEvent prevents the user from moving ego when on control $10.
+//  Walking up the stairs diagonally puts ego in control $10 facing left or
+//  right and so the room never changes and the user never regains control.
+//
+// We fix this by allowing ego to face any direction except south to trigger the
+//  attic room change. This also fixes an edge case that allows walking through
+//  the staircase wall into Clarence's room.
+//
+// Applies to: DOS, Amiga, Atari ST
+// Responsible method: Room47:doit
+// Fixes bug: #9949
+static const uint16 laurabow1SignatureAtticStairsLockupFix[] = {
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(loop),          // pushi loop
+	0x76,                               // push0
+	0x81, 0x00,                         // lag global[0]
+	0x4a, 0x04,                         // send 4 [ ego:loop? ]
+	0x36,                               // push
+	0x35, 0x03,                         // ldi 03 [ facing north ]
+	0x1a,                               // eq?
+	SIG_END
+};
+
+static const uint16 laurabow1PatchAtticStairsLockupFix[] = {
+	PATCH_ADDTOOFFSET(+8),
+	0x35, 0x02,                         // ldi 02 [ facing south ]
+	0x1c,                               // ne?
+	PATCH_END
+};
+
+// Laura can get stuck at the top of the left stairs in room 47 and lockup the
+//  game. This also occurs in the original. There is a 30x2 control area at the
+//  top of the stairs in which Room47:handleEvent prevents input. This assumes
+//  that ego can't be interrupted when walking through the area, but there is a
+//  notch in the left wall that ego can collide with, leaving ego stuck with
+//  input disabled. The right wall doesn't have a notch.
+//
+// We fix this by allowing input at the top of the stairs. Up and down movements
+//  are allowed when on the staircase's control area ($0200) and we extend that
+//  to include the top of the stairs ($0800).
+//
+// Applies to: DOS, Amiga, Atari ST
+// Responsible method: Room47:handleEvent
+// Fixes bug #10879
+static const uint16 laurabow1SignatureLeftStairsLockupFix[] = {
+	SIG_MAGICDWORD,
+	0x34, SIG_UINT16(0x0200),           // ldi 0200 [ left stairs ]
+	0x1a,                               // eq? [ is ego entirely on the stairs? ]
+	SIG_END
+};
+
+static const uint16 laurabow1PatchLeftStairsLockupFix[] = {
+	0x34, PATCH_UINT16(0x0a00),         // ldi 0a00 [ left stairs | top of left stairs ]
+	0x12,                               // and [ is ego touching the stairs or the top? ]
+	PATCH_END
+};
+
+// LB1's fingerprint copy protection randomly rejects the correct answer and may
+//  even fail to draw a fingerprint. myCopy:init selects the fingerprint by
+//  generating random loop and cel numbers for view 553, but it passes incorrect
+//  ranges to kRandom. If kRandom returns the maximum value then the loop or cel
+//  overflow and a different image is displayed than what was intended.
+//
+// We correct the ranges from 0-600 and 1-1000 to 0-599 and 0-999 so that
+//  invalid cel 6 and loop 10 are never used after the script divides by 10.
+//
+// Applies to: DOS, Amiga, Atari ST
+// Responsible method: myCopy:init
+static const uint16 laurabow1SignatureCopyProtectionRandomFix[] = {
+	0x38, SIG_UINT16(0x0258),           // pushi 600d
+	SIG_ADDTOOFFSET(+10),
+	SIG_MAGICDWORD,
+	0x78,                               // push1
+	0x38, SIG_UINT16(0x03e8),           // pushi 1000d
+	SIG_END
+};
+
+static const uint16 laurabow1PatchCopyProtectionRandomFix[] = {
+	0x38, PATCH_UINT16(0x0257),         // pushi 599d
+	PATCH_ADDTOOFFSET(+10),
+	0x76,                               // push0
+	0x38, PATCH_UINT16(0x03e7),         // pushi 999d
+	PATCH_END
+};
+
+// At the end of the game a dialog asks if you'd like to review your notes.
+//  Pressing the escape key dismisses the dialog and locks up the game with the
+//  menu and input disabled. The script is missing a handler for this result.
+//  We fix this by repeating the dialog when escape is pressed, just like the
+//  other dialogs do in room 786. Sierra fixed this in later versions.
+//
+// Applies to: DOS
+// Responsible method: Notes:changeState(1)
+static const uint16 laurabow1SignatureReviewNotesDialog[] = {
+	0x39, 0x0f,                         // pushi 0f
+	SIG_ADDTOOFFSET(+0x20),
+	SIG_MAGICDWORD,
+	0x7a,                               // push2
+	0x47, 0xff, 0x00, 0x1e,             // calle proc255_0 [ print dialog ]
+	0x36,                               // push
+	0x3c,                               // dup
+	0x35, 0x01,                         // ldi 01
+	0x1a,                               // eq?
+	SIG_END
+};
+
+static const uint16 laurabow1PatchReviewNotesDialog[] = {
+	PATCH_ADDTOOFFSET(+0x27),
+	0x31, 0xd7,                         // bnt -29 [ repeat dialog if escape pressed ]
+	0x36,                               // push
+	0x78,                               // push1
+	PATCH_END
+};
+
+//          script, description,                                signature                                             patch
+static const SciScriptPatcherEntry laurabow1Signatures[] = {
+	{  true,     4, "easter egg view fix",                      1, laurabow1SignatureEasterEggViewFix,                laurabow1PatchEasterEggViewFix },
+	{  true,    37, "armor open visor fix",                     1, laurabow1SignatureArmorOpenVisorFix,               laurabow1PatchArmorOpenVisorFix },
+	{  true,    37, "armor move to fix",                        2, laurabow1SignatureArmorMoveToFix,                  laurabow1PatchArmorMoveToFix },
+	{  true,    37, "allowing input, after oiling arm",         1, laurabow1SignatureArmorOilingArmFix,               laurabow1PatchArmorOilingArmFix },
+	{  true,    44, "lillian bed fix",                          1, laurabow1SignatureLillianBedFix,                   laurabow1PatchLillianBedFix },
+	{  true,    44, "room 44 cursor fix",                       1, laurabow1SignatureRoom44CursorFix,                 laurabow1PatchRoom44CursorFix },
+	{  true,    47, "attic stairs lockup fix",                  1, laurabow1SignatureAtticStairsLockupFix,            laurabow1PatchAtticStairsLockupFix },
+	{  true,    47, "left stairs lockup fix",                   3, laurabow1SignatureLeftStairsLockupFix,             laurabow1PatchLeftStairsLockupFix },
+	{  true,    58, "chapel candles persistence",               1, laurabow1SignatureChapelCandlesPersistence,        laurabow1PatchChapelCandlesPersistence },
+	{  true,    99, "disable speed test",                       1, sci01SpeedTestGlobalSignature,                     sci01SpeedTestGlobalPatch },
+	{  true,   236, "tell Lilly about Gertie blocking fix 1/2", 1, laurabow1SignatureTellLillyAboutGerieBlockingFix1, laurabow1PatchTellLillyAboutGertieBlockingFix1 },
+	{  true,   236, "tell Lilly about Gertie blocking fix 2/2", 1, laurabow1SignatureTellLillyAboutGerieBlockingFix2, laurabow1PatchTellLillyAboutGertieBlockingFix2 },
+	{  true,   414, "copy protection random fix",               1, laurabow1SignatureCopyProtectionRandomFix,         laurabow1PatchCopyProtectionRandomFix },
+	{  true,   786, "review notes dialog fix",                  1, laurabow1SignatureReviewNotesDialog,               laurabow1PatchReviewNotesDialog },
+	{  true,   998, "obstacle collision lockups fix",           1, laurabow1SignatureObstacleCollisionLockupsFix,     laurabow1PatchObstacleCollisionLockupsFix },
+	SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
+// Laura Bow 2
+//
+// Moving away the painting in the room with the hidden safe is problematic
+//  for the CD version of the game. safePic::doVerb gets triggered by the mouse-click.
+// This method sets local[0] as signal, which is only meant to get handled, when
+//  the player clicks again to move the painting back. This signal is processed by
+//  the room doit-script.
+// That doit-script checks safePic::cel to be not equal 0 and would then skip over
+//  the "close painting" trigger code. On very fast computers this script may
+//  get called too early (which is the case when running under ScummVM and when
+//  running the game using Sierra SCI in DOS-Box with cycles 15000) and thinks
+//  that it's supposed to move the painting back. Which then results in the painting
+//  getting moved to its original position immediately (which means it won't be possible
+//  to access the safe behind it).
+//
+// We patch the script, so that we check for cel to be not equal 4 (the final cel) and
+//  we also reset the safePic-signal immediately as well.
+//
+// In the floppy version Laura's coordinates are checked directly in rm560::doit
+//  and as soon as she moves, the painting will automatically move to its original position.
+//  This is not the case for the CD version of the game. The painting will only "move" back,
+//  when the player actually exits the room and re-enters.
+//
+// Applies to at least: English PC-CD
+// Responsible method: rm560::doit
+// Fixes bug: #6460
+static const uint16 laurabow2CDSignaturePaintingClosing[] = {
+	0x39, 0x04,                         // pushi 04 (cel)
+	0x76,                               // push0
+	SIG_MAGICDWORD,
+	0x7a,                               // push2
+	0x38, SIG_UINT16(0x0231),           // pushi 0231h (561)
+	0x76,                               // push0
+	0x43, 0x02, 0x04,                   // callk ScriptID, 04 (get export 0 of script 561)
+	0x4a, 0x04,                         // send 04 (gets safePicture::cel)
+	0x18,                               // not
+	0x31, 0x21,                         // bnt [exit]
+	0x38, SIG_UINT16(0x0283),           // pushi 0283h
+	0x76,                               // push0
+	0x7a,                               // push2
+	0x39, 0x20,                         // pushi 20
+	0x76,                               // push0
+	0x43, 0x02, 0x04,                   // callk ScriptID, 04 (get export 0 of script 32)
+	0x4a, 0x04,                         // send 04 (get sHeimlich::room)
+	0x36,                               // push
+	0x81, 0x0b,                         // lag global[b] (current room)
+	0x1c,                               // ne?
+	0x31, 0x0e,                         // bnt [exit]
+	0x35, 0x00,                         // ldi 00
+	0xa3, 0x00,                         // sal local[0] (reset safePic signal)
+	SIG_END
+};
+
+static const uint16 laurabow2CDPatchPaintingClosing[] = {
+	PATCH_ADDTOOFFSET(+2),
+	0x3c,                               // dup (1 additional byte)
+	0x76,                               // push0
+	0x3c,                               // dup (1 additional byte)
+	0xab, 0x00,                         // ssl local[0] (reset safePic signal)
+	0x7a,                               // push2
+	0x38, PATCH_UINT16(0x0231),         // pushi 0231h (561)
+	0x76,                               // push0
+	0x43, 0x02, 0x04,                   // callk ScriptID, 04 (get export 0 of script 561)
+	0x4a, 0x04,                         // send 04 (gets safePicture::cel)
+	0x1a,                               // eq?
+	0x31, 0x1d,                         // bnt [exit]
+	0x38, PATCH_UINT16(0x0283),         // pushi 0283h
+	0x76,                               // push0
+	0x7a,                               // push2
+	0x39, 0x20,                         // pushi 20
+	0x76,                               // push0
+	0x43, 0x02, 0x04,                   // callk ScriptID, 04 (get export 0 of script 32)
+	0x4a, 0x04,                         // send 04 (get sHeimlich::room)
+	0x36,                               // push
+	0x81, 0x0b,                         // lag global[b] (current room)
+	0x1a,                               // eq? (2 opcodes changed, to save 2 bytes)
+	0x2f, 0x0a,                         // bt [exit]
+	PATCH_END
+};
+
+// In the CD version the system menu is disabled for certain rooms. LB2::handsOff is called,
+//  when leaving the room (and in other cases as well). This method remembers the disabled
+//  icons of the icon bar. In the new room LB2::handsOn will get called, which then enables
+//  all icons, but also disabled the ones, that were disabled before.
+//
+// Because of this behaviour certain rooms, that should have the system menu enabled, have
+//  it disabled, when entering those rooms from rooms, where the menu is supposed to be
+//  disabled.
+//
+// We patch this by injecting code into LB2::newRoom (which is called right after a room change)
+//  and reset the global variable there, that normally holds the disabled buttons.
+//
+// This patch may cause side-effects and it's difficult to test, because it affects every room
+//  in the game. At least for the intro, the speakeasy and plenty of rooms in the beginning it
+//  seems to work correctly.
+//
+// Applies to at least: English PC-CD
+// Responsible method: LB2::newRoom, LB2::handsOff, LB2::handsOn
+// Fixes bug: #6440
+static const uint16 laurabow2CDSignatureFixProblematicIconBar[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_UINT16(0x00f1),           // pushi 00f1 (disable) - hardcoded, we only want to patch the CD version
+	0x76,                               // push0
+	0x81, 0x45,                         // lag global[45]
+	0x4a, 0x04,                         // send 04
+	SIG_END
+};
+
+static const uint16 laurabow2CDPatchFixProblematicIconBar[] = {
+	0x35, 0x00,                      // ldi 00
+	0xa1, 0x74,                      // sag global[74]
+	0x35, 0x00,                      // ldi 00 (waste bytes)
+	0x35, 0x00,                      // ldi 00
+	PATCH_END
+};
+
+// LB2 CD responds with the wrong message when asking Yvette about Tut in acts 3+.
+//
+// aYvette:doVerb(6) tests flag 134, which is set when Pippin dies, to determine
+//  which Tut message to display but they got it backwards. One of the messages
+//  has additional dialogue about Pippin's murder.
+//
+// This is a regression introduced by Sierra when they fixed a bug from the floppy
+//  versions where asking Yvette about Tut in act 2 responds with the message
+//  about Pippin's murder which hasn't occurred yet, bug #10723. Sierra correctly
+//  fixed that in Yvette:doVerb in script 93, which applies to act 2, but then went
+//  on to add incorrect code to aYvette:doVerb in script 90, which applies to the
+//  later acts after the murder.
+//
+// We fix this by reversing the flag test so that the correct message is displayed.
+//
+// Applies to: CD version, at least English
+// Responsible method: aYvette:doVerb
+// Fixes bug: #10724
+static const uint16 laurabow2CDSignatureFixYvetteTutResponse[] = {
+	SIG_MAGICDWORD,
+	0x34, SIG_UINT16(0x010f),           // ldi 010f [ tut ]
+	0x1a,                               // eq? [ asked about tut? ]
+	0x30, SIG_UINT16(0x0036),           // bnt 0036
+	0x78,                               // push1
+	0x38, SIG_UINT16(0x0086),           // pushi 0086 [ pippin-dead flag ]
+	0x45, 0x02, 0x02,                   // callb [export 2 of script 0], 02 [ is pippin-dead flag set? ]
+	0x30, SIG_UINT16(0x0016),           // bnt 0016 [ pippin-dead message ]
+	SIG_END
+};
+
+static const uint16 laurabow2CDPatchFixYvetteTutResponse[] = {
+	PATCH_ADDTOOFFSET(+14),
+	0x2e,                               // bt (replace bnt)
+	PATCH_END
+};
+
+// In the CD version, Wolf stands facing the wrong direction in most scenes.
+//  O'Riley also does this in the Old Masters Gallery. Their views were reduced
+//  from nine loops to five in the CD version, but the scripts weren't updated.
+//  They still set the actors' loops to eight instead of four. kAnimate adjusts
+//  invalid cels and the result is usually the last cel in the last loop, which
+//  is the actor standing facing north west.
+//
+// We fix this by setting the correct loop in the CD version so that Wolf and
+//  O'Riley face the direction the scripts request like in the floppy versions.
+//  This patch is only enabled in the CD version since the scripts don't change.
+//
+// Applies to: English CD
+// Responsible methods: sPartysOver:changeState, rm400:init, sHeimlichShoos:changeState
+//                      sEnterNorth:changeState, rm500:init, rm650:init
+static const uint16 laurabow2CDSignatureFixMuseumActorLoops1[] = {
+	0x38, SIG_SELECTOR16(setLoop),      // pushi setLoop
+	0x78,                               // push1
+	0x39, SIG_MAGICDWORD, 0x08,         // pushi 08 [ standing loop in floppy ]
+	0x38, SIG_SELECTOR16(setCel),       // pushi setCel
+	SIG_END
+};
+
+static const uint16 laurabow2CDPatchFixMuseumActorLoops1[] = {
+	PATCH_ADDTOOFFSET(+4),
+	0x39, 0x04,                         // pushi 04 [ standing loop in CD ]
+	PATCH_END
+};
+
+static const uint16 laurabow2CDSignatureFixMuseumActorLoops2[] = {
+	0x39, SIG_SELECTOR8(loop),          // pushi loop
+	0x78,                               // push1
+	SIG_MAGICDWORD,
+	0x39, 0x08,                         // pushi 08 [ standing loop in floppy ]
+	0x39, SIG_SELECTOR8(cel),           // pushi cel
+	SIG_END
+};
+
+static const uint16 laurabow2CDPatchFixMuseumActorLoops2[] = {
+	PATCH_ADDTOOFFSET(+3),
+	0x39, 0x04,                         // pushi 04 [ standing loop in CD ]
+	PATCH_END
+};
+
+// When entering the main museum party room (w/ the golden Egyptian head), Laura
+// is walking a bit into the room automatically. If you press a mouse button
+// while this is happening, you will get stuck inside that room and won't be
+// able to exit it anymore.
+//
+// Users, who played the game w/ a previous version of ScummVM can simply enter
+// the debugger and then enter "send rm350 script 0:0", which will fix the
+// script state.
+//
+// This is caused by the user controls not being locked at that point. Pressing
+// a button will cause the cue from the PolyPath walker to never happen, which
+// then causes sEnterSouth to never dispose itself.
+//
+// User controls are locked in the previous room 335, but controls are unlocked
+// by frontDoor::cue. We do not want to change this, because it could have
+// side-effects. We instead add another LB2::handsOff call inside the script
+// responsible for Laura's walk into the room (sEnterSouth::changeState(0).
+//
+// Applies to at least: English PC-CD, English PC-Floppy, German PC-Floppy
+// Responsible method: sEnterSouth::changeState
+// Fixes bug: (no bug report, from GOG forum post)
+static const uint16 laurabow2SignatureMuseumPartyFixEnteringSouth1[] = {
+	0x3c,                              // dup
+	0x35, 0x00,                        // ldi 00
+	0x1a,                              // eq?
+	0x30, SIG_UINT16(0x0097),          // bnt [state 1 code]
+	SIG_ADDTOOFFSET(+141),             // skip to end of follow-up code
+	0x32, SIG_ADDTOOFFSET(+2),         // jmp [ret] (0x008d for CD, 0x007d for floppy)
+	0x35, 0x01,                        // ldi 01
+	0x65, 0x1a,                        // aTop cycles
+	0x32, SIG_ADDTOOFFSET(+2),         // jmp [ret] (0x0086 for CD, 0x0076 for floppy)
+	// state 1 code
+	0x3c,                              // dup
+	0x35, 0x01,                        // ldi 01
+	0x1a,                              // eq?
+	SIG_MAGICDWORD,
+	0x31, 0x05,                        // bnt [state 2 code]
+	0x35, 0x00,                        // ldi 00
+	0x32, SIG_ADDTOOFFSET(+2),         // jmp [ret] (0x007b for CD, 0x006b for floppy)
+	// state 2 code
+	0x3c,                              // dup
+	SIG_END
+};
+
+static const uint16 laurabow2PatchMuseumPartyFixEnteringSouth1[] = {
+	0x2e, PATCH_UINT16(0x00a6),        // bt [state 2 code] (we skip state 1, because it's a NOP anyways)
+	// state 0 processing
+	0x32, PATCH_UINT16(0x0097),        // jmp 151d [after this ret]
+	PATCH_ADDTOOFFSET(+149),           // skip to end of follow-up code
+	// save 1 byte by replacing jump to [ret] into straight toss/ret
+	0x3a,                              // toss
+	0x48,                              // ret
+
+	// additional code, that gets called right at the start of step 0 processing
+	0x18,                              // not -- this here is where pushi handsOff will be inserted by the second patch
+	0x18,                              // not    offset and handsOff is different for floppy + CD, that's why we do this
+	0x18,                              // not    floppy also does not have a selector table, so we can't go by "handsOff" name
+	0x18,                              // not
+	0x76,                              // push0
+	0x81, 0x01,                        // lag global[1]
+	0x4a, 0x04,                        // send 04
+	0x32, PATCH_UINT16(0xff5e),        // jmp [back to start of step 0 processing]
+	PATCH_END
+};
+
+// Second patch, which only inserts pushi handsOff inside our new code. There
+// is no other way to do this except making 2 full patches for floppy + CD,
+// because handsOff/handsOn is not the same value between floppy + CD *and*
+// floppy doesn't even have a vocab, so we can't figure out the id by
+// ourselves.
+static const uint16 laurabow2SignatureMuseumPartyFixEnteringSouth2[] = {
+	0x18,                              // our injected code
+	0x18,
+	0x18,
+	SIG_ADDTOOFFSET(+92),              // skip to the handsOn code, that we are interested in
+	0x38, SIG_ADDTOOFFSET(+2),         // pushi handsOn (0x0189 for CD, 0x024b for floppy)
+	0x76,                              // push0
+	0x81, 0x01,                        // lag global[1]
+	0x4a, 0x04,                        // send 04
+	0x38, SIG_ADDTOOFFSET(+2),         // pushi 0274h
+	SIG_MAGICDWORD,
+	0x78,                              // push1
+	0x38, SIG_UINT16(0x033f),          // pushi 033f
+	SIG_END
+};
+
+static const uint16 laurabow2PatchMuseumPartyFixEnteringSouth2[] = {
+	0x38, PATCH_GETORIGINALUINT16ADJUST(+96, -1), // pushi handsOff (@handsOn - 1)
+	PATCH_END
+};
+
+// Opening/Closing the east door in the pterodactyl room doesn't check, if it's
+//  locked and will open/close the door internally even when it is.
+//
+// It will get wired shut later in the game by Laura Bow and will be "locked"
+//  because of this. We patch in a check for the locked state. We also add
+//  code, that will set the "locked" state in case our eastDoor-wired-global is
+//  set. This makes the locked state effectively persistent.
+//
+// Applies to at least: English PC-CD, English PC-Floppy
+// Responsible method (CD): eastDoor::doVerb
+// Responsible method (Floppy): eastDoor::<noname300>
+// Fixes bug: #6458 (partly, see additional patch below)
+static const uint16 laurabow2SignatureFixWiredEastDoor[] = {
+	0x30, SIG_UINT16(0x0022),           // bnt [skip hand action]
+	0x67, SIG_ADDTOOFFSET(+1),          // pTos (CD: doorState, Floppy: state)
+	0x35, 0x00,                         // ldi 00
+	0x1a,                               // eq?
+	0x31, 0x08,                         // bnt [close door code]
+	0x78,                               // push1
+	SIG_MAGICDWORD,
+	0x39, 0x63,                         // pushi 63h
+	0x45, 0x04, 0x02,                   // callb [export 4 of script 0], 02 (sets door-bitflag)
+	0x33, 0x06,                         // jmp [super-code]
+	0x78,                               // push1
+	0x39, 0x63,                         // pushi 63h
+	0x45, 0x03, 0x02,                   // callb [export 3 of script 0], 02 (resets door-bitflag)
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi (CD: 011dh, Floppy: 012ch)
+	0x78,                               // push1
+	0x8f, 0x01,                         // lsp param[1]
+	0x59, 0x02,                         // rest 02
+	0x57, SIG_ADDTOOFFSET(+1), 0x06,    // super (CD: LbDoor, Floppy: Door), 06
+	0x33, 0x0b,                         // jmp [ret]
+	SIG_END
+};
+
+static const uint16 laurabow2PatchFixWiredEastDoor[] = {
+	0x31, 0x23,                         // bnt [skip hand action] (saves 1 byte)
+	0x81, 0x61,                         // lag global[97d] (get our eastDoor-wired-global)
+	0x31, 0x04,                         // bnt [skip setting locked property]
+	0x35, 0x01,                         // ldi 01
+	0x65, 0x6a,                         // aTop locked (set eastDoor::locked to 1)
+	0x63, 0x6a,                         // pToa locked (get eastDoor::locked)
+	0x2f, 0x17,                         // bt [skip hand action]
+	0x63, PATCH_GETORIGINALBYTE(+4),    // pToa (CD: doorState, Floppy: state)
+	0x78,                               // push1
+	0x39, 0x63,                         // pushi 63h
+	0x2f, 0x05,                         // bt [close door code]
+	0x45, 0x04, 0x02,                   // callb [export 4 of script 0], 02 (sets door-bitflag)
+	0x33, 0x0b,                         // jmp [super-code]
+	0x45, 0x03, 0x02,                   // callb [export 3 of script 0], 02 (resets door-bitflag)
+	0x33, 0x06,                         // jmp [super-code]
+	PATCH_END
+};
+
+// We patch in code, so that our eastDoor-wired-global will get set to 1.
+//  This way the wired-state won't get lost when exiting room 430.
+//
+// Applies to at least: English PC-CD, English PC-Floppy
+// Responsible method (CD): sWireItShut::changeState
+// Responsible method (Floppy): sWireItShut::<noname144>
+// Fixes bug: #6458 (partly, see additional patch above)
+static const uint16 laurabow2SignatureRememberWiredEastDoor[] = {
+	SIG_MAGICDWORD,
+	0x33, 0x27,                         // jmp [ret]
+	0x3c,                               // dup
+	0x35, 0x06,                         // ldi 06
+	0x1a,                               // eq?
+	0x31, 0x21,                         // bnt [skip step]
+	SIG_END
+};
+
+static const uint16 laurabow2PatchRememberWiredEastDoor[] = {
+	PATCH_ADDTOOFFSET(+2),              // skip jmp [ret]
+	0x34, PATCH_UINT16(0x0001),         // ldi 0001
+	0xa1, PATCH_UINT16(0x0061),         // sag global[97d] (set our eastDoor-wired-global)
+	PATCH_END
+};
+
+// WORKAROUND: Script needed, because of differences in our pathfinding
+// algorithm
+// It's possible to walk through the closed door in room 448 and enter the crate
+//  room before act 5 due to differences in our pathfinding algorithm from Sierra's.
+//  This edge case appears to be due to one of the door's points being one pixel
+//  within the room's walkable boundary, allowing ego to walk through this edge
+//  from certain positions. We work around this by moving the door's point by
+//  two pixels so that it's outside the room's walkable boundary.
+//
+// Applies to: All Floppy and CD versions
+// Responsible method: transomDoor:createPoly
+// Fixes bug: #9952
+static const uint16 laurabow2SignatureFixArmorHallDoorPathfinding[] = {
+	SIG_MAGICDWORD,
+	0x39, 0x50,                         // pushi 50 [ x =  80 ]
+	0x39, 0x7d,                         // pushi 7d [ y = 125 ]
+	SIG_END
+};
+
+static const uint16 laurabow2PatchFixArmorHallDoorPathfinding[] = {
+	PATCH_ADDTOOFFSET(+2),
+	0x39, 0x7f,                         // pushi 7f [ y = 127 ]
+	PATCH_END
+};
+
+// Clicking most inventory items on the Dagger of Amon Ra case in the Egyptian
+//  exhibit errors the floppy versions. The doVerb methods contain nonsensical
+//  instructions that attempt to access a non-existent class and property.
+//  This would silently fail in the original. It was fixed in the CD version.
+//
+// We patch out the illegal class instructions to avoid the error.
+//
+// Applies to: All floppy versions
+// Responsible methods: glass:doVerb, daggerCase:doVerb
+static const uint16 laurabow2SignatureFixDaggerCaseError[] = {
+	0x81, SIG_MAGICDWORD, 0x5b,         // lag 5b
+	0x4a, 0x0a,                         // send 4a
+	0x33, SIG_ADDTOOFFSET(+1),          // jmp [ end of method ]
+	0x50, SIG_ADDTOOFFSET(+2),          // class ????
+	SIG_END
+};
+
+static const uint16 laurabow2PatchFixDaggerCaseError[] = {
+	PATCH_ADDTOOFFSET(+6),
+	0x18,                               // not [ acc = 1 ]
+	0x3a,                               // toss
+	0x48,                               // ret
+	PATCH_END
+};
+
+// The crate room (room 460) in act 5 locks up the game if you enter from the
+//  elevator (room 660), swing the hanging crate, and then attempt to leave
+//  back through the elevator door.
+//
+// The state of the wall crate that blocks the elevator door is tracked by
+//  setting local[0] to 1 when you push it out of the way, but Sierra forgot
+//  to reinitialize local[0] when you re-enter via the elevator door, causing
+//  it to be out of sync with the room state. When you then swing the hanging
+//  crate, sSwingIt:changeState(6) tests local[0] to see which polygon it
+//  should set as the room's obstacle and incorrectly uses the one that blocks
+//  both doors. Attempting to use the elevator door then locks up the game as
+//  the obstacle polygon prevents ego from reaching the destination.
+//
+// Someone noticed that local[0] wasn't always initialized as
+//  shoveCrate:doVerb(4) tests both local[0] and the previous room to see if it
+//  was the elevator.
+//
+// We fix this by setting local[0] to 1 if the previous room was the elevator
+//  during sSwingIt:changeState(3), just in time before it gets tested in
+//  sSwingIt:changeState(6). Luckily for us, the handlers for states 3 and 4
+//  don't do anything but load zero, making them two consecutive conditions
+//  of no-ops. By merging them into a single condition for state 3 we have
+//  a whopping 13 bytes available to add code to set local[0] correctly.
+//
+// Applies to: All Floppy and CD versions
+// Fixes bug: #10701
+static const uint16 laurabow2SignatureFixCrateRoomEastDoorLockup[] = {
+	0x1a,                               // eq? [ state 3? ]
+	SIG_MAGICDWORD,
+	0x31, 0x05,                         // bnt [ state 4 ]
+	0x35, 0x00,                         // ldi 0
+	0x32, SIG_ADDTOOFFSET(+2),          // jmp [ exit switch. floppy: b3, cd: bb ]
+	0x3c,                               // dup
+	0x35, 0x04,                         // ldi 4
+	0x1a,                               // eq? [ state 4? ]
+	0x31, 0x05,                         // bnt [ state 5 ]
+	SIG_END
+};
+
+static const uint16 laurabow2PatchFixCrateRoomEastDoorLockup[] = {
+	PATCH_ADDTOOFFSET(+1),              // eq? [ state 3? ]
+	0x31, 0x10,                         // bnt [ state 5 ]
+	0x89, 0x0c,                         // lsg global[0c] [ previous room # ]
+	0x34, PATCH_UINT16(0x0294),         // ldi 660d [ elevator room # ]
+	0x1a,                               // eq?
+	0x8b, 0x00,                         // lsl local[0]
+	0x02,                               // add
+	0xa3, 0x00,                         // sal local[0] [ local[0] += (global[0c] == 660d) ]
+	PATCH_END
+};
+
+// Ego can get stuck in the elevator (room 660) by walking to the lower left.
+//  This also happens in Sierra's interpreter. We adjust the room's obstacle
+//  polygon so that ego can't reach the problematic corner positions.
+//  This is a heap patch for the coordinates used in poly2660a:points.
+//
+// Applies to: All Floppy and CD versions
+// Fixes bug: #10702
+static const uint16 laurabow2SignatureFixElevatorLockup[] = {
+	SIG_MAGICDWORD,
+	SIG_UINT16(0x008b),                 // x = 139d
+	SIG_UINT16(0x0072),                 // y = 114d
+	SIG_UINT16(0x007b),                 // x = 123d
+	SIG_UINT16(0x008d),                 // y = 141d
+	SIG_END
+};
+
+static const uint16 laurabow2PatchFixElevatorLockup[] = {
+	PATCH_UINT16(0x008f),               // x = 143d
+	PATCH_ADDTOOFFSET(+4),
+	PATCH_UINT16(0x00aa),               // y = 170d
+	PATCH_END
+};
+
+// The act 4 back rub scene in Yvette's (room 550) locks up the game when
+//  entered from Carrington's (room 560) instead of the hallway (room 510).
+//
+// The difference is that entering from the hallway sets the room script to
+//  eRS (Enter Room Script) and entering from Carrington's doesn't set any
+//  room script. When sBackRubInterrupted moves ego off screen to the south,
+//  lRS (Leave Room Script) is run by LBRoom:doit if a room script isn't set,
+//  and lRS:changState(0) calls handsOff. Since control is already disabled,
+//  this unexpected second handsOff causes handsOn(1) to restore the disabled
+//  state in the hallway and the user never regains control.
+//
+// We fix this by setting sBackRubInterrupted as the room's script instead of
+//  backRub's script in backRub:doVerb/<noname300>(0). The script executes the
+//  same but having it set as the room script prevents LBRoom:doit from running
+//  lRS which prevents the extra handsOff. This patch overwrites backRub's
+//  default verb handler but that's okay because that code never executes.
+//  doVerb is only called by sBackRubViewing:changeState(6) which passes verb 0.
+//  The entire scene is in handsOff mode so the user can't send any verbs.
+//
+// Affects: All Floppy and CD versions
+// Responsible method: backRub:doVerb/<noname300> in script 550
+// Fixes bug: #10729
+static const uint16 laurabow2SignatureFixBackRubEastEntranceLockup[] = {
+	SIG_MAGICDWORD,
+	0x31, 0x0c,                         // bnt 0c    [ unused default verb handler ]
+	0x38, SIG_UINT16(0x0092),           // pushi 0092 [ setScript/<noname146> ]
+	0x78,                               // push1
+	0x72, SIG_ADDTOOFFSET(+2),          // lofsa sBackRubInterrupted [ cd: 0c94, floppy: 0c70 ]
+	0x36,                               // push
+	0x54, 0x06,                         // self 6 [ self:setScript sBackRubInterrupted ]


Commit: 3e953e42c0a0c156818c8a4e16f34dfc24cf818b
    https://github.com/scummvm/scummvm/commit/3e953e42c0a0c156818c8a4e16f34dfc24cf818b
Author: Hubert Maier (raziel- at users.noreply.github.com)
Date: 2022-11-01T17:09:25+02:00

Commit Message:
ULTIMA: Remove superflous space

Changed paths:
    engines/ultima/ultima8/world/item_selection_process.h


diff --git a/engines/ultima/ultima8/world/item_selection_process.h b/engines/ultima/ultima8/world/item_selection_process.h
index 26ff99d2a5d..74b92583d62 100644
--- a/engines/ultima/ultima8/world/item_selection_process.h
+++ b/engines/ultima/ultima8/world/item_selection_process.h
@@ -42,7 +42,7 @@ public:
 
 	void run() override;
 
-	//! Select the next item.  If grab is true, pick up loose items now.
+	//! Select the next item. If grab is true, pick up loose items now.
 	bool selectNextItem(bool grab);
 
 	//! Clear the selector sprite




More information about the Scummvm-git-logs mailing list