[Scummvm-git-logs] scummvm branch-2-5 -> cdd463a37afe43b76b565a9dd405ebb57d930ca8

sluicebox noreply at scummvm.org
Sat Nov 27 04:50:47 UTC 2021


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

Summary:
7468a2e17f CLOUD: Fix crash on HTTP request with unparsed path
a1edf88adb SCI: Fix kSetPort return value
5bbf5bd603 SCI: Remove GUIO_NOSPEECH from HOYLE4
11d1088298 SCI: Remove redundant check
b44afb45e6 GUI: Don't apply values from disabled subtitle toggle
ff357137b0 SCI: Apply workarounds to Mac games without object names
ffbc5f37b7 SCI: Add LAURABOW2 workaround for uninit read in museum
e66e6c374c SCI: Handle HOYLE4 Mac palette endianness
e3ae9057ed SCI32: Create kScummVMSleep for script patches
2740f075d4 SCI32; Improve KQ7 cursor script patch
ca03effcb5 SCI32: Fix GK2 "bad" cursor not appearing
75f7151676 SCI: Clarify passing of parameter: pass instead of parse for `class_table` debug command.
2dcc62bfe3 SCI: Fix class_table debugging command output
c8fb104306 SCI: Add uninit read workarounds for QFG3, QFG4
2387712453 SCI32: Fix QFG4 upgraded inventory views
71875456ab SCI32: Add QFG4 uninit param read workaround
55488baecd SCI: Update QFG3 uninit read workaround
a50d84a32b WIN32: Fix build when USE_WINDBG is defined
ebfecf8487 SCI: Fix HOYLE4 Gin Rummy undercut sound
5a63f261b6 SCI: Only throttle kGameIsRestarting from game loops
f08f2a52fc CREATE_PROJECT: Add DETECTION_FULL feature
c67adbb301 CREATE_PROJECT: Add --include-dir and --library-dir
2021a1495c SCI32: Remove kFileIOReadString warning
2830063c0e VIDEO: QuickTime comments, mild cleanup
6a55907932 VIDEO: Limit QuickTime workaround to Riven
f4aa6b9578 VIDEO: Fix QuickTime decoding of edits with mediaTime
4180555675 SCI: Fix KQ6 Mac inconsistent timing in opening movie
cdd463a37a VIDEO: Fix QuickTime decoding when color depth is 32


Commit: 7468a2e17fb0bbdc456412eb1b665b1d75ededf7
    https://github.com/scummvm/scummvm/commit/7468a2e17fb0bbdc456412eb1b665b1d75ededf7
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:05-07:00

Commit Message:
CLOUD: Fix crash on HTTP request with unparsed path

Occurred during an nmap scan. Fixes bug #12997

Changed paths:
    backends/networking/sdl_net/handlers/resourcehandler.cpp


diff --git a/backends/networking/sdl_net/handlers/resourcehandler.cpp b/backends/networking/sdl_net/handlers/resourcehandler.cpp
index ecd8eb296a..40c414da71 100644
--- a/backends/networking/sdl_net/handlers/resourcehandler.cpp
+++ b/backends/networking/sdl_net/handlers/resourcehandler.cpp
@@ -54,10 +54,13 @@ const char *ResourceHandler::determineMimeType(Common::String &filename) {
 
 void ResourceHandler::handle(Client &client) {
 	Common::String filename = client.path();
-	filename.deleteChar(0);
+    
+	// remove leading slash
+	if (filename.size() > 0 && filename[0] == '/')
+		filename.deleteChar(0);
 
 	// if archive hidden file is requested, ignore
-	if (filename.size() && filename[0] == '.')
+	if (filename.size() > 0 && filename[0] == '.')
 		return;
 
 	// if file not found, don't set handler either


Commit: a1edf88adb1197b0e6732f02b24db3d0d4978908
    https://github.com/scummvm/scummvm/commit/a1edf88adb1197b0e6732f02b24db3d0d4978908
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:05-07:00

Commit Message:
SCI: Fix kSetPort return value

SSCI doesn't return zero; it doesn't return anything. This shouldn't
affect any games since no scripts should depend on a non-existent
return value, but this discrepancy came up while investigating a
fan script that accidentally relies on this.

Changed paths:
    engines/sci/engine/kgraphics.cpp


diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index a1d8fd70cc..2ed31016c6 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -1119,7 +1119,7 @@ reg_t kSetPort(EngineState *s, int argc, reg_t *argv) {
 		error("SetPort was called with %d parameters", argc);
 		break;
 	}
-	return NULL_REG;
+	return s->r_acc;
 }
 
 reg_t kDrawCel(EngineState *s, int argc, reg_t *argv) {


Commit: 5bbf5bd6030fe7015697f9b7c8e4ca4f6703fe00
    https://github.com/scummvm/scummvm/commit/5bbf5bd6030fe7015697f9b7c8e4ca4f6703fe00
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:05-07:00

Commit Message:
SCI: Remove GUIO_NOSPEECH from HOYLE4

HOYLE4 has speech. Bug #13007

Changed paths:
    engines/sci/detection_tables.h


diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 31e5f8aec7..f715ba6081 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -31,6 +31,7 @@ namespace Sci {
 #define GUIO_STD16_MAC GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_MIDI_MODE, GAMEOPTION_RGB_RENDERING)
 #define GUIO_STD16_MAC_UNDITHER GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_MIDI_MODE, GAMEOPTION_RGB_RENDERING)
 #define GUIO_STD16_MAC_PALETTEMODS GUIO6(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_MIDI_MODE, GAMEOPTION_RGB_RENDERING, GAMEOPTION_PALETTE_MODS)
+#define GUIO_STD16_MAC_SPEECH GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_MIDI_MODE, GAMEOPTION_RGB_RENDERING)
 
 #define FANMADE_L(name, resMapMd5, resMapSize, resMd5, resSize, resVol, lang) \
 	{"sci-fanmade", name, { \
@@ -1292,19 +1293,21 @@ static const struct ADGameDescription SciGameDescriptions[] = {
 
 	// Hoyle 4 (Hoyle Classic Card Games) - English DOS/Win
 	// Supplied by abevi in bug report #5131
+	// Although this is a floppy game, it does have speech. (bug #13007)
 	{"hoyle4", "", {
 		{"resource.map", 0, "2b577c975cc8d8d43f61b6a756129fe3", 4352},
 		{"resource.000", 0, "43e2c15ce436aab611a462ad0603e12d", 2000132},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformDOS, 0, GUIO_STD16	},
+		Common::EN_ANY, Common::kPlatformDOS, 0, GUIO_STD16_SPEECH	},
 
 	// Hoyle 4 (Hoyle Classic Card Games) - English Macintosh Floppy
 	// VERSION file reports "2.0"
+	// Although this is a floppy game, it does have speech. (bug #13007)
 	{"hoyle4", "", {
 		{"Data1", 0, "99575fae4579540a314bbedd72d51e8c", 7682887},
 		{"Data2", 0, "7d4bf5bdf3c02edbf35cb8471c84ec13", 1539134},
 		AD_LISTEND},
-		Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO_STD16_MAC },
+		Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO_STD16_MAC_SPEECH },
 
 #define GUIO_HOYLE5 GUIO5(GUIO_NOMIDI, \
 						  GUIO_NOLAUNCHLOAD, \


Commit: 11d1088298058c025ffdf8bf741d9c4f2ef6044c
    https://github.com/scummvm/scummvm/commit/11d1088298058c025ffdf8bf741d9c4f2ef6044c
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:05-07:00

Commit Message:
SCI: Remove redundant check

Changed paths:
    engines/sci/engine/scriptdebug.cpp


diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 22a6056680..93bc908f2d 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -1122,8 +1122,7 @@ void logBacktrace() {
 
 		switch (call.type) {
 		case EXEC_STACK_TYPE_CALL: // Normal function
-			if (call.type == EXEC_STACK_TYPE_CALL)
-				con->debugPrintf(" %x: script %d - ", i, s->_segMan->getScript(call.addr.pc.getSegment())->getScriptNumber());
+			con->debugPrintf(" %x: script %d - ", i, s->_segMan->getScript(call.addr.pc.getSegment())->getScriptNumber());
 
 			if (call.debugSelector != -1) {
 				con->debugPrintf("%s::%s(", objname, g_sci->getKernel()->getSelectorName(call.debugSelector).c_str());


Commit: b44afb45e6b1994d11d3360412859ab90be5890a
    https://github.com/scummvm/scummvm/commit/b44afb45e6b1994d11d3360412859ab90be5890a
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:05-07:00

Commit Message:
GUI: Don't apply values from disabled subtitle toggle

When the subtitle toggle controls are disabled for a game, don't
read the value and then set config values based on it.
This caused "Override global audio settings" to always set "subtitles"
and "mute_speech" even when the controls were disabled.

Fixes bug #13007 where "Override global audio settings" always
mutes the speech clips in Hoyle4.

Changed paths:
    gui/options.cpp
    gui/options.h


diff --git a/gui/options.cpp b/gui/options.cpp
index d62ed5db6a..f817e347f3 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -231,6 +231,7 @@ void OptionsDialog::init() {
 	_speechVolumeLabel = nullptr;
 	_muteCheckbox = nullptr;
 	_enableSubtitleSettings = false;
+	_enableSubtitleToggle = false;
 	_subToggleDesc = nullptr;
 	_subToggleGroup = nullptr;
 	_subToggleSubOnly = nullptr;
@@ -909,11 +910,9 @@ void OptionsDialog::apply() {
 	// Subtitle options
 	if (_subToggleGroup) {
 		if (_enableSubtitleSettings) {
-			bool subtitles, speech_mute;
-			int talkspeed;
-			int sliderMaxValue = _subSpeedSlider->getMaxValue();
-
-			switch (_subToggleGroup->getValue()) {
+			if (_enableSubtitleToggle) {
+				bool subtitles, speech_mute;
+				switch (_subToggleGroup->getValue()) {
 				case kSubtitlesSpeech:
 					subtitles = speech_mute = false;
 					break;
@@ -925,14 +924,19 @@ void OptionsDialog::apply() {
 				default:
 					subtitles = speech_mute = true;
 					break;
-			}
+				}
 
-			ConfMan.setBool("subtitles", subtitles, _domain);
-			ConfMan.setBool("speech_mute", speech_mute, _domain);
+				ConfMan.setBool("subtitles", subtitles, _domain);
+				ConfMan.setBool("speech_mute", speech_mute, _domain);
+			} else {
+				ConfMan.removeKey("subtitles", _domain);
+				ConfMan.removeKey("speech_mute", _domain);
+			}
 
 			// Engines that reuse the subtitle speed widget set their own max value.
 			// Scale the config value accordingly (see addSubtitleControls)
-			talkspeed = (_subSpeedSlider->getValue() * 255 + sliderMaxValue / 2) / sliderMaxValue;
+			int sliderMaxValue = _subSpeedSlider->getMaxValue();
+			int talkspeed = (_subSpeedSlider->getValue() * 255 + sliderMaxValue / 2) / sliderMaxValue;
 			ConfMan.setInt("talkspeed", talkspeed, _domain);
 
 		} else {
@@ -1218,6 +1222,7 @@ void OptionsDialog::setSubtitleSettingsState(bool enabled) {
 	if ((_guioptions.contains(GUIO_NOSUBTITLES)) || (_guioptions.contains(GUIO_NOSPEECH)))
 		ena = false;
 
+	_enableSubtitleToggle = ena;
 	_subToggleGroup->setEnabled(ena);
 	_subToggleDesc->setEnabled(ena);
 
@@ -1678,6 +1683,7 @@ void OptionsDialog::addSubtitleControls(GuiObject *boss, const Common::String &p
 	_subSpeedLabel->setFlags(WIDGET_CLEARBG);
 
 	_enableSubtitleSettings = true;
+	_enableSubtitleToggle = true;
 }
 
 void OptionsDialog::addVolumeControls(GuiObject *boss, const Common::String &prefix) {
diff --git a/gui/options.h b/gui/options.h
index 7a189a42d6..175a4dd21e 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -208,6 +208,7 @@ private:
 	//
 	int getSubtitleMode(bool subtitles, bool speech_mute);
 	bool _enableSubtitleSettings;
+	bool _enableSubtitleToggle;
 	StaticTextWidget *_subToggleDesc;
 	RadiobuttonGroup *_subToggleGroup;
 	RadiobuttonWidget *_subToggleSubOnly;


Commit: ff357137b0e67511248afdc907ee8cb9526a36fe
    https://github.com/scummvm/scummvm/commit/ff357137b0e67511248afdc907ee8cb9526a36fe
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:05-07:00

Commit Message:
SCI: Apply workarounds to Mac games without object names

Restore object names in QFG1VGA workarounds that were removed to
accommodate the Mac version. Instead, don't match object names
on games that are known to not have them, since there are several.

Fixes workarounds not being applied to HOYLE4 Mac and LSL6 Mac.

Changed paths:
    engines/sci/engine/features.cpp
    engines/sci/engine/features.h
    engines/sci/engine/workarounds.cpp


diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index 910bbbb715..5279d2bb94 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -838,4 +838,16 @@ bool GameFeatures::useEarlyGetLongestTextCalculations() const {
 	}
 }
 
+bool GameFeatures::hasScriptObjectNames() const {
+	switch (g_sci->getGameId()) {
+	case GID_HOYLE4:
+	case GID_LSL6:
+	case GID_QFG1VGA:
+		return (g_sci->getPlatform() != Common::kPlatformMacintosh);
+	
+	default:
+		return true;
+	}
+}
+
 } // End of namespace Sci
diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h
index 3c0893fd6a..73ab28e55f 100644
--- a/engines/sci/engine/features.h
+++ b/engines/sci/engine/features.h
@@ -268,6 +268,14 @@ public:
 
 	bool useEarlyGetLongestTextCalculations() const;
 
+	/**
+	 * Several SCI1.1 Macintosh games have empty strings for almost all of the
+	 * object names in the script resources.
+	 *
+	 * @return true if the game's object names aren't empty strings.
+	 */
+	bool hasScriptObjectNames() const;
+
 private:
 	reg_t getDetectionAddr(const Common::String &objName, Selector slc, int methodNum = -1);
 
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 566dbac815..8bef0ee72a 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -20,6 +20,7 @@
  *
  */
 
+#include "sci/engine/features.h"
 #include "sci/engine/kernel.h"
 #include "sci/engine/object.h"
 #include "sci/engine/state.h"
@@ -86,7 +87,7 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = {
 	{ GID_MOTHERGOOSE256,  -1,    4,  0,              "rm004", "doit",                            NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // op_or: when going north and reaching the castle (rooms 4 and 37) - bug #5101
 	{ GID_MOTHERGOOSEHIRES,90,   90,  0,      "newGameButton", "select",                          NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // op_ge: MUMG Deluxe, when selecting "New Game" in the main menu. It tries to compare an integer with a list. Needs to return false for the game to continue.
 	{ GID_PHANTASMAGORIA, 902,    0,  0,                   "", "export 7",                        NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // op_shr: when starting a chapter in Phantasmagoria
-	{ GID_QFG1VGA,        301,  928,  0,                 NULL, "init",                            NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // op_div: when entering the inn, Blink:init called with 1 parameter, but 2nd parameter is used for div which happens to be an object. NULL object name as Mac version has none.
+	{ GID_QFG1VGA,        301,  928,  0,              "Blink", "init",                            NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // op_div: when entering the inn, Blink:init called with 1 parameter, but 2nd parameter is used for div which happens to be an object.
 	{ GID_QFG2,           200,  200,  0,              "astro", "messages",                        NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // op_lsi: when getting asked for your name by the astrologer - bug #5152
 	{ GID_QFG3,           780,  999,  0,                   "", "export 6",                        NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // op_add: trying to talk to yourself at the top of the giant tree - bug #6692
 	{ GID_TORIN,        51400,64928,  0,              "Blink", "init",                            NULL,     0,     0, { WORKAROUND_FAKE,   1 } }, // op_div: when Lycentia knocks Torin out after he removes her collar
@@ -515,8 +516,8 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
 	{ GID_PQSWAT,       2990,  2990,  0,    "talkToSchienbly", "changeState",                     NULL,     1,     1, { WORKAROUND_FAKE,   0 } }, // When the video of Schienbly talking for the first time ends
 	{ GID_QFG1,           -1,   210,  0,          "Encounter", "init",           sig_uninitread_qfg1_1,     0,     0, { WORKAROUND_FAKE,   0 } }, // qfg1/hq1: going to the brigands hideout
 	{ GID_QFG1VGA,        -1,   210,  0,          "Encounter", "init",        sig_uninitread_qfg1vga_1,     0,     0, { WORKAROUND_FAKE,   0 } }, // qfg1vga: going to the brigands hideout - bug #5515
-	{ GID_QFG1VGA,        -1,   210,  0,                 NULL, "init",        sig_uninitread_qfg1vga_2,     0,     0, { WORKAROUND_FAKE,   0 } }, // qfg1vga mac: going to the brigands hideout - bug #5515. object is "Encounter" but Mac version has blank names
-	{ GID_QFG1VGA,        58,    58,  0,                 NULL, "doVerb",                          NULL,     0,     0, { WORKAROUND_FAKE,  18 } }, // qfg1vga: casting "detect magic" at giant's cave, temp 0 used instead of spell number. object is "rm58" but Mac version has blank names
+	{ GID_QFG1VGA,        -1,   210,  0,          "Encounter", "init",        sig_uninitread_qfg1vga_2,     0,     0, { WORKAROUND_FAKE,   0 } }, // qfg1vga mac: going to the brigands hideout - bug #5515
+	{ GID_QFG1VGA,        58,    58,  0,               "rm58", "doVerb",                          NULL,     0,     0, { WORKAROUND_FAKE,  18 } }, // qfg1vga: casting "detect magic" at giant's cave, temp 0 used instead of spell number
 	{ GID_QFG1VGA,        96,    96,  0,                 NULL, "changeState",                     NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // qfg1vga mac: when yorick throws an object
 	{ GID_QFG1VGA,       320,   320,  0,                 NULL, "changeState",                     NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // qfg1vga mac: first time entering room 320 when centaur offers fruits and vegetables
 	{ GID_QFG2,           -1,    71,  0,        "theInvSheet", "doit",                            NULL,     1,     1, { WORKAROUND_FAKE,   0 } }, // accessing the inventory
@@ -1187,7 +1188,7 @@ SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroun
 						&& ((workaround->scriptNr == -1) || (workaround->scriptNr == curScriptNr))
 						&& ((workaround->roomNr == -1) || (workaround->roomNr == curRoomNumber))
 						&& ((workaround->inheritanceLevel == -1) || (workaround->inheritanceLevel == inheritanceLevel))
-						&& objectNameMatches
+						&& (objectNameMatches || !g_sci->_features->hasScriptObjectNames())
 						&& workaround->methodName == g_sci->getSciLanguageString(curMethodName, K_LANG_ENGLISH)
 						&& ((workaround->fromIndex == -1) || ((workaround->fromIndex <= index) && (workaround->toIndex >= index)))) {
 					// Workaround found


Commit: ffbc5f37b7d3e2a1f358d3aafa392bc0fd5b2f91
    https://github.com/scummvm/scummvm/commit/ffbc5f37b7d3e2a1f358d3aafa392bc0fd5b2f91
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI: Add LAURABOW2 workaround for uninit read in museum

Prevents a warning that frequently occurs during most of the game
as actors walk around the museum.

Changed paths:
    engines/sci/engine/workarounds.cpp


diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 8bef0ee72a..b6937fa107 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -352,6 +352,7 @@ const SciWorkaroundEntry uninitializedReadForParamWorkarounds[] = {
 	{ GID_HOYLE5,         -1,    15, -1,               "Hand", "add",                             NULL,     1,     1,{ WORKAROUND_FAKE,   0 } }, // When the game adds cards to your hand in any mini-game
 	{ GID_HOYLE5,        700,   730,  0,                 NULL, "runningSuit",                     NULL,     2,     2,{ WORKAROUND_FAKE,   0 } }, // when an opponent is playing in Bridge
 	{ GID_HOYLE5,       1100,    22, -1,           "HandPile", "show",                            NULL,     1,     1,{ WORKAROUND_FAKE,   0 } }, // when showing money piles in Poker
+	{ GID_LAURABOW2,      -1,    90,  0,          "MuseumRgn", "crowdInRoom",                     NULL,     3,     4,{ WORKAROUND_FAKE,   0 } }, // When actors walk around the museum. Out-of-bounds parameters are read but not used. Doesn't matter, but generates a lot of warnings.
 	{ GID_PHANTASMAGORIA2,-1, 63019,  0,     "WynDocTextView", "cue",                             NULL,     2,     2,{ WORKAROUND_FAKE,   0 } }, // When dragging the slider next to an e-mail message
 	{ GID_SHIVERS,        -1, 64918,  0,                "Str", "strip",                           NULL,     1,     1,{ WORKAROUND_FAKE,   0 } }, // When starting a new game and entering a name
 	{ GID_SQ4,            35,   928,  0,           "Narrator", "say",                             NULL,     1,     1,{ WORKAROUND_FAKE,  11 } }, // Clicking smell on sidewalk, fixes message due to missing say parameter in sidewalk1:doVerb(6) - bug #10917


Commit: e66e6c374cf42efb13c18b805688a8f98ad73af8
    https://github.com/scummvm/scummvm/commit/e66e6c374cf42efb13c18b805688a8f98ad73af8
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI: Handle HOYLE4 Mac palette endianness

Changed paths:
    engines/sci/graphics/palette.cpp


diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 21772b8a6f..d8b2f93cb9 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -159,14 +159,20 @@ void GfxPalette::createFromData(const SciSpan<const byte> &data, Palette *palett
 		// SCI0/SCI1 palette
 		palFormat = SCI_PAL_FORMAT_VARIABLE; // CONSTANT;
 		palOffset = 260;
-		palColorStart = 0; palColorCount = 256;
-		//memcpy(&paletteOut->mapping, data, 256);
+		palColorStart = 0;
+		palColorCount = 256;
 	} else {
 		// SCI1.1 palette
 		palFormat = data[32];
 		palOffset = 37;
 		palColorStart = data[25];
-		palColorCount = data.getUint16SEAt(29);
+		if (g_sci->getGameId() != GID_HOYLE4) {
+			palColorCount = data.getUint16SEAt(29);
+		} else {
+			// HOYLE4's SCI1.1 palettes are little endian even in
+			// the Mac version, unlike every other SCI1.1 Mac game.
+			palColorCount = data.getUint16LEAt(29);
+		}
 	}
 
 	switch (palFormat) {


Commit: e3ae9057eda13c3c00c7ba7e3e4afdd863c73931
    https://github.com/scummvm/scummvm/commit/e3ae9057eda13c3c00c7ba7e3e4afdd863c73931
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI32: Create kScummVMSleep for script patches

We have several SCI32 script patches that replace kGetTime spin loops
with calls to kWait for the intended delay. This prevents blocking
the main thread and allows ScummVM to be responsive and update the
screen. But kWait isn't a simple sleep, it's a throttling function,
and the duration that it sleeps (if any) is determined by the time
since it was last called. kWait was only in SCI16 interpreters so it
had to be restored to SCI32 and this required a further workaround
for Phant2 compatibility.

Now we have a dedicated custom kernel function, kScummVMSleep, which
does a simple sleep so that SCI32 script patch delays are consistent
and the Phant2 workaround isn't needed. This approach is similar to
kScummVMSaveLoad.

Changed paths:
    engines/sci/engine/guest_additions.cpp
    engines/sci/engine/kernel.cpp
    engines/sci/engine/kernel.h
    engines/sci/engine/kernel_tables.h
    engines/sci/engine/kgraphics.cpp
    engines/sci/engine/script_patches.cpp


diff --git a/engines/sci/engine/guest_additions.cpp b/engines/sci/engine/guest_additions.cpp
index 49ba1a9187..2c4e67d7d0 100644
--- a/engines/sci/engine/guest_additions.cpp
+++ b/engines/sci/engine/guest_additions.cpp
@@ -292,15 +292,6 @@ bool GuestAdditions::kWaitHook() const {
 		return false;
 	}
 
-	// kWait cannot be used in Phant2 for delayed restore because it is
-	// called during the fade-in of music in the intro room, before graphics
-	// are fully initialized, which causes "Click to continue" text to be
-	// brokenly drawn over the game and then crashes the engine on the next
-	// room transition
-	if (g_sci->getGameId() == GID_PHANTASMAGORIA2) {
-		return false;
-	}
-
 	return g_sci->_guestAdditions->restoreFromLauncher();
 }
 
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index b199a9946a..f4d12c0a9f 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -865,9 +865,8 @@ void Kernel::loadKernelNames(GameFeatures *features) {
 			_kernelNames[id] = "Dummy";
 		}
 
-		// Used by Hoyle5 script patches to remove CPU spinning on kGetTime
-		// (this repurposes the existing SCI16 kWait call that was removed in SCI32)
-		_kernelNames[kScummVMWaitId] = "Wait";
+		// Used by SCI32 script patches to remove CPU spinning on kGetTime
+		_kernelNames[kScummVMSleepId] = "ScummVMSleep";
 
 		// Used by GuestAdditions to support integrated save/load dialogue
 		_kernelNames[kScummVMSaveLoadId] = "ScummVMSaveLoad";
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index d64b719a85..5462c4be48 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -105,10 +105,13 @@ struct SciWorkaroundEntry;	// from workarounds.h
 
 // ---- Kernel signatures -----------------------------------------------------
 
+#ifdef ENABLE_SCI32
+// Kernel functions that have been added for ScummVM script patches to call
 enum {
-	kScummVMWaitId     = 0xe0,
-	kScummVMSaveLoadId = 0xe1
+	kScummVMSleepId    = 0xe0, // sleeps for a delay while remaining responsive
+	kScummVMSaveLoadId = 0xe1  // launches ScummVM's save/load dialog
 };
+#endif
 
 // internal kernel signature data
 enum {
@@ -496,7 +499,6 @@ reg_t kGetSaveFiles32(EngineState *s, int argc, reg_t *argv);
 reg_t kCheckSaveGame32(EngineState *s, int argc, reg_t *argv);
 reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv);
 reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv);
-reg_t kScummVMSaveLoad(EngineState *s, int argc, reg_t *argv);
 
 reg_t kSetHotRectangles(EngineState *s, int argc, reg_t *argv);
 reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv);
@@ -668,6 +670,10 @@ reg_t kPlayDuckClose(EngineState *s, int argc, reg_t *argv);
 reg_t kPlayDuckSetVolume(EngineState *s, int argc, reg_t *argv);
 reg_t kWebConnect(EngineState *s, int argc, reg_t *argv);
 reg_t kWinExec(EngineState *s, int argc, reg_t *argv);
+
+// SCI32 custom ScummVM kernel functions
+reg_t kScummVMSleep(EngineState *s, int argc, reg_t *argv);
+reg_t kScummVMSaveLoad(EngineState *s, int argc, reg_t *argv);
 #endif
 
 reg_t kDoSoundInit(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 8079ad11d3..9808179fec 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -833,6 +833,9 @@ static SciKernelMapEntry s_kernelMap[] = {
 #endif
 	{ MAP_CALL(Show),              SIG_EVERYWHERE,           "i",                     NULL,            NULL },
 	{ MAP_CALL(SinDiv),            SIG_EVERYWHERE,           "ii",                    NULL,            NULL },
+#ifdef ENABLE_SCI32
+	{ MAP_CALL(ScummVMSleep),      SIG_SCI32, SIGFOR_ALL,    "i",                     NULL,            NULL },
+#endif
 	{ MAP_CALL(Sort),              SIG_EVERYWHERE,           "ooo",                   NULL,            NULL },
 	{ MAP_CALL(Sqrt),              SIG_EVERYWHERE,           "i",                     NULL,            NULL },
 	{ MAP_CALL(StrAt),             SIG_EVERYWHERE,           "ri(i)",                 NULL,            kStrAt_workarounds },
@@ -855,7 +858,7 @@ static SciKernelMapEntry s_kernelMap[] = {
 	{ MAP_CALL(UnLoad),            SIG_EVERYWHERE,           "i[ir!]",                NULL,            kUnLoad_workarounds },
 	// ^ We allow invalid references here (e.g. bug #6600), since they will be invalidated anyway by the call itself
 	{ MAP_CALL(ValidPath),         SIG_EVERYWHERE,           "r",                     NULL,            NULL },
-	{ MAP_CALL(Wait),              SIG_EVERYWHERE,           "i",                     NULL,            NULL },
+	{ MAP_CALL(Wait),              SIG_SCI16, SIGFOR_ALL,    "i",                     NULL,            NULL },
 
 	// Unimplemented SCI0-SCI1.1 unused functions, always mapped to kDummy
 	{ MAP_DUMMY(InspectObj),      SIG_EVERYWHERE,           "(.*)",                  NULL,            NULL },
@@ -1445,7 +1448,7 @@ static const char *const sci21_default_knames[] = {
 	/*0x4c*/ "ScrollWindow",	// Dummy in SCI3
 	/*0x4d*/ "Dummy",
 	/*0x4e*/ "Dummy",
-	/*0x4f*/ "Dummy",           // Replaced with kWait for Hoyle5 in ScummVM
+	/*0x4f*/ "Dummy",
 	/*0x50*/ "GetEvent",
 	/*0x51*/ "GlobalToLocal",
 	/*0x52*/ "LocalToGlobal",
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 2ed31016c6..e954afbc16 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -394,6 +394,9 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) {
 	return s->r_acc;
 }
 
+// kWait is a throttling function that sleeps up to the requested
+// number of ticks, or possibly not at all. The sleep duration
+// is based on the time since kWait was last called.
 reg_t kWait(EngineState *s, int argc, reg_t *argv) {
 	uint16 ticks = argv[0].toUint16();
 
@@ -407,6 +410,19 @@ reg_t kWait(EngineState *s, int argc, reg_t *argv) {
 	return make_reg(0, delta);
 }
 
+#ifdef ENABLE_SCI32
+// kScummVMSleep is our own custom kernel function that sleeps for
+// the number of ticks requested. We use this in SCI32 script patches
+// to replace spin loops so that the application remains responsive
+// and doesn't just block the thread without updating the screen or
+// processing input events.
+reg_t kScummVMSleep(EngineState *s, int argc, reg_t *argv) {
+	uint16 ticks = argv[0].toUint16();
+	s->sleep(ticks);
+	return s->r_acc;
+}
+#endif
+
 reg_t kCoordPri(EngineState *s, int argc, reg_t *argv) {
 	int16 y = argv[0].toSint16();
 
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 2fa89a5d32..7408a26997 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -2181,10 +2181,9 @@ static const SciScriptPatcherEntry hoyle4Signatures[] = {
 
 // Several scripts in Hoyle5 contain a subroutine which spins on kGetTime until
 // a certain number of ticks elapse. Since this wastes CPU and makes ScummVM
-// unresponsive, the kWait kernel function (which was removed in SCI2) is
-// reintroduced for Hoyle5, and the spin subroutines are patched here to call
-// that function instead.
-// Applies to at least: English Demo
+// 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
@@ -2199,7 +2198,7 @@ static const uint16 hoyle5SignatureSpinLoop[] = {
 static const uint16 hoyle5PatchSpinLoop[] = {
 	0x78,                                     // push1
 	0x8f, 0x01,                               // lsp param[1]
-	0x43, kScummVMWaitId, PATCH_UINT16(0x02), // callk Wait, $2
+	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, $2
 	0x48,                                     // ret
 	PATCH_END
 };
@@ -6579,7 +6578,7 @@ static const uint16 kq7BenchmarkPatch[] = {
 // 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 kWait().
+// We replace the loop with a call to kScummVMSleep.
 //
 // Applies to at least: KQ7 English 2.00b
 // Responsible method: KQ7CD::pragmaFail in script 0
@@ -6596,7 +6595,7 @@ static const uint16 kq7PragmaFailSpinSignature[] = {
 static const uint16 kq7PragmaFailSpinPatch[] = {
 	0x78,                                     // push1
 	0x39, 0x12,                               // pushi 18 (~300ms)
-	0x43, kScummVMWaitId, PATCH_UINT16(0x02), // callk Wait, 2
+	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, 2
 	0x33, 0x16,                               // jmp [to setCursor]
 	PATCH_END
 };
@@ -10287,7 +10286,7 @@ static const SciScriptPatcherEntry phantasmagoriaSignatures[] = {
 
 // The game uses a spin loop when navigating to and from Curtis's computer in
 // the office, and when entering passwords, which causes the mouse to appear
-// unresponsive. Replace the spin loop with a call to ScummVM kWait.
+// unresponsive. Replace the spin loop with a call to kScummVMSleep.
 // Applies to at least: US English
 // Responsible method: Script 3000 localproc 2ee4, script 63019 localproc 4f04
 static const uint16 phant2WaitParam1Signature[] = {
@@ -10302,7 +10301,7 @@ static const uint16 phant2WaitParam1Signature[] = {
 static const uint16 phant2WaitParam1Patch[] = {
 	0x78,                                     // push1
 	0x8f, 0x01,                               // lsp param[1]
-	0x43, kScummVMWaitId, PATCH_UINT16(0x02), // callk Wait, 2
+	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, 2
 	0x48,                                     // ret
 	PATCH_END
 };
@@ -10330,7 +10329,7 @@ static const uint16 phant2SlowIFadePatch[] = {
 
 // The game uses a spin loop during music transitions which causes the mouse to
 // appear unresponsive during scene changes. Replace the spin loop with a call
-// to ScummVM kWait.
+// to kScummVMSleep.
 // Applies to at least: US English
 // Responsible method: P2SongPlyr::wait4Fade
 static const uint16 phant2Wait4FadeSignature[] = {
@@ -10345,7 +10344,7 @@ static const uint16 phant2Wait4FadeSignature[] = {
 static const uint16 phant2Wait4FadePatch[] = {
 	0x78,                                     // push1
 	0x8d, 0x00,                               // lst temp[0]
-	0x43, kScummVMWaitId, PATCH_UINT16(0x02), // callk Wait, 2
+	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, 2
 	0x48,                                     // ret
 	PATCH_END
 };
@@ -10417,13 +10416,13 @@ static const uint16 phant2RatboyPatch[] = {
 	0x78,                                     // push1
 	0x35, 0x1e,                               // ldi $1e
 	0x36,                                     // push
-	0x43, kScummVMWaitId, PATCH_UINT16(0x02), // callk Wait, $2
+	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, $2
 	0x33, 0x14,                               // jmp [to next outer loop]
 	PATCH_END
 };
 
 // The game uses a spin loop during the floating head easter egg, which causes
-//  the mouse to appear unresponsive. Replace the inner loop with kWait.
+//  the mouse to appear unresponsive. Replace the inner loop with kScummVMSleep.
 //
 // Applies to at least: US English
 // Responsible method: bigScript:changeState
@@ -10441,7 +10440,7 @@ static const uint16 phant2FloatingHeadSignature[] = {
 static const uint16 phant2FloatingHeadPatch[] = {
 	0x78,                                     // push1
 	0x39, 0x3c,                               // pushi 3c [ 1 second ]
-	0x43, kScummVMWaitId, PATCH_UINT16(0x02), // callk Wait, 2
+	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, 2
 	0x33, 0x04,                               // jmp 04
 	PATCH_END
 };
@@ -10557,7 +10556,7 @@ static const uint16 phant2SlowScrollSignature[] = {
 static const uint16 phant2SlowScrollPatch[] = {
 	0x78,                                     // push1
 	0x39, 0x03,                               // pushi 3
-	0x43, kScummVMWaitId, PATCH_UINT16(0x02), // callk Wait, 2
+	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, 2
 	0x33, 0x13,                               // jmp [end of loop]
 	PATCH_END
 };


Commit: 2740f075d447509d2864f78adcf1b24eba8a1674
    https://github.com/scummvm/scummvm/commit/2740f075d447509d2864f78adcf1b24eba8a1674
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI32; Improve KQ7 cursor script patch

Removes a jump to an unverified offset

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


diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 7408a26997..fffd31a30b 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -6596,7 +6596,7 @@ static const uint16 kq7PragmaFailSpinPatch[] = {
 	0x78,                                     // push1
 	0x39, 0x12,                               // pushi 18 (~300ms)
 	0x43, kScummVMSleepId, PATCH_UINT16(0x02),// callk ScummVMSleep, 2
-	0x33, 0x16,                               // jmp [to setCursor]
+	0x35, 0x00,                               // ldi 0 [ exit loop ]
 	PATCH_END
 };
 


Commit: ca03effcb589706198bcc7a1de055685d595db3e
    https://github.com/scummvm/scummvm/commit/ca03effcb589706198bcc7a1de055685d595db3e
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI32: Fix GK2 "bad" cursor not appearing

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


diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index fffd31a30b..21d0501745 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -3975,6 +3975,33 @@ static const SciScriptPatcherEntry gk1Signatures[] = {
 #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
@@ -4422,6 +4449,7 @@ static const SciScriptPatcherEntry gk2Signatures[] = {
 	{  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 },


Commit: 75f7151676a2066e25f146f85897aa149aa4d2b0
    https://github.com/scummvm/scummvm/commit/75f7151676a2066e25f146f85897aa149aa4d2b0
Author: Ralph Caraveo III (deckarep at gmail.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI: Clarify passing of parameter: pass instead of parse for `class_table` debug command.

Minor wording change to say pass instead of parse.

Changed paths:
    engines/sci/console.cpp


diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 8b5a44536e..9807848e85 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -1662,7 +1662,7 @@ bool Console::cmdListSaves(int argc, const char **argv) {
 }
 
 bool Console::cmdClassTable(int argc, const char **argv) {
-	debugPrintf("Available classes (parse a parameter to filter the table by a specific class):\n");
+	debugPrintf("Available classes (pass a parameter to filter the table by a specific class):\n");
 
 	for (uint i = 0; i < _engine->_gamestate->_segMan->classTableSize(); i++) {
 		Class temp = _engine->_gamestate->_segMan->_classTable[i];


Commit: 2dcc62bfe389a6d8704e21bd0e77cc6e86c1fc4c
    https://github.com/scummvm/scummvm/commit/2dcc62bfe389a6d8704e21bd0e77cc6e86c1fc4c
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI: Fix class_table debugging command output

Changed paths:
    engines/sci/console.cpp


diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 9807848e85..87fccc747b 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -1673,7 +1673,9 @@ bool Console::cmdClassTable(int argc, const char **argv) {
 						className,
 						PRINT_REG(temp.reg),
 						temp.script);
-			} else debugPrintf(" Class 0x%x (not loaded; can't get name) (script %d)\n", i, temp.script);
+			}
+		} else if (argc == 1) {
+			debugPrintf(" Class 0x%x (not loaded; can't get name) (script %d)\n", i, temp.script);
 		}
 	}
 


Commit: c8fb10430613f88c683b88689e827bfed352d5d3
    https://github.com/scummvm/scummvm/commit/c8fb10430613f88c683b88689e827bfed352d5d3
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI: Add uninit read workarounds for QFG3, QFG4

Fixes bugs #13045, #13046

Changed paths:
    engines/sci/engine/workarounds.cpp


diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index b6937fa107..5c84681d6d 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -354,6 +354,8 @@ const SciWorkaroundEntry uninitializedReadForParamWorkarounds[] = {
 	{ GID_HOYLE5,       1100,    22, -1,           "HandPile", "show",                            NULL,     1,     1,{ WORKAROUND_FAKE,   0 } }, // when showing money piles in Poker
 	{ GID_LAURABOW2,      -1,    90,  0,          "MuseumRgn", "crowdInRoom",                     NULL,     3,     4,{ WORKAROUND_FAKE,   0 } }, // When actors walk around the museum. Out-of-bounds parameters are read but not used. Doesn't matter, but generates a lot of warnings.
 	{ GID_PHANTASMAGORIA2,-1, 63019,  0,     "WynDocTextView", "cue",                             NULL,     2,     2,{ WORKAROUND_FAKE,   0 } }, // When dragging the slider next to an e-mail message
+	{ GID_QFG3,           -1,    28,  0,               "hero", "changeGait",                      NULL,     2,     2,{ WORKAROUND_FAKE,   0 } }, // When ego's walk style is adjusted throughout the game
+	{ GID_QFG4,           -1,    28,  0,               "hero", "changeGait",                      NULL,     1,     2,{ WORKAROUND_FAKE,   0 } }, // When ego's walk style is adjusted throughout the game (some scripts don't pass either parameter)
 	{ GID_SHIVERS,        -1, 64918,  0,                "Str", "strip",                           NULL,     1,     1,{ WORKAROUND_FAKE,   0 } }, // When starting a new game and entering a name
 	{ GID_SQ4,            35,   928,  0,           "Narrator", "say",                             NULL,     1,     1,{ WORKAROUND_FAKE,  11 } }, // Clicking smell on sidewalk, fixes message due to missing say parameter in sidewalk1:doVerb(6) - bug #10917
 	SCI_WORKAROUNDENTRY_TERMINATOR
@@ -538,6 +540,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
 	{ GID_QFG3,          490,   490, -1,      "computersMove", "changeState",                     NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // when finishing awari game, bug #5167
 	{ GID_QFG3,          490,   490, -1,      "computersMove", "changeState",    sig_uninitread_qfg3_2,     4,     4, { WORKAROUND_FAKE,   0 } }, // also when finishing awari game
 	{ GID_QFG3,           -1,    32, -1,            "ProjObj", "doit",                            NULL,     1,     1, { WORKAROUND_FAKE,   0 } }, // near the end, when throwing the spear of death or sword, bugs #5282, #11477
+	{ GID_QFG3,          130,   937, -1,            "IconBar", "dispatchEvent",                   NULL,    58,    58, { WORKAROUND_FAKE,   0 } }, // pressing the Enter key on the main menu screen, bug #13045
 	{ GID_QFG4,           -1,    15, -1,     "charInitScreen", "dispatchEvent",                   NULL,     5,     5, { WORKAROUND_FAKE,   0 } }, // floppy version, when viewing the character screen
 	{ GID_QFG4,           -1,    23, -1,     "tellerControls", "dispatchEvent",                   NULL,     6,     6, { WORKAROUND_FAKE,   0 } }, // floppy version, when using keyboard controls in the conversation interface
 	{ GID_QFG4,           -1,    50, -1,     "sSearchMonster", "changeState",                     NULL,     2,     2, { WORKAROUND_FAKE,   0 } }, // CD version, when searching a chernovy or revenant with speech disabled


Commit: 2387712453c3fddc2e933f647c477e6e95af7231
    https://github.com/scummvm/scummvm/commit/2387712453c3fddc2e933f647c477e6e95af7231
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI32: Fix QFG4 upgraded inventory views

Fixes script bugs where items are upgraded but their graphics aren't

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


diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 21d0501745..613c630b99 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -193,6 +193,7 @@ static const char *const selectorNameTable[] = {
 	"advanceCurIcon", // QFG4
 	"amount",       // QFG4
 	"cue",          // QFG4
+	"drop",         // QFG4
 	"getCursor",    // QFG4
 	"heading",      // QFG4
 	"moveSpeed",    // QFG4
@@ -322,6 +323,7 @@ enum ScriptPatcherSelectors {
 	SELECTOR_advanceCurIcon,
 	SELECTOR_amount,
 	SELECTOR_cue,
+	SELECTOR_drop,
 	SELECTOR_getCursor,
 	SELECTOR_heading,
 	SELECTOR_moveSpeed,
@@ -17799,6 +17801,158 @@ static const uint16 qfg4BoneCageTellerPatch[] = {
 	PATCH_END
 };
 
+// When finding the battle axe in the wraith mound in room 575, the inventory
+//  view isn't updated from the old sword. theSword:show contains the logic to
+//  set the loop and cel based on the state property but this code doesn't run.
+//  hero:get also contains this logic but it also doesn't run since a fighter
+//  already has the sword at this point.
+//
+// We fix this by replacing a redundant inventory check with a call to hero:drop
+//  so that the sword is removed from and re-added to inventory. This causes
+//  hero:get to update theSword's cel and loop based on the new state property.
+//  This patch avoids touching the final bnt instruction as that instruction's
+//  size is different in the NRS fan patch.
+//
+// Applies to: All versions
+// Responsible method: sSearch:changeState(4)
+static const uint16 qfg4BattleAxeViewSignature[] = {
+	0x7a,                               // push2
+	SIG_ADDTOOFFSET(+13),
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(has),          // pushi has
+	0x78,                               // push1
+	0x39, 0x13,                         // pushi 13 [ theSword ]
+	0x81, 0x00,                         // lag 00
+	0x4a, SIG_UINT16(0x0006),           // send 06 [ hero has: 19 ]
+	0x18,                               // not
+	SIG_END                             // bnt [ skips hero get: 19 1 ]
+};
+
+static const uint16 qfg4BattleAxeViewPatch[] = {
+	PATCH_ADDTOOFFSET(+14),
+	0x38, PATCH_SELECTOR16(drop),       // pushi drop [ drop theSword, forcing cel refresh ]
+	PATCH_ADDTOOFFSET(+8),
+	0x00,                               // bnot [ set acc to true, don't skip hero get: 19 1 ]
+	PATCH_END
+};
+
+// When a magic user searches the wraith mound in room 590 they find metal armor
+//  but the inventory view isn't updated from the leather armor. As with the
+//  battle axe patch above, theArmor:show and hero:get contain the logic to
+//  update this view but neither method runs.
+//
+// We fix this like the battle axe by calling hero:drop and hero:get to update
+//  the armor's view based on its new state property.
+//
+// Applies to: All versions
+// Responsible method: sSearch:changeState(4)
+static const uint16 qfg4MetalArmorViewSignature[] = {
+	SIG_MAGICDWORD,
+	0x38, SIG_SELECTOR16(has),          // pushi has
+	0x78,                               // push1
+	0x39, 0x11,                         // pushi 11 [ theArmor ]
+	0x81, 0x00,                         // lag 00
+	0x4a, SIG_UINT16(0x0006),           // send 06 [ hero has: 17 ]
+	0x18,                               // not
+	SIG_END                             // bnt [ skips hero get: 17 1 ]
+};
+
+static const uint16 qfg4MetalArmorViewPatch[] = {
+	0x38, PATCH_SELECTOR16(drop),       // pushi drop [ drop theArmor, forcing cel refresh ]
+	PATCH_ADDTOOFFSET(+8),
+	0x00,                               // bnot [ set acc to true, don't skip hero get: 17 1 ]
+	PATCH_END
+};
+
+
+// When finding the magic sword in the wraith mound in room 575, the inventory
+//  view isn't updated from the old sword. theSword:show contains the logic to
+//  set the loop and cel based on the state property but this code doesn't run.
+//
+// We fix this by setting the cel when updating the sword's state. The loop is
+//  zero for all sword states and doesn't need to be updated.
+//
+// Applies to: All versions
+// Responsible method: sSearch:changeState(4)
+static const uint16 qfg4MagicSwordViewSignature[] = {
+	0x3c,                               // dup
+	0x35, 0x03,                         // ldi 03
+	0x1a,                               // eq?
+	0x30, SIG_ADDTOOFFSET(+2),          // bnt [ end of switch ]
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(state),         // pushi state
+	0x78,                               // push1
+	0x39, 0x03,                         // pushi 03
+	SIG_ADDTOOFFSET(+10),
+	0x4a, SIG_UINT16(0x0006),           // send 06 [ theSword state: 3 (magic sword) ]
+	SIG_END
+};
+
+static const uint16 qfg4MagicSwordViewPatch[] = {
+	0x38, PATCH_SELECTOR16(cel),        // pushi cel
+	0x78,                               // push1
+	0x38, PATCH_UINT16(0x000e),         // pushi 000e
+	PATCH_ADDTOOFFSET(+15),
+	0x4a, PATCH_UINT16(0x000c),         // send 0c [ theSword cel: 14 state: 3 (magic sword) ]
+	PATCH_END
+};
+
+// When the Burgomeister gives the magic shield, the inventory view isn't
+//  updated from the old shield. theShield:show contains the logic to set the
+//  loop and cel based on the state property but this code doesn't run.
+//
+// We fix this by setting the loop and cel when updating the shield's state.
+//
+// Applies to: All versions
+// Responsible method: sGetShield:changeState(3)
+static const uint16 qfg4MagicShieldViewSignature[] = {
+	SIG_MAGICDWORD,
+	0x39, SIG_SELECTOR8(state),         // pushi state
+	0x78,                               // push1
+	0x78,                               // push1
+	SIG_ADDTOOFFSET(+10),
+	0x4a, SIG_UINT16(0x0006),           // send 06 [ theShield state: 1 (magic shield) ]
+	0x38, SIG_SELECTOR16(dispose),      // pushi dispose
+	0x76,                               // push0
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi actions
+	0x76,                               // push0
+	0x72, SIG_ADDTOOFFSET(+2),          // lofsa burgoMeister
+	0x4a, SIG_UINT16(0x0004),           // send 04 [ burgoMeter actions? (burgoTeller) ]
+	0x4a, SIG_UINT16(0x0004),           // send 04 [ burgoTeller dispose: ]
+	0x38, SIG_SELECTOR16(dispose),      // pushi dispose
+	0x76,                               // push0
+	0x38, SIG_ADDTOOFFSET(+2),          // pushi actions
+	0x76,                               // push0
+	0x81, 0x00,                         // lag 00
+	0x4a, SIG_UINT16(0x0004),           // send 04 [ hero actions? (heroTeller) ]
+	0x4a, SIG_UINT16(0x0004),           // send 04 [ heroTeller dispose: ]
+	SIG_ADDTOOFFSET(+32),
+	0x72, SIG_ADDTOOFFSET(+2),          // lofsa  heroTeller
+	SIG_ADDTOOFFSET(+23),
+	0x72, SIG_ADDTOOFFSET(+2),          // lofsa  burgoTeller
+	SIG_END
+};
+
+static const uint16 qfg4MagicShieldViewPatch[] = {
+	PATCH_ADDTOOFFSET(+14),
+	0x38, PATCH_SELECTOR16(loop),       // pushi loop
+	0x78,                               // push1
+	0x38, PATCH_UINT16(0x0008),         // pushi 0008
+	0x38, PATCH_SELECTOR16(cel),        // pushi cel
+	0x78,                               // push1
+	0x39, 0x0d,                         // pushi 0d
+	0x4a, PATCH_UINT16(0x0012),         // send 12 [ theShield state: 1 (magic shield) loop: 8 cel: 13 ]
+	0x38, PATCH_SELECTOR16(dispose),    // pushi dispose
+	0x76,                               // push0
+	0x72, PATCH_GETORIGINALUINT16(+109),// lofsa burgoTeller
+	0x4a, PATCH_UINT16(0x0004),         // send 04 [ burgoTeller dispose: ]
+	0x38, PATCH_SELECTOR16(dispose),    // pushi dispose
+	0x76,                               // push0
+	0x72, PATCH_GETORIGINALUINT16(+83), // lofsa heroTeller
+	0x4a, PATCH_UINT16(0x0004),         // send 04 [ heroTeller dispose: ]
+	PATCH_END
+};
+
 //          script, description,                                     signature                      patch
 static const SciScriptPatcherEntry qfg4Signatures[] = {
 	{  true,     0, "prevent autosave from deleting save games",   1, qfg4AutosaveSignature,         qfg4AutosavePatch },
@@ -17819,6 +17973,9 @@ static const SciScriptPatcherEntry qfg4Signatures[] = {
 	{  true,    51, "fix necrotaur blackout",                      1, qfg4NecrotaurBlackoutSignature,qfg4NecrotaurBlackoutPatch },
 	{  true,    51, "CD: fix necrotaur capture",                   3, qfg4NecrotaurCaptureSignature, qfg4NecrotaurCapturePatch },
 	{  true,    53, "NRS: fix wraith lockup",                      1, qfg4WraithLockupNrsSignature,  qfg4WraithLockupNrsPatch },
+	{  true,    53, "fix battle axe view",                         1, qfg4BattleAxeViewSignature,    qfg4BattleAxeViewPatch },
+	{  true,    53, "fix metal armor view",                        1, qfg4MetalArmorViewSignature,   qfg4MetalArmorViewPatch },
+	{  true,    53, "fix magic sword view",                        1, qfg4MagicSwordViewSignature,   qfg4MagicSwordViewPatch },
 	{  true,    83, "fix incorrect array type",                    1, qfg4TrapArrayTypeSignature,    qfg4TrapArrayTypePatch },
 	{  true,   140, "fix character selection",                     1, qfg4CharacterSelectSignature,  qfg4CharacterSelectPatch },
 	{  true,   250, "fix hectapus death lockup",                   1, qfg4HectapusDeathSignature,    qfg4HectapusDeathPatch },
@@ -17828,6 +17985,7 @@ static const SciScriptPatcherEntry qfg4Signatures[] = {
 	{  true,   290, "fix chase repeating",                         1, qfg4ChaseRepeatsSignature,     qfg4ChaseRepeatsPatch },
 	{  true,   290, "fix bridge secret exit",                      1, qfg4BridgeSecretExitSignature, qfg4BridgeSecretExitPatch },
 	{  true,   300, "fix empty burgomeister room teller",          1, qfg4EmptyBurgoRoomSignature,   qfg4EmptyBurgoRoomPatch },
+	{  true,   300, "fix magic shield view",                       1, qfg4MagicShieldViewSignature,  qfg4MagicShieldViewPatch },
 	{  true,   320, "fix pathfinding at the inn",                  1, qfg4InnPathfindingSignature,   qfg4InnPathfindingPatch },
 	{  true,   320, "fix talking to absent innkeeper",             1, qfg4AbsentInnkeeperSignature,  qfg4AbsentInnkeeperPatch },
 	{  true,   320, "CD: fix domovoi never appearing",             1, qfg4DomovoiInnSignature,       qfg4DomovoiInnPatch },


Commit: 71875456ab7c5d0ec4969073b994ff8d78bdd6c0
    https://github.com/scummvm/scummvm/commit/71875456ab7c5d0ec4969073b994ff8d78bdd6c0
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI32: Add QFG4 uninit param read workaround

Changed paths:
    engines/sci/engine/workarounds.cpp


diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 5c84681d6d..dd94199aa8 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -356,6 +356,7 @@ const SciWorkaroundEntry uninitializedReadForParamWorkarounds[] = {
 	{ GID_PHANTASMAGORIA2,-1, 63019,  0,     "WynDocTextView", "cue",                             NULL,     2,     2,{ WORKAROUND_FAKE,   0 } }, // When dragging the slider next to an e-mail message
 	{ GID_QFG3,           -1,    28,  0,               "hero", "changeGait",                      NULL,     2,     2,{ WORKAROUND_FAKE,   0 } }, // When ego's walk style is adjusted throughout the game
 	{ GID_QFG4,           -1,    28,  0,               "hero", "changeGait",                      NULL,     1,     2,{ WORKAROUND_FAKE,   0 } }, // When ego's walk style is adjusted throughout the game (some scripts don't pass either parameter)
+	{ GID_QFG4,           -1, 64924,  0,      "gloryMessager", "nextMsg",                         NULL,     1,     5,{ WORKAROUND_FAKE,   0 } }, // Floppy: when saying a message. Passes 5 non-existent parameters to GloryTalker:say which never reads them, but generates a lot of warnings.
 	{ GID_SHIVERS,        -1, 64918,  0,                "Str", "strip",                           NULL,     1,     1,{ WORKAROUND_FAKE,   0 } }, // When starting a new game and entering a name
 	{ GID_SQ4,            35,   928,  0,           "Narrator", "say",                             NULL,     1,     1,{ WORKAROUND_FAKE,  11 } }, // Clicking smell on sidewalk, fixes message due to missing say parameter in sidewalk1:doVerb(6) - bug #10917
 	SCI_WORKAROUNDENTRY_TERMINATOR


Commit: 55488baecd80e70fffe7e1b379a780411599254d
    https://github.com/scummvm/scummvm/commit/55488baecd80e70fffe7e1b379a780411599254d
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:06-07:00

Commit Message:
SCI: Update QFG3 uninit read workaround

Changed paths:
    engines/sci/engine/workarounds.cpp


diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index dd94199aa8..6d86ac4555 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -541,7 +541,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
 	{ GID_QFG3,          490,   490, -1,      "computersMove", "changeState",                     NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // when finishing awari game, bug #5167
 	{ GID_QFG3,          490,   490, -1,      "computersMove", "changeState",    sig_uninitread_qfg3_2,     4,     4, { WORKAROUND_FAKE,   0 } }, // also when finishing awari game
 	{ GID_QFG3,           -1,    32, -1,            "ProjObj", "doit",                            NULL,     1,     1, { WORKAROUND_FAKE,   0 } }, // near the end, when throwing the spear of death or sword, bugs #5282, #11477
-	{ GID_QFG3,          130,   937, -1,            "IconBar", "dispatchEvent",                   NULL,    58,    58, { WORKAROUND_FAKE,   0 } }, // pressing the Enter key on the main menu screen, bug #13045
+	{ GID_QFG3,           -1,   937, -1,            "IconBar", "dispatchEvent",                   NULL,    58,    58, { WORKAROUND_FAKE,   0 } }, // pressing the Enter key on the main menu screen, bug #13045 (affects multiple room numbers)
 	{ GID_QFG4,           -1,    15, -1,     "charInitScreen", "dispatchEvent",                   NULL,     5,     5, { WORKAROUND_FAKE,   0 } }, // floppy version, when viewing the character screen
 	{ GID_QFG4,           -1,    23, -1,     "tellerControls", "dispatchEvent",                   NULL,     6,     6, { WORKAROUND_FAKE,   0 } }, // floppy version, when using keyboard controls in the conversation interface
 	{ GID_QFG4,           -1,    50, -1,     "sSearchMonster", "changeState",                     NULL,     2,     2, { WORKAROUND_FAKE,   0 } }, // CD version, when searching a chernovy or revenant with speech disabled


Commit: a50d84a32b43a88a88bc23ae25948ac8ff35874b
    https://github.com/scummvm/scummvm/commit/a50d84a32b43a88a88bc23ae25948ac8ff35874b
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
WIN32: Fix build when USE_WINDBG is defined

Changed paths:
    backends/platform/sdl/win32/win32.cpp


diff --git a/backends/platform/sdl/win32/win32.cpp b/backends/platform/sdl/win32/win32.cpp
index 31db3c2ee1..14b97d8050 100644
--- a/backends/platform/sdl/win32/win32.cpp
+++ b/backends/platform/sdl/win32/win32.cpp
@@ -205,7 +205,9 @@ void OSystem_Win32::logMessage(LogMessageType::Type type, const char *message) {
 	OSystem_SDL::logMessage(type, message);
 
 #if defined( USE_WINDBG )
-	OutputDebugString(message);
+	TCHAR *tMessage = Win32::stringToTchar(message);
+	OutputDebugString(tMessage);
+	free(tMessage);
 #endif
 }
 


Commit: ebfecf848741abb8d2d6e479882639c93dec4d6c
    https://github.com/scummvm/scummvm/commit/ebfecf848741abb8d2d6e479882639c93dec4d6c
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
SCI: Fix HOYLE4 Gin Rummy undercut sound

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


diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 613c630b99..41f7b2b7b1 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -2170,9 +2170,54 @@ static const uint16 hoyle4PatchCrazyEightsSound[] = {
 	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
+//  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
 };


Commit: 5a63f261b6d4ddc3f09d375a002a0549473e00e0
    https://github.com/scummvm/scummvm/commit/5a63f261b6d4ddc3f09d375a002a0549473e00e0
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
SCI: Only throttle kGameIsRestarting from game loops

Prevents extra speed throttling from being applied when a script queries
the restart flag. Some rooms such as the KQ6 caves and the QFG4 caves do
this on every game cycle. In practice, this extra throttling didn't seem
to have much effect, but the intent is to only throttle game loops and
the script patches that fix inner loops.

Updated script patches to call kGameIsRestarting like game loops.

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


diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 64e8ea6eb4..265e306a80 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -60,11 +60,16 @@ reg_t kRestartGame16(EngineState *s, int argc, reg_t *argv) {
 ** Returns the restarting_flag in acc
 */
 reg_t kGameIsRestarting(EngineState *s, int argc, reg_t *argv) {
-	s->r_acc = make_reg(0, s->gameIsRestarting);
+	// Always return the previous flag value
+	const int16 previousRestartingFlag = s->gameIsRestarting;
 
-	if (argc) { // Only happens during replay
-		if (!argv[0].toUint16()) // Set restarting flag
-			s->gameIsRestarting = GAMEISRESTARTING_NONE;
+	// Games pass zero to clear the restarting flag from their Game:doit method on
+	// each cycle. Other scripts query the restarting flag by passing no parameters.
+	if (argc > 0 && argv[0].toUint16() == 0) {
+		s->gameIsRestarting = GAMEISRESTARTING_NONE;
+	} else {
+		// Only speed throttle calls from game loops or our script patches.
+		return make_reg(0, previousRestartingFlag);
 	}
 
 	uint32 neededSleep = 30;
@@ -133,7 +138,7 @@ reg_t kGameIsRestarting(EngineState *s, int argc, reg_t *argv) {
 	s->speedThrottler(neededSleep);
 
 	s->_paletteSetIntensityCounter = 0;
-	return s->r_acc;
+	return make_reg(0, previousRestartingFlag);
 }
 
 reg_t kHaveMouse(EngineState *s, int argc, reg_t *argv) {
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 41f7b2b7b1..0f6cf95ef2 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -1799,8 +1799,9 @@ static const uint16 freddypharkasPatchIntroScaling[] = {
 	0x35, 0x0a,                      // ldi 0a
 	0xa3, 0x02,                      // sal local[2]
 	// start of new inner loop
-	0x39, 0x00,                      // pushi 00
-	0x43, 0x2c, 0x00,                // callk GameIsRestarting (add this to trigger our speed throttler)
+	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
@@ -2172,7 +2173,7 @@ static const uint16 hoyle4PatchCrazyEightsSound[] = {
 
 // In Gin Rummy, sound 404 plays when undercutting the computer but it gets
 //  interrupted. layEmOut:changeState sets a half-second delay, which is long
-//  long enough for the undercut sound when the computer wins, but not this one.
+//  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.
 //
@@ -5749,8 +5750,9 @@ static const uint16 kq6SignatureTalkingInventory[] = {
 
 static const uint16 kq6PatchTalkingInventory[] = {
 	PATCH_ADDTOOFFSET(+2),
-	0x39, 0x00,                         // pushi 00
-	0x43, 0x2c, 0x00,                   // callk GameIsRestarting [ custom throttling ]
+	0x78,                               // push1
+	0x76,                               // push0
+	0x43, 0x2c, 0x02,                   // callk GameIsRestarting 02 [ custom throttling ]
 	0x34, PATCH_UINT16(0x0000),         // ldi 0000 [ exit loop ]
 	PATCH_END
 };
@@ -13336,23 +13338,23 @@ static const uint16 qfg3SignatureCombatSpeedThrottling1[] = {
 
 static const uint16 qfg3PatchCombatSpeedThrottling1[] = {
 	0x76,                               // push0  (no link, freed +2 bytes)
-	0x43, 0x42, 0x00,                   // callk GetTime, 0d
+	0x43, 0x42, 0x00,                   // callk GetTime, 00
 	0xa1, 0x58,                         // sag global[88] (no push, leave time in acc)
 	0x8b, 0x01,                         // lsl local[1] (stack up the local instead, freed +1 byte)
+	0xa3, 0x01,                         // sal local[1] (update with new time)
 	0x1c,                               // ne?
-	0x31, 0x0c,                         // bnt 12d [after sal]
+	0x31, 0x08,                         // bnt 08 [ GameIsRestarting  0 ]
 										//
 	0x81, 0xd2,                         // lag global[210] (load into acc instead of stack)
 	0x76,                               // push0 (push0 instead of ldi 0, freed +1 byte)
 	0x22,                               // lt? (flip the comparison)
-	0x31, 0x06,                         // bnt 6d [after sal]
+	0x31, 0x02,                         // bnt 02 [ GameIsRestarting  0 ]
 										//
 	0xe1, 0xd2,                         // -ag global[210]
-	0x81, 0x58,                         // lag global[88]
-	0xa3, 0x01,                         // sal local[1]
-
-	0x76,                               // push0 (0 call args)
-	0x43, 0x2c, 0x00,                   // callk GameIsRestarting, 0d (add this to trigger our speed throttler)
+										//
+	0x39, 0x01,                         // push 01
+	0x76,                               // push0
+	0x43, 0x2c, 0x02,                   // callk GameIsRestarting, 02 (add this to trigger our speed throttler)
 	PATCH_END
 };
 


Commit: f08f2a52fcf888089657d4b20f54e5da2af4a457
    https://github.com/scummvm/scummvm/commit/f08f2a52fcf888089657d4b20f54e5da2af4a457
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
CREATE_PROJECT: Add DETECTION_FULL feature

Allows disabling full detection with --disable-detection-full,
just like the configure script.

Changed paths:
    devtools/create_project/create_project.cpp


diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp
index c1535cf9f6..1dbe506655 100644
--- a/devtools/create_project/create_project.cpp
+++ b/devtools/create_project/create_project.cpp
@@ -1093,6 +1093,7 @@ const Feature s_features[] = {
 	{     "text-console", "USE_TEXT_CONSOLE_FOR_DEBUGGER", false, false, "Text console debugger" }, // This feature is always applied in xcode projects
 	{              "tts",                       "USE_TTS", false, true,  "Text to speech support"},
 	{"builtin-resources",             "BUILTIN_RESOURCES", false, true,  "include resources (e.g. engine data, fonts) into the binary"},
+	{   "detection-full",                "DETECTION_FULL", false, true,  "Include detection objects for all engines" },
 	{ "detection-static", "USE_DETECTION_FEATURES_STATIC", false, true,  "Static linking of detection objects for engines."},
 	{            "cxx11",                     "USE_CXX11", false, true,  "Compile with c++11 support"}
 };
@@ -1571,12 +1572,17 @@ void ProjectProvider::createProject(BuildSetup &setup) {
 		ex.clear();
 		std::vector<std::string> detectionModuleDirs;
 		detectionModuleDirs.reserve(setup.engines.size());
+		bool detectAllEngines = getFeatureBuildState("detection-full", setup.features);
 
 		for (EngineDescList::const_iterator i = setup.engines.begin(), end = setup.engines.end(); i != end; ++i) {
 			// We ignore all sub engines here because they require no special handling.
 			if (isSubEngine(i->name, setup.engines)) {
 				continue;
 			}
+			// If we're not detecting all engines then ignore the disabled ones
+			if (!(detectAllEngines || i->enable)) {
+				continue;
+			}
 			detectionModuleDirs.push_back(setup.srcDir + "/engines/" + i->name);
 		}
 
@@ -2133,7 +2139,9 @@ void ProjectProvider::createEnginePluginsTable(const BuildSetup &setup) {
 		                   << "LINK_PLUGIN(" << engineName << ")\n"
 		                   << "#endif\n";
 
-		detectionTable << "LINK_PLUGIN(" << engineName << "_DETECTION)\n";
+		detectionTable << "#if defined(ENABLE_" << engineName << ") || defined(DETECTION_FULL)\n"
+					   << "LINK_PLUGIN(" << engineName << "_DETECTION)\n"
+					   << "#endif\n";
 	}
 }
 } // namespace CreateProjectTool


Commit: c67adbb30174dc2728e43bfe81408fc320c5ad71
    https://github.com/scummvm/scummvm/commit/c67adbb30174dc2728e43bfe81408fc320c5ad71
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
CREATE_PROJECT: Add --include-dir and --library-dir

Additional include and library directories can now be added.

This is most useful to Xcode Mac projects where a vanilla Homebrew setup
requires manually adding five directories through the Xcode UI and then
repeating that every time the project needs to be regenerated.

Now create_project can be scripted to regenerate a working Mac project
without any extra Xcode steps.

Changed paths:
    devtools/create_project/cmake.cpp
    devtools/create_project/codeblocks.cpp
    devtools/create_project/create_project.cpp
    devtools/create_project/create_project.h
    devtools/create_project/msbuild.cpp
    devtools/create_project/visualstudio.cpp
    devtools/create_project/xcode.cpp


diff --git a/devtools/create_project/cmake.cpp b/devtools/create_project/cmake.cpp
index b91232d0ef..8569df91e6 100644
--- a/devtools/create_project/cmake.cpp
+++ b/devtools/create_project/cmake.cpp
@@ -121,8 +121,12 @@ void CMakeProvider::createWorkspace(const BuildSetup &setup) {
 	workspace << "# Generate options for the engines\n";
 	writeEngineOptions(workspace);
 
+	std::string includeDirsList;
+	for (StringList::const_iterator i = setup.includeDirs.begin(); i != setup.includeDirs.end(); ++i)
+		includeDirsList += *i + ' ';
+
 	workspace << "include_directories(${" << setup.projectDescription << "_SOURCE_DIR}/" <<  setup.filePrefix << " ${" << setup.projectDescription << "_SOURCE_DIR}/" <<  setup.filePrefix << "/engines "
-			"$ENV{"<<LIBS_DEFINE<<"}/include .)\n\n";
+			  << includeDirsList << "$ENV{"<<LIBS_DEFINE<<"}/include .)\n\n";
 
 	workspace << "# Libraries and features\n\n";
 	writeFeatureLibSearch(setup, workspace, "sdl");
@@ -281,7 +285,10 @@ void CMakeProvider::createProjectFile(const std::string &name, const std::string
 
 		project << "# Libraries\n";
 		const Library *sdlLibrary = getLibraryFromFeature("sdl", setup.useSDL2);
-		project << "target_link_libraries(" << name << " ${" << sdlLibrary->librariesVar << "} ${SCUMMVM_LIBS})\n";
+		std::string libraryDirsList;
+		for (StringList::const_iterator i = setup.libraryDirs.begin(); i != setup.libraryDirs.end(); ++i)
+			libraryDirsList += *i + ' ';
+		project << "target_link_libraries(" << name << " " << libraryDirsList << "${" << sdlLibrary->librariesVar << "} ${SCUMMVM_LIBS})\n";
 
 		project << "if (WIN32)\n";
 		project << "\ttarget_sources(" << name << " PUBLIC " << setup.filePrefix << "/dists/" << name << ".rc)\n";
diff --git a/devtools/create_project/codeblocks.cpp b/devtools/create_project/codeblocks.cpp
index a0d7d20156..31f29b64b0 100644
--- a/devtools/create_project/codeblocks.cpp
+++ b/devtools/create_project/codeblocks.cpp
@@ -135,6 +135,9 @@ void CodeBlocksProvider::createProjectFile(const std::string &name, const std::s
 		writeWarnings(name, project);
 		writeDefines(setup.defines, project);
 
+		for (StringList::const_iterator i = setup.includeDirs.begin(); i != setup.includeDirs.end(); ++i)
+			project << "\t\t\t\t\t<Add directory=\"" << convertPathToWin(*i) << "\" />\n";
+
 		project << "\t\t\t\t\t<Add directory=\"$(" << LIBS_DEFINE << ")include\" />\n"
 		           "\t\t\t\t\t<Add directory=\"$(" << LIBS_DEFINE << ")include\\SDL\" />\n"
 		           "\t\t\t\t\t<Add directory=\"..\\..\\engines\" />\n"
@@ -154,6 +157,9 @@ void CodeBlocksProvider::createProjectFile(const std::string &name, const std::s
 			project << "\t\t\t\t\t<Add library=\"" << setup.projectName << "\\engines\\" << i->first << "\\lib" << i->first << ".a\" />\n";
 		}
 
+		for (StringList::const_iterator i = setup.libraryDirs.begin(); i != setup.libraryDirs.end(); ++i)
+			project << "\t\t\t\t\t<Add directory=\"" << convertPathToWin(*i) << "\" />\n";
+
 		project << "\t\t\t\t\t<Add directory=\"$(" << LIBS_DEFINE << ")lib\\mingw\" />\n"
 		           "\t\t\t\t\t<Add directory=\"$(" << LIBS_DEFINE << ")lib\" />\n"
 		           "\t\t\t\t</Linker>\n";
diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp
index 1dbe506655..c9ff76b839 100644
--- a/devtools/create_project/create_project.cpp
+++ b/devtools/create_project/create_project.cpp
@@ -74,6 +74,13 @@ namespace {
  */
 std::string unifyPath(const std::string &path);
 
+/**
+ * Removes trailing slash from path if it exists
+ *
+ * @param path Path string.
+ */
+void removeTrailingSlash(std::string& path);
+
 /**
  * Display the help text for the program.
  *
@@ -114,9 +121,7 @@ int main(int argc, char *argv[]) {
 
 	BuildSetup setup;
 	setup.srcDir = unifyPath(srcDir);
-
-	if (setup.srcDir.at(setup.srcDir.size() - 1) == '/')
-		setup.srcDir.erase(setup.srcDir.size() - 1);
+	removeTrailingSlash(setup.srcDir);
 
 	setup.filePrefix = setup.srcDir;
 	setup.outputDir = '.';
@@ -258,8 +263,7 @@ int main(int argc, char *argv[]) {
 			}
 
 			setup.filePrefix = unifyPath(argv[++i]);
-			if (setup.filePrefix.at(setup.filePrefix.size() - 1) == '/')
-				setup.filePrefix.erase(setup.filePrefix.size() - 1);
+			removeTrailingSlash(setup.filePrefix);
 		} else if (!std::strcmp(argv[i], "--output-dir")) {
 			if (i + 1 >= argc) {
 				std::cerr << "ERROR: Missing \"path\" parameter for \"--output-dir\"!\n";
@@ -267,9 +271,23 @@ int main(int argc, char *argv[]) {
 			}
 
 			setup.outputDir = unifyPath(argv[++i]);
-			if (setup.outputDir.at(setup.outputDir.size() - 1) == '/')
-				setup.outputDir.erase(setup.outputDir.size() - 1);
-
+			removeTrailingSlash(setup.outputDir);
+		} else if (!std::strcmp(argv[i], "--include-dir")) {
+			if (i + 1 >= argc) {
+				std::cerr << "ERROR: Missing \"path\" parameter for \"--include-dir\"!\n";
+				return -1;
+			}
+			std::string includeDir = unifyPath(argv[++i]);
+			removeTrailingSlash(includeDir);
+			setup.includeDirs.push_back(includeDir);
+		} else if (!std::strcmp(argv[i], "--library-dir")) {
+			if (i + 1 >= argc) {
+				std::cerr << "ERROR: Missing \"path\" parameter for \"--library-dir\"!\n";
+				return -1;
+			}
+			std::string libraryDir = unifyPath(argv[++i]);
+			removeTrailingSlash(libraryDir);
+			setup.libraryDirs.push_back(libraryDir);
 		} else if (!std::strcmp(argv[i], "--build-events")) {
 			setup.runBuildEvents = true;
 		} else if (!std::strcmp(argv[i], "--installer")) {
@@ -678,6 +696,11 @@ std::string unifyPath(const std::string &path) {
 	return result;
 }
 
+void removeTrailingSlash(std::string& path) {
+	if (path.size() > 0 && path.at(path.size() - 1) == '/')
+		path.erase(path.size() - 1);
+}
+
 void displayHelp(const char *exe) {
 	using std::cout;
 
@@ -702,6 +725,8 @@ void displayHelp(const char *exe) {
 	        " --output-dir path          overwrite path, where the project files are placed\n"
 	        "                            By default this is \".\", i.e. the current working\n"
 	        "                            directory\n"
+			" --include-dir path         add a path to the include search path"
+			" --library-dir path         add a path to the library search path"
 	        "\n"
 	        "MSVC specific settings:\n"
 	        " --msvc-version version     set the targeted MSVC version. Possible values:\n";
diff --git a/devtools/create_project/create_project.h b/devtools/create_project/create_project.h
index 102c9ea9e5..9acace6d02 100644
--- a/devtools/create_project/create_project.h
+++ b/devtools/create_project/create_project.h
@@ -232,6 +232,9 @@ struct BuildSetup {
 	std::string filePrefix; ///< Prefix for the relative path arguments in the project files.
 	std::string outputDir;  ///< Path where to put the MSVC project files.
 
+	StringList includeDirs; ///< List of additional include paths
+	StringList libraryDirs; ///< List of additional library paths
+
 	EngineDescList engines; ///< Engine list for the build (this may contain engines, which are *not* enabled!).
 	FeatureList features;   ///< Feature list for the build (this may contain features, which are *not* enabled!).
 
diff --git a/devtools/create_project/msbuild.cpp b/devtools/create_project/msbuild.cpp
index 84126946c4..293ccca05f 100644
--- a/devtools/create_project/msbuild.cpp
+++ b/devtools/create_project/msbuild.cpp
@@ -358,13 +358,21 @@ void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstrea
 	if (runBuildEvents)
 		definesList += REVISION_DEFINE ";";
 
+	std::string includeDirsList;
+	for (StringList::const_iterator i = setup.includeDirs.begin(); i != setup.includeDirs.end(); ++i)
+		includeDirsList += convertPathToWin(*i) + ';';
+
+	std::string libraryDirsList;
+	for (StringList::const_iterator i = setup.libraryDirs.begin(); i != setup.libraryDirs.end(); ++i)
+		libraryDirsList += convertPathToWin(*i) + ';';
+
 	properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
 	           << "<Project DefaultTargets=\"Build\" ToolsVersion=\"" << _msvcVersion.project << "\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
 	           << "\t<PropertyGroup>\n"
 	           << "\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_Global</_PropertySheetDisplayName>\n"
 	           << "\t\t<ExecutablePath>$(" << LIBS_DEFINE << ")\\bin;$(" << LIBS_DEFINE << ")\\bin\\" << getMSVCArchName(arch) << ";$(" << LIBS_DEFINE << ")\\$(Configuration)\\bin;$(ExecutablePath)</ExecutablePath>\n"
-	           << "\t\t<LibraryPath>$(" << LIBS_DEFINE << ")\\lib\\" << getMSVCArchName(arch) << ";$(" << LIBS_DEFINE << ")\\lib\\" << getMSVCArchName(arch) << "\\$(Configuration);$(" << LIBS_DEFINE << ")\\lib;$(" << LIBS_DEFINE << ")\\$(Configuration)\\lib;$(LibraryPath)</LibraryPath>\n"
-	           << "\t\t<IncludePath>$(" << LIBS_DEFINE << ")\\include;$(" << LIBS_DEFINE << ")\\include\\" << (setup.useSDL2 ? "SDL2" : "SDL") << ";$(IncludePath)</IncludePath>\n"
+	           << "\t\t<LibraryPath>" << libraryDirsList << "$(" << LIBS_DEFINE << ")\\lib\\" << getMSVCArchName(arch) << ";$(" << LIBS_DEFINE << ")\\lib\\" << getMSVCArchName(arch) << "\\$(Configuration);$(" << LIBS_DEFINE << ")\\lib;$(" << LIBS_DEFINE << ")\\$(Configuration)\\lib;$(LibraryPath)</LibraryPath>\n"
+	           << "\t\t<IncludePath>" << includeDirsList << "$(" << LIBS_DEFINE << ")\\include;$(" << LIBS_DEFINE << ")\\include\\" << (setup.useSDL2 ? "SDL2" : "SDL") << ";$(IncludePath)</IncludePath>\n"
 	           << "\t\t<OutDir>$(Configuration)" << getMSVCArchName(arch) << "\\</OutDir>\n"
 	           << "\t\t<IntDir>$(Configuration)" << getMSVCArchName(arch) << "\\$(ProjectName)\\</IntDir>\n"
 	           << "\t</PropertyGroup>\n"
diff --git a/devtools/create_project/visualstudio.cpp b/devtools/create_project/visualstudio.cpp
index f8196d65e4..459e0fdace 100644
--- a/devtools/create_project/visualstudio.cpp
+++ b/devtools/create_project/visualstudio.cpp
@@ -187,6 +187,10 @@ void VisualStudioProvider::outputGlobalPropFile(const BuildSetup &setup, std::of
 	for (StringList::const_iterator i = _globalWarnings.begin(); i != _globalWarnings.end(); ++i)
 		warnings += *i + ';';
 
+	std::string includeDirsList;
+	for (StringList::const_iterator i = setup.includeDirs.begin(); i != setup.includeDirs.end(); ++i)
+		includeDirsList += convertPathToWin(*i) + ';';
+
 	std::string definesList;
 	for (StringList::const_iterator i = defines.begin(); i != defines.end(); ++i) {
 		if (i != defines.begin())
@@ -210,7 +214,7 @@ void VisualStudioProvider::outputGlobalPropFile(const BuildSetup &setup, std::of
 	           << "\t\tName=\"VCCLCompilerTool\"\n"
 	           << "\t\tDisableLanguageExtensions=\"" << (setup.devTools ? "false" : "true") << "\"\n"
 	           << "\t\tDisableSpecificWarnings=\"" << warnings << "\"\n"
-	           << "\t\tAdditionalIncludeDirectories=\".\\;" << prefix << ";" << prefix << "\\engines;$(" << LIBS_DEFINE << ")\\include;$(" << LIBS_DEFINE << ")\\include\\SDL;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "\"\n"
+	           << "\t\tAdditionalIncludeDirectories=\".\\;" << prefix << ";" << prefix << "\\engines;" << includeDirsList << "$(" << LIBS_DEFINE << ")\\include;$(" << LIBS_DEFINE << ")\\include\\SDL;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "\"\n"
 	           << "\t\tPreprocessorDefinitions=\"" << definesList << "\"\n"
 	           << "\t\tExceptionHandling=\"" << ((setup.devTools || setup.tests || _version == 14) ? "1" : "0") << "\"\n";
 
@@ -241,7 +245,11 @@ void VisualStudioProvider::outputGlobalPropFile(const BuildSetup &setup, std::of
 	if (!setup.devTools && !setup.tests)
 		properties << "\t\tEntryPointSymbol=\"WinMainCRTStartup\"\n";
 
-	properties << "\t\tAdditionalLibraryDirectories=\"$(" << LIBS_DEFINE << ")\\lib\\" << getMSVCArchName(arch) << "\"\n"
+	std::string libraryDirsList;
+	for (StringList::const_iterator i = setup.libraryDirs.begin(); i != setup.libraryDirs.end(); ++i)
+		libraryDirsList += convertPathToWin(*i) + ';';
+
+	properties << "\t\tAdditionalLibraryDirectories=\"" << libraryDirsList << "$(" << LIBS_DEFINE << ")\\lib\\" << getMSVCArchName(arch) << "\"\n"
 	           << "\t/>\n"
 	           << "\t<Tool\n"
 	           << "\t\tName=\"VCResourceCompilerTool\"\n"
diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp
index cf7784bb2f..3ac40d8c48 100644
--- a/devtools/create_project/xcode.cpp
+++ b/devtools/create_project/xcode.cpp
@@ -1068,6 +1068,8 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
 	ValueList iPhone_HeaderSearchPaths;
 	iPhone_HeaderSearchPaths.push_back("$(SRCROOT)/engines/");
 	iPhone_HeaderSearchPaths.push_back("$(SRCROOT)");
+	for (StringList::const_iterator i = setup.includeDirs.begin(); i != setup.includeDirs.end(); ++i)
+		iPhone_HeaderSearchPaths.push_back("\"" + *i + "\"");
 	iPhone_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "\"");
 	iPhone_HeaderSearchPaths.push_back("\"" + projectOutputDirectory + "/include\"");
 	if (CONTAINS_DEFINE(setup.defines, "USE_SDL_NET")) {
@@ -1079,6 +1081,8 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
 	ADD_SETTING_LIST(iPhone_Debug, "HEADER_SEARCH_PATHS", iPhone_HeaderSearchPaths, kSettingsAsList | kSettingsQuoteVariable, 5);
 	ADD_SETTING_QUOTE(iPhone_Debug, "INFOPLIST_FILE", "$(SRCROOT)/dists/ios7/Info.plist");
 	ValueList iPhone_LibPaths;
+	for (StringList::const_iterator i = setup.libraryDirs.begin(); i != setup.libraryDirs.end(); ++i)
+		iPhone_LibPaths.push_back("\"" + *i + "\"");
 	iPhone_LibPaths.push_back("$(inherited)");
 	iPhone_LibPaths.push_back("\"" + projectOutputDirectory + "/lib\"");
 	ADD_SETTING_LIST(iPhone_Debug, "LIBRARY_SEARCH_PATHS", iPhone_LibPaths, kSettingsAsList, 5);
@@ -1148,6 +1152,8 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
 	ADD_SETTING_LIST(scummvmOSX_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvmOSX_defines, kSettingsNoQuote | kSettingsAsList, 5);
 	ADD_SETTING_QUOTE(scummvmOSX_Debug, "GCC_VERSION", "");
 	ValueList scummvmOSX_HeaderPaths;
+	for (StringList::const_iterator i = setup.includeDirs.begin(); i != setup.includeDirs.end(); ++i)
+		scummvmOSX_HeaderPaths.push_back("\"" + *i + "\"");
 	if (setup.useSDL2) {
 		scummvmOSX_HeaderPaths.push_back("/usr/local/include/SDL2");
 		scummvmOSX_HeaderPaths.push_back("/opt/local/include/SDL2");
@@ -1165,6 +1171,8 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
 	ADD_SETTING_LIST(scummvmOSX_Debug, "HEADER_SEARCH_PATHS", scummvmOSX_HeaderPaths, kSettingsQuoteVariable | kSettingsAsList, 5);
 	ADD_SETTING_QUOTE(scummvmOSX_Debug, "INFOPLIST_FILE", "$(SRCROOT)/dists/macosx/Info.plist");
 	ValueList scummvmOSX_LibPaths;
+	for (StringList::const_iterator i = setup.libraryDirs.begin(); i != setup.libraryDirs.end(); ++i)
+		scummvmOSX_LibPaths.push_back("\"" + *i + "\"");
 	scummvmOSX_LibPaths.push_back("/usr/local/lib");
 	scummvmOSX_LibPaths.push_back("/opt/local/lib");
 	scummvmOSX_LibPaths.push_back("\"$(inherited)\"");


Commit: 2021a1495cff1f47b3c4f00cbfaff3917f1a8fe9
    https://github.com/scummvm/scummvm/commit/2021a1495cff1f47b3c4f00cbfaff3917f1a8fe9
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
SCI32: Remove kFileIOReadString warning

It's normal for fewer charcters to be available than the maximum buffer
size . Confirmed that nothing depends on not zeroing out the remaining
bytes. (In fact, we've had problems before when not zeroing out buffers
in other kernel functions as scripts have been known to assume success
and use the buffer regardless of the return value.)

Changed paths:
    engines/sci/engine/kfile.cpp


diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index f6ec127333..9a4d0cdd69 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -721,11 +721,6 @@ reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) {
 	} else if ((int)bytesRead > dest_r.maxSize) {
 		error("kFileIO(readString) attempting to read %u bytes into buffer of size %u", bytesRead, dest_r.maxSize);
 	} else if (maxsize > dest_r.maxSize) {
-		// This happens at least in the QfG4 character import.
-		// CHECKME: We zero the remainder of the dest buffer, while
-		// at least several (and maybe all) SSCI interpreters didn't do this.
-		// Therefore this warning is presumably no problem.
-		warning("kFileIO(readString) attempting to copy %u bytes into buffer of size %u (%u/%u bytes actually read)", maxsize, dest_r.maxSize, bytesRead, maxsize);
 		maxsize = dest_r.maxSize;
 	}
 


Commit: 2830063c0eb3b19597b3f9599cda3c6b9a39702a
    https://github.com/scummvm/scummvm/commit/2830063c0eb3b19597b3f9599cda3c6b9a39702a
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
VIDEO: QuickTime comments, mild cleanup

Changed paths:
    common/quicktime.cpp
    common/quicktime.h
    video/qt_decoder.cpp
    video/qt_decoder.h


diff --git a/common/quicktime.cpp b/common/quicktime.cpp
index 7b84b3aaea..3bbf4590b7 100644
--- a/common/quicktime.cpp
+++ b/common/quicktime.cpp
@@ -368,7 +368,6 @@ int QuickTimeParser::readTRAK(Atom atom) {
 	Track *track = new Track();
 
 	track->codecType = CODEC_TYPE_MOV_OTHER;
-	track->startTime = 0; // XXX: check
 	_tracks.push_back(track);
 
 	return readDefault(atom);
@@ -837,7 +836,6 @@ QuickTimeParser::Track::Track() {
 	codecType = CODEC_TYPE_MOV_OTHER;
 	frameCount = 0;
 	duration = 0;
-	startTime = 0;
 	mediaDuration = 0;
 }
 
diff --git a/common/quicktime.h b/common/quicktime.h
index 9d91027043..52932f3cb6 100644
--- a/common/quicktime.h
+++ b/common/quicktime.h
@@ -93,7 +93,7 @@ protected:
 
 	struct TimeToSampleEntry {
 		int count;
-		int duration;
+		int duration; // media time
 	};
 
 	struct SampleToChunkEntry {
@@ -103,9 +103,9 @@ protected:
 	};
 
 	struct EditListEntry {
-		uint32 trackDuration;
-		uint32 timeOffset;
-		int32 mediaTime;
+		uint32 trackDuration; // movie time
+		uint32 timeOffset;    // movie time
+		int32 mediaTime;      // media time
 		Rational mediaRate;
 	};
 
@@ -148,7 +148,7 @@ protected:
 		uint32 *sampleSizes;
 		uint32 keyframeCount;
 		uint32 *keyframes;
-		int32 timeScale;
+		int32 timeScale; // media time
 
 		uint16 width;
 		uint16 height;
@@ -158,18 +158,17 @@ protected:
 
 		Common::Array<EditListEntry> editList;
 
-		uint32 frameCount;
-		uint32 duration;
-		uint32 mediaDuration;
-		uint32 startTime;
+		uint32 frameCount;    // from stts
+		uint32 duration;      // movie time
+		uint32 mediaDuration; // media time
 		Rational scaleFactorX;
 		Rational scaleFactorY;
 	};
 
 	virtual SampleDesc *readSampleDesc(Track *track, uint32 format, uint32 descSize) = 0;
 
-	uint32 _timeScale;
-	uint32 _duration;
+	uint32 _timeScale;      // movie time
+	uint32 _duration;       // movie time
 	Rational _scaleFactorX;
 	Rational _scaleFactorY;
 	Array<Track *> _tracks;
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 1644dc9f5c..00d8686376 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -295,7 +295,7 @@ QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder
 	checkEditListBounds();
 
 	_curEdit = 0;
-	enterNewEditList(false);
+	enterNewEditListEntry(false);
 
 	_curFrame = -1;
 	_durationOverride = -1;
@@ -380,12 +380,12 @@ bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requested
 			_curEdit++;
 
 		if (!atLastEdit())
-			enterNewEditList(true);
+			enterNewEditListEntry(true);
 
 		return true;
 	}
 
-	enterNewEditList(false);
+	enterNewEditListEntry(false);
 
 	// One extra check for the end of a track
 	if (atLastEdit()) {
@@ -403,7 +403,7 @@ bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requested
 			_nextFrameStartTime += _durationOverride;
 			_durationOverride = -1;
 		} else {
-			_nextFrameStartTime += getFrameDuration();
+			_nextFrameStartTime += getCurFrameDuration();
 		}
 	}
 
@@ -505,7 +505,7 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame()
 		if (atLastEdit())
 			return 0;
 
-		enterNewEditList(true);
+		enterNewEditListEntry(true);
 	}
 
 	const Graphics::Surface *frame = bufferNextFrame();
@@ -517,7 +517,7 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame()
 			_durationOverride = -1;
 		} else {
 			// Just need to subtract the time
-			_nextFrameStartTime -= getFrameDuration();
+			_nextFrameStartTime -= getCurFrameDuration();
 		}
 	} else {
 		if (_durationOverride >= 0) {
@@ -525,7 +525,7 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame()
  			_nextFrameStartTime += _durationOverride;
 			_durationOverride = -1;
 		} else {
-			_nextFrameStartTime += getFrameDuration();
+			_nextFrameStartTime += getCurFrameDuration();
 		}
 	}
 
@@ -665,7 +665,7 @@ Common::SeekableReadStream *QuickTimeDecoder::VideoTrackHandler::getNextFramePac
 	return stream->readStream(_parent->sampleSizes[_curFrame]);
 }
 
-uint32 QuickTimeDecoder::VideoTrackHandler::getFrameDuration() {
+uint32 QuickTimeDecoder::VideoTrackHandler::getCurFrameDuration() {
 	uint32 curFrameIndex = 0;
 	for (int32 i = 0; i < _parent->timeToSampleCount; i++) {
 		curFrameIndex += _parent->timeToSample[i].count;
@@ -689,7 +689,7 @@ uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const {
 	return frame;
 }
 
-void QuickTimeDecoder::VideoTrackHandler::enterNewEditList(bool bufferFrames) {
+void QuickTimeDecoder::VideoTrackHandler::enterNewEditListEntry(bool bufferFrames) {
 	// Bypass all empty edit lists first
 	while (!atLastEdit() && _parent->editList[_curEdit].mediaTime == -1)
 		_curEdit++;
@@ -812,7 +812,7 @@ uint32 QuickTimeDecoder::VideoTrackHandler::getCurEditTimeOffset() const {
 }
 
 uint32 QuickTimeDecoder::VideoTrackHandler::getCurEditTrackDuration() const {
-	// Need to convert to the track scale
+	// convert from movie time scale to the track's media time scale
 	return _parent->editList[_curEdit].trackDuration * _parent->timeScale / _decoder->_timeScale;
 }
 
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index 3b1e461b84..8f90327bda 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -134,7 +134,7 @@ private:
 		Graphics::PixelFormat getPixelFormat() const;
 		int getCurFrame() const { return _curFrame; }
 		int getFrameCount() const;
-		uint32 getNextFrameStartTime() const;
+		uint32 getNextFrameStartTime() const; // milliseconds
 		const Graphics::Surface *decodeNextFrame();
 		const byte *getPalette() const;
 		bool hasDirtyPalette() const { return _curPalette; }
@@ -151,9 +151,9 @@ private:
 		Common::QuickTimeParser::Track *_parent;
 		uint32 _curEdit;
 		int32 _curFrame;
-		uint32 _nextFrameStartTime;
+		uint32 _nextFrameStartTime; // media time
 		Graphics::Surface *_scaledSurface;
-		int32 _durationOverride;
+		int32 _durationOverride;    // media time
 		const byte *_curPalette;
 		mutable bool _dirtyPalette;
 		bool _reversed;
@@ -165,13 +165,13 @@ private:
 		const Graphics::Surface *forceDither(const Graphics::Surface &frame);
 
 		Common::SeekableReadStream *getNextFramePacket(uint32 &descId);
-		uint32 getFrameDuration();
+		uint32 getCurFrameDuration();            // media time
 		uint32 findKeyFrame(uint32 frame) const;
-		void enterNewEditList(bool bufferFrames);
+		void enterNewEditListEntry(bool bufferFrames);
 		const Graphics::Surface *bufferNextFrame();
-		uint32 getRateAdjustedFrameTime() const;
-		uint32 getCurEditTimeOffset() const;
-		uint32 getCurEditTrackDuration() const;
+		uint32 getRateAdjustedFrameTime() const; // media time
+		uint32 getCurEditTimeOffset() const;     // media time
+		uint32 getCurEditTrackDuration() const;  // media time
 		bool atLastEdit() const;
 		bool endOfCurEdit() const;
 		void checkEditListBounds();


Commit: 6a55907932e09d1ee457c593e6ab59756592c9ee
    https://github.com/scummvm/scummvm/commit/6a55907932e09d1ee457c593e6ab59756592c9ee
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
VIDEO: Limit QuickTime workaround to Riven

QuickTimeDecoder has a workaround for a video in a Spanish version of
Riven, but this workaround breaks valid QuickTime videos such as the
KQ6 Macintosh opening movie. (Bug #11085)

Until the original Riven video bug can be debugged to improve the
workaround, it is now disabled unless an engine enables it.

Workaround added in: b8abe400850a23d12fe5cdc24d7106820d0f13fd

Changed paths:
    engines/mohawk/riven_video.cpp
    video/qt_decoder.cpp
    video/qt_decoder.h


diff --git a/engines/mohawk/riven_video.cpp b/engines/mohawk/riven_video.cpp
index 38d7e7f6c8..b0d20f3194 100644
--- a/engines/mohawk/riven_video.cpp
+++ b/engines/mohawk/riven_video.cpp
@@ -65,6 +65,7 @@ void RivenVideo::load(uint16 id) {
 	_video->setSoundType(Audio::Mixer::kSFXSoundType);
 	_video->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id));
 	_video->loadStream(_vm->getResource(ID_TMOV, id));
+	_video->enableEditListBoundsCheckQuirk(true); // for Spanish olw.mov
 }
 
 void RivenVideo::close() {
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 00d8686376..71780fd334 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -51,6 +51,7 @@ namespace Video {
 QuickTimeDecoder::QuickTimeDecoder() {
 	_scaledSurface = 0;
 	_width = _height = 0;
+	_enableEditListBoundsCheckQuirk = false;
 }
 
 QuickTimeDecoder::~QuickTimeDecoder() {
@@ -292,7 +293,9 @@ Audio::SeekableAudioStream *QuickTimeDecoder::AudioTrackHandler::getSeekableAudi
 }
 
 QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : _decoder(decoder), _parent(parent) {
-	checkEditListBounds();
+	if (decoder->_enableEditListBoundsCheckQuirk) {
+		checkEditListBounds();
+	}
 
 	_curEdit = 0;
 	enterNewEditListEntry(false);
@@ -308,6 +311,12 @@ QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder
 	_ditherFrame = 0;
 }
 
+// FIXME: This check breaks valid QuickTime movies, such as the KQ6 Mac opening.
+// It doesn't take media rate into account and mixes up units that are in movie
+// time scale and media time scale, which is easy to do since they're often the
+// same value. Other decoder bugs have been fixed since this was written, so it
+// would be good to re-evaluate what the problem was with the Riven Spanish video.
+// It's now disabled for everything except Riven.
 void QuickTimeDecoder::VideoTrackHandler::checkEditListBounds() {
 	// Check all the edit list entries are within the bounds of the media
 	// In the Spanish version of Riven, the last edit of the video ogk.mov
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index 8f90327bda..c2aef7da3c 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -71,6 +71,8 @@ public:
 	const Graphics::Surface *decodeNextFrame();
 	Audio::Timestamp getDuration() const { return Audio::Timestamp(0, _duration, _timeScale); }
 
+	void enableEditListBoundsCheckQuirk(bool enable) { _enableEditListBoundsCheckQuirk = enable; }
+
 protected:
 	Common::QuickTimeParser::SampleDesc *readSampleDesc(Common::QuickTimeParser::Track *track, uint32 format, uint32 descSize);
 
@@ -85,6 +87,8 @@ private:
 	void scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst,
 			const Common::Rational &scaleFactorX, const Common::Rational &scaleFactorY);
 
+	bool _enableEditListBoundsCheckQuirk;
+
 	class VideoSampleDesc : public Common::QuickTimeParser::SampleDesc {
 	public:
 		VideoSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag);


Commit: f4aa6b957839a4ca55f1c07bd5923fd401d048c3
    https://github.com/scummvm/scummvm/commit/f4aa6b957839a4ca55f1c07bd5923fd401d048c3
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
VIDEO: Fix QuickTime decoding of edits with mediaTime

QuickTimeDecoder has a bug which causes the mediaTime offset to be
ignored when a track begins with an empty edit and is followed by an
edit with a non-zero mediaTime. This causes the KQ6 Mac opening movie
to start several tracks at unintended frames (they're never supposed to
be displayed) and the intended frames at the end of the edit to never
be displayed. (Bug #11085)

Changed paths:
    video/qt_decoder.cpp
    video/qt_decoder.h


diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 71780fd334..48e7c130bc 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -298,9 +298,9 @@ QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder
 	}
 
 	_curEdit = 0;
-	enterNewEditListEntry(false);
-
 	_curFrame = -1;
+	enterNewEditListEntry(true); // might set _curFrame
+
 	_durationOverride = -1;
 	_scaledSurface = 0;
 	_curPalette = 0;
@@ -515,6 +515,9 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame()
 			return 0;
 
 		enterNewEditListEntry(true);
+
+		if (isEmptyEdit())
+			return 0;
 	}
 
 	const Graphics::Surface *frame = bufferNextFrame();
@@ -698,14 +701,22 @@ uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const {
 	return frame;
 }
 
-void QuickTimeDecoder::VideoTrackHandler::enterNewEditListEntry(bool bufferFrames) {
-	// Bypass all empty edit lists first
-	while (!atLastEdit() && _parent->editList[_curEdit].mediaTime == -1)
-		_curEdit++;
+bool QuickTimeDecoder::VideoTrackHandler::isEmptyEdit() const {
+	return (_parent->editList[_curEdit].mediaTime == -1);
+}
 
+void QuickTimeDecoder::VideoTrackHandler::enterNewEditListEntry(bool bufferFrames) {
 	if (atLastEdit())
 		return;
 
+	// if this is an empty edit then the only thing to do is set the
+	// time for the next frame, which is the duration of this edit.
+	if (isEmptyEdit()) {
+		_curFrame = -1;
+		_nextFrameStartTime = getCurEditTimeOffset() + getCurEditTrackDuration();
+		return;
+	}
+
 	uint32 mediaTime = _parent->editList[_curEdit].mediaTime;
 	uint32 frameNum = 0;
 	uint32 totalDuration = 0;
@@ -793,8 +804,12 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::bufferNextFrame()
 }
 
 uint32 QuickTimeDecoder::VideoTrackHandler::getRateAdjustedFrameTime() const {
-	// Figure out what time the next frame is at taking the edit list rate into account
-	Common::Rational offsetFromEdit = Common::Rational(_nextFrameStartTime - getCurEditTimeOffset()) / _parent->editList[_curEdit].mediaRate;
+	// Figure out what time the next frame is at taking the edit list rate into account,
+	// unless this is an empty edit, in which case the rate isn't applicable.
+	Common::Rational offsetFromEdit = Common::Rational(_nextFrameStartTime - getCurEditTimeOffset());
+	if (!isEmptyEdit()) {
+		offsetFromEdit /= _parent->editList[_curEdit].mediaRate;
+	}
 	uint32 convertedTime = offsetFromEdit.toInt();
 
 	if ((offsetFromEdit.getNumerator() % offsetFromEdit.getDenominator()) > (offsetFromEdit.getDenominator() / 2))
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index c2aef7da3c..5f1a19cfcb 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -171,6 +171,7 @@ private:
 		Common::SeekableReadStream *getNextFramePacket(uint32 &descId);
 		uint32 getCurFrameDuration();            // media time
 		uint32 findKeyFrame(uint32 frame) const;
+		bool isEmptyEdit() const;
 		void enterNewEditListEntry(bool bufferFrames);
 		const Graphics::Surface *bufferNextFrame();
 		uint32 getRateAdjustedFrameTime() const; // media time


Commit: 4180555675165afa0807d480260ed5bfcf156739
    https://github.com/scummvm/scummvm/commit/4180555675165afa0807d480260ed5bfcf156739
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
SCI: Fix KQ6 Mac inconsistent timing in opening movie

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


diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 0f6cf95ef2..861649eeb8 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -6444,12 +6444,34 @@ static const uint16 kq6PatchFeatureEventHandling[] = {
 	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,   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 },


Commit: cdd463a37afe43b76b565a9dd405ebb57d930ca8
    https://github.com/scummvm/scummvm/commit/cdd463a37afe43b76b565a9dd405ebb57d930ca8
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2021-11-26T21:30:07-07:00

Commit Message:
VIDEO: Fix QuickTime decoding when color depth is 32

Color depths greater than 32 have grayscale bit 0x20 set, but the
decoder incorrectly treats 32 as grayscale and and clears the bit,
leaving the color depth as zero and causing codecs to fail.

Confirmed correct behavior in the ffmpeg code that the decoder was
based off. The decoder was introduced with the Mohawk engine in
2009,so presumably no Mohawk movies had color depth 32.

Fixes videos in the Director game Virtual Cocktail Bar

Changed paths:
    video/qt_decoder.cpp


diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 48e7c130bc..5022054753 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -201,6 +201,8 @@ Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Common::Qu
 					_fd->readByte();
 				}
 			}
+
+			entry->_bitsPerSample &= 0x1f; // clear grayscale bit
 		}
 
 		return entry;
@@ -272,7 +274,7 @@ QuickTimeDecoder::VideoSampleDesc::~VideoSampleDesc() {
 }
 
 void QuickTimeDecoder::VideoSampleDesc::initCodec() {
-	_videoCodec = Image::createQuickTimeCodec(_codecTag, _parentTrack->width, _parentTrack->height, _bitsPerSample & 0x1f);
+	_videoCodec = Image::createQuickTimeCodec(_codecTag, _parentTrack->width, _parentTrack->height, _bitsPerSample);
 }
 
 QuickTimeDecoder::AudioTrackHandler::AudioTrackHandler(QuickTimeDecoder *decoder, QuickTimeAudioTrack *audioTrack) :




More information about the Scummvm-git-logs mailing list