[Scummvm-git-logs] scummvm master -> 0f93142ac9a6d92e16b3e7a3d16cdb2cdf72be80

sev- noreply at scummvm.org
Mon Nov 28 22:22:06 UTC 2022


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

Summary:
13e7c9d4d9 SCUMM: Implement basic support for v0-3 GUI
9cb7293de3 SCUMM: Clean-up and implement remaining messages for v0-1-2-3
213b49336a SCUMM: LOOM v3: Fix query quit banner
6560244a81 SCUMM: GUI: Fix regression in snap scroll message
a8fc3f706d SCUMM: GUI: Update the detection tables for the new games supporting the GUI
bf0ecd47ff SCUMM: Implement message boxes for Mac Loom and Last Crusade
0c0bfe70ad SCUMM: GUI: Clean-up and fix v3 Mac banners
5f9d6d7780 SCUMM: GUI: Fix v5 banner colors for Mac versions
b8e4fbb72b SCUMM: GUI: Fix GMM not opening on F5 press for v3 Mac games
172bc2d4c4 SCUMM: GUI: Fix v3 FM-Towns games crashing on banner display
415370598c SCUMM: GUI: Fix black screen glitches on FMTowns v3 games
ca3d80e281 SCUMM: GUI: Fix banner color for v3 FM-Towns games
a3a7d4a131 SCUMM: GUI: Fix banner and text position on v3 FM-Towns games
0944412c0e SCUMM: GUI: Fix graphical glitches in LOOM Towns
a0baee6e6f SCUMM: GUI: Fix remaining v3 FM-Towns banner-related glitches
89009fedcd SCUMM: GUI: Fix graphical glitches and random distaff disappearances on LOOM v3
3519891ca1 SCUMM: GUI: Fix regression on v3 Towns games
617a52fc76 SCUMM: GUI: Flag Loom PC-Engine as unsupported
3bc9064278 SCUMM: GUI: Make the restart prompt more consistent
f1a18f26e2 SCUMM: GUI: Fix regression on v4 games restart prompts
3f96b8980b SCUMM: GUI: Implement a v3 table for hardcoded quit prompts
81cee05840 SCUMM: Fix missable termination condition on strings parsing
9900bbd616 SCUMM: GUI: Implement original save/load menus for v5 FM-Towns games
a0613993d3 SCUMM: GUI: Substitute 0 with nullptr for pointer values
2c36f10932 SCUMM: GUI: Cleanup
e93f6d2b83 SCUMM: GUI: Fix v5 FM-Towns menu box title
ab5010e04b SCUMM: GUI: Remove menu inner box on v5 FM-Towns games
26cc83566d SCUMM: GUI: Add Amiga snail cursor for v2 games
7a007db0f8 SCUMM: Fix warning
9fee7adf52 SCUMM: Explicitly remove support for original GUI to ST v2 games
1d206fbc53 SCUMM: v0-1-2-3: Implement actual saving\loading system
918b7f95f1 SCUMM: v3: Fix minor graphical glitch on game quit
939a9bba39 SCUMM: LOOM (Towns): Implement original save menu quirk with slot 0
2a91e8ef70 SCUMM: LOOM (Towns): Fix save slot boxes being smaller than they look on the original
617e7f6077 SCUMM: LOOM (Towns): Fix crashes on the menu when no savegames are available
0f93142ac9 SCUMM: MI1 (Sega CD): Fix message banner colors


Commit: 13e7c9d4d9c6ff0ae682c4885d902c2dda516d22
    https://github.com/scummvm/scummvm/commit/13e7c9d4d9c6ff0ae682c4885d902c2dda516d22
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: Implement basic support for v0-3 GUI

Changed paths:
    engines/scumm/cursor.cpp
    engines/scumm/dialogs.cpp
    engines/scumm/dialogs.h
    engines/scumm/gfx_gui.cpp
    engines/scumm/input.cpp
    engines/scumm/script_v2.cpp
    engines/scumm/script_v4.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v2.h
    engines/scumm/scumm_v5.h
    engines/scumm/string.cpp


diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index 857cdd42271..9652ef273ca 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -91,6 +91,32 @@ static const byte default_v6_cursor[] = {
 	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
 };
 
+static const byte c64_dos_snail_cursor[] = {
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0x0F,0x0F,0xFF,0xFF,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0x0F,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0x0F,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0xFF,0x0F,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0xFF,0x0F,0x0F,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,
+	0xFF,0xFF,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,
+	0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,
+	0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0xFF,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0xFF,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,0x0F,0x0F,
+
+	// Blank pixels...
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+};
+
 #ifdef ENABLE_SCUMM_7_8
 static const byte default_v7_cursor[] = {
 	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
@@ -809,6 +835,24 @@ void ScummEngine_v2::setBuiltinCursor(int idx) {
 	updateCursor();
 }
 
+void ScummEngine_v2::setSnailCursor() {
+	memcpy(_grabbedCursor, c64_dos_snail_cursor, sizeof(c64_dos_snail_cursor));
+
+	if (_game.version == 0) {
+		for (int i = 0; i < sizeof(c64_dos_snail_cursor); i++) {
+			if (_grabbedCursor[i] == 0x0F)
+				_grabbedCursor[i] = 0x01;
+		}
+	}
+
+	_cursor.width = 24;
+	_cursor.height = 21;
+	_cursor.hotspotX = 11;
+	_cursor.hotspotY = 10;
+
+	updateCursor();
+}
+
 void ScummEngine_v5::resetCursors() {
 	static const uint16 default_cursor_images[4][16] = {
 		/* cross-hair */
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 0e0d4d03a97..86bb9bdef02 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -429,8 +429,8 @@ void InfoDialog::reflowLayout() {
 	_text->setSize(_w, _h);
 }
 
-const char *InfoDialog::getPlainEngineString(int stringno) {
-	const char *result;
+const char *InfoDialog::getPlainEngineString(int stringno, bool forceHardcodedString) {
+	const char *result = nullptr;
 
 	if (stringno == 0)
 		return nullptr;
@@ -450,7 +450,8 @@ const char *InfoDialog::getPlainEngineString(int stringno) {
 			result = string_map_table_v6[stringno - 1].string;
 		}
 	} else if (_vm->_game.version >= 3) {
-		result = (const char *)_vm->getStringAddress(getStaticResString(_vm->_language, stringno - 1).num);
+		if (!forceHardcodedString)
+			result = (const char *)_vm->getStringAddress(getStaticResString(_vm->_language, stringno - 1).num);
 
 		if (!result) {
 			result = getStaticResString(_vm->_language, stringno - 1).string;
@@ -587,12 +588,12 @@ const ResString &InfoDialog::getStaticResString(Common::Language lang, int strin
 			{6, "Wollen Sie wirklich beenden? (j/n)j"}				// (matching the previous sentence)
 		},
 		{	// Italian
-			{1, "Inserisci il disco %c e premi un pulsante per continuare."},
-			{2, "Impossibile trovare %s, (%c%d) Premere un pulsante."},
-			{3, "Errore nella lettura del disco %c, (%c%d) Premere un pulsante."},
-			{4, "Gioco in pausa. Premi SPAZIO per continuare."},
-			{5, "Sei sicuro di voler ricominciare?  (S/N)S"},
-			{6, "Sei sicuro di voler uscire?  (S/N)S"}
+			{1, "Inserisci il Disk n. Premi ENTER."},			// Original DOS Italian v2
+			{2, "Non trovato il file nn.lfl. Premi ENTER."},	// Original DOS Italian v2
+			{3, "ERROR READING %d type %d"},					// As found on the Italian v2 executable...
+			{4, "PAUSA - Premere SPAZIO per continuare."},		// Original DOS Italian v2
+			{5, "Sei sicuro di voler ricominciare? (s/n)s"},	// Original DOS Italian v2
+			{6, "Sei sicuro di voler uscire?  (s/n)s"}			// Original DOS Italian v2
 		},
 		{	// Spanish
 			{1, "Introduce el disco %c y pulsa un bot""\xa2""n para continuar."},
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index df3a60e95e4..a561f9a5353 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -96,7 +96,7 @@ public:
 	}
 
 	void reflowLayout() override;
-	const char *getPlainEngineString(int stringno);
+	const char *getPlainEngineString(int stringno, bool forceHardcodedString = false);
 
 protected:
 	// Query a string from the resources
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 04a82984a4c..fc29df89e3b 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "scumm/scumm.h"
+#include "scumm/scumm_v2.h"
 #include "scumm/scumm_v4.h"
 #include "scumm/scumm_v6.h"
 #include "scumm/scumm_v8.h"
@@ -261,6 +262,91 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	return ks;
 }
 
+Common::KeyState ScummEngine::printMessageAndPause(const char *msg, int32 waitTime, bool drawOnSentenceLine) {
+	Common::Rect sentenceline;
+
+	// Pause the engine
+	PauseToken pt = pauseEngine();
+
+	if (drawOnSentenceLine) {
+		setSnailCursor();
+
+		_string[2].charset = 1;
+		_string[2].ypos = _virtscr[kVerbVirtScreen].topline;
+		_string[2].xpos = 0;
+		_string[2].right = _virtscr[kVerbVirtScreen].w - 1;
+		if (_game.platform == Common::kPlatformNES) {
+			_string[2].xpos = 16;
+			_string[2].color = 0;
+		} else if (_game.platform == Common::kPlatformC64) {
+			_string[2].color = 16;
+		} else {
+			_string[2].color = 13;
+		}
+
+		byte string[80];
+		const char *ptr = msg;
+		int i = 0, len = 0;
+
+		// Maximum length of printable characters
+		int maxChars = (_game.platform == Common::kPlatformNES) ? 60 : 40;
+		while (*ptr) {
+			if (*ptr != '@')
+				len++;
+			if (len > maxChars) {
+				break;
+			}
+
+			string[i++] = *ptr++;
+
+			if (_game.platform == Common::kPlatformNES && len == 30) {
+				string[i++] = 0xFF;
+				string[i++] = 8;
+			}
+		}
+		string[i] = 0;
+
+		if (_game.platform == Common::kPlatformNES) {
+			sentenceline.top = _virtscr[kVerbVirtScreen].topline;
+			sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 16;
+			sentenceline.left = 16;
+			sentenceline.right = _virtscr[kVerbVirtScreen].w - 1;
+		} else {
+			sentenceline.top = _virtscr[kVerbVirtScreen].topline;
+			sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 8;
+			sentenceline.left = 0;
+			sentenceline.right = _virtscr[kVerbVirtScreen].w - 1;
+		}
+		restoreBackground(sentenceline);
+		drawString(2, (byte *)string);
+		drawDirtyScreenParts();
+	} else {
+
+	}
+
+	// Wait until the engine receives a new Keyboard or Mouse input,
+	// unless we have specified a positive waitTime: in that case, the banner
+	// will stay on screen until an input has been received or until the time-out.
+	Common::KeyState ks = Common::KEYCODE_INVALID;
+	bool leftBtnPressed = false, rightBtnPressed = false;
+	if (waitTime) {
+		waitForBannerInput(waitTime, ks, leftBtnPressed, rightBtnPressed);
+	}
+	setBuiltinCursor(0);
+	restoreBackground(sentenceline);
+
+	// Restore the sentence which was being displayed before
+	// (MANIAC v1 doesn't do this)
+	if (!(_game.id == GID_MANIAC && _game.version <= 1))
+		drawSentence();
+
+	// Finally, resume the engine, clear the input state, and restore the charset.
+	pt.clear();
+	clearClickedStatus();;
+
+	return ks;
+}
+
 Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int color, int32 waitTime) {
 	// LOOM VGA uses the new style GUI
 	if (_game.version == 4 && _game.id == GID_LOOM) {
@@ -291,10 +377,9 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	// Pause the engine
 	PauseToken pt = pauseEngine();
 
-	// Backup the current charsetId, since we're going to switch
-	// to charsetId == 1...
+	// Backup the current charsetId...
 	int oldId = _charset->getCurID();
-	_charset->setCurID(1);
+	_charset->setCurID(_game.version > 3 ? 1 : 0);
 
 	// Take all the necessary measurements for the box which
 	// will contain the string...
@@ -304,14 +389,35 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 		bannerMsgWidth = 100;
 
 	startingPointY = 80;
-	bannerSaveYStart = startingPointY - 2;
-
+	bannerSaveYStart = startingPointY - (_game.version == 4 ? 2 : _virtscr[kMainVirtScreen].topline);
 
 	// Save the pixels which will be overwritten by the banner,
 	// so that we can restore them later...
 	if (!_bannerMem) {
-		int rowSize = _screenWidth + 8;
-		_bannerMemSize = (bannerMsgHeight + 2) * (_screenWidth + 8);
+		int rowSize = _screenWidth + (_game.version == 4 ? 8 : 0);
+
+		// FM-Towns games draw the banner on the text surface, so let's save that
+#ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
+		if (_game.platform == Common::kPlatformFMTowns && !_textSurfBannerMem) {
+			rowSize *= _textSurfaceMultiplier;
+			bannerSaveYStart *= _textSurfaceMultiplier;
+			_textSurfBannerMemSize = bannerMsgHeight * rowSize * _textSurfaceMultiplier;
+			_textSurfBannerMem = (byte *)malloc(_textSurfBannerMemSize * sizeof(byte));
+			if (_textSurfBannerMem) {
+				memcpy(
+					_textSurfBannerMem,
+					&((byte *)_textSurface.getBasePtr(0, _screenTop * _textSurfaceMultiplier))[rowSize * bannerSaveYStart],
+					_textSurfBannerMemSize);
+			}
+
+			// We're going to use these same values for saving the
+			// virtual screen surface, so let's un-multiply them...
+			rowSize /= _textSurfaceMultiplier;
+			bannerSaveYStart /= _textSurfaceMultiplier;
+		}
+#endif
+
+		_bannerMemSize = (bannerMsgHeight + 2) * (rowSize);
 		_bannerMem = (byte *)malloc(_bannerMemSize * sizeof(byte));
 		if (_bannerMem) {
 			memcpy(
@@ -362,7 +468,7 @@ void ScummEngine::clearBanner() {
 	// Restore the GFX content which was under the banner,
 	// and then mark that part of the screen as dirty.
 	if (_bannerMem) {
-		int rowSize = _screenWidth + 8;
+		int rowSize = _screenWidth + (_game.version >= 4 ? 8 : 0);
 		// Don't manually clear the banner if a SMUSH movie is playing,
 		// as that will cause some rare small glitches. The SMUSH player
 		// will take care of that for us automatically when updating the
@@ -371,12 +477,14 @@ void ScummEngine::clearBanner() {
 			int startingPointY;
 			if (_game.version == 8) {
 				startingPointY = _screenHeight / 2 - 10;
+			} else if (_game.version < 4) {
+				startingPointY = 80;
 			} else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformFMTowns) {
 				startingPointY = 78;
 			} else {
 				startingPointY = ((_game.version < 7) ? 80 - 2 : _screenHeight / 2 - 10);
 			}
-
+			startingPointY -= (_game.version >= 4 ? 0 : _virtscr[kMainVirtScreen].topline);
 			// FM-Towns games draw the banners on the text surface, so restore both surfaces...
 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
 			if (_game.platform == Common::kPlatformFMTowns && _textSurfBannerMem) {
@@ -393,6 +501,7 @@ void ScummEngine::clearBanner() {
 				startingPointY /= _textSurfaceMultiplier;
 			}
 #endif
+
 			memcpy(
 				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * startingPointY],
 				_bannerMem,
@@ -1138,7 +1247,7 @@ void ScummEngine::saveSurfacesPreGUI() {
 	// so the last line is being drawn on the verb surface; to address this, we
 	// save and restore that too.
 
-	if (_game.version < 4 || _game.version > 6)
+	if (_game.version < 3 || _game.version > 6)
 		return;
 
 	_tempTextSurface = (byte *)malloc(_textSurface.pitch * _textSurface.h * sizeof(byte));
@@ -1181,7 +1290,7 @@ void ScummEngine::saveSurfacesPreGUI() {
 
 void ScummEngine::restoreSurfacesPostGUI() {
 
-	if (_game.version < 4 || _game.version > 6)
+	if (_game.version < 3 || _game.version > 6)
 		return;
 
 	if (_tempTextSurface) {
@@ -1282,10 +1391,13 @@ void ScummEngine::queryQuit(bool returnToLauncher) {
 
 		// "Are you sure you want to quit?  (Y/N)"
 		Common::KeyState ks;
-		if (_game.version > 4)
+		if (_game.version > 4) {
 			ks = showBannerAndPause(0, -1, msgLabelPtr);
-		else
+		} else if (_game.version == 4) {
 			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
+		} else {
+			ks = printMessageAndPause(msgLabelPtr, -1, true);
+		}
 
 		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
 
@@ -2999,7 +3111,7 @@ void ScummEngine::drawGUIText(const char *buttonString, Common::Rect *clipRect,
 	_string[5].right = clipRect ? clipRect->right : _screenWidth - 1;
 	_string[5].center = centerFlag;
 	_string[5].color = textColor;
-	_string[5].charset = 1;
+	_string[5].charset = _game.version > 3 ? 1 : 0;
 
 	drawString(5, (const byte *)buttonString);
 	_string[5].right = tmpRight;
@@ -3222,7 +3334,7 @@ const char *ScummEngine::getGUIString(int stringId) {
 	}
 
 	if (resStringId > 0)
-		return d.getPlainEngineString(resStringId);
+		return d.getPlainEngineString(resStringId, (_game.id == GID_INDY3) && stringId == gsQuitPrompt);
 	else
 		return _emptyMsg;
 }
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 716e56a0ea3..b6791c0bf1e 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -121,7 +121,7 @@ void ScummEngine::parseEvent(Common::Event event) {
 			_fastMode ^= 1;
 		} else if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_g) {
 			_fastMode ^= 2;
-		} else if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_s) {
+		} else if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.hasFlags(Common::KBD_ALT) && event.kbd.keycode == Common::KEYCODE_s) {
 			_res->resourceStats();
 		} else if (event.kbd.hasFlags(Common::KBD_ALT) && event.kbd.keycode == Common::KEYCODE_x) {
 			if (_game.version < 8) {
@@ -195,6 +195,7 @@ void ScummEngine::parseEvent(Common::Event event) {
 			_leftBtnPressed |= msClicked|msDown;
 		else if (event.type == Common::EVENT_RBUTTONDOWN)
 			_rightBtnPressed |= msClicked|msDown;
+
 		_mouse.x = event.mouse.x;
 		_mouse.y = event.mouse.y;
 
@@ -582,7 +583,7 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 		while (!validKey && !leftBtnClicked && !rightBtnClicked && !(handeleMouseWheel && _mouseWheelFlag)) {
 			waitForTimer(1); // Allow the engine to update the screen and fetch new inputs...
 
-			if (_game.version < 7 && (_guiCursorAnimCounter++ & 16)) {
+			if (_game.version > 2 && _game.version < 7 && (_guiCursorAnimCounter++ & 16)) {
 				_guiCursorAnimCounter = 0;
 				animateCursor();
 			}
@@ -794,6 +795,18 @@ void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) {
 }
 
 void ScummEngine_v2::processKeyboard(Common::KeyState lastKeyHit) {
+	if (isUsingOriginalGUI()) {
+		if (lastKeyHit.keycode == Common::KEYCODE_F5) {
+			prepareSavegame();
+			if (_game.id == GID_MANIAC && _game.version == 0) {
+				runScript(2, 0, 0, nullptr);
+			}
+			if (_game.id == GID_MANIAC && _game.platform == Common::kPlatformNES) {
+				runScript(163, 0, 0, nullptr);
+			}
+		}
+	}
+
 	// RETURN is used to skip cutscenes in the Commodore 64 version of Zak McKracken
 	if (_game.id == GID_ZAK &&_game.platform == Common::kPlatformC64 && lastKeyHit.keycode == Common::KEYCODE_RETURN && lastKeyHit.hasFlags(0)) {
 		lastKeyHit = Common::KeyState(Common::KEYCODE_ESCAPE);
@@ -823,13 +836,15 @@ void ScummEngine_v2::processKeyboard(Common::KeyState lastKeyHit) {
 	ScummEngine::processKeyboard(lastKeyHit);
 
 	// On Alt-F5 prepare savegame for the original save/load dialog.
-	if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(Common::KBD_ALT)) {
-		prepareSavegame();
-		if (_game.id == GID_MANIAC && _game.version == 0) {
-			runScript(2, 0, 0, nullptr);
-		}
-		if (_game.id == GID_MANIAC &&_game.platform == Common::kPlatformNES) {
-			runScript(163, 0, 0, nullptr);
+	if (!isUsingOriginalGUI()) {
+		if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(Common::KBD_ALT)) {
+			prepareSavegame();
+			if (_game.id == GID_MANIAC && _game.version == 0) {
+				runScript(2, 0, 0, nullptr);
+			}
+			if (_game.id == GID_MANIAC && _game.platform == Common::kPlatformNES) {
+				runScript(163, 0, 0, nullptr);
+			}
 		}
 	}
 
@@ -844,25 +859,33 @@ void ScummEngine_v2::processKeyboard(Common::KeyState lastKeyHit) {
 }
 
 void ScummEngine_v3::processKeyboard(Common::KeyState lastKeyHit) {
+	if (isUsingOriginalGUI()) {
+		if (lastKeyHit.keycode == Common::KEYCODE_F5) {
+			prepareSavegame();
+		}
+	}
+
 	// Fall back to default behavior
 	ScummEngine::processKeyboard(lastKeyHit);
 
-	// On Alt-F5 prepare savegame for the original save/load dialog.
-	if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(Common::KBD_ALT)) {
-		prepareSavegame();
-	}
+	if (!isUsingOriginalGUI()) {
+		// On Alt-F5 prepare savegame for the original save/load dialog.
+		if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(Common::KBD_ALT)) {
+			prepareSavegame();
+		}
 
-	// 'i' brings up an IQ dialog in Indy3 (disabled in save/load dialog for input)
-	if (lastKeyHit.ascii == 'i' && _game.id == GID_INDY3 && _currentRoom != 14) {
-		// SCUMM var 244 is the episode score
-		// and var 245 is the series score
-		char text[50];
+		// 'i' brings up an IQ dialog in Indy3 (disabled in save/load dialog for input)
+		if (lastKeyHit.ascii == 'i' && _game.id == GID_INDY3 && _currentRoom != 14) {
+			// SCUMM var 244 is the episode score
+			// and var 245 is the series score
+			char text[50];
 
-		updateIQPoints();
+			updateIQPoints();
 
-		Common::sprintf_s(text, "IQ Points: Episode = %d, Series = %d", _scummVars[244], _scummVars[245]);
-		Indy3IQPointsDialog indy3IQPointsDialog(this, text);
-		runDialog(indy3IQPointsDialog);
+			Common::sprintf_s(text, "IQ Points: Episode = %d, Series = %d", _scummVars[244], _scummVars[245]);
+			Indy3IQPointsDialog indy3IQPointsDialog(this, text);
+			runDialog(indy3IQPointsDialog);
+		}
 	}
 }
 
@@ -898,6 +921,9 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 
 			_cursor.state = oldCursorState;
 			return;
+		} else if (_game.version <= 2 && lastKeyHit.keycode == Common::KEYCODE_SPACE) {
+			printMessageAndPause(getGUIString(gsPause), -1, true);
+			return;
 		}
 
 		if ((VAR_RESTART_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_RESTART_KEY))) ||
@@ -1013,18 +1039,22 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		}
 
 		if (VAR_MAINMENU_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_MAINMENU_KEY) && lastKeyHit.hasFlags(0))
-			&& _game.platform != Common::kPlatformFMTowns) {
+			&& _game.platform != Common::kPlatformFMTowns && _game.version > 3) {
 			showMainMenu();
 			return;
 		}
 
-		if (_game.version == 4) {
-			if (lastKeyHit.keycode == Common::KEYCODE_r && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+		if (snapScrollKeyEnabled) {
+			if ((_game.version <= 3 && lastKeyHit.keycode == Common::KEYCODE_i && lastKeyHit.hasFlags(Common::KBD_ALT)) ||
+				(_game.version == 4 && lastKeyHit.keycode == Common::KEYCODE_r && lastKeyHit.hasFlags(Common::KBD_CTRL))) {
+				const char *msgSnap = _game.version == 4 ? "Horizontal Screen Snap" : "Screen reposition instantly";
+				const char *msgScroll = _game.version == 4 ? "Horizontal Screen Scroll" : "Screen reposition by Scrolling";
+
 				_snapScroll ^= 1;
 				if (_snapScroll) {
-					showOldStyleBannerAndPause("Horizontal Screen Snap", 9, 90);
+					showOldStyleBannerAndPause(msgSnap, 9, 90);
 				} else {
-					showOldStyleBannerAndPause("Horizontal Screen Scroll", 9, 90);
+					showOldStyleBannerAndPause(msgScroll, 9, 90);
 				}
 
 				if (VAR_CAMERA_FAST_X != 0xFF)
@@ -1066,7 +1096,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 	if (_game.id == GID_CMI)
 		mainmenuKeyEnabled = true;
 
-	if (mainmenuKeyEnabled && (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(0))) {
+	if (mainmenuKeyEnabled && !isUsingOriginalGUI() && (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(0))) {
 		if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
 			runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, nullptr);
 
@@ -1078,10 +1108,10 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		if (VAR_SAVELOAD_SCRIPT2 != 0xFF && _currentRoom != 0)
 			runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, nullptr);
 
-	} else if (restartKeyEnabled && (lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0))) {
+	} else if (restartKeyEnabled && !isUsingOriginalGUI() && (lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0))) {
 		confirmRestartDialog();
 
-	} else if (pauseKeyEnabled && (lastKeyHit.keycode == Common::KEYCODE_SPACE && lastKeyHit.hasFlags(0))) {
+	} else if (pauseKeyEnabled && !isUsingOriginalGUI() && (lastKeyHit.keycode == Common::KEYCODE_SPACE && lastKeyHit.hasFlags(0))) {
 		pauseGame();
 
 	} else if (talkstopKeyEnabled && lastKeyHit.ascii == '.') {
@@ -1095,7 +1125,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		// VAR_CUTSCENEEXIT_KEY doesn't exist in SCUMM0
 		if (VAR_CUTSCENEEXIT_KEY != 0xFF)
 			_mouseAndKeyboardStat = VAR(VAR_CUTSCENEEXIT_KEY);
-	} else if (snapScrollKeyEnabled && lastKeyHit.keycode == Common::KEYCODE_r &&
+	} else if (snapScrollKeyEnabled && !isUsingOriginalGUI() && lastKeyHit.keycode == Common::KEYCODE_r &&
 		lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 		_snapScroll ^= 1;
 		if (_snapScroll) {
diff --git a/engines/scumm/script_v2.cpp b/engines/scumm/script_v2.cpp
index 99db95ce3d1..7981e67b65f 100644
--- a/engines/scumm/script_v2.cpp
+++ b/engines/scumm/script_v2.cpp
@@ -1051,99 +1051,7 @@ void ScummEngine_v2::drawPreposition(int index) {
 }
 
 void ScummEngine_v2::o2_drawSentence() {
-	Common::Rect sentenceline;
-	const byte *temp;
-	int slot = getVerbSlot(VAR(VAR_SENTENCE_VERB), 0);
-
-	if (!((_userState & USERSTATE_IFACE_SENTENCE) ||
-	      (_game.platform == Common::kPlatformNES && (_userState & USERSTATE_IFACE_ALL))))
-		return;
-
-	if (getResourceAddress(rtVerb, slot))
-		_sentenceBuf = (char *)getResourceAddress(rtVerb, slot);
-	else
-		return;
-
-	if (VAR(VAR_SENTENCE_OBJECT1) > 0) {
-		temp = getObjOrActorName(VAR(VAR_SENTENCE_OBJECT1));
-		if (temp) {
-			_sentenceBuf += " ";
-			_sentenceBuf += (const char *)temp;
-		}
-
-		// For V1 games, the engine must compute the preposition.
-		// In all other Scumm versions, this is done by the sentence script.
-		if ((_game.id == GID_MANIAC && _game.version == 1 && !(_game.platform == Common::kPlatformNES)) && (VAR(VAR_SENTENCE_PREPOSITION) == 0)) {
-			if (_verbs[slot].prep == 0xFF) {
-				byte *ptr = getOBCDFromObject(VAR(VAR_SENTENCE_OBJECT1));
-				assert(ptr);
-				VAR(VAR_SENTENCE_PREPOSITION) = (*(ptr + 12) >> 5);
-			} else
-				VAR(VAR_SENTENCE_PREPOSITION) = _verbs[slot].prep;
-		}
-	}
-
-	if (0 < VAR(VAR_SENTENCE_PREPOSITION) && VAR(VAR_SENTENCE_PREPOSITION) <= 4) {
-		drawPreposition(VAR(VAR_SENTENCE_PREPOSITION));
-	}
-
-	if (VAR(VAR_SENTENCE_OBJECT2) > 0) {
-		temp = getObjOrActorName(VAR(VAR_SENTENCE_OBJECT2));
-		if (temp) {
-			_sentenceBuf += " ";
-			_sentenceBuf += (const char *)temp;
-		}
-	}
-
-	_string[2].charset = 1;
-	_string[2].ypos = _virtscr[kVerbVirtScreen].topline;
-	_string[2].xpos = 0;
-	_string[2].right = _virtscr[kVerbVirtScreen].w - 1;
-	if (_game.platform == Common::kPlatformNES) {
-		_string[2].xpos = 16;
-		_string[2].color = 0;
-	} else if (_game.platform == Common::kPlatformC64) {
-		_string[2].color = 16;
-	} else {
-		_string[2].color = 13;
-	}
-
-	byte string[80];
-	const char *ptr = _sentenceBuf.c_str();
-	int i = 0, len = 0;
-
-	// Maximum length of printable characters
-	int maxChars = (_game.platform == Common::kPlatformNES) ? 60 : 40;
-	while (*ptr) {
-		if (*ptr != '@')
-			len++;
-		if (len > maxChars) {
-			break;
-		}
-
-		string[i++] = *ptr++;
-
-		if (_game.platform == Common::kPlatformNES && len == 30) {
-			string[i++] = 0xFF;
-			string[i++] = 8;
-		}
-	}
-	string[i] = 0;
-
-	if (_game.platform == Common::kPlatformNES) {
-		sentenceline.top = _virtscr[kVerbVirtScreen].topline;
-		sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 16;
-		sentenceline.left = 16;
-		sentenceline.right = _virtscr[kVerbVirtScreen].w - 1;
-	} else {
-		sentenceline.top = _virtscr[kVerbVirtScreen].topline;
-		sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 8;
-		sentenceline.left = 0;
-		sentenceline.right = _virtscr[kVerbVirtScreen].w - 1;
-	}
-	restoreBackground(sentenceline);
-
-	drawString(2, (byte *)string);
+	drawSentence();
 }
 
 void ScummEngine_v2::o2_ifClassOfIs() {
diff --git a/engines/scumm/script_v4.cpp b/engines/scumm/script_v4.cpp
index 62052370855..07e74906425 100644
--- a/engines/scumm/script_v4.cpp
+++ b/engines/scumm/script_v4.cpp
@@ -408,12 +408,14 @@ void ScummEngine_v4::o4_saveLoadGame() {
 		}
 		break;
 	case 0x40: // load
+		_lastLoadedRoom = -1;
 		if (loadState(slot, false))
 			result = 3; // sucess
 		else
 			result = 5; // failed to load
 		break;
 	case 0x80: // save
+		_lastLoadedRoom = -1;
 		if (_game.version <= 3) {
 			char name[32];
 			if (_game.version <= 2) {
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 961d8b976d4..678a265b3fe 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2596,7 +2596,8 @@ load_game:
 
 	_res->increaseExpireCounter();
 
-	animateCursor();
+	if (!isUsingOriginalGUI() || ((_game.version >= 3) || !isPaused()))
+		animateCursor();
 
 	/* show or hide mouse */
 	CursorMan.showMouse(_cursor.state > 0);
@@ -3146,7 +3147,7 @@ bool ScummEngine::isUsingOriginalGUI() {
 	if (_game.heversion != 0)
 		return false;
 
-	if (_game.version > 3)
+	if (_game.version >= 0)
 		return _useOriginalGUI;
 
 	return false;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 401c9b9004c..b846ae8a26c 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -653,9 +653,13 @@ protected:
 	int _curCursorHotspotX = 0;
 	int _curCursorHotspotY = 0;
 
+	virtual void setSnailCursor() {}
+
 	void initBanners();
 	Common::KeyState showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...);
 	Common::KeyState showOldStyleBannerAndPause(const char *msg, int color, int32 waitTime);
+	Common::KeyState printMessageAndPause(const char *msg, int32 waitTime, bool drawOnSentenceLine);
+
 	void clearBanner();
 	void setBannerColors(int bannerId, byte r, byte g, byte b);
 	virtual int getBannerColor(int bannerId);
@@ -1201,6 +1205,8 @@ protected:
 	bool _doEffect = false;
 
 	bool _snapScroll = false;
+
+	virtual void setBuiltinCursor(int index) {}
 public:
 	bool isLightOn() const;
 
@@ -1478,6 +1484,7 @@ protected:
 	virtual void printString(int m, const byte *msg);
 
 	virtual bool handleNextCharsetCode(Actor *a, int *c);
+	virtual void drawSentence() {}
 	virtual void CHARSET_1();
 	bool newLine();
 	void drawString(int a, const byte *msg);
diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h
index 37e3048739e..264b2bc25e9 100644
--- a/engines/scumm/scumm_v2.h
+++ b/engines/scumm/scumm_v2.h
@@ -92,6 +92,7 @@ protected:
 	void clearStateCommon(byte type);
 	void stopScriptCommon(int script);
 
+	void drawSentence() override;
 	void resetSentence() override;
 	void setUserState(byte state);
 
@@ -104,6 +105,7 @@ protected:
 	void initNESMouseOver();
 
 	void setBuiltinCursor(int index) override;
+	void setSnailCursor() override;
 
 	void drawPreposition(int index);
 
diff --git a/engines/scumm/scumm_v5.h b/engines/scumm/scumm_v5.h
index 39b41a2072b..557381b2132 100644
--- a/engines/scumm/scumm_v5.h
+++ b/engines/scumm/scumm_v5.h
@@ -82,7 +82,7 @@ protected:
 
 	void animateCursor() override;
 
-	virtual void setBuiltinCursor(int index);
+	void setBuiltinCursor(int index) override;
 	void redefineBuiltinCursorFromChar(int index, int chr);
 	void redefineBuiltinCursorHotspot(int index, int x, int y);
 
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index c0139fef4fc..6d04c9cacae 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -36,6 +36,7 @@
 #endif
 #include "scumm/resource.h"
 #include "scumm/scumm.h"
+#include "scumm/scumm_v2.h"
 #include "scumm/scumm_v6.h"
 #include "scumm/scumm_v7.h"
 #include "scumm/verbs.h"
@@ -706,6 +707,102 @@ void ScummEngine::fakeBidiString(byte *ltext, bool ignoreVerb, int ltextSize) co
 	free(stack);
 }
 
+void ScummEngine_v2::drawSentence() {
+	Common::Rect sentenceline;
+	const byte *temp;
+	int slot = getVerbSlot(VAR(VAR_SENTENCE_VERB), 0);
+
+	if (!((_userState & USERSTATE_IFACE_SENTENCE) ||
+		  (_game.platform == Common::kPlatformNES && (_userState & USERSTATE_IFACE_ALL))))
+		return;
+
+	if (getResourceAddress(rtVerb, slot))
+		_sentenceBuf = (char *)getResourceAddress(rtVerb, slot);
+	else
+		return;
+
+	if (VAR(VAR_SENTENCE_OBJECT1) > 0) {
+		temp = getObjOrActorName(VAR(VAR_SENTENCE_OBJECT1));
+		if (temp) {
+			_sentenceBuf += " ";
+			_sentenceBuf += (const char *)temp;
+		}
+
+		// For V1 games, the engine must compute the preposition.
+		// In all other Scumm versions, this is done by the sentence script.
+		if ((_game.id == GID_MANIAC && _game.version == 1 && !(_game.platform == Common::kPlatformNES)) && (VAR(VAR_SENTENCE_PREPOSITION) == 0)) {
+			if (_verbs[slot].prep == 0xFF) {
+				byte *ptr = getOBCDFromObject(VAR(VAR_SENTENCE_OBJECT1));
+				assert(ptr);
+				VAR(VAR_SENTENCE_PREPOSITION) = (*(ptr + 12) >> 5);
+			} else
+				VAR(VAR_SENTENCE_PREPOSITION) = _verbs[slot].prep;
+		}
+	}
+
+	if (0 < VAR(VAR_SENTENCE_PREPOSITION) && VAR(VAR_SENTENCE_PREPOSITION) <= 4) {
+		drawPreposition(VAR(VAR_SENTENCE_PREPOSITION));
+	}
+
+	if (VAR(VAR_SENTENCE_OBJECT2) > 0) {
+		temp = getObjOrActorName(VAR(VAR_SENTENCE_OBJECT2));
+		if (temp) {
+			_sentenceBuf += " ";
+			_sentenceBuf += (const char *)temp;
+		}
+	}
+
+	_string[2].charset = 1;
+	_string[2].ypos = _virtscr[kVerbVirtScreen].topline;
+	_string[2].xpos = 0;
+	_string[2].right = _virtscr[kVerbVirtScreen].w - 1;
+	if (_game.platform == Common::kPlatformNES) {
+		_string[2].xpos = 16;
+		_string[2].color = 0;
+	} else if (_game.platform == Common::kPlatformC64) {
+		_string[2].color = 16;
+	} else {
+		_string[2].color = 13;
+	}
+
+	byte string[80];
+	const char *ptr = _sentenceBuf.c_str();
+	int i = 0, len = 0;
+
+	// Maximum length of printable characters
+	int maxChars = (_game.platform == Common::kPlatformNES) ? 60 : 40;
+	while (*ptr) {
+		if (*ptr != '@')
+			len++;
+		if (len > maxChars) {
+			break;
+		}
+
+		string[i++] = *ptr++;
+
+		if (_game.platform == Common::kPlatformNES && len == 30) {
+			string[i++] = 0xFF;
+			string[i++] = 8;
+		}
+	}
+	string[i] = 0;
+
+	if (_game.platform == Common::kPlatformNES) {
+		sentenceline.top = _virtscr[kVerbVirtScreen].topline;
+		sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 16;
+		sentenceline.left = 16;
+		sentenceline.right = _virtscr[kVerbVirtScreen].w - 1;
+	} else {
+		sentenceline.top = _virtscr[kVerbVirtScreen].topline;
+		sentenceline.bottom = _virtscr[kVerbVirtScreen].topline + 8;
+		sentenceline.left = 0;
+		sentenceline.right = _virtscr[kVerbVirtScreen].w - 1;
+	}
+	restoreBackground(sentenceline);
+
+	drawString(2, (byte *)string);
+}
+
 void ScummEngine::CHARSET_1() {
 	Actor *a;
 	if (_game.heversion >= 70 && _haveMsg == 3) {


Commit: 9cb7293de35eefabe21fd0bf37e6774003d384c0
    https://github.com/scummvm/scummvm/commit/9cb7293de35eefabe21fd0bf37e6774003d384c0
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: Clean-up and implement remaining messages for v0-1-2-3

Changed paths:
    engines/scumm/dialogs.cpp
    engines/scumm/gfx_gui.cpp
    engines/scumm/input.cpp
    engines/scumm/scumm.h


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 86bb9bdef02..e1fdd7809a1 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -593,7 +593,7 @@ const ResString &InfoDialog::getStaticResString(Common::Language lang, int strin
 			{3, "ERROR READING %d type %d"},					// As found on the Italian v2 executable...
 			{4, "PAUSA - Premere SPAZIO per continuare."},		// Original DOS Italian v2
 			{5, "Sei sicuro di voler ricominciare? (s/n)s"},	// Original DOS Italian v2
-			{6, "Sei sicuro di voler uscire?  (s/n)s"}			// Original DOS Italian v2
+			{6, "Sei sicuro di voler uscire? (s/n)s"}			// (matching the previous sentence)
 		},
 		{	// Spanish
 			{1, "Introduce el disco %c y pulsa un bot""\xa2""n para continuar."},
@@ -648,12 +648,34 @@ const ResString &InfoDialog::getStaticResString(Common::Language lang, int strin
 		{0, "Text Display Only"},
 		{0, "Text Speed   Slow  ==========  Fast"},
 		{0, "Roland Volume    Low  =========  High"},
-		{0, "Heap %dK"}
+		{0, "Heap %dK"},
+		// Snap scroll messages
+		{0, "Snap Scroll On"}, // v2
+		{0, "Snap Scroll Off"},
+		{0, "Screen reposition instantly"}, // v3
+		{0, "Screen reposition by Scrolling"},
+		{0, "Horizontal Screen Snap"}, // v4
+		{0, "Horizontal Screen Scroll"},
+		// Miscellaneous input messages
+		{0, "Recalibrating Joystick"},
+		{0, "Mouse Mode"},
+		{0, "Mouse On"},
+		{0, "Mouse Off"},
+		{0, "Joystick On"},
+		{0, "Joystick Off"},
+		{0, "Sounds On"},
+		{0, "Sounds Off"},
+		// V1-2 graphic modes
+		{0, "VGA Graphics"},
+		{0, "EGA Graphics"},
+		{0, "CGA Graphics"},
+		{0, "Hercules Graphics"},
+		{0, "TANDY Graphics"}
 	};
 
 	if (stringno + 1 >= ARRAYSIZE(strMap1)) {
 		stringno -= ARRAYSIZE(strMap1) - 1;
-		assert(stringno + 1 < ARRAYSIZE(strMap2));
+		assert(stringno < ARRAYSIZE(strMap2));
 		return strMap2[stringno];
 	}
 
@@ -683,6 +705,20 @@ const ResString &InfoDialog::getStaticResString(Common::Language lang, int strin
 		break;
 	}
 
+	// Special case for ZAK v2 ITA, which has a different string both for the pause
+	// message and for the restart message.
+	// If it can be verified that other languages have different strings for this game
+	// we can refactor strMap1 to contain both a MM string and a ZAK string; but with
+	// currently only one language doing this, it seems overkill...
+	if (_vm->_game.version == 2 && _vm->_game.id == GID_ZAK && langIndex == 3) {
+		if (stringno == 3) {
+			static const ResString altStr = {4, "PAUSE - Premere SPACE per continuare."};
+			return altStr;
+		} else if (stringno == 4) {
+			static const ResString altStr = {5, "Sei sicuro che vuoi ricominciare? (s/n)s"};
+			return altStr;
+		}
+	}
 	return strMap1[langIndex][stringno];
 }
 
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index fc29df89e3b..fbac6adb4e6 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -262,7 +262,7 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	return ks;
 }
 
-Common::KeyState ScummEngine::printMessageAndPause(const char *msg, int32 waitTime, bool drawOnSentenceLine) {
+Common::KeyState ScummEngine::printMessageAndPause(const char *msg, int color, int32 waitTime, bool drawOnSentenceLine) {
 	Common::Rect sentenceline;
 
 	// Pause the engine
@@ -321,28 +321,49 @@ Common::KeyState ScummEngine::printMessageAndPause(const char *msg, int32 waitTi
 		drawString(2, (byte *)string);
 		drawDirtyScreenParts();
 	} else {
+		_string[0].xpos = 0;
+		_string[0].ypos = 0;
+		_string[0].right = _screenWidth - 1;
+		_string[0].center = false;
+		_string[0].overhead = false;
 
+		byte tmpColor = _string[0].color;
+		byte tmpAct = _actorToPrintStrFor;
+
+		_string[0].color = color;
+		_actorToPrintStrFor = 0xFF;
+
+		actorTalk((const byte *)msg);
+
+		_actorToPrintStrFor = tmpAct;
+		_string[0].color = tmpColor;
 	}
 
+	Common::KeyState ks = Common::KEYCODE_INVALID;
+	bool leftBtnPressed = false, rightBtnPressed = false;
+
 	// Wait until the engine receives a new Keyboard or Mouse input,
 	// unless we have specified a positive waitTime: in that case, the banner
 	// will stay on screen until an input has been received or until the time-out.
-	Common::KeyState ks = Common::KEYCODE_INVALID;
-	bool leftBtnPressed = false, rightBtnPressed = false;
 	if (waitTime) {
+		ScummEngine::drawDirtyScreenParts();
 		waitForBannerInput(waitTime, ks, leftBtnPressed, rightBtnPressed);
+		stopTalk();
 	}
-	setBuiltinCursor(0);
-	restoreBackground(sentenceline);
 
-	// Restore the sentence which was being displayed before
-	// (MANIAC v1 doesn't do this)
-	if (!(_game.id == GID_MANIAC && _game.version <= 1))
-		drawSentence();
+	if (drawOnSentenceLine) {
+		setBuiltinCursor(0);
+		restoreBackground(sentenceline);
+
+		// Restore the sentence which was being displayed before
+		// (MANIAC v1 doesn't do this)
+		if (!(_game.id == GID_MANIAC && _game.version <= 1))
+			drawSentence();
+	}
 
 	// Finally, resume the engine, clear the input state, and restore the charset.
 	pt.clear();
-	clearClickedStatus();;
+	clearClickedStatus();
 
 	return ks;
 }
@@ -1396,7 +1417,7 @@ void ScummEngine::queryQuit(bool returnToLauncher) {
 		} else if (_game.version == 4) {
 			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
 		} else {
-			ks = printMessageAndPause(msgLabelPtr, -1, true);
+			ks = printMessageAndPause(msgLabelPtr, 0, -1, true);
 		}
 
 		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
@@ -1429,10 +1450,13 @@ void ScummEngine::queryRestart() {
 
 		// "Are you sure you want to restart?  (Y/N)"
 		Common::KeyState ks;
-		if (_game.version > 4)
+		if (_game.version > 4) {
 			ks = showBannerAndPause(0, -1, msgLabelPtr);
-		else
+		} else if (_game.version == 3) {
 			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
+		} else {
+			ks = printMessageAndPause(msgLabelPtr, 4, -1, false);
+		}
 
 		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
 
@@ -3120,23 +3144,31 @@ void ScummEngine::drawGUIText(const char *buttonString, Common::Rect *clipRect,
 void ScummEngine::getSliderString(int stringId, int value, char *sliderString, int size) {
 	char *ptrToChar;
 	char tempStr[256];
+	if (_game.version > 2) {
+		Common::strlcpy(tempStr, getGUIString(stringId), sizeof(tempStr));
+		convertMessageToString((const byte *)tempStr, (byte *)sliderString, size);
 
-	Common::strlcpy(tempStr, getGUIString(stringId), sizeof(tempStr));
-	convertMessageToString((const byte *)tempStr, (byte *)sliderString, size);
+		ptrToChar = strchr(sliderString, '=');
 
-	ptrToChar = strchr(sliderString, '=');
-
-	if (!ptrToChar) {
-		ptrToChar = strstr(sliderString, "xxx");
-	}
+		if (!ptrToChar) {
+			ptrToChar = strstr(sliderString, "xxx");
+		}
 
-	if (ptrToChar) {
+		if (ptrToChar) {
+			if (stringId == gsTextSpeedSlider) {
+				memset(ptrToChar, '\v', 10);
+				ptrToChar[9 - value] = '\f';
+			} else {
+				memset(ptrToChar, '\v', 9);
+				ptrToChar[value / 15] = '\f';
+			}
+		}
+	} else {
 		if (stringId == gsTextSpeedSlider) {
-			memset(ptrToChar, '\v', 10);
-			ptrToChar[9 - value] = '\f';
-		} else {
-			memset(ptrToChar, '\v', 9);
-			ptrToChar[value / 15] = '\f';
+			Common::strlcpy(tempStr, getGUIString(stringId), sizeof(tempStr));
+
+			// Format the string with the arguments...
+			Common::sprintf_s(sliderString, size, tempStr, value);
 		}
 	}
 }
@@ -3321,13 +3353,83 @@ const char *ScummEngine::getGUIString(int stringId) {
 		resStringId = 24;
 		break;
 	case gsTextSpeedSlider:
-		resStringId = 25;
+		if (_game.version <= 2) {
+			return "TextRate %d";
+		} else {
+			resStringId = 25;
+		}
+
 		break;
 	case gsMusicVolumeSlider:
 		resStringId = 26;
 		break;
 	case gsHeap:
-		resStringId = 28;
+		resStringId = 27;
+		break;
+	case gsSnapOn:
+		switch (_game.version) {
+		case 2:
+			resStringId = 28;
+			break;
+		case 3:
+			resStringId = 30;
+			break;
+		default:
+			resStringId = 32;
+		}
+
+		break;
+	case gsSnapOff:
+		switch (_game.version) {
+		case 2:
+			resStringId = 29;
+			break;
+		case 3:
+			resStringId = 31;
+			break;
+		default:
+			resStringId = 33;
+		}
+
+		break;
+	case gsRecalJoystick:
+		resStringId = 34;
+		break;
+	case gsMouseMode:
+		resStringId = 35;
+		break;
+	case gsMouseOn:
+		resStringId = 36;
+		break;
+	case gsMouseOff:
+		resStringId = 37;
+		break;
+	case gsJoystickOn:
+		resStringId = 38;
+		break;
+	case gsJoystickOff:
+		resStringId = 39;
+		break;
+	case gsSoundsOn:
+		resStringId = 40;
+		break;
+	case gsSoundsOff:
+		resStringId = 41;
+		break;
+	case gsVGAMode:
+		resStringId = 42;
+		break;
+	case gsEGAMode:
+		resStringId = 43;
+		break;
+	case gsCGAMode:
+		resStringId = 44;
+		break;
+	case gsHerculesMode:
+		resStringId = 45;
+		break;
+	case gsTandyMode:
+		resStringId = 46;
 		break;
 	default:
 		break;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index b6791c0bf1e..53a1874975c 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -922,11 +922,12 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			_cursor.state = oldCursorState;
 			return;
 		} else if (_game.version <= 2 && lastKeyHit.keycode == Common::KEYCODE_SPACE) {
-			printMessageAndPause(getGUIString(gsPause), -1, true);
+			printMessageAndPause(getGUIString(gsPause), 0, -1, true);
 			return;
 		}
 
 		if ((VAR_RESTART_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_RESTART_KEY))) ||
+			(_game.version == 2 && (lastKeyHit.keycode == Common::KEYCODE_F8)) ||
 			((_game.id == GID_CMI && !(_game.features & GF_DEMO))
 				&& lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0))) {
 			queryRestart();
@@ -989,7 +990,6 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 				return;
 
 			Common::KeyState ks = lastKeyHit;
-
 			pt = pauseEngine();
 
 			do {
@@ -1008,10 +1008,11 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 				setTalkSpeed(_defaultTextSpeed);
 
 				getSliderString(gsTextSpeedSlider, VAR(VAR_CHARINC), sliderString, sizeof(sliderString));
-				if (_game.version > 4)
+				if (_game.version > 4) {
 					showBannerAndPause(0, 0, sliderString);
-				else
+				} else if (_game.version == 4) {
 					showOldStyleBannerAndPause(sliderString, 9, 0);
+				}
 
 				ks = Common::KEYCODE_INVALID;
 				bool leftBtnPressed = false, rightBtnPressed = false;
@@ -1024,12 +1025,37 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			return;
 		}
 
+		if (_game.version <= 2 && (lastKeyHit.ascii == '+' || lastKeyHit.ascii == '-' ||
+			lastKeyHit.ascii == '>' || lastKeyHit.ascii == '<')) {
+			Common::KeyState ks = lastKeyHit;
+			byte textSpeedColor;
+
+			if (ks.ascii == '+' || ks.ascii == '>') {
+				textSpeedColor = _game.version <= 1 ? 7 : 14;
+				if (_defaultTextSpeed > 0)
+					_defaultTextSpeed -= 1;
+
+			} else {
+				textSpeedColor = _game.version <= 1 ? 2 : 4;
+				if (_defaultTextSpeed < 9)
+					_defaultTextSpeed += 1;
+			}
+
+			setTalkSpeed(_defaultTextSpeed);
+			ConfMan.setInt("original_gui_text_speed", _defaultTextSpeed);
+
+			getSliderString(gsTextSpeedSlider, 9 - _defaultTextSpeed + 1, sliderString, sizeof(sliderString));
+			printMessageAndPause(sliderString, textSpeedColor, 0, false);
+			return;
+		}
+
 
 		if (_game.version > 4 && lastKeyHit.keycode == Common::KEYCODE_k && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 			showBannerAndPause(0, 120, getGUIString(gsHeap), _res->getHeapSize() / 1024);
 			return;
 		}
 
+		// NOTE: For consistency we enable the quit message even for sub v3 games which don't have it.
 		if ((lastKeyHit.keycode == Common::KEYCODE_c && lastKeyHit.hasFlags(Common::KBD_CTRL)) ||
 			(lastKeyHit.keycode == Common::KEYCODE_x && lastKeyHit.hasFlags(Common::KBD_ALT))) {
 			Common::Event event;
@@ -1045,16 +1071,23 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		}
 
 		if (snapScrollKeyEnabled) {
-			if ((_game.version <= 3 && lastKeyHit.keycode == Common::KEYCODE_i && lastKeyHit.hasFlags(Common::KBD_ALT)) ||
+			if ((_game.version == 2 && lastKeyHit.keycode == Common::KEYCODE_s && lastKeyHit.hasFlags(Common::KBD_SHIFT)) ||
+				(_game.version == 3 && lastKeyHit.keycode == Common::KEYCODE_i && lastKeyHit.hasFlags(Common::KBD_ALT)) ||
 				(_game.version == 4 && lastKeyHit.keycode == Common::KEYCODE_r && lastKeyHit.hasFlags(Common::KBD_CTRL))) {
-				const char *msgSnap = _game.version == 4 ? "Horizontal Screen Snap" : "Screen reposition instantly";
-				const char *msgScroll = _game.version == 4 ? "Horizontal Screen Scroll" : "Screen reposition by Scrolling";
 
 				_snapScroll ^= 1;
-				if (_snapScroll) {
-					showOldStyleBannerAndPause(msgSnap, 9, 90);
-				} else {
-					showOldStyleBannerAndPause(msgScroll, 9, 90);
+				if (_game.version < 3) {
+					if (_snapScroll) {
+						printMessageAndPause(getGUIString(gsSnapOn), 2, 0, false);
+					} else {
+						printMessageAndPause(getGUIString(gsSnapOff), 14, 0, false);
+					}
+				}  else {
+					if (_snapScroll) {
+						showBannerAndPause(0, 90, getGUIString(gsSnapOn));
+					} else {
+						showBannerAndPause(0, 90, getGUIString(gsSnapOff));
+					}
 				}
 
 				if (VAR_CAMERA_FAST_X != 0xFF)
@@ -1062,31 +1095,102 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 
 				return;
 			}
+		}
 
-			// The following ones serve no purpose whatsoever, but just for the sake of completeness...
-			// Also, these were originally mapped with the CTRL flag, but they would clash with other
-			// internal ScummVM commands, so they are instead available with the SHIFT flag.
-			if (lastKeyHit.keycode == Common::KEYCODE_j && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
-				showOldStyleBannerAndPause("Recalibrating Joystick", 2, 90);
+		// The following ones serve no purpose whatsoever, but just for the sake of completeness...
+		// Also, some of these were originally mapped with the CTRL flag, but they would clash with other
+		// internal ScummVM commands, so they are instead available with the SHIFT flag.
+		if (_game.version < 7) {
+			if (_game.version >= 4 && lastKeyHit.keycode == Common::KEYCODE_j && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+				if (_game.version == 4) {
+					showOldStyleBannerAndPause(getGUIString(gsRecalJoystick), 2, 90);
+				} else {
+					showBannerAndPause(0, 90, getGUIString(gsRecalJoystick));
+				}
 				return;
 			}
 
-			if (lastKeyHit.keycode == Common::KEYCODE_m && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
-				showOldStyleBannerAndPause("Mouse Mode", 2, 90);
+			if (_game.version >= 4 && lastKeyHit.keycode == Common::KEYCODE_m && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+				if (_game.version == 4) {
+					showOldStyleBannerAndPause(getGUIString(gsMouseMode), 2, 90);
+				} else {
+					showBannerAndPause(0, 90, getGUIString(gsMouseMode));
+				}
 				return;
 			}
 
-			if (lastKeyHit.keycode == Common::KEYCODE_s && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
-				_internalSpeakerSoundsAreOn ^= 1;
-				if (_internalSpeakerSoundsAreOn) {
-					showOldStyleBannerAndPause("Sounds On", 9, 90);
-				} else {
-					showOldStyleBannerAndPause("Sounds Off", 9, 90);
+			if (_game.version < 3) {
+				if (lastKeyHit.keycode == Common::KEYCODE_m && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+					_guiMouseFlag ^= 1;
+					if (_guiMouseFlag) {
+						printMessageAndPause(getGUIString(gsMouseOn), _game.version <= 1 ? 5 : 2, 0, false);
+					} else {
+						printMessageAndPause(getGUIString(gsMouseOff), _game.version <= 1 ? 2 : 4, 0, false);
+					}
+					return;
 				}
 
-				return;
+				if (lastKeyHit.keycode == Common::KEYCODE_j && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+					_guiJoystickFlag ^= 1;
+					if (_guiJoystickFlag) {
+						printMessageAndPause(getGUIString(gsJoystickOn), _game.version <= 1 ? 5 : 2, 0, false);
+					} else {
+						printMessageAndPause(getGUIString(gsJoystickOff), _game.version <= 1 ? 2 : 4, 0, false);
+					}
+					return;
+				}
+
+				if (lastKeyHit.keycode == Common::KEYCODE_F6) {
+					_internalSpeakerSoundsAreOn ^= 1;
+					if (_internalSpeakerSoundsAreOn) {
+						printMessageAndPause(getGUIString(gsSoundsOn), _game.version <= 1 ? 5 : 2, 0, false);
+					} else {
+						printMessageAndPause(getGUIString(gsSoundsOff), _game.version <= 1 ? 2 : 4, 0, false);
+					}
+					return;
+				}
 			}
 
+			if ((_game.version > 2 && _game.version < 5)) {
+				if (lastKeyHit.keycode == Common::KEYCODE_s && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+					_internalSpeakerSoundsAreOn ^= 1;
+
+					if (_internalSpeakerSoundsAreOn) {
+						showOldStyleBannerAndPause(getGUIString(gsSoundsOn), 9, 90);
+					} else {
+						showOldStyleBannerAndPause(getGUIString(gsSoundsOff), 9, 90);
+					}
+					return;
+				}
+			}
+
+			// Graphic mode toggles for v1-2... maybe one day they'll actually do something :-)
+			if (_game.version == 1 || _game.version == 2) {
+				// VGA/MCGA mode
+				if (lastKeyHit.keycode == Common::KEYCODE_v && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+					printMessageAndPause(getGUIString(gsVGAMode), _game.version <= 1 ? 5 : 2, 0, false);
+				}
+
+				// EGA mode
+				if (lastKeyHit.keycode == Common::KEYCODE_e && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+					printMessageAndPause(getGUIString(gsEGAMode), _game.version <= 1 ? 5 : 2, 0, false);
+				}
+
+				// CGA mode
+				if (lastKeyHit.keycode == Common::KEYCODE_c && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+					printMessageAndPause(getGUIString(gsCGAMode), _game.version <= 1 ? 5 : 2, 0, false);
+				}
+
+				// Hercules mode
+				if (lastKeyHit.keycode == Common::KEYCODE_h && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+					printMessageAndPause(getGUIString(gsHerculesMode), _game.version <= 1 ? 5 : 2, 0, false);
+				}
+
+				// Tandy 16-color mode
+				if (lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+					printMessageAndPause(getGUIString(gsTandyMode), _game.version <= 1 ? 5 : 2, 0, false);
+				}
+			}
 		}
 	}
 
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index b846ae8a26c..de8351aa598 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -429,7 +429,22 @@ enum GUIString {
 	gsTextSpeed = 37,
 	gsDisplayText = 38,
 	gsSpooledMusic = 39,
-	gsInsertSaveDisk = 40
+	gsInsertSaveDisk = 40,
+	gsSnapOn = 41,
+	gsSnapOff = 42,
+	gsRecalJoystick = 43,
+	gsMouseMode = 44,
+	gsMouseOn = 45,
+	gsMouseOff = 46,
+	gsJoystickOn = 47,
+	gsJoystickOff = 48,
+	gsSoundsOn = 49,
+	gsSoundsOff = 50,
+	gsVGAMode = 51,
+	gsEGAMode = 52,
+	gsCGAMode = 53,
+	gsHerculesMode = 54,
+	gsTandyMode = 55
 };
 
 struct InternalGUIControl {
@@ -636,7 +651,11 @@ protected:
 	int _saveScriptParam = 0;
 	int _guiCursorAnimCounter = 0;
 	int _v5VoiceMode = 0;
+
+	// Fake flags just for sub v5 GUIs
 	int _internalSpeakerSoundsAreOn = 1;
+	int _guiMouseFlag = 1;
+	int _guiJoystickFlag = 1;
 
 	Graphics::Surface _savegameThumbnail;
 	byte *_tempTextSurface = nullptr;
@@ -658,7 +677,7 @@ protected:
 	void initBanners();
 	Common::KeyState showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...);
 	Common::KeyState showOldStyleBannerAndPause(const char *msg, int color, int32 waitTime);
-	Common::KeyState printMessageAndPause(const char *msg, int32 waitTime, bool drawOnSentenceLine);
+	Common::KeyState printMessageAndPause(const char *msg, int color, int32 waitTime, bool drawOnSentenceLine);
 
 	void clearBanner();
 	void setBannerColors(int bannerId, byte r, byte g, byte b);


Commit: 213b49336aec172830928aacd6c14115e6dfdeba
    https://github.com/scummvm/scummvm/commit/213b49336aec172830928aacd6c14115e6dfdeba
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: LOOM v3: Fix query quit banner

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index fbac6adb4e6..6f498e09efd 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1414,10 +1414,10 @@ void ScummEngine::queryQuit(bool returnToLauncher) {
 		Common::KeyState ks;
 		if (_game.version > 4) {
 			ks = showBannerAndPause(0, -1, msgLabelPtr);
-		} else if (_game.version == 4) {
-			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
-		} else {
+		} else if (_game.version < 3) {
 			ks = printMessageAndPause(msgLabelPtr, 0, -1, true);
+		} else {
+			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
 		}
 
 		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);


Commit: 6560244a81f48545af4e2213a80656b6a9b8a255
    https://github.com/scummvm/scummvm/commit/6560244a81f48545af4e2213a80656b6a9b8a255
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix regression in snap scroll message

Changed paths:
    engines/scumm/input.cpp


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 53a1874975c..fd0b6f9f940 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -1084,9 +1084,9 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 					}
 				}  else {
 					if (_snapScroll) {
-						showBannerAndPause(0, 90, getGUIString(gsSnapOn));
+						showOldStyleBannerAndPause(getGUIString(gsSnapOn), 9, 90);
 					} else {
-						showBannerAndPause(0, 90, getGUIString(gsSnapOff));
+						showOldStyleBannerAndPause(getGUIString(gsSnapOff), 9, 90);
 					}
 				}
 


Commit: a8fc3f706d3c5ff42dedff7bb293fd6e607c1bae
    https://github.com/scummvm/scummvm/commit/a8fc3f706d3c5ff42dedff7bb293fd6e607c1bae
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Update the detection tables for the new games supporting the GUI

Changed paths:
    engines/scumm/detection_tables.h
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 7f708e366d3..d8428ed80aa 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -153,36 +153,36 @@ static const PlainGameDescriptor gameDescriptions[] = {
 // only a single unique variant. This is used to help the detector quickly
 // decide whether it has to worry about distinguishing multiple variants or not.
 static const GameSettings gameVariantsTable[] = {
-	{"maniac", "Apple II",   0, GID_MANIAC, 0, 0, MDT_APPLEIIGS, 0, Common::kPlatformApple2GS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
-	{"maniac", "C64",        0, GID_MANIAC, 0, 0, MDT_C64, 0, Common::kPlatformC64, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI) },
-	{"maniac", "C64 Demo",   0, GID_MANIAC, 0, 0, MDT_C64, GF_DEMO, Common::kPlatformC64, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI) },
-	{"maniac", "V1",      "v1", GID_MANIAC, 1, 0, MDT_PCSPK | MDT_PCJR, 0, Common::kPlatformDOS, GUIO8(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGABW, GUIO_RENDERCGACOMP, GUIO_RENDERCGA, GUIO_ENHANCEMENTS)},
-	{"maniac", "V1 Demo", "v1", GID_MANIAC, 1, 0, MDT_PCSPK | MDT_PCJR, GF_DEMO, Common::kPlatformDOS, GUIO7(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGABW, GUIO_RENDERCGACOMP, GUIO_RENDERCGA)},
+	{"maniac", "Apple II",   0, GID_MANIAC, 0, 0, MDT_APPLEIIGS, 0, Common::kPlatformApple2GS, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ORIGINALGUI)},
+	{"maniac", "C64",        0, GID_MANIAC, 0, 0, MDT_C64, 0, Common::kPlatformC64, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ORIGINALGUI) },
+	{"maniac", "C64 Demo",   0, GID_MANIAC, 0, 0, MDT_C64, GF_DEMO, Common::kPlatformC64, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ORIGINALGUI) },
+	{"maniac", "V1",      "v1", GID_MANIAC, 1, 0, MDT_PCSPK | MDT_PCJR, 0, Common::kPlatformDOS, GUIO9(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGABW, GUIO_RENDERCGACOMP, GUIO_RENDERCGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"maniac", "V1 Demo", "v1", GID_MANIAC, 1, 0, MDT_PCSPK | MDT_PCJR, GF_DEMO, Common::kPlatformDOS, GUIO8(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGABW, GUIO_RENDERCGACOMP, GUIO_RENDERCGA, GUIO_ORIGINALGUI)},
 	{"maniac", "NES",        0, GID_MANIAC, 1, 0, MDT_NONE,  0, Common::kPlatformNES, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_NOASPECT, GUIO_ENHANCEMENTS)},
-	{"maniac", "V2",      "v2", GID_MANIAC, 2, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO7(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA, GUIO_ENHANCEMENTS)},
-	{"maniac", "V2 Demo", "v2", GID_MANIAC, 2, 0, MDT_PCSPK | MDT_PCJR, GF_DEMO, Common::kPlatformDOS, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA)},
-
-	{"zak", "V1",       "v1", GID_ZAK, 1, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO7(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGABW, GUIO_RENDERCGACOMP, GUIO_RENDERCGA)},
-	{"zak", "V2",       "v2", GID_ZAK, 2, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA)},
-	{"zak", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS)},
-	{"zakloom", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS)},
-	{"indyloom", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS)},
-	{"indyzak", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS)},
-
-	{"indy3", "EGA",      "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, 0, UNK, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERCGA, GUIO_ENHANCEMENTS)},
-	{"indy3", "Mac",      "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR,             0, Common::kPlatformMacintosh, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERMACINTOSHBW, GUIO_ENHANCEMENTS)},
-	{"indy3", "No AdLib", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR,             0, UNK, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERCGA, GUIO_ENHANCEMENTS)},
-	{"indy3", "VGA",      "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS,                  Common::kPlatformDOS, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
-	{"indy3", "Steam",  "steam", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, UNK, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
-	{"indy3", "FM-TOWNS",     0, GID_INDY3, 3, 0, MDT_TOWNS,             GF_OLD256 | GF_FEW_LOCALS | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS)},
-
-	{"loom", "EGA",      "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO3(GUIO_NOSPEECH, GUIO_RENDERCGA, GUIO_ENHANCEMENTS)},
-	{"loom", "No AdLib", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS,                        0, UNK, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
+	{"maniac", "V2",      "v2", GID_MANIAC, 2, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO8(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"maniac", "V2 Demo", "v2", GID_MANIAC, 2, 0, MDT_PCSPK | MDT_PCJR, GF_DEMO, Common::kPlatformDOS, GUIO7(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA, GUIO_ORIGINALGUI)},
+
+	{"zak", "V1",       "v1", GID_ZAK, 1, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO8(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGABW, GUIO_RENDERCGACOMP, GUIO_RENDERCGA, GUIO_ORIGINALGUI)},
+	{"zak", "V2",       "v2", GID_ZAK, 2, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO7(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERHERCGREEN, GUIO_RENDERHERCAMBER, GUIO_RENDERCGA, GUIO_RENDERAMIGA, GUIO_ORIGINALGUI)},
+	{"zak", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"zakloom", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ORIGINALGUI)},
+	{"indyloom", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ORIGINALGUI)},
+	{"indyzak", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ORIGINALGUI)},
+
+	{"indy3", "EGA",      "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, 0, UNK, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERCGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"indy3", "Mac",      "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR,             0, Common::kPlatformMacintosh, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERMACINTOSHBW, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"indy3", "No AdLib", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR,             0, UNK, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDERCGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"indy3", "VGA",      "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS,                  Common::kPlatformDOS, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"indy3", "Steam",  "steam", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, UNK, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"indy3", "FM-TOWNS",     0, GID_INDY3, 3, 0, MDT_TOWNS,             GF_OLD256 | GF_FEW_LOCALS | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+
+	{"loom", "EGA",      "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO4(GUIO_NOSPEECH, GUIO_RENDERCGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"loom", "No AdLib", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS,                        0, UNK, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
 	{"loom", "PC-Engine",    0, GID_LOOM, 3, 0, MDT_NONE,                         GF_AUDIOTRACKS | GF_OLD256 | GF_16BIT_COLOR, Common::kPlatformPCEngine, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
-	{"loom", "FM-TOWNS",     0, GID_LOOM, 3, 0, MDT_TOWNS,                        GF_AUDIOTRACKS | GF_OLD256, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT, GUIO_ENHANCEMENTS)},
+	{"loom", "FM-TOWNS",     0, GID_LOOM, 3, 0, MDT_TOWNS,                        GF_AUDIOTRACKS | GF_OLD256, Common::kPlatformFMTowns, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
 	{"loom", "VGA",      "vga", GID_LOOM, 4, 0, MDT_NONE,                         GF_AUDIOTRACKS,             Common::kPlatformDOS, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDEREGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
 	{"loom", "Steam",  "steam", GID_LOOM, 4, 0, MDT_NONE,                         GF_AUDIOTRACKS,  UNK, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_RENDEREGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
-	{"loom", "Demo",      "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_DEMO, UNK, GUIO2(GUIO_NOSPEECH, GUIO_RENDERCGA)},
+	{"loom", "Demo",      "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_DEMO, UNK, GUIO3(GUIO_NOSPEECH, GUIO_RENDERCGA, GUIO_ORIGINALGUI)},
 
 	{"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_16COLOR, Common::kPlatformDOS, GUIO4(GUIO_NOSPEECH, GUIO_RENDERCGA, GUIO_NOMIDI, GUIO_ORIGINALGUI)},
 
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 678a265b3fe..f5e82c015e0 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -360,7 +360,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
 
 	setV1ColorTable(_renderMode);
 
-	_isRTL = (_language == Common::HE_ISR && (_game.heversion == 0 || _game.heversion >= 72)) 
+	_isRTL = (_language == Common::HE_ISR && (_game.heversion == 0 || _game.heversion >= 72))
 			&& (_game.id == GID_MANIAC || (_game.version >= 4 && _game.version < 7)) && !(_game.features & GF_HE_NO_BIDI);
 #ifndef DISABLE_HELP
 	// Create custom GMM dialog providing a help subdialog
@@ -3144,13 +3144,13 @@ bool ScummEngine::isUsingOriginalGUI() {
 	if (_game.id == GID_MONKEY2 && (_game.features & GF_DEMO))
 		return false;
 
-	if (_game.heversion != 0)
+	if (_game.platform == Common::kPlatformNES)
 		return false;
 
-	if (_game.version >= 0)
-		return _useOriginalGUI;
+	if (_game.heversion != 0)
+		return false;
 
-	return false;
+	return _useOriginalGUI;
 }
 
 void ScummEngine::runBootscript() {


Commit: bf0ecd47ff4f3abad59682706499770336566cdb
    https://github.com/scummvm/scummvm/commit/bf0ecd47ff4f3abad59682706499770336566cdb
Author: Torbjörn Andersson (eriktorbjorn at users.sourceforge.net)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: Implement message boxes for Mac Loom and Last Crusade

I'm committing this as is, while leaving final integration to someone
else. Note that this doesn't really replicate the original Mac GUI (e.g.
the quit dialog is nothing like the original), but at least the pause
dialog looks right. And that's what matters to me.

Changed paths:
    engines/scumm/charset.cpp
    engines/scumm/charset.h
    engines/scumm/gfx_gui.cpp
    engines/scumm/gfx_mac.cpp
    engines/scumm/scumm.h


diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 8eb54ed9c34..15772daf5b2 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -1514,7 +1514,7 @@ CharsetRendererMac::CharsetRendererMac(ScummEngine *vm, const Common::String &fo
 	// (At the time of writing, there are still cases, at least in Loom,
 	// where text isn't correctly positioned.)
 
-	_correctFontSpacing = _vm->_game.id == GID_LOOM || _vm->_enableEnhancements;
+	_useCorrectFontSpacing = _vm->_game.id == GID_LOOM || _vm->_enableEnhancements;
 	_pad = false;
 	_glyphSurface = nullptr;
 
@@ -1523,13 +1523,10 @@ CharsetRendererMac::CharsetRendererMac(ScummEngine *vm, const Common::String &fo
 	// headline. The rest of the Mac GUI seems to use a system font, but
 	// that is not implemented.
 
-	// As far as I can tell, Loom uses only font size 13 for in-game text.
-	// The font is also provided in sizes 9 and 12, and it's possible that
-	// 12 is used for system messages, e.g. the original pause dialog. We
-	// don't support that.
-	//
-	// I have no idea what size 9 is used for. Possibly the original About
-	// dialog?
+	// As far as I can tell, Loom uses only font size 13 for in-game text,
+	// but size 12 is used for system messages, e.g. the original pause
+	// dialog. I have no idea what size 9 is used for. Possibly the
+	// original About dialog?
 	//
 	// As far as I can tell, the game does not use anything fancy, like
 	// different styles, and the font does not appear to have a kerning
@@ -1570,6 +1567,8 @@ CharsetRendererMac::CharsetRendererMac(ScummEngine *vm, const Common::String &fo
 		} else {
 			if (fontSize == 13)
 				fontId = 0;
+			else if (fontSize == 12)
+				fontId = 1;
 		}
 		if (fontId != -1) {
 			Common::SeekableReadStream *font = resource.getResource(MKTAG('F', 'O', 'N', 'T'), (*assoc)[i]._fontID);
@@ -1606,6 +1605,9 @@ void CharsetRendererMac::setCurID(int32 id) {
 	if  (id == -1)
 		return;
 
+	_useRealCharWidth = (id & 0x80) != 0;
+	id = id & 0x7F;
+
 	// Indiana Jones and the Last Crusade uses font id 1 in a number of
 	// places. In the DOS version, this is a bolder font than font 0, but
 	// by the looks of it the Mac version uses the same font for both
@@ -1619,9 +1621,7 @@ void CharsetRendererMac::setCurID(int32 id) {
 		}
 	}
 
-	int maxId = (_vm->_game.id == GID_LOOM) ? 0 : 1;
-
-	if (id > maxId) {
+	if (id > 1) {
 		warning("CharsetRendererMac::setCurID(%d) - invalid charset", id);
 		id = 0;
 	}
@@ -1671,13 +1671,7 @@ int CharsetRendererMac::getFontHeight() const {
 
 int CharsetRendererMac::getCharWidth(uint16 chr) const {
 	int width = getDrawWidthIntern(chr);
-
-	// For font 1 in Last Crusade, we want the real width. It is used for
-	// text box titles, which are drawn outside the normal font rendering.
-	if (_curId == 0 || _vm->_game.id != GID_INDY3)
-		width /= 2;
-
-	return width;
+	return _useRealCharWidth ? width : width / 2;
 }
 
 void CharsetRendererMac::printChar(int chr, bool ignoreCharsetMask) {
@@ -1785,7 +1779,7 @@ void CharsetRendererMac::printChar(int chr, bool ignoreCharsetMask) {
 	// the width of a string (e.g. to center text on screen). It is,
 	// however, used for things like the Grail Diary.
 
-	if (!_correctFontSpacing && !drawToTextBox && (width & 1))
+	if (!_useCorrectFontSpacing && !drawToTextBox && (width & 1))
 		width++;
 
 	if (enableShadow) {
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index 563f1f564c2..0fbc0f1e21f 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -278,7 +278,8 @@ public:
 class CharsetRendererMac : public CharsetRendererCommon {
 protected:
 	Graphics::MacFONTFont _macFonts[2];
-	bool _correctFontSpacing;
+	bool _useRealCharWidth;
+	bool _useCorrectFontSpacing;
 	bool _pad;
 	int _lastTop;
 
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 6f498e09efd..57279ca014b 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -374,6 +374,10 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 		return showBannerAndPause(0, waitTime, msg);
 	}
 
+	if (_macScreen) {
+		return mac_showOldStyleBannerAndPause(msg, waitTime);
+	}
+
 	char bannerMsg[512];
 	int bannerMsgWidth, bannerMsgHeight;
 	int startingPointY;
diff --git a/engines/scumm/gfx_mac.cpp b/engines/scumm/gfx_mac.cpp
index 4ab0eadf4bc..d71b756c200 100644
--- a/engines/scumm/gfx_mac.cpp
+++ b/engines/scumm/gfx_mac.cpp
@@ -28,6 +28,26 @@
 
 namespace Scumm {
 
+void ScummEngine::mac_markScreenAsDirty(int x, int y, int w, int h) {
+	// Mark the virtual screen as dirty. The top and left coordinates are
+	// rounded down, while the bottom and right ones are rounded up.
+
+	VirtScreen *vs = &_virtscr[kMainVirtScreen];
+
+	int vsTop = y / 2 - vs->topline;
+	int vsBottom = (y + h) / 2 - vs->topline;
+	int vsLeft = x / 2;
+	int vsRight = (x + w) / 2;
+
+	if ((y + h) & 1)
+		vsBottom++;
+
+	if ((x + w) & 1)
+		vsRight++;
+
+	markRectAsDirty(kMainVirtScreen, vsLeft, vsRight, vsTop, vsBottom);
+}
+
 void ScummEngine::mac_drawStripToScreen(VirtScreen *vs, int top, int x, int y, int width, int height) {
 
 	const byte *pixels = vs->getPixels(x, top);
@@ -155,7 +175,7 @@ void ScummEngine::mac_createIndy3TextBox(Actor *a) {
 
 	if (a) {
 		int oldID = _charset->getCurID();
-		_charset->setCurID(2);
+		_charset->setCurID(2 | 0x80);
 
 		const char *name = (const char *)a->getActorName();
 		int charX = 25;
@@ -194,29 +214,13 @@ void ScummEngine::mac_drawIndy3TextBox() {
 	// had been one giant glyph. Note that it will be drawn on the main
 	// virtual screen, but we still pretend it's on the text one.
 
-	VirtScreen *vs = &_virtscr[kMainVirtScreen];
-
 	byte *ptr = (byte *)_macIndy3TextBox->getBasePtr(0, 2);
 	int pitch = _macIndy3TextBox->pitch;
 
 	_macScreen->copyRectToSurface(ptr, pitch, x, y, w, h);
 	_textSurface.fillRect(Common::Rect(x, y, x + w, y + h), 0);
 
-	// Mark the virtual screen as dirty. The top and left coordinates are
-	// rounded down, while the bottom and right ones are rounded up.
-
-	int vsTop = y / 2 - vs->topline;
-	int vsBottom = (y + h) / 2 - vs->topline;
-	int vsLeft = x / 2;
-	int vsRight = (x + w) / 2;
-
-	if ((y + h) & 1)
-		vsBottom++;
-
-	if ((x + w) & 1)
-		vsRight++;
-
-	markRectAsDirty(kMainVirtScreen, vsLeft, vsRight, vsTop, vsBottom);
+	mac_markScreenAsDirty(x, y, w, h);
 }
 
 void ScummEngine::mac_undrawIndy3TextBox() {
@@ -228,20 +232,7 @@ void ScummEngine::mac_undrawIndy3TextBox() {
 	_macScreen->fillRect(Common::Rect(x, y, x + w, y + h), 0);
 	_textSurface.fillRect(Common::Rect(x, y, x + w, y + h), CHARSET_MASK_TRANSPARENCY);
 
-	VirtScreen *vs = &_virtscr[kMainVirtScreen];
-
-	int vsTop = y / 2 - vs->topline;
-	int vsBottom = (y + h) / 2 - vs->topline;
-	int vsLeft = x / 2;
-	int vsRight = (x + w) / 2;
-
-	if ((y + h) & 1)
-		vsBottom++;
-
-	if ((x + w) & 1)
-		vsRight++;
-
-	markRectAsDirty(kMainVirtScreen, vsLeft, vsRight, vsTop, vsBottom);
+	mac_markScreenAsDirty(x, y, w, h);
 }
 
 void ScummEngine::mac_undrawIndy3CreditsText() {
@@ -265,4 +256,109 @@ void ScummEngine::mac_undrawIndy3CreditsText() {
 	}
 }
 
+void ScummEngine::mac_drawBorder(int x, int y, int w, int h, byte color) {
+	_macScreen->hLine(x + 2, y, x + w - 2, 0);
+	_macScreen->hLine(x + 2, y + h - 1, x + w - 2, 0);
+	_macScreen->vLine(x, y + 2, y + h - 3, 0);
+	_macScreen->vLine(x + w, y + 2, y + h - 3, 0);
+	_macScreen->setPixel(x + 1, y + 1, 0);
+	_macScreen->setPixel(x + w - 1, y + 1, 0);
+	_macScreen->setPixel(x + 1, y + h - 2, 0);
+	_macScreen->setPixel(x + w - 1, y + h - 2, 0);
+}
+
+Common::KeyState ScummEngine::mac_showOldStyleBannerAndPause(const char *msg, int32 waitTime) {
+	char bannerMsg[512];
+
+	_messageBannerActive = true;
+
+	// Fetch the translated string for the message...
+	convertMessageToString((const byte *)msg, (byte *)bannerMsg, sizeof(bannerMsg));
+
+	// Backup the text surface...
+	if (!_mainMenuIsActive) {
+		saveSurfacesPreGUI();
+		if (_charset->_textScreenID == kMainVirtScreen)
+			restoreCharsetBg();
+	}
+
+	// Pause shake effect
+	_shakeTempSavedState = _shakeEnabled;
+	setShake(0);
+
+	// Pause the engine
+	PauseToken pt = pauseEngine();
+
+	// Backup the current charsetId...
+	int oldId = _charset->getCurID();
+	_charset->setCurID(1 | 0x80);
+	_charset->setColor(0);
+
+	int x = 70;
+	int y = 189;
+	int w = 499;
+	int h = 22;
+
+	Graphics::Surface backupTextSurface;
+	Graphics::Surface backupMacScreen;
+
+	backupTextSurface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+	backupMacScreen.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+
+	backupTextSurface.copyRectToSurface(_textSurface, 0, 0, Common::Rect(x, y, x + w, y + h));
+	backupMacScreen.copyRectToSurface(*_macScreen, 0, 0, Common::Rect(x, y, x + w, y + h));
+
+	_textSurface.fillRect(Common::Rect(x, y, x + w + 1, y + h), 0);
+	_macScreen->fillRect(Common::Rect(x + 1, y + 1, x + w, y + h - 1), 15);
+	mac_drawBorder(x, y, w, h, 0);
+	mac_drawBorder(x + 2, y + 2, w - 4, h - 4, 0);
+
+	int stringWidth = 0;
+
+	for (int i = 0; msg[i]; i++)
+		stringWidth += _charset->getCharWidth(msg[i]);
+
+	int stringX = 1 + x + (w - stringWidth) / 2;
+
+	for (int i = 0; msg[i]; i++) {
+		_charset->drawChar(msg[i], *_macScreen, stringX, y + 4);
+		stringX += _charset->getCharWidth(msg[i]);
+	}
+
+	mac_markScreenAsDirty(x, y, w, h);
+	ScummEngine::drawDirtyScreenParts();
+
+	Common::KeyState ks = Common::KEYCODE_INVALID;
+	bool leftBtnPressed = false, rightBtnPressed = false;
+	if (waitTime) {
+		waitForBannerInput(waitTime, ks, leftBtnPressed, rightBtnPressed);
+		clearBanner();
+	}
+
+	// Restore the text surface...
+	if (!_mainMenuIsActive) {
+		restoreSurfacesPostGUI();
+	}
+
+	_textSurface.copyRectToSurface(backupTextSurface, x, y, Common::Rect(0, 0, w, h));
+	_macScreen->copyRectToSurface(backupMacScreen, x, y, Common::Rect(0, 0, w, h));
+
+	backupTextSurface.free();
+	backupMacScreen.free();
+
+	// Finally, resume the engine, clear the input state, and restore the charset.
+	pt.clear();
+	clearClickedStatus();
+
+	_charset->setCurID(oldId);
+
+	// Deactivate this, so it does not trigger as invalid click target inside
+	// getInternalGUIControlFromCoordinates() (which can cause serious errors)
+	_internalGUIControls[0].relativeCenterX = -1;
+
+	_messageBannerActive = false;
+
+	return ks;
+}
+
 } // End of namespace Scumm
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index de8351aa598..1d70791ebb0 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1315,12 +1315,16 @@ protected:
 	virtual void drawDirtyScreenParts();
 	void updateDirtyScreen(VirtScreenNumber slot);
 	void drawStripToScreen(VirtScreen *vs, int x, int width, int top, int bottom);
+
+	void mac_markScreenAsDirty(int x, int y, int w, int h);
 	void mac_drawStripToScreen(VirtScreen *vs, int top, int x, int y, int width, int height);
 	void mac_drawLoomPracticeMode();
 	void mac_createIndy3TextBox(Actor *a);
 	void mac_drawIndy3TextBox();
 	void mac_undrawIndy3TextBox();
 	void mac_undrawIndy3CreditsText();
+	void mac_drawBorder(int x, int y, int w, int h, byte color);
+	Common::KeyState mac_showOldStyleBannerAndPause(const char *msg, int32 waitTime);
 
 	const byte *postProcessDOSGraphics(VirtScreen *vs, int &pitch, int &x, int &y, int &width, int &height) const;
 	const byte *ditherVGAtoEGA(int &pitch, int &x, int &y, int &width, int &height) const;


Commit: 0c0bfe70ad1c18e651f37594953329a50bf137f5
    https://github.com/scummvm/scummvm/commit/0c0bfe70ad1c18e651f37594953329a50bf137f5
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Clean-up and fix v3 Mac banners

These changes fix issues related to surfaces saving and restoring, and remove
unneeded code for the Mac GUI.

Changed paths:
    engines/scumm/gfx_mac.cpp


diff --git a/engines/scumm/gfx_mac.cpp b/engines/scumm/gfx_mac.cpp
index d71b756c200..7e5a4ec65f2 100644
--- a/engines/scumm/gfx_mac.cpp
+++ b/engines/scumm/gfx_mac.cpp
@@ -275,12 +275,20 @@ Common::KeyState ScummEngine::mac_showOldStyleBannerAndPause(const char *msg, in
 	// Fetch the translated string for the message...
 	convertMessageToString((const byte *)msg, (byte *)bannerMsg, sizeof(bannerMsg));
 
-	// Backup the text surface...
-	if (!_mainMenuIsActive) {
-		saveSurfacesPreGUI();
-		if (_charset->_textScreenID == kMainVirtScreen)
-			restoreCharsetBg();
-	}
+	// Backup the surfaces...
+	int x = 70;
+	int y = 189;
+	int w = 499;
+	int h = 22;
+
+	Graphics::Surface backupTextSurface;
+	Graphics::Surface backupMacScreen;
+
+	backupTextSurface.create(w + 1, h, Graphics::PixelFormat::createFormatCLUT8());
+	backupMacScreen.create(w + 1, h, Graphics::PixelFormat::createFormatCLUT8());
+
+	backupTextSurface.copyRectToSurface(_textSurface, 0, 0, Common::Rect(x, y, x + w + 1, y + h));
+	backupMacScreen.copyRectToSurface(*_macScreen, 0, 0, Common::Rect(x, y, x + w + 1, y + h));
 
 	// Pause shake effect
 	_shakeTempSavedState = _shakeEnabled;
@@ -294,20 +302,6 @@ Common::KeyState ScummEngine::mac_showOldStyleBannerAndPause(const char *msg, in
 	_charset->setCurID(1 | 0x80);
 	_charset->setColor(0);
 
-	int x = 70;
-	int y = 189;
-	int w = 499;
-	int h = 22;
-
-	Graphics::Surface backupTextSurface;
-	Graphics::Surface backupMacScreen;
-
-	backupTextSurface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
-	backupMacScreen.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
-
-	backupTextSurface.copyRectToSurface(_textSurface, 0, 0, Common::Rect(x, y, x + w, y + h));
-	backupMacScreen.copyRectToSurface(*_macScreen, 0, 0, Common::Rect(x, y, x + w, y + h));
-
 	_textSurface.fillRect(Common::Rect(x, y, x + w + 1, y + h), 0);
 	_macScreen->fillRect(Common::Rect(x + 1, y + 1, x + w, y + h - 1), 15);
 	mac_drawBorder(x, y, w, h, 0);
@@ -332,30 +326,25 @@ Common::KeyState ScummEngine::mac_showOldStyleBannerAndPause(const char *msg, in
 	bool leftBtnPressed = false, rightBtnPressed = false;
 	if (waitTime) {
 		waitForBannerInput(waitTime, ks, leftBtnPressed, rightBtnPressed);
-		clearBanner();
-	}
-
-	// Restore the text surface...
-	if (!_mainMenuIsActive) {
-		restoreSurfacesPostGUI();
 	}
 
-	_textSurface.copyRectToSurface(backupTextSurface, x, y, Common::Rect(0, 0, w, h));
-	_macScreen->copyRectToSurface(backupMacScreen, x, y, Common::Rect(0, 0, w, h));
+	// Restore the surfaces...
+	_textSurface.copyRectToSurface(backupTextSurface, x, y, Common::Rect(0, 0, w + 1, h));
+	_macScreen->copyRectToSurface(backupMacScreen, x, y, Common::Rect(0, 0, w + 1, h));
 
 	backupTextSurface.free();
 	backupMacScreen.free();
 
+	// Notify the gfx system that we restored the surfaces...
+	mac_markScreenAsDirty(x, y, w + 1, h);
+	ScummEngine::drawDirtyScreenParts();
+
 	// Finally, resume the engine, clear the input state, and restore the charset.
 	pt.clear();
 	clearClickedStatus();
 
 	_charset->setCurID(oldId);
 
-	// Deactivate this, so it does not trigger as invalid click target inside
-	// getInternalGUIControlFromCoordinates() (which can cause serious errors)
-	_internalGUIControls[0].relativeCenterX = -1;
-
 	_messageBannerActive = false;
 
 	return ks;


Commit: 5f9d6d77803542e765dcf79f6d8515de7d5a0e02
    https://github.com/scummvm/scummvm/commit/5f9d6d77803542e765dcf79f6d8515de7d5a0e02
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix v5 banner colors for Mac versions

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 57279ca014b..1d19399335e 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -136,10 +136,21 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		int palOffset = (_game.version == 8) ? 0 : 11;
 		normalFillColor = getBannerColor(6 * bannerId + 15 + palOffset);
 		normalTextColor = getBannerColor(6 * bannerId + 14 + palOffset);
-		topLineColor = getBannerColor(6 * bannerId + 16 + palOffset);
-		bottomLineColor = getBannerColor(6 * bannerId + 17 + palOffset);
-		leftLineColor = getBannerColor(6 * bannerId + 18 + palOffset);
-		rightLineColor = getBannerColor(6 * bannerId + 19 + palOffset);
+
+		if (_game.version == 5 && _game.platform == Common::kPlatformMacintosh) {
+			// Mac versions of MI1, MI2 and INDY4 invert the colors of the bottom
+			// and left lines, which means they have the brightest colors on the top
+			// and bottom lines, and the darker colors on the left and right lines.
+			topLineColor = getBannerColor(6 * bannerId + 16 + palOffset);
+			bottomLineColor = getBannerColor(6 * bannerId + 18 + palOffset);
+			leftLineColor = getBannerColor(6 * bannerId + 17 + palOffset);
+			rightLineColor = getBannerColor(6 * bannerId + 19 + palOffset);
+		} else {
+			topLineColor = getBannerColor(6 * bannerId + 16 + palOffset);
+			bottomLineColor = getBannerColor(6 * bannerId + 17 + palOffset);
+			leftLineColor = getBannerColor(6 * bannerId + 18 + palOffset);
+			rightLineColor = getBannerColor(6 * bannerId + 19 + palOffset);
+		}
 	}
 
 	// Backup the current charsetId, since we're going to switch


Commit: b8e4fbb72b7a37fa21e59c008eeff0b874b8c3f2
    https://github.com/scummvm/scummvm/commit/b8e4fbb72b7a37fa21e59c008eeff0b874b8c3f2
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix GMM not opening on F5 press for v3 Mac games

Changed paths:
    engines/scumm/input.cpp


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index fd0b6f9f940..affe76fdb77 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -1068,6 +1068,10 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			&& _game.platform != Common::kPlatformFMTowns && _game.version > 3) {
 			showMainMenu();
 			return;
+		} else if (lastKeyHit.keycode == Common::KEYCODE_F5 && _game.version == 3 && _game.platform == Common::kPlatformMacintosh) {
+			// We don't have original menus for Mac versions of LOOM and INDY3, so let's just open the GMM...
+			openMainMenuDialog();
+			return;
 		}
 
 		if (snapScrollKeyEnabled) {


Commit: 172bc2d4c4f7bde22cdc2b4d9a83c95471c01fae
    https://github.com/scummvm/scummvm/commit/172bc2d4c4f7bde22cdc2b4d9a83c95471c01fae
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix v3 FM-Towns games crashing on banner display

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 1d19399335e..da52d4f8e8e 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1286,7 +1286,7 @@ void ScummEngine::saveSurfacesPreGUI() {
 	if (_game.version < 3 || _game.version > 6)
 		return;
 
-	_tempTextSurface = (byte *)malloc(_textSurface.pitch * _textSurface.h * sizeof(byte));
+	_tempTextSurface = (byte *)malloc(_textSurface.pitch * _textSurface.h * _textSurfaceMultiplier * sizeof(byte));
 	_tempMainSurface = (byte *)malloc(_virtscr[kMainVirtScreen].w * _virtscr[kMainVirtScreen].h * sizeof(byte));
 	_tempVerbSurface = (byte *)malloc(_virtscr[kVerbVirtScreen].w * _virtscr[kVerbVirtScreen].h * sizeof(byte));
 
@@ -1316,7 +1316,8 @@ void ScummEngine::saveSurfacesPreGUI() {
 				for (int x = 0; x < _screenWidth; x++) {
 					// Only draw non transparent pixels
 					if (_tempTextSurface[x + y * _screenWidth] != 0xFD) {
-						_virtscr[kMainVirtScreen].setPixel(_virtscr[kMainVirtScreen].xstart + x, y, _tempTextSurface[x + y * _screenWidth]);
+						if (x < _virtscr[kMainVirtScreen].pitch && y < _virtscr[kMainVirtScreen].h)
+							_virtscr[kMainVirtScreen].setPixel(_virtscr[kMainVirtScreen].xstart + x, y, _tempTextSurface[x + y * _screenWidth]);
 					}
 				}
 			}


Commit: 415370598c73810de62162fc590399d9a7b8bf6a
    https://github.com/scummvm/scummvm/commit/415370598c73810de62162fc590399d9a7b8bf6a
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix black screen glitches on FMTowns v3 games

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index da52d4f8e8e..9f59975f2cf 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1305,7 +1305,7 @@ void ScummEngine::saveSurfacesPreGUI() {
 	}
 
 	if (_tempTextSurface) {
-		memcpy(_tempTextSurface, _textSurface.getBasePtr(0, 0), _textSurface.pitch * _textSurface.h);
+		memcpy(_tempTextSurface, _textSurface.getBasePtr(0, 0), _textSurface.pitch * _textSurface.h * _textSurfaceMultiplier);
 
 		// For each v4-v6 game (except for LOOM VGA which does its own thing), we take the text surface
 		// and stamp it on top of the main screen: this is done to ensure that the GUI is drawn on top
@@ -1331,13 +1331,15 @@ void ScummEngine::restoreSurfacesPostGUI() {
 		return;
 
 	if (_tempTextSurface) {
-		memcpy(_textSurface.getBasePtr(0, 0), _tempTextSurface, _textSurface.pitch * _textSurface.h);
+		memcpy(_textSurface.getBasePtr(0, 0), _tempTextSurface, _textSurface.pitch * _textSurface.h * _textSurfaceMultiplier);
 
 		// Signal the restoreCharsetBg() function that there's text
 		// on the text surface, so it gets deleted the next time another
 		// text is displayed...
-		if (_game.version != 4 || _game.id != GID_LOOM)
+		if (!(_game.version == 3 && _game.platform == Common::kPlatformFMTowns) &&
+			!(_game.version == 4 && _game.id == GID_LOOM)) {
 			_postGUICharMask = true;
+		}
 
 		free(_tempTextSurface);
 		_tempTextSurface = nullptr;
@@ -1366,6 +1368,11 @@ void ScummEngine::restoreSurfacesPostGUI() {
 
 		_virtscr[kVerbVirtScreen].setDirtyRange(0, _virtscr[kVerbVirtScreen].h);
 	}
+
+	// Immediately redraw the screen for v3 FMTowns games, to avoid rendering
+	// a black frame after clearing the GUI element...
+	if (_game.version == 3 && _game.platform == Common::kPlatformFMTowns)
+		ScummEngine::drawDirtyScreenParts();
 }
 
 void ScummEngine::toggleVoiceMode() {


Commit: ca3d80e281e94e8c485c9a8f42ace39a3a591f45
    https://github.com/scummvm/scummvm/commit/ca3d80e281e94e8c485c9a8f42ace39a3a591f45
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix banner color for v3 FM-Towns games

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 9f59975f2cf..8c18ebf8d80 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -464,7 +464,8 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	}
 
 	// Draw the GUI control
-	drawBox(0, startingPointY, _screenWidth - 1, startingPointY + bannerMsgHeight, 0);
+	int boxColor = (_game.platform == Common::kPlatformFMTowns && _game.version == 3) ? 8 : 0;
+	drawBox(0, startingPointY, _screenWidth - 1, startingPointY + bannerMsgHeight, boxColor);
 	drawBox(0, startingPointY, _screenWidth - 1, startingPointY, color);
 	drawBox(0, startingPointY + bannerMsgHeight, _screenWidth - 1, startingPointY + bannerMsgHeight, color);
 	drawGUIText(bannerMsg, 0, _screenWidth / 2, startingPointY + 2, color, true);


Commit: a3a7d4a131c15d48fbf463d21a6afe5638b36c08
    https://github.com/scummvm/scummvm/commit/a3a7d4a131c15d48fbf463d21a6afe5638b36c08
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix banner and text position on v3 FM-Towns games

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 8c18ebf8d80..e9d4180f6a6 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -464,11 +464,36 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	}
 
 	// Draw the GUI control
-	int boxColor = (_game.platform == Common::kPlatformFMTowns && _game.version == 3) ? 8 : 0;
+	bool isV3Towns = (_game.platform == Common::kPlatformFMTowns && _game.version == 3);
+
+	int boxColor = 0;
+	int textXPos = _screenWidth / 2;
+	int textYPos = startingPointY + 2;
+
+	if (isV3Towns) {
+		boxColor = 8;
+		textXPos = (320 - bannerMsgWidth) / 2;
+		textYPos = 2 + (_virtscr[kMainVirtScreen].h + _virtscr[kMainVirtScreen].topline - (bannerMsgHeight - 6)) / 2;
+
+		// Game specific corrections
+		if (_game.id == GID_INDY3)
+			textXPos += 8;
+		if (_game.id == GID_LOOM)
+			textYPos -= 8;
+
+		startingPointY = textYPos - 2;
+
+		if (_useCJKMode) {
+			textXPos -= _game.id == GID_INDY3 ? 34 : 8;
+		}
+	}
+
 	drawBox(0, startingPointY, _screenWidth - 1, startingPointY + bannerMsgHeight, boxColor);
 	drawBox(0, startingPointY, _screenWidth - 1, startingPointY, color);
 	drawBox(0, startingPointY + bannerMsgHeight, _screenWidth - 1, startingPointY + bannerMsgHeight, color);
-	drawGUIText(bannerMsg, 0, _screenWidth / 2, startingPointY + 2, color, true);
+
+	drawGUIText(bannerMsg, 0, textXPos, textYPos, color, !isV3Towns);
+
 	ScummEngine::drawDirtyScreenParts();
 
 	// Wait until the engine receives a new Keyboard or Mouse input,


Commit: 0944412c0e027466da54d7fdc4bca6f19d589c6c
    https://github.com/scummvm/scummvm/commit/0944412c0e027466da54d7fdc4bca6f19d589c6c
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix graphical glitches in LOOM Towns

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index e9d4180f6a6..f05a2cfe885 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -402,7 +402,8 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	// Backup the text surface...
 	if (!_mainMenuIsActive) {
 		saveSurfacesPreGUI();
-		if (_charset->_textScreenID == kMainVirtScreen)
+		if (_charset->_textScreenID == kMainVirtScreen &&
+			!(_game.id == GID_LOOM && _game.platform == Common::kPlatformFMTowns))
 			restoreCharsetBg();
 	}
 


Commit: a0baee6e6f067dfa9bcf8270aa2e408c6e3f706b
    https://github.com/scummvm/scummvm/commit/a0baee6e6f067dfa9bcf8270aa2e408c6e3f706b
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix remaining v3 FM-Towns banner-related glitches

Changed paths:
    engines/scumm/gfx_gui.cpp
    engines/scumm/scumm.h


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index f05a2cfe885..dccbfadcfd9 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -84,7 +84,6 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	char *ptrToBreak;
 	int bannerMsgWidth, bannerMsgHeight, roundedWidth;
 	int startingPointX, startingPointY;
-	int bannerSaveYStart;
 	int xPos, yPos;
 	int rightLineColor, leftLineColor, bottomLineColor, topLineColor;
 	int normalTextColor, normalFillColor;
@@ -177,20 +176,20 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		startingPointY = _screenHeight / 2 - 10;
 		xPos = _screenWidth / 2 + roundedWidth + 3;
 		yPos = 1 - bannerMsgHeight;
-		bannerSaveYStart = startingPointY;
+		_bannerSaveYStart = startingPointY;
 	} else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformFMTowns) {
 		bannerMsgWidth = getGUIStringWidth(bannerMsg) / 2;
 		startingPointX = ((160 - bannerMsgWidth) - 8) & 0xFFF8;
 		startingPointY = (bannerMsgWidth + 168) | 0x7;
 		xPos = startingPointX + 1; // Bogus value, since it is unused
 		yPos = startingPointY + 1; // Bogus value, since it is unused
-		bannerSaveYStart = 78;
+		_bannerSaveYStart = 78;
 	} else {
 		startingPointX = 156 - roundedWidth;
 		startingPointY = ((_game.version < 7) ? 80 : _screenHeight / 2 - 10);
 		xPos = roundedWidth + 163 + ((_game.version < 7) ? 1 : 0);
 		yPos = 1 - bannerMsgHeight; // For the normal font this will end up as -12, for CJK modes it will be appropriately adjusted.
-		bannerSaveYStart = startingPointY - ((_game.version < 7) ? 2 : 0);
+		_bannerSaveYStart = startingPointY - ((_game.version < 7) ? 2 : 0);
 	}
 
 	// Save the pixels which will be overwritten by the banner,
@@ -204,26 +203,26 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
 			if (_game.platform == Common::kPlatformFMTowns && !_textSurfBannerMem) {
 				rowSize *= _textSurfaceMultiplier;
-				bannerSaveYStart *= _textSurfaceMultiplier;
+				_bannerSaveYStart *= _textSurfaceMultiplier;
 				_textSurfBannerMemSize = bannerMsgHeight * rowSize * _textSurfaceMultiplier;
 				_textSurfBannerMem = (byte *)malloc(_textSurfBannerMemSize * sizeof(byte));
 				if (_textSurfBannerMem) {
 					memcpy(
 						_textSurfBannerMem,
-						&((byte *)_textSurface.getBasePtr(0, _screenTop * _textSurfaceMultiplier))[rowSize * bannerSaveYStart],
+						&((byte *)_textSurface.getBasePtr(0, _screenTop * _textSurfaceMultiplier))[rowSize * _bannerSaveYStart],
 						_textSurfBannerMemSize);
 				}
 
 				// We're going to use these same values for saving the
 				// virtual screen surface, so let's un-multiply them...
 				rowSize /= _textSurfaceMultiplier;
-				bannerSaveYStart /= _textSurfaceMultiplier;
+				_bannerSaveYStart /= _textSurfaceMultiplier;
 			}
 #endif
 
 			memcpy(
 				_bannerMem,
-				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * bannerSaveYStart],
+				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * _bannerSaveYStart],
 				_bannerMemSize);
 		}
 	}
@@ -392,7 +391,9 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	char bannerMsg[512];
 	int bannerMsgWidth, bannerMsgHeight;
 	int startingPointY;
-	int bannerSaveYStart;
+	int boxColor;
+	int textXPos, textYPos;
+	bool isV3Towns = (_game.platform == Common::kPlatformFMTowns && _game.version == 3);
 
 	_messageBannerActive = true;
 
@@ -426,10 +427,33 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 		bannerMsgWidth = 100;
 
 	startingPointY = 80;
-	bannerSaveYStart = startingPointY - (_game.version == 4 ? 2 : _virtscr[kMainVirtScreen].topline);
+
+	boxColor = 0;
+	textXPos = _screenWidth / 2;
+	textYPos = startingPointY + 2;
+
+	if (isV3Towns) {
+		boxColor = 8;
+		textXPos = (320 - bannerMsgWidth) / 2;
+		textYPos = 2 + (_virtscr[kMainVirtScreen].h + _virtscr[kMainVirtScreen].topline - (bannerMsgHeight - 6)) / 2;
+
+		// Game specific corrections
+		if (_game.id == GID_INDY3)
+			textXPos += 8;
+		if (_game.id == GID_LOOM)
+			textYPos -= 8;
+
+		startingPointY = textYPos - 2;
+
+		if (_useCJKMode) {
+			textXPos -= _game.id == GID_INDY3 ? 34 : 8;
+		}
+	}
 
 	// Save the pixels which will be overwritten by the banner,
 	// so that we can restore them later...
+	_bannerSaveYStart = startingPointY - (_game.version == 4 ? 2 : _virtscr[kMainVirtScreen].topline);
+
 	if (!_bannerMem) {
 		int rowSize = _screenWidth + (_game.version == 4 ? 8 : 0);
 
@@ -437,20 +461,20 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
 		if (_game.platform == Common::kPlatformFMTowns && !_textSurfBannerMem) {
 			rowSize *= _textSurfaceMultiplier;
-			bannerSaveYStart *= _textSurfaceMultiplier;
-			_textSurfBannerMemSize = bannerMsgHeight * rowSize * _textSurfaceMultiplier;
+			startingPointY *= _textSurfaceMultiplier;
+			_textSurfBannerMemSize = (bannerMsgHeight + 2) * rowSize * _textSurfaceMultiplier;
 			_textSurfBannerMem = (byte *)malloc(_textSurfBannerMemSize * sizeof(byte));
 			if (_textSurfBannerMem) {
 				memcpy(
 					_textSurfBannerMem,
-					&((byte *)_textSurface.getBasePtr(0, _screenTop * _textSurfaceMultiplier))[rowSize * bannerSaveYStart],
+					&((byte *)_textSurface.getBasePtr(0, _screenTop * _textSurfaceMultiplier))[rowSize * startingPointY],
 					_textSurfBannerMemSize);
 			}
 
 			// We're going to use these same values for saving the
 			// virtual screen surface, so let's un-multiply them...
 			rowSize /= _textSurfaceMultiplier;
-			bannerSaveYStart /= _textSurfaceMultiplier;
+			startingPointY /= _textSurfaceMultiplier;
 		}
 #endif
 
@@ -459,36 +483,12 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 		if (_bannerMem) {
 			memcpy(
 				_bannerMem,
-				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * bannerSaveYStart],
+				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * startingPointY],
 				_bannerMemSize);
 		}
 	}
 
 	// Draw the GUI control
-	bool isV3Towns = (_game.platform == Common::kPlatformFMTowns && _game.version == 3);
-
-	int boxColor = 0;
-	int textXPos = _screenWidth / 2;
-	int textYPos = startingPointY + 2;
-
-	if (isV3Towns) {
-		boxColor = 8;
-		textXPos = (320 - bannerMsgWidth) / 2;
-		textYPos = 2 + (_virtscr[kMainVirtScreen].h + _virtscr[kMainVirtScreen].topline - (bannerMsgHeight - 6)) / 2;
-
-		// Game specific corrections
-		if (_game.id == GID_INDY3)
-			textXPos += 8;
-		if (_game.id == GID_LOOM)
-			textYPos -= 8;
-
-		startingPointY = textYPos - 2;
-
-		if (_useCJKMode) {
-			textXPos -= _game.id == GID_INDY3 ? 34 : 8;
-		}
-	}
-
 	drawBox(0, startingPointY, _screenWidth - 1, startingPointY + bannerMsgHeight, boxColor);
 	drawBox(0, startingPointY, _screenWidth - 1, startingPointY, color);
 	drawBox(0, startingPointY + bannerMsgHeight, _screenWidth - 1, startingPointY + bannerMsgHeight, color);
@@ -528,6 +528,8 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 }
 
 void ScummEngine::clearBanner() {
+	int startingPointY = _bannerSaveYStart;
+
 	// Restore the GFX content which was under the banner,
 	// and then mark that part of the screen as dirty.
 	if (_bannerMem) {
@@ -537,17 +539,6 @@ void ScummEngine::clearBanner() {
 		// will take care of that for us automatically when updating the
 		// screen for next frame.
 		if (!isSmushActive()) {
-			int startingPointY;
-			if (_game.version == 8) {
-				startingPointY = _screenHeight / 2 - 10;
-			} else if (_game.version < 4) {
-				startingPointY = 80;
-			} else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformFMTowns) {
-				startingPointY = 78;
-			} else {
-				startingPointY = ((_game.version < 7) ? 80 - 2 : _screenHeight / 2 - 10);
-			}
-			startingPointY -= (_game.version >= 4 ? 0 : _virtscr[kMainVirtScreen].topline);
 			// FM-Towns games draw the banners on the text surface, so restore both surfaces...
 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
 			if (_game.platform == Common::kPlatformFMTowns && _textSurfBannerMem) {
@@ -1310,10 +1301,11 @@ void ScummEngine::saveSurfacesPreGUI() {
 	// so the last line is being drawn on the verb surface; to address this, we
 	// save and restore that too.
 
-	if (_game.version < 3 || _game.version > 6)
+	if (_game.version < 3 || _game.version > 6 ||
+		(_game.version == 3 && _game.platform == Common::kPlatformFMTowns))
 		return;
 
-	_tempTextSurface = (byte *)malloc(_textSurface.pitch * _textSurface.h * _textSurfaceMultiplier * sizeof(byte));
+	_tempTextSurface = (byte *)malloc(_textSurface.pitch * _textSurface.h * sizeof(byte));
 	_tempMainSurface = (byte *)malloc(_virtscr[kMainVirtScreen].w * _virtscr[kMainVirtScreen].h * sizeof(byte));
 	_tempVerbSurface = (byte *)malloc(_virtscr[kVerbVirtScreen].w * _virtscr[kVerbVirtScreen].h * sizeof(byte));
 
@@ -1332,7 +1324,7 @@ void ScummEngine::saveSurfacesPreGUI() {
 	}
 
 	if (_tempTextSurface) {
-		memcpy(_tempTextSurface, _textSurface.getBasePtr(0, 0), _textSurface.pitch * _textSurface.h * _textSurfaceMultiplier);
+		memcpy(_tempTextSurface, _textSurface.getBasePtr(0, 0), _textSurface.pitch * _textSurface.h);
 
 		// For each v4-v6 game (except for LOOM VGA which does its own thing), we take the text surface
 		// and stamp it on top of the main screen: this is done to ensure that the GUI is drawn on top
@@ -1354,17 +1346,17 @@ void ScummEngine::saveSurfacesPreGUI() {
 
 void ScummEngine::restoreSurfacesPostGUI() {
 
-	if (_game.version < 3 || _game.version > 6)
+	if (_game.version < 3 || _game.version > 6 ||
+		(_game.version == 3 && _game.platform == Common::kPlatformFMTowns))
 		return;
 
 	if (_tempTextSurface) {
-		memcpy(_textSurface.getBasePtr(0, 0), _tempTextSurface, _textSurface.pitch * _textSurface.h * _textSurfaceMultiplier);
+		memcpy(_textSurface.getBasePtr(0, 0), _tempTextSurface, _textSurface.pitch * _textSurface.h);
 
 		// Signal the restoreCharsetBg() function that there's text
 		// on the text surface, so it gets deleted the next time another
 		// text is displayed...
-		if (!(_game.version == 3 && _game.platform == Common::kPlatformFMTowns) &&
-			!(_game.version == 4 && _game.id == GID_LOOM)) {
+		if (!(_game.version == 4 && _game.id == GID_LOOM)) {
 			_postGUICharMask = true;
 		}
 
@@ -1395,11 +1387,6 @@ void ScummEngine::restoreSurfacesPostGUI() {
 
 		_virtscr[kVerbVirtScreen].setDirtyRange(0, _virtscr[kVerbVirtScreen].h);
 	}
-
-	// Immediately redraw the screen for v3 FMTowns games, to avoid rendering
-	// a black frame after clearing the GUI element...
-	if (_game.version == 3 && _game.platform == Common::kPlatformFMTowns)
-		ScummEngine::drawDirtyScreenParts();
 }
 
 void ScummEngine::toggleVoiceMode() {
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 1d70791ebb0..bf2284dfd51 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -619,6 +619,8 @@ protected:
 	int32 _bannerColors[50]; // Colors for the original GUI
 	byte *_bannerMem = nullptr;
 	uint32 _bannerMemSize = 0;
+	int _bannerSaveYStart = 0;
+
 	bool _messageBannerActive = false;
 	bool _comiQuitMenuIsOpen = false;
 	bool _closeBannerAndQueryQuitFlag = false;


Commit: 89009fedcdd3aebd5791d01481fe6bec167da661
    https://github.com/scummvm/scummvm/commit/89009fedcdd3aebd5791d01481fe6bec167da661
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix graphical glitches and random distaff disappearances on LOOM v3

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index dccbfadcfd9..9359213d48d 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -403,9 +403,9 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	// Backup the text surface...
 	if (!_mainMenuIsActive) {
 		saveSurfacesPreGUI();
-		if (_charset->_textScreenID == kMainVirtScreen &&
-			!(_game.id == GID_LOOM && _game.platform == Common::kPlatformFMTowns))
+		if (_charset->_textScreenID == kMainVirtScreen && _game.id != GID_LOOM) {
 			restoreCharsetBg();
+		}
 	}
 
 	// Pause shake effect
@@ -1341,6 +1341,16 @@ void ScummEngine::saveSurfacesPreGUI() {
 				}
 			}
 		}
+
+		// A bit of trickery to prevent in-game texts to be positioned on top of the GUI banners:
+		// draw transparent lines on the text surface, over the area of the main virtual screen.
+		if (_game.id == GID_LOOM && _game.version == 3 && _game.platform != Common::kPlatformFMTowns) {
+			int yBegin = _virtscr[kMainVirtScreen].topline;
+			int yEnd = _virtscr[kMainVirtScreen].topline + _virtscr[kMainVirtScreen].h;
+			for (int y = yBegin; y < yEnd; y++) {
+				memset(_textSurface.getBasePtr(0, y), 0xFD, _virtscr[kMainVirtScreen].w);
+			}
+		}
 	}
 }
 
@@ -1355,8 +1365,9 @@ void ScummEngine::restoreSurfacesPostGUI() {
 
 		// Signal the restoreCharsetBg() function that there's text
 		// on the text surface, so it gets deleted the next time another
-		// text is displayed...
-		if (!(_game.version == 4 && _game.id == GID_LOOM)) {
+		// text is displayed. Just don't do that for LOOM, or it might
+		// randomly cause the distaff to disappear on rare occasions. :-)
+		if (_game.id != GID_LOOM) {
 			_postGUICharMask = true;
 		}
 


Commit: 3519891ca1ccd6bafcaad7fc51a340f5256944d9
    https://github.com/scummvm/scummvm/commit/3519891ca1ccd6bafcaad7fc51a340f5256944d9
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix regression on v3 Towns games

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 9359213d48d..380f40a5241 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -448,12 +448,14 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 		if (_useCJKMode) {
 			textXPos -= _game.id == GID_INDY3 ? 34 : 8;
 		}
+
+		_bannerSaveYStart = startingPointY;
+	} else {
+		_bannerSaveYStart = startingPointY - (_game.version == 4 ? 2 : _virtscr[kMainVirtScreen].topline);
 	}
 
 	// Save the pixels which will be overwritten by the banner,
 	// so that we can restore them later...
-	_bannerSaveYStart = startingPointY - (_game.version == 4 ? 2 : _virtscr[kMainVirtScreen].topline);
-
 	if (!_bannerMem) {
 		int rowSize = _screenWidth + (_game.version == 4 ? 8 : 0);
 


Commit: 617a52fc764e22d07d3d44d9a841f7df1ae78b63
    https://github.com/scummvm/scummvm/commit/617a52fc764e22d07d3d44d9a841f7df1ae78b63
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Flag Loom PC-Engine as unsupported

Changed paths:
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index f5e82c015e0..3270af73e74 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -3144,7 +3144,7 @@ bool ScummEngine::isUsingOriginalGUI() {
 	if (_game.id == GID_MONKEY2 && (_game.features & GF_DEMO))
 		return false;
 
-	if (_game.platform == Common::kPlatformNES)
+	if (_game.platform == Common::kPlatformNES || _game.platform == Common::kPlatformPCEngine)
 		return false;
 
 	if (_game.heversion != 0)


Commit: 3bc906427814e0edc1d9a8d9d1b02998ee91ea95
    https://github.com/scummvm/scummvm/commit/3bc906427814e0edc1d9a8d9d1b02998ee91ea95
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Make the restart prompt more consistent

Also make it work for v3 Towns games, which have their own mapping for the F keys

Changed paths:
    engines/scumm/dialogs.cpp
    engines/scumm/gfx_gui.cpp
    engines/scumm/input.cpp


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index e1fdd7809a1..968e1785280 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -84,7 +84,8 @@ static const ResString string_map_table_v8[] = {
 	{0, "/NEW.24/Music Volume  Low  =========  High"},
 	{0, "/NEW.25/Voice Volume  Low  =========  High"},
 	{0, "/NEW.26/Sfx Volume  Low  =========  High"},
-	{0, "Heap %dK"} // Non-translatable string
+	{0, "Heap %dK"}, // Non-translatable string
+	{0, "Are you sure you want to restart?  (Y-N)Y"} // Not in the original
 };
 
 static const ResString string_map_table_v7[] = {
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 380f40a5241..4a14252d0c3 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1001,7 +1001,7 @@ const char *ScummEngine_v8::getGUIString(int stringId) {
 		resStringId = 4;
 		break;
 	case gsRestart:
-		resStringId = 5;
+		resStringId = (_game.features & GF_DEMO) ? 36 : 5;
 		break;
 	case gsQuitPrompt:
 		resStringId = (_game.features & GF_DEMO) ? 30 : 22;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index affe76fdb77..7e56287d605 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -926,10 +926,20 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			return;
 		}
 
-		if ((VAR_RESTART_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_RESTART_KEY))) ||
-			(_game.version == 2 && (lastKeyHit.keycode == Common::KEYCODE_F8)) ||
-			((_game.id == GID_CMI && !(_game.features & GF_DEMO))
-				&& lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0))) {
+		bool restartKeyPressed = false;
+
+		// Restart if we've hit the restart key or if there is none but F8 is pressed...
+		restartKeyPressed |= ((VAR_RESTART_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_RESTART_KEY))));
+
+		// ...or if this is a pre v3 or post v6, force the restart prompt on F8...
+		restartKeyPressed |= ((_game.version < 3 || _game.version > 6) &&
+			lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0));
+
+		// ...or if this is a v3 FM-Towns game, restart on F8 (the original accepted a key value of 0xFFFF8008)
+		restartKeyPressed |= _game.platform == Common::kPlatformFMTowns && _game.version == 3 &&
+			lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0);
+
+		if (restartKeyPressed) {
 			queryRestart();
 			return;
 		}


Commit: f1a18f26e24386636ca914ed0d533f34f3994bd3
    https://github.com/scummvm/scummvm/commit/f1a18f26e24386636ca914ed0d533f34f3994bd3
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix regression on v4 games restart prompts

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 4a14252d0c3..0b277342edb 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1502,10 +1502,10 @@ void ScummEngine::queryRestart() {
 		Common::KeyState ks;
 		if (_game.version > 4) {
 			ks = showBannerAndPause(0, -1, msgLabelPtr);
-		} else if (_game.version == 3) {
-			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
-		} else {
+		} else if (_game.version < 3) {
 			ks = printMessageAndPause(msgLabelPtr, 4, -1, false);
+		} else {
+			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
 		}
 
 		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);


Commit: 3f96b8980b35f2bb3e66542a07f42e2da64b5033
    https://github.com/scummvm/scummvm/commit/3f96b8980b35f2bb3e66542a07f42e2da64b5033
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Implement a v3 table for hardcoded quit prompts

Changed paths:
    engines/scumm/dialogs.cpp


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 968e1785280..b706cf336c0 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -674,11 +674,20 @@ const ResString &InfoDialog::getStaticResString(Common::Language lang, int strin
 		{0, "TANDY Graphics"}
 	};
 
-	if (stringno + 1 >= ARRAYSIZE(strMap1)) {
-		stringno -= ARRAYSIZE(strMap1) - 1;
-		assert(stringno < ARRAYSIZE(strMap2));
-		return strMap2[stringno];
-	}
+	// V3 games (except LOOM) do not have a quit prompt message set in the scripts:
+	// we use this table to hardcode one for each language...
+	static const ResString hardcodedV3QuitPrompt[] = {
+		{0, "Are you sure you want to quit? (Y/N)Y"}, // EN
+		{0, "Etes vous s\x96r de vouloir quitter (O/N)O"}, // FR
+		{0, "Wollen Sie wirklich aufh\x94ren? (J/N)J"}, // DE
+		{0, "Sei sicuro di voler uscire? (S/N)S"}, // IT
+		{0, """\xc2\xa8""Est""\xc2\xa0""s seguro de querer abandonar? (S/N)S"}, // ES
+		{0, "(Y/N)Y"}, // RU - Placeholder: I don't know of any RU version of v3 games
+		{0, "(Y/N)Y"}, // SE - Placeholder: I don't know of any SE version of v3 games
+		{0, "\x96{\x93\x96\x82\xC9\x8FI\x97\xB9\x82\xB5\x82\xC4\x82\xE0\x82\xA2\x82\xA2\x82\xC5\x82\xB7\x82\xA9\x81H  (Y/N)Y"} // JA
+	};
+
+	bool useHardcodedV3QuitPrompt = stringno == 5 && _vm->_game.version == 3 && _vm->_game.id != GID_LOOM;
 
 	// I have added the langugages I found in scumm-md5.h for v1/2 games...
 	int langIndex = 0;
@@ -701,11 +710,24 @@ const ResString &InfoDialog::getStaticResString(Common::Language lang, int strin
 	case Common::SE_SWE:
 		langIndex = 6;
 		break;
+	case Common::JA_JPN:
+		langIndex = useHardcodedV3QuitPrompt ? 7 : 0;
+		break;
 	default:
 		// Just stick with English.
 		break;
 	}
 
+	if (useHardcodedV3QuitPrompt) {
+		return hardcodedV3QuitPrompt[langIndex];
+	}
+
+	if (stringno + 1 >= ARRAYSIZE(strMap1)) {
+		stringno -= ARRAYSIZE(strMap1) - 1;
+		assert(stringno < ARRAYSIZE(strMap2));
+		return strMap2[stringno];
+	}
+
 	// Special case for ZAK v2 ITA, which has a different string both for the pause
 	// message and for the restart message.
 	// If it can be verified that other languages have different strings for this game


Commit: 81cee05840d4d1e62e60042ae6483a6528dc7b79
    https://github.com/scummvm/scummvm/commit/81cee05840d4d1e62e60042ae6483a6528dc7b79
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: Fix missable termination condition on strings parsing

Changed paths:
    engines/scumm/charset.cpp
    engines/scumm/string.cpp


diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 15772daf5b2..b0089e8d7da 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -456,6 +456,7 @@ int CharsetRendererClassic::getCharWidth(uint16 chr) const {
 
 int CharsetRenderer::getStringWidth(int arg, const byte *text) {
 	int pos = 0;
+	bool isV3Towns = _vm->_game.version == 3 && _vm->_game.platform == Common::kPlatformFMTowns;
 
 	// I have confirmed from disasm that neither LOOM EGA and FM-TOWNS (EN/JP) nor any other games withing the
 	// v0-v3 version range add 1 to the width. There isn't even a getStringWidth method. And the v0-2 games don't
@@ -468,6 +469,12 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) {
 	int code = (_vm->_game.heversion >= 80) ? 127 : 64;
 
 	while ((chr = text[pos++]) != 0) {
+		// Given that the loop increments pos two times per loop in Towns games,
+		// we risk missing the termination character. Let's catch it and break the loop.
+		// This happens at least for the restart prompt message on INDY3 Towns JAP.
+		if (isV3Towns && pos > 1 && text[pos - 2] == 0)
+			break;
+
 		if (chr == '\n' || chr == '\r' || chr == _vm->_newLineCharacter)
 			break;
 
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index 6d04c9cacae..49085559dce 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -1038,6 +1038,7 @@ void ScummEngine::drawString(int a, const byte *msg) {
 	byte fontHeight = 0;
 	uint color;
 	int code = (_game.heversion >= 80) ? 127 : 64;
+	bool isV3Towns = _game.version == 3 && _game.platform == Common::kPlatformFMTowns;
 
 	// drawString is not used in SCUMM v7 and v8
 	assert(_game.version < 7);
@@ -1198,6 +1199,12 @@ void ScummEngine::drawString(int a, const byte *msg) {
 				if (is2ByteCharacter(_language, c))
 					c += buf[i++] * 256;
 			}
+
+			// With the code above, we risk missing the termination character.
+			// This happens at least for the restart prompt message on INDY3 Towns JAP.
+			if (isV3Towns && i > 1 && buf[i - 1] == 0)
+				break;
+
 			_charset->printChar(c, true);
 			_charset->_blitAlso = false;
 		}


Commit: 9900bbd616173c0ae765ab9fee1f7775a330049f
    https://github.com/scummvm/scummvm/commit/9900bbd616173c0ae765ab9fee1f7775a330049f
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Implement original save/load menus for v5 FM-Towns games

Changed paths:
    engines/scumm/gfx_gui.cpp
    engines/scumm/input.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 0b277342edb..4f7f3c7e8d7 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -227,14 +227,33 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		}
 	}
 
-	// Set up the GUI control, specifying all the related colors, the message and the position...
-	setUpInternalGUIControl(0, normalFillColor, normalTextColor,
-							topLineColor, bottomLineColor, leftLineColor, rightLineColor, 0, 0,
-							startingPointX, startingPointY, xPos, yPos,
-							bannerMsg, true, true);
-
-	// Draw it!
-	drawInternalGUIControl(0, 0);
+	if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformFMTowns) {
+		// MI1 for FMTowns does its own thing with hardcoded values here...
+		drawBox(startingPointX + 1, 81, startingPointY - 1, 90, normalFillColor);
+
+		drawLine(startingPointX + 1, 80, startingPointY - 1, 80, topLineColor);
+		drawLine(startingPointX + 1, 91, startingPointY - 1, 91, bottomLineColor);
+		drawLine(startingPointX, 81, startingPointX, 90, leftLineColor);
+		drawLine(startingPointY, 81, startingPointY, 90, rightLineColor);
+
+		int textXPos = 160;
+		int textYPos = 82;
+		int tmpRight = _string[5].right;
+		_string[5].right = _screenWidth - 1;
+
+		drawGUIText(bannerMsg, nullptr, textXPos, textYPos, normalTextColor, true);
+		_string[5].right = tmpRight;
+	} else {
+		// Set up the GUI control, specifying all the related colors, the message and the position...
+		setUpInternalGUIControl(0, normalFillColor, normalTextColor,
+								topLineColor, bottomLineColor, leftLineColor, rightLineColor, 0, 0,
+								startingPointX, startingPointY, xPos, yPos,
+								bannerMsg, true, true);
+
+		// Draw it!
+		drawInternalGUIControl(0, 0);
+	}
+
 	ScummEngine::drawDirtyScreenParts();
 
 	// Wait until the engine receives a new Keyboard or Mouse input,
@@ -495,7 +514,7 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	drawBox(0, startingPointY, _screenWidth - 1, startingPointY, color);
 	drawBox(0, startingPointY + bannerMsgHeight, _screenWidth - 1, startingPointY + bannerMsgHeight, color);
 
-	drawGUIText(bannerMsg, 0, textXPos, textYPos, color, !isV3Towns);
+	drawGUIText(bannerMsg, nullptr, textXPos, textYPos, color, !isV3Towns);
 
 	ScummEngine::drawDirtyScreenParts();
 
@@ -644,60 +663,50 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 
 		fillColor = highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor;
 
-		if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformFMTowns) {
-			// MI1 for FMTowns does its own thing with hardcoded values here...
-			drawBox(relCentX + 1, 81, relCentY - 1, 90, fillColor);
-
-			drawLine(relCentX + 1, 80, relCentY - 1, 80, ctrl->topLineColor);
-			drawLine(relCentX + 1, 91, relCentY - 1, 91, ctrl->bottomLineColor);
-			drawLine(relCentX, 81, relCentX, 90, ctrl->leftLineColor);
-			drawLine(relCentY, 81, relCentY, 90, ctrl->rightLineColor);
+		if (ctrl->doubleLinesFlag) {
+			// Draw the main box...
+			drawBox(relCentX + 1, relCentY + 1 + topComp, boxSizeX - offset, boxSizeY - offset + topComp, fillColor);
+
+			if (_game.version == 4 && _game.id != GID_LOOM) {
+				// This is for MI1 v4 (EGA and VGA floppy versions) and the Passport to Adventure demo;
+				// these games use a very early version of this GUI system, with only
+				// one line color; we will use the topLineColor to mimick that.
+
+				// Draw the contour lines...
+				drawBox(relCentX + 2, relCentY, x - 2, relCentY, ctrl->topLineColor);
+				drawBox(relCentX + 2, y, x - 2, y, ctrl->topLineColor);
+				drawBox(relCentX, relCentY + 2, relCentX, y - 2, ctrl->topLineColor);
+				drawBox(x, relCentY + 2, x, y - 2, ctrl->topLineColor);
+
+				// Draw single pixels for the button roundness effect...
+				drawBox(relCentX + 1, relCentY + 1, relCentX + 1, relCentY + 1, ctrl->topLineColor);
+				drawBox(x - 1, relCentY + 1, x - 1, relCentY + 1, ctrl->topLineColor);
+				drawBox(relCentX + 1, y - 1, relCentX + 1, y - 1, ctrl->topLineColor);
+				drawBox(x - 1, y - 1, x - 1, y - 1, ctrl->topLineColor);
+			} else {
+				// Draw the contour lines for the box; each of the lines is doubled to give a 3D effect.
+				drawLine(relCentX + 1, relCentY, x - 1, relCentY, ctrl->topLineColor);
+				drawLine(relCentX + 1, y, x - 1, y, ctrl->bottomLineColor);
+				drawLine(relCentX, relCentY + 1, relCentX, y - 1, ctrl->leftLineColor);
+				drawLine(x, relCentY + 1, x, y - 1, ctrl->rightLineColor);
+
+				drawLine(relCentX + 1, relCentY + 1, x - 1, relCentY + 1, ctrl->topLineColor);
+				drawLine(relCentX + 1, y - 1, x - 1, y - 1, ctrl->bottomLineColor);
+				drawLine(relCentX + 1, relCentY + 1, relCentX + 1, y - 1, ctrl->leftLineColor);
+				drawLine(x - 1, relCentY + 1, x - 1, y - 1, ctrl->rightLineColor);
+			}
 		} else {
-			if (ctrl->doubleLinesFlag) {
-				// Draw the main box...
-				drawBox(relCentX + 1, relCentY + 1 + topComp, boxSizeX - offset, boxSizeY - offset + topComp, fillColor);
-
-				if (_game.version == 4 && _game.id != GID_LOOM) {
-					// This is for MI1 v4 (EGA and VGA floppy versions) and the Passport to Adventure demo;
-					// these games use a very early version of this GUI system, with only
-					// one line color; we will use the topLineColor to mimick that.
-
-					// Draw the contour lines...
-					drawBox(relCentX + 2, relCentY, x - 2, relCentY, ctrl->topLineColor);
-					drawBox(relCentX + 2, y, x - 2, y, ctrl->topLineColor);
-					drawBox(relCentX, relCentY + 2, relCentX, y - 2, ctrl->topLineColor);
-					drawBox(x, relCentY + 2, x, y - 2, ctrl->topLineColor);
-
-					// Draw single pixels for the button roundness effect...
-					drawBox(relCentX + 1, relCentY + 1, relCentX + 1, relCentY + 1, ctrl->topLineColor);
-					drawBox(x - 1, relCentY + 1, x - 1, relCentY + 1, ctrl->topLineColor);
-					drawBox(relCentX + 1, y - 1, relCentX + 1, y - 1, ctrl->topLineColor);
-					drawBox(x - 1, y - 1, x - 1, y - 1, ctrl->topLineColor);
-				} else {
-					// Draw the contour lines for the box; each of the lines is doubled to give a 3D effect.
-					drawLine(relCentX + 1, relCentY, x - 1, relCentY, ctrl->topLineColor);
-					drawLine(relCentX + 1, y, x - 1, y, ctrl->bottomLineColor);
-					drawLine(relCentX, relCentY + 1, relCentX, y - 1, ctrl->leftLineColor);
-					drawLine(x, relCentY + 1, x, y - 1, ctrl->rightLineColor);
-
-					drawLine(relCentX + 1, relCentY + 1, x - 1, relCentY + 1, ctrl->topLineColor);
-					drawLine(relCentX + 1, y - 1, x - 1, y - 1, ctrl->bottomLineColor);
-					drawLine(relCentX + 1, relCentY + 1, relCentX + 1, y - 1, ctrl->leftLineColor);
-					drawLine(x - 1, relCentY + 1, x - 1, y - 1, ctrl->rightLineColor);
-				}
+			drawBox(relCentX, relCentY + topComp, x, y + topComp, (highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor));
+			if (_game.version == 4 && _game.id != GID_LOOM) {
+				drawBox(relCentX, relCentY, x, relCentY, ctrl->topLineColor);
+				drawBox(relCentX, y, x, y, ctrl->bottomLineColor);
+				drawBox(relCentX, relCentY, relCentX, y, ctrl->leftLineColor);
+				drawBox(x, relCentY, x, y, ctrl->rightLineColor);
 			} else {
-				drawBox(relCentX, relCentY + topComp, x, y + topComp, (highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor));
-				if (_game.version == 4 && _game.id != GID_LOOM) {
-					drawBox(relCentX, relCentY, x, relCentY, ctrl->topLineColor);
-					drawBox(relCentX, y, x, y, ctrl->bottomLineColor);
-					drawBox(relCentX, relCentY, relCentX, y, ctrl->leftLineColor);
-					drawBox(x, relCentY, x, y, ctrl->rightLineColor);
-				} else {
-					drawLine(relCentX, relCentY, x, relCentY, ctrl->topLineColor);
-					drawLine(relCentX, y, x, y, ctrl->bottomLineColor);
-					drawLine(relCentX, relCentY, relCentX, y, ctrl->leftLineColor);
-					drawLine(x, relCentY, x, y, ctrl->rightLineColor);
-				}
+				drawLine(relCentX, relCentY, x, relCentY, ctrl->topLineColor);
+				drawLine(relCentX, y, x, y, ctrl->bottomLineColor);
+				drawLine(relCentX, relCentY, relCentX, y, ctrl->leftLineColor);
+				drawLine(x, relCentY, x, y, ctrl->rightLineColor);
 			}
 		}
 
@@ -706,23 +715,18 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 		_charset->setCurID(1);
 
 		centerFlag = ctrl->centerText;
-		if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformFMTowns) {
-			// Again, MI1 for FMTowns hardcodes the values...
-			textXPos = 160;
-			textYPos = 82;
-		} else {
-			textHeight = getGUIStringHeight(ctrl->label.c_str());
 
-			if (centerFlag)
-				textXPos = relCentX + (x - ctrl->relativeCenterX) / 2;
-			else
-				textXPos = relCentX + 2;
+		textHeight = getGUIStringHeight(ctrl->label.c_str());
 
-			if (_game.version == 8 || _game.id == GID_DIG)
-				textYPos = relCentY + (y - relCentY - textHeight) / 2 + 1;
-			else
-				textYPos = relCentY + (y - 8 - relCentY + 2) / 2;
-		}
+		if (centerFlag)
+			textXPos = relCentX + (x - ctrl->relativeCenterX) / 2;
+		else
+			textXPos = relCentX + 2;
+
+		if (_game.version == 8 || _game.id == GID_DIG)
+			textYPos = relCentY + (y - relCentY - textHeight) / 2 + 1;
+		else
+			textYPos = relCentY + (y - 8 - relCentY + 2) / 2;
 
 		// Finally, choose the color and draw the text message
 		if (highlightColor)
@@ -757,7 +761,7 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 			// seem to (theoretically) be allowed to draw text wherever they want...
 			bool isSaveSlot = (id >= GUI_CTRL_FIRST_SG && id <= GUI_CTRL_LAST_SG);
 			Common::Rect clipRect(relCentX, relCentY, x, y);
-			drawGUIText(buttonString, isSaveSlot ? &clipRect : 0, textXPos, textYPos, textColor, centerFlag);
+			drawGUIText(buttonString, isSaveSlot ? &clipRect : nullptr, textXPos, textYPos, textColor, centerFlag);
 			_string[5].right = tmpRight;
 		}
 
@@ -1332,7 +1336,8 @@ void ScummEngine::saveSurfacesPreGUI() {
 		// and stamp it on top of the main screen: this is done to ensure that the GUI is drawn on top
 		// of possible subtitle texts instead of having the latters being deleted or being drawn on top
 		// of the GUI...
-		if (!(_game.version == 4 && _game.id == GID_LOOM)) {
+		if (!(_game.version == 4 && _game.id == GID_LOOM) &&
+			!(_game.version == 5 && _game.platform == Common::kPlatformFMTowns)) {
 			for (int y = 0; y < _screenHeight; y++) {
 				for (int x = 0; x < _screenWidth; x++) {
 					// Only draw non transparent pixels
@@ -1742,7 +1747,8 @@ void ScummEngine::showMainMenu() {
 
 		// V6 games should call for stopTalk() instead, but that's a bit too drastic;
 		// this ensures that we can at least hear the speech after the menu is closed.
-		if (_charset->_textScreenID == kMainVirtScreen && !(_game.version == 4 && _game.id == GID_LOOM))
+		if (_charset->_textScreenID == kMainVirtScreen && !(_game.version == 4 && _game.id == GID_LOOM) &&
+			!(_game.version == 5 && _game.platform == Common::kPlatformFMTowns))
 			restoreCharsetBg();
 	}
 
@@ -3053,7 +3059,7 @@ void ScummEngine::updateMainMenuControls() {
 		// not rendered in the other games, so adjust that...
 		if (_game.id == GID_FT) {
 			convertMessageToString((const byte *)getGUIString(gsSpooledMusic), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 19, textColor, false);
+			drawGUIText(msg, nullptr, 29, yCntr - calculatedHeight - yOffset + 19, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
 			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 33, textColor, false);
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 7e56287d605..08e59ff02e7 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -1075,7 +1075,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		}
 
 		if (VAR_MAINMENU_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_MAINMENU_KEY) && lastKeyHit.hasFlags(0))
-			&& _game.platform != Common::kPlatformFMTowns && _game.version > 3) {
+			&& _game.version > 3) {
 			showMainMenu();
 			return;
 		} else if (lastKeyHit.keycode == Common::KEYCODE_F5 && _game.version == 3 && _game.platform == Common::kPlatformMacintosh) {


Commit: a0613993d356acc9f8645e194722fc98a8eb1e7f
    https://github.com/scummvm/scummvm/commit/a0613993d356acc9f8645e194722fc98a8eb1e7f
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Substitute 0 with nullptr for pointer values

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 4f7f3c7e8d7..aed5c3236aa 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -3062,26 +3062,26 @@ void ScummEngine::updateMainMenuControls() {
 			drawGUIText(msg, nullptr, 29, yCntr - calculatedHeight - yOffset + 19, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 33, textColor, false);
+			drawGUIText(msg, nullptr, 29, yCntr - calculatedHeight - yOffset + 33, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 47, textColor, false);
+			drawGUIText(msg, nullptr, 29, yCntr - calculatedHeight - yOffset + 47, textColor, false);
 		} else {
 			convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 25, textColor, false);
+			drawGUIText(msg, nullptr, 29, yCntr - calculatedHeight - yOffset + 25, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 43, textColor, false);
+			drawGUIText(msg, nullptr, 29, yCntr - calculatedHeight - yOffset + 43, textColor, false);
 		}
 
 		convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 61, textColor, false);
+		drawGUIText(msg, nullptr, 29, yCntr - calculatedHeight - yOffset + 61, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 88, textColor, false);
+		drawGUIText(msg, nullptr, 29, yCntr - calculatedHeight - yOffset + 88, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 102, textColor, false);
+		drawGUIText(msg, nullptr, 29, yCntr - calculatedHeight - yOffset + 102, textColor, false);
 
 		drawLine(23, yCntr - calculatedHeight - yOffset + 77, 204, yCntr - calculatedHeight - yOffset + 77, getBannerColor(17));
 		drawLine(23, yCntr - calculatedHeight - yOffset + 78, 204, yCntr - calculatedHeight - yOffset + 78, getBannerColor(4));
@@ -3094,19 +3094,19 @@ void ScummEngine::updateMainMenuControls() {
 		// drawLine(24, yCntr - calculatedHeight + 81, 204, yCntr - calculatedHeight + 81, getBannerColor(4));
 	} else {
 		convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 33, yConstantV6 - 36, textColor, false);
+		drawGUIText(msg, nullptr, 33, yConstantV6 - 36, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 33, yConstantV6 - 22, textColor, false);
+		drawGUIText(msg, nullptr, 33, yConstantV6 - 22, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 33, yConstantV6 - 8, textColor, false);
+		drawGUIText(msg, nullptr, 33, yConstantV6 - 8, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 33, yConstantV6 + 19, textColor, false);
+		drawGUIText(msg, nullptr, 33, yConstantV6 + 19, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 33, yConstantV6 + 34, textColor, false);
+		drawGUIText(msg, nullptr, 33, yConstantV6 + 34, textColor, false);
 
 		drawLine(27, yConstantV6 + 8,  201, yConstantV6 + 8,  getBannerColor(17));
 		drawLine(27, yConstantV6 + 9,  201, yConstantV6 + 9,  getBannerColor(4));
@@ -3150,25 +3150,25 @@ void ScummEngine::drawMainMenuTitle(const char *title) {
 			yCntr - calculatedHeight + _screenTop - yOffset + 3 + lh,
 			boxColor);
 
-		drawGUIText(title, 0,
+		drawGUIText(title, nullptr,
 			159,
 			yCntr - calculatedHeight - yOffset + 4,
 			stringColor,
 			true);
 	} else if (_game.version == 7) {
 		drawBox(18, _screenTop + 44, 301, _screenTop + 52, boxColor);
-		drawGUIText(title, 0, 159, 44, stringColor, true);
+		drawGUIText(title, nullptr, 159, 44, stringColor, true);
 	} else if (_game.version == 4) {
 		if (_game.id == GID_LOOM) {
 			drawBox(22, yConstantV6 - 57, 298, yConstantV6 - 49, boxColor);
-			drawGUIText(title, 0, 160, yConstantV6 - 57, stringColor, true);
+			drawGUIText(title, nullptr, 160, yConstantV6 - 57, stringColor, true);
 		} else {
 			drawBox(21, yConstantV6 - 55, 299, yConstantV6 - 47, boxColor);
-			drawGUIText(title, 0, 160, yConstantV6 - 55, stringColor, true);
+			drawGUIText(title, nullptr, 160, yConstantV6 - 55, stringColor, true);
 		}
 	} else {
 		drawBox(22, yConstantV6 - 56, 298, yConstantV6 - 48, boxColor);
-		drawGUIText(title, 0, 160, yConstantV6 - 56, stringColor, true);
+		drawGUIText(title, nullptr, 160, yConstantV6 - 56, stringColor, true);
 	}
 
 	ScummEngine::drawDirtyScreenParts();


Commit: 2c36f10932b86f59b1c6e1fb91799ac25d031e72
    https://github.com/scummvm/scummvm/commit/2c36f10932b86f59b1c6e1fb91799ac25d031e72
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Cleanup

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index aed5c3236aa..3741c4d29f0 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -236,12 +236,10 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		drawLine(startingPointX, 81, startingPointX, 90, leftLineColor);
 		drawLine(startingPointY, 81, startingPointY, 90, rightLineColor);
 
-		int textXPos = 160;
-		int textYPos = 82;
 		int tmpRight = _string[5].right;
 		_string[5].right = _screenWidth - 1;
 
-		drawGUIText(bannerMsg, nullptr, textXPos, textYPos, normalTextColor, true);
+		drawGUIText(bannerMsg, nullptr, 160, 82, normalTextColor, true);
 		_string[5].right = tmpRight;
 	} else {
 		// Set up the GUI control, specifying all the related colors, the message and the position...


Commit: e93f6d2b838dd274820c91c7dd33440c0ddb2884
    https://github.com/scummvm/scummvm/commit/e93f6d2b838dd274820c91c7dd33440c0ddb2884
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Fix v5 FM-Towns menu box title

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 3741c4d29f0..24f5884b7d2 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1754,7 +1754,7 @@ void ScummEngine::showMainMenu() {
 	setUpMainMenuControls();
 	drawMainMenuControls();
 
-	if (_game.platform == Common::kPlatformAmiga) {
+	if (_game.platform == Common::kPlatformAmiga || _game.platform == Common::kPlatformFMTowns) {
 		convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 		drawMainMenuTitle(saveScreenTitle);
 	} else if (_game.version > 4 && _game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
@@ -2100,7 +2100,7 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool
 		setUpMainMenuControls();
 		drawMainMenuControls();
 
-		if (_game.platform == Common::kPlatformAmiga) {
+		if (_game.platform == Common::kPlatformAmiga || _game.platform == Common::kPlatformFMTowns) {
 			convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 			drawMainMenuTitle(saveScreenTitle);
 		} else if (_game.version > 4 && _game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
@@ -2943,7 +2943,8 @@ void ScummEngine::drawMainMenuControls() {
 			drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button
 		}
 
-		if ((VAR_FIXEDDISK != 0xFF && VAR(VAR_FIXEDDISK) == 0) || _game.platform == Common::kPlatformAmiga) {
+		if ((VAR_FIXEDDISK != 0xFF && VAR(VAR_FIXEDDISK) == 0) ||
+			_game.platform == Common::kPlatformAmiga || _game.platform == Common::kPlatformFMTowns) {
 			convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)insertDisk, sizeof(insertDisk));
 			drawMainMenuTitle(insertDisk);
 		}


Commit: ab5010e04b1d0e508fbda6430a019281a9f2148f
    https://github.com/scummvm/scummvm/commit/ab5010e04b1d0e508fbda6430a019281a9f2148f
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Remove menu inner box on v5 FM-Towns games

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 24f5884b7d2..e4d4e0439d9 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -2933,11 +2933,14 @@ void ScummEngine::drawMainMenuControls() {
 
 		if (_game.version > 4 &&
 			_game.id != GID_MONKEY2 && _game.id != GID_MONKEY &&
-			_game.platform != Common::kPlatformAmiga)
+			_game.platform != Common::kPlatformAmiga &&
+			_game.platform != Common::kPlatformFMTowns)
 			drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0); // Inner box
 
 		if ((_game.version == 5 &&
-			(_game.id != GID_MONKEY2 && _game.id != GID_MONKEY && _game.platform != Common::kPlatformAmiga)) ||
+			(_game.id != GID_MONKEY2 && _game.id != GID_MONKEY &&
+			_game.platform != Common::kPlatformAmiga &&
+			_game.platform != Common::kPlatformFMTowns)) ||
 			_game.version == 6) {
 			drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);   // Arrow up button
 			drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button


Commit: 26cc83566d6246dfdb1d7a2c630f0283f97ddd62
    https://github.com/scummvm/scummvm/commit/26cc83566d6246dfdb1d7a2c630f0283f97ddd62
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: GUI: Add Amiga snail cursor for v2 games

Changed paths:
    engines/scumm/cursor.cpp


diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index 9652ef273ca..543408d0c57 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -117,6 +117,25 @@ static const byte c64_dos_snail_cursor[] = {
 	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
 };
 
+static const byte amiga_snail_cursor[] = {
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x00,0xFF,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x06,0x06,0x00,0x06,0x00,0x00,0x06,0x06,0x00,0xFF,
+	0xFF,0xFF,0x0F,0xFF,0x00,0x06,0x06,0x00,0x06,0x06,0x06,0x06,0x00,0x06,0x06,0x00,
+	0x0F,0xFF,0xFF,0x0F,0x00,0x06,0x00,0x06,0x06,0x00,0x00,0x06,0x06,0x00,0x06,0x00,
+	0xFF,0x0F,0xFF,0x0F,0x00,0x06,0x00,0x06,0x06,0x06,0x06,0x00,0x06,0x00,0x06,0x00,
+	0xFF,0x0F,0xFF,0x0F,0x00,0x06,0x00,0x06,0x00,0x06,0x06,0x00,0x06,0x00,0x06,0x00,
+	0xFF,0x0F,0xFF,0x0F,0x00,0x06,0x06,0x06,0x00,0x06,0x00,0x06,0x06,0x06,0x06,0x00,
+	0xFF,0x0F,0x0F,0x0F,0x00,0x06,0x00,0x06,0x06,0x06,0x06,0x06,0x00,0x06,0x06,0x00,
+	0x0F,0x06,0x0F,0x0F,0x00,0x06,0x06,0x00,0x06,0x00,0x00,0x00,0x06,0x06,0x00,0xFF,
+	0x0F,0x0F,0x0F,0x0F,0x00,0x06,0x06,0x00,0x06,0x06,0x06,0x06,0x06,0x00,0xFF,0xFF,
+	0xFF,0xFF,0x0F,0x0F,0x0F,0x00,0x06,0x06,0x00,0x00,0x06,0x00,0x06,0x06,0x00,0xFF,
+	0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x00,0x00,0xFF,
+	0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0xFF,
+	0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+};
+
 #ifdef ENABLE_SCUMM_7_8
 static const byte default_v7_cursor[] = {
 	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
@@ -836,19 +855,30 @@ void ScummEngine_v2::setBuiltinCursor(int idx) {
 }
 
 void ScummEngine_v2::setSnailCursor() {
-	memcpy(_grabbedCursor, c64_dos_snail_cursor, sizeof(c64_dos_snail_cursor));
 
-	if (_game.version == 0) {
-		for (int i = 0; i < sizeof(c64_dos_snail_cursor); i++) {
-			if (_grabbedCursor[i] == 0x0F)
-				_grabbedCursor[i] = 0x01;
+	if (_game.platform == Common::kPlatformAmiga) {
+		memcpy(_grabbedCursor, amiga_snail_cursor, sizeof(amiga_snail_cursor));
+
+		_cursor.width = 16;
+		_cursor.height = 16;
+		_cursor.hotspotX = 7;
+		_cursor.hotspotY = 7;
+
+	} else {
+		memcpy(_grabbedCursor, c64_dos_snail_cursor, sizeof(c64_dos_snail_cursor));
+
+		if (_game.version == 0) {
+			for (int i = 0; i < sizeof(c64_dos_snail_cursor); i++) {
+				if (_grabbedCursor[i] == 0x0F)
+					_grabbedCursor[i] = 0x01;
+			}
 		}
-	}
 
-	_cursor.width = 24;
-	_cursor.height = 21;
-	_cursor.hotspotX = 11;
-	_cursor.hotspotY = 10;
+		_cursor.width = 24;
+		_cursor.height = 21;
+		_cursor.hotspotX = 11;
+		_cursor.hotspotY = 10;
+	}
 
 	updateCursor();
 }


Commit: 7a007db0f8200250d98dbc3e4ac7d16932d97fda
    https://github.com/scummvm/scummvm/commit/7a007db0f8200250d98dbc3e4ac7d16932d97fda
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: Fix warning

Changed paths:
    engines/scumm/cursor.cpp


diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index 543408d0c57..37043ce07b3 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -868,7 +868,7 @@ void ScummEngine_v2::setSnailCursor() {
 		memcpy(_grabbedCursor, c64_dos_snail_cursor, sizeof(c64_dos_snail_cursor));
 
 		if (_game.version == 0) {
-			for (int i = 0; i < sizeof(c64_dos_snail_cursor); i++) {
+			for (uint i = 0; i < sizeof(c64_dos_snail_cursor); i++) {
 				if (_grabbedCursor[i] == 0x0F)
 					_grabbedCursor[i] = 0x01;
 			}


Commit: 9fee7adf526e8d5078bdd231aee9a8e42d1fb20a
    https://github.com/scummvm/scummvm/commit/9fee7adf526e8d5078bdd231aee9a8e42d1fb20a
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: Explicitly remove support for original GUI to ST v2 games

Changed paths:
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 3270af73e74..f91f8eb1ace 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -3144,7 +3144,9 @@ bool ScummEngine::isUsingOriginalGUI() {
 	if (_game.id == GID_MONKEY2 && (_game.features & GF_DEMO))
 		return false;
 
-	if (_game.platform == Common::kPlatformNES || _game.platform == Common::kPlatformPCEngine)
+	if (_game.platform == Common::kPlatformNES ||
+		_game.platform == Common::kPlatformPCEngine ||
+		(_game.platform == Common::kPlatformAtariST && _game.version == 2))
 		return false;
 
 	if (_game.heversion != 0)


Commit: 1d206fbc53c8580d17bb42824f95534267058194
    https://github.com/scummvm/scummvm/commit/1d206fbc53c8580d17bb42824f95534267058194
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: v0-1-2-3: Implement actual saving\loading system

This commit implements saving and loading in the same way the original interpreters
for MANIAC v0-1-2, ZAK v1-2-3, LOOM v3 and INDY v3 do. This makes it possible to
use the original save menus without glitches or crashes.

Saves done from GMM can also be loaded from the original menu.

Changed paths:
    engines/scumm/input.cpp
    engines/scumm/saveload.cpp
    engines/scumm/script_v4.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm_v3.h
    engines/scumm/scumm_v4.h


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 08e59ff02e7..70c5079cc5b 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -42,6 +42,7 @@
 #include "scumm/dialogs.h"
 
 #include "graphics/cursorman.h"
+#include "graphics/thumbnail.h"
 
 namespace Scumm {
 
@@ -797,10 +798,10 @@ void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) {
 void ScummEngine_v2::processKeyboard(Common::KeyState lastKeyHit) {
 	if (isUsingOriginalGUI()) {
 		if (lastKeyHit.keycode == Common::KEYCODE_F5) {
-			prepareSavegame();
 			if (_game.id == GID_MANIAC && _game.version == 0) {
 				runScript(2, 0, 0, nullptr);
 			}
+
 			if (_game.id == GID_MANIAC && _game.platform == Common::kPlatformNES) {
 				runScript(163, 0, 0, nullptr);
 			}
@@ -835,16 +836,10 @@ void ScummEngine_v2::processKeyboard(Common::KeyState lastKeyHit) {
 	// Fall back to default behavior
 	ScummEngine::processKeyboard(lastKeyHit);
 
-	// On Alt-F5 prepare savegame for the original save/load dialog.
-	if (!isUsingOriginalGUI()) {
-		if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(Common::KBD_ALT)) {
-			prepareSavegame();
-			if (_game.id == GID_MANIAC && _game.version == 0) {
-				runScript(2, 0, 0, nullptr);
-			}
-			if (_game.id == GID_MANIAC && _game.platform == Common::kPlatformNES) {
-				runScript(163, 0, 0, nullptr);
-			}
+	// On Alt-F5 load the original save/load dialog for MANIAC NES
+	if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(Common::KBD_ALT)) {
+		if (_game.id == GID_MANIAC && _game.platform == Common::kPlatformNES) {
+			runScript(163, 0, 0, nullptr);
 		}
 	}
 
@@ -859,21 +854,10 @@ void ScummEngine_v2::processKeyboard(Common::KeyState lastKeyHit) {
 }
 
 void ScummEngine_v3::processKeyboard(Common::KeyState lastKeyHit) {
-	if (isUsingOriginalGUI()) {
-		if (lastKeyHit.keycode == Common::KEYCODE_F5) {
-			prepareSavegame();
-		}
-	}
-
 	// Fall back to default behavior
 	ScummEngine::processKeyboard(lastKeyHit);
 
 	if (!isUsingOriginalGUI()) {
-		// On Alt-F5 prepare savegame for the original save/load dialog.
-		if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(Common::KBD_ALT)) {
-			prepareSavegame();
-		}
-
 		// 'i' brings up an IQ dialog in Indy3 (disabled in save/load dialog for input)
 		if (lastKeyHit.ascii == 'i' && _game.id == GID_INDY3 && _currentRoom != 14) {
 			// SCUMM var 244 is the episode score
@@ -904,6 +888,12 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		restartKeyEnabled = true;
 
 	if (isUsingOriginalGUI()) {
+
+		if (lastKeyHit.keycode == Common::KEYCODE_F5 && _game.version <= 3) {
+			_savegameThumbnail.free();
+			Graphics::createThumbnail(_savegameThumbnail);
+		}
+
 		char sliderString[256];
 		PauseToken pt;
 
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 8bcb6773399..e6e38bce689 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -101,6 +101,17 @@ bool ScummEngine::canLoadGameStateCurrently() {
 
 	bool isOriginalMenuActive = isUsingOriginalGUI() && _mainMenuIsActive;
 
+	if (_game.version <= 3) {
+		int saveRoom = 50;
+
+		if (_game.id == GID_INDY3)
+			saveRoom = 14;
+		else if (_game.id == GID_LOOM)
+			saveRoom = 70;
+
+		isOriginalMenuActive = _currentRoom == saveRoom;
+	}
+
 	return (VAR_MAINMENU_KEY == 0xFF || VAR(VAR_MAINMENU_KEY) != 0) && !isOriginalMenuActive;
 }
 
@@ -148,6 +159,17 @@ bool ScummEngine::canSaveGameStateCurrently() {
 
 	bool isOriginalMenuActive = isUsingOriginalGUI() && _mainMenuIsActive;
 
+	if (_game.version <= 3) {
+		int saveRoom = 50;
+
+		if (_game.id == GID_INDY3)
+			saveRoom = 14;
+		else if (_game.id == GID_LOOM)
+			saveRoom = 70;
+
+		isOriginalMenuActive = _currentRoom == saveRoom;
+	}
+
 	// SCUMM v4+ doesn't allow saving in room 0 or if
 	// VAR(VAR_MAINMENU_KEY) to set to zero.
 	return (VAR_MAINMENU_KEY == 0xFF || (VAR(VAR_MAINMENU_KEY) != 0 && _currentRoom != 0)) && !isOriginalMenuActive;
@@ -541,91 +563,6 @@ bool ScummEngine::saveState(int slot, bool compat, Common::String &filename) {
 	return !saveFailed;
 }
 
-
-void ScummEngine_v4::prepareSavegame() {
-	Common::MemoryWriteStreamDynamic *memStream;
-	Common::WriteStream *writeStream;
-
-	// free memory of the last prepared savegame
-	delete _savePreparedSavegame;
-	_savePreparedSavegame = nullptr;
-
-	// store headerless savegame in a compressed memory stream
-	memStream = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::NO);
-	writeStream = Common::wrapCompressedWriteStream(memStream);
-	if (saveState(writeStream, false)) {
-		// we have to finalize the compression-stream first, otherwise the internal
-		// memory-stream pointer will be zero (Important: flush() does not work here!).
-		writeStream->finalize();
-		if (!writeStream->err()) {
-			// wrap uncompressing MemoryReadStream around the savegame data
-			_savePreparedSavegame = Common::wrapCompressedReadStream(
-				new Common::MemoryReadStream(memStream->getData(), memStream->size(), DisposeAfterUse::YES));
-		}
-	}
-	// free the CompressedWriteStream and MemoryWriteStreamDynamic
-	// but not the memory stream's internal buffer
-	delete writeStream;
-}
-
-bool ScummEngine_v4::savePreparedSavegame(int slot, char *desc) {
-	bool success;
-	Common::String filename;
-	Common::OutSaveFile *out;
-	SaveGameHeader hdr;
-	uint32 nread, nwritten;
-
-	out = nullptr;
-	success = true;
-
-	// check if savegame was successfully stored in memory
-	if (!_savePreparedSavegame)
-		success = false;
-
-	// open savegame file
-	if (success) {
-		filename = makeSavegameName(slot, false);
-		if (!(out = _saveFileMan->openForSaving(filename))) {
-			success = false;
-		}
-	}
-
-	// write header to file
-	if (success) {
-		memset(hdr.name, 0, sizeof(hdr.name));
-		strncpy(hdr.name, desc, sizeof(hdr.name)-1);
-		success = saveSaveGameHeader(out, hdr);
-	}
-
-	// copy savegame from memory-stream to file
-	if (success) {
-		_savePreparedSavegame->seek(0, SEEK_SET);
-		byte buffer[1024];
-		while ((nread = _savePreparedSavegame->read(buffer, sizeof(buffer)))) {
-			nwritten = out->write(buffer, nread);
-			if (nwritten < nread) {
-				success = false;
-				break;
-			}
-		}
-	}
-
-	if (out) {
-		out->finalize();
-		if (out->err())
-			success = false;
-		delete out;
-	}
-
-	if (!success) {
-		debug(1, "State save as '%s' FAILED", filename.c_str());
-		return false;
-	} else {
-		debug(1, "State saved as '%s'", filename.c_str());
-		return true;
-	}
-}
-
 bool ScummEngine::loadState(int slot, bool compat) {
 	// Wrapper around the other variant
 	Common::String filename;
diff --git a/engines/scumm/script_v4.cpp b/engines/scumm/script_v4.cpp
index 07e74906425..3729d96c017 100644
--- a/engines/scumm/script_v4.cpp
+++ b/engines/scumm/script_v4.cpp
@@ -368,6 +368,16 @@ void ScummEngine_v4::o4_saveLoadGame() {
 	byte slot;
 	byte a = getVarOrDirectByte(PARAM_1);
 	byte result = 0;
+	Common::String dummyName;
+
+	int saveRoom = 50;
+
+	if (_game.id == GID_INDY3)
+		saveRoom = 14;
+	else if (_game.id == GID_LOOM)
+		saveRoom = 70;
+
+	_mainMenuIsActive = true;
 
 	if ((_game.id == GID_MANIAC && _game.version <= 1) || (_game.id == GID_ZAK && _game.platform == Common::kPlatformC64)) {
 		// Convert V0/V1 load/save screen (they support only one savegame per disk)
@@ -393,51 +403,66 @@ void ScummEngine_v4::o4_saveLoadGame() {
 	}
 
 	switch (_opcode) {
-	case 0x00: // num slots available
+	case 0x00: // Num slots available
 		result = 100;
 		break;
-	case 0x20: // drive
+	case 0x20: // Drive
 		if (_game.version <= 3) {
 			// 0 = ???
-			// [1,2] = disk drive [A:,B:]
-			// 3 = hard drive
+			// [1,2] = Disk drive [A:,B:]
+			// 3 = Hard drive
 			result = 3;
 		} else {
-			// set current drive
+			// Set current drive
 			result = 1;
 		}
 		break;
 	case 0x40: // load
 		_lastLoadedRoom = -1;
 		if (loadState(slot, false))
-			result = 3; // sucess
+			result = 3; // Success
 		else
-			result = 5; // failed to load
+			result = 5; // Failed to load
+
+		// If the loaded state loads a different room from the save menu room
+		// it means that we are loading a game saved from the GMM. To correctly
+		// handle this, we run the boot script, we reload the state, and then signal
+		// the ScummEngine_v3::scummLoop_handleSaveLoad() function that we need to
+		// perform the post load fixes.
+		if (result == 3 && _currentRoom != saveRoom) {
+			_loadFromLauncher = true;
+			runBootscript();
+			loadState(slot, false);
+			_mainMenuIsActive = false;
+			return;
+		}
+
 		break;
-	case 0x80: // save
+	case 0x80: // Save
 		_lastLoadedRoom = -1;
 		if (_game.version <= 3) {
 			char name[32];
 			if (_game.version <= 2) {
-				// use generic name
-				Common::sprintf_s(name, "Game %c", 'A'+slot-1);
+				// V2 and below use a hardcoded name for savestates
+				Common::sprintf_s(name, "Game %c", 'A' + slot - 1);
 			} else {
-				// use name entered by the user
+				// Use the name entered by the user...
 				char* ptr;
 				int firstSlot = (_game.id == GID_LOOM) ? STRINGID_SAVENAME1_LOOM : STRINGID_SAVENAME1;
 				ptr = (char *)getStringAddress(slot + firstSlot - 1);
 				Common::strlcpy(name, ptr, sizeof(name));
 			}
 
-			if (savePreparedSavegame(slot, name))
+			Common::strlcpy((char *)_saveLoadDescription.c_str(), name, sizeof(_saveLoadDescription));
+			if (saveState(slot, false, dummyName))
 				result = 0;
 			else
 				result = 2;
 		} else {
-			result = 2; // failed to save
+			result = 2; // Failed to save
 		}
 		break;
-	case 0xC0: // test if save exists
+	case 0xC0: // Test if the save file exists
 		{
 		Common::InSaveFile *file;
 		bool avail_saves[100];
@@ -445,17 +470,24 @@ void ScummEngine_v4::o4_saveLoadGame() {
 		listSavegames(avail_saves, ARRAYSIZE(avail_saves));
 		Common::String filename = makeSavegameName(slot, false);
 		if (avail_saves[slot] && (file = _saveFileMan->openForLoading(filename))) {
-			result = 6; // save file exists
+			result = 6; // Save file exists
 			delete file;
 		} else
-			result = 7; // save file does not exist
+			result = 7; // Save file does not exist
 		}
 		break;
 	default:
 		error("o4_saveLoadGame: unknown subopcode %d", _opcode);
 	}
 
+	_mainMenuIsActive = false;
+
 	setResult(result);
+
+	// Did the script move? Update its state!
+	updateScriptPtr();
+	getScriptBaseAddress();
+	resetScriptPointer();
 }
 
 } // End of namespace Scumm
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index f91f8eb1ace..cff5102c24f 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -483,12 +483,6 @@ ScummEngine_v3::ScummEngine_v3(OSystem *syst, const DetectorResult &dr)
 	// All v3 and older games only used 16 colors with exception of the GF_OLD256 games.
 	if (!(_game.features & GF_OLD256))
 		_game.features |= GF_16COLOR;
-
-	_savePreparedSavegame = nullptr;
-}
-
-ScummEngine_v3::~ScummEngine_v3() {
-	delete _savePreparedSavegame;
 }
 
 ScummEngine_v3old::ScummEngine_v3old(OSystem *syst, const DetectorResult &dr)
@@ -1748,7 +1742,6 @@ void ScummEngine_v2::resetScumm() {
 void ScummEngine_v3::resetScumm() {
 	ScummEngine_v4::resetScumm();
 
-
 	if (_game.id == GID_LOOM && _game.platform == Common::kPlatformPCEngine) {
 		// Load tile set and palette for the distaff
 		byte *roomptr = getResourceAddress(rtRoom, 90);
@@ -1760,9 +1753,6 @@ void ScummEngine_v3::resetScumm() {
 		_gdi->loadTiles(roomptr);
 		_gdi->_distaff = false;
 	}
-
-	delete _savePreparedSavegame;
-	_savePreparedSavegame = nullptr;
 }
 
 void ScummEngine_v4::resetScumm() {
@@ -2724,6 +2714,9 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 }
 
 void ScummEngine_v3::scummLoop_handleSaveLoad() {
+	if (isUsingOriginalGUI() && _saveLoadFlag == 0 && !_loadFromLauncher)
+		return;
+
 	bool processIQPoints = (_game.id == GID_INDY3 && (_saveLoadFlag == 2 || _loadFromLauncher));
 	_loadFromLauncher = false;
 
diff --git a/engines/scumm/scumm_v3.h b/engines/scumm/scumm_v3.h
index c79f4a3a2da..d6a32450ca9 100644
--- a/engines/scumm/scumm_v3.h
+++ b/engines/scumm/scumm_v3.h
@@ -32,7 +32,6 @@ namespace Scumm {
 class ScummEngine_v3 : public ScummEngine_v4 {
 public:
 	ScummEngine_v3(OSystem *syst, const DetectorResult &dr);
-	~ScummEngine_v3() override;
 
 	void resetScumm() override;
 
diff --git a/engines/scumm/scumm_v4.h b/engines/scumm/scumm_v4.h
index b7b07e3d594..2ca7a8aa645 100644
--- a/engines/scumm/scumm_v4.h
+++ b/engines/scumm/scumm_v4.h
@@ -31,19 +31,6 @@ namespace Scumm {
  */
 class ScummEngine_v4 : public ScummEngine_v5 {
 	friend class ScummEngine_v5;
-public:
-
-	/**
-	 * Prepared savegame used by the original save/load dialog.
-	 * Must be valid as long as the savescreen is active. As we are not
-	 * notified when the savescreen is closed, memory is only freed on a game
-	 * reset, at the destruction of the engine or when the original save/load
-	 * dialog is entered the next time.
-	 */
-	Common::SeekableReadStream *_savePreparedSavegame;
-
-	void prepareSavegame();
-	bool savePreparedSavegame(int slot, char *desc);
 
 public:
 	ScummEngine_v4(OSystem *syst, const DetectorResult &dr);


Commit: 918b7f95f1872b28b2e508de72e0593d7a0afb0b
    https://github.com/scummvm/scummvm/commit/918b7f95f1872b28b2e508de72e0593d7a0afb0b
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: v3: Fix minor graphical glitch on game quit

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index e4d4e0439d9..c2916f8df55 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -502,7 +502,7 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 		if (_bannerMem) {
 			memcpy(
 				_bannerMem,
-				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * startingPointY],
+				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * _bannerSaveYStart],
 				_bannerMemSize);
 		}
 	}


Commit: 939a9bba39fdeeda4e2fa1f85048564471f5e071
    https://github.com/scummvm/scummvm/commit/939a9bba39fdeeda4e2fa1f85048564471f5e071
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: LOOM (Towns): Implement original save menu quirk with slot 0

Changed paths:
    engines/scumm/saveload.cpp
    engines/scumm/script_v4.cpp


diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index e6e38bce689..ae793e2c81c 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -860,20 +860,20 @@ void ScummEngine::listSavegames(bool *marks, int num) {
 	Common::StringArray files;
 
 	Common::String prefix = makeSavegameName(99, false);
-	prefix.setChar('*', prefix.size()-2);
-	prefix.setChar(0, prefix.size()-1);
-	memset(marks, false, num * sizeof(bool));	//assume no savegames for this title
+	prefix.setChar('*', prefix.size() - 2);
+	prefix.setChar(0, prefix.size() - 1);
+	memset(marks, false, num * sizeof(bool));	// Assume no savegames for this title
 	files = _saveFileMan->listSavefiles(prefix);
 
 	for (Common::StringArray::const_iterator file = files.begin(); file != files.end(); ++file) {
-		//Obtain the last 2 digits of the filename, since they correspond to the save slot
-		slot[0] = file->c_str()[file->size()-2];
-		slot[1] = file->c_str()[file->size()-1];
+		// Obtain the last 2 digits of the filename, since they correspond to the save slot
+		slot[0] = file->c_str()[file->size() - 2];
+		slot[1] = file->c_str()[file->size() - 1];
 		slot[2] = 0;
 
 		slotNum = atoi(slot);
 		if (slotNum >= 0 && slotNum < num)
-			marks[slotNum] = true;	//mark this slot as valid
+			marks[slotNum] = true;	// Mark this slot as valid
 	}
 }
 
diff --git a/engines/scumm/script_v4.cpp b/engines/scumm/script_v4.cpp
index 3729d96c017..c1ded19ffcd 100644
--- a/engines/scumm/script_v4.cpp
+++ b/engines/scumm/script_v4.cpp
@@ -464,16 +464,21 @@ void ScummEngine_v4::o4_saveLoadGame() {
 		break;
 	case 0xC0: // Test if the save file exists
 		{
-		Common::InSaveFile *file;
-		bool avail_saves[100];
+		Common::InSaveFile *file = nullptr;
+		bool availableSaves[100];
 
-		listSavegames(avail_saves, ARRAYSIZE(avail_saves));
+		listSavegames(availableSaves, ARRAYSIZE(availableSaves));
 		Common::String filename = makeSavegameName(slot, false);
-		if (avail_saves[slot] && (file = _saveFileMan->openForLoading(filename))) {
+
+		// LOOM Towns explicitly sets the result to 6 if the selected slot is 0
+		if (availableSaves[slot] && (file = _saveFileMan->openForLoading(filename))) {
 			result = 6; // Save file exists
 			delete file;
+		} else if (_game.id == GID_LOOM && _game.platform == Common::kPlatformFMTowns && slot == 0) {
+			// LOOM Towns explicitly sets the result to 6 if the selected slot is 0
+			result = 6;
 		} else
-			result = 7; // Save file does not exist
+			result = (_game.id == GID_LOOM && _game.platform == Common::kPlatformFMTowns) ? 8 : 7; // Save file does not exist
 		}
 		break;
 	default:


Commit: 2a91e8ef700ff51f0b3b4bc90d056be6b32d1262
    https://github.com/scummvm/scummvm/commit/2a91e8ef700ff51f0b3b4bc90d056be6b32d1262
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: LOOM (Towns): Fix save slot boxes being smaller than they look on the original

Changed paths:
    engines/scumm/script_v5.cpp


diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index 03f2221ac8d..ec188fe63a7 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -1026,6 +1026,15 @@ void ScummEngine_v5::o5_drawBox() {
 	y2 = getVarOrDirectWord(PARAM_2);
 	color = getVarOrDirectByte(PARAM_3);
 
+	// HACK! In the menu room scripts, LOOM Towns draws the save slots boxes one pixel smaller than expected (on both dimensions).
+	// The interpreter (somehow) manages to draw them correctly, though. Our drawBox implementation appears to be correct,
+	// and attempting to directly change it breaks some stuff (like the GUI banners), so it's really not clear what we're missing.
+	// So, for now, let's do this...
+	if (_game.id == GID_LOOM && _game.platform == Common::kPlatformFMTowns && _currentRoom == 70) {
+		x2 += 1;
+		y2 += 1;
+	}
+
 	drawBox(x, y, x2, y2, color);
 }
 


Commit: 617e7f6077c5636adf210a5047b2d2a31ec8ebb9
    https://github.com/scummvm/scummvm/commit/617e7f6077c5636adf210a5047b2d2a31ec8ebb9
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: LOOM (Towns): Fix crashes on the menu when no savegames are available

Changed paths:
    engines/scumm/script_v4.cpp


diff --git a/engines/scumm/script_v4.cpp b/engines/scumm/script_v4.cpp
index c1ded19ffcd..6cce5e067f9 100644
--- a/engines/scumm/script_v4.cpp
+++ b/engines/scumm/script_v4.cpp
@@ -466,20 +466,30 @@ void ScummEngine_v4::o4_saveLoadGame() {
 		{
 		Common::InSaveFile *file = nullptr;
 		bool availableSaves[100];
+		bool atLeastOneSaveExists = false;
 
 		listSavegames(availableSaves, ARRAYSIZE(availableSaves));
 		Common::String filename = makeSavegameName(slot, false);
 
-		// LOOM Towns explicitly sets the result to 6 if the selected slot is 0
+		for (int i = 0; i < ARRAYSIZE(availableSaves); i++) {
+			if (availableSaves[i]) {
+				atLeastOneSaveExists = true;
+				break;
+			}
+		}
+
 		if (availableSaves[slot] && (file = _saveFileMan->openForLoading(filename))) {
 			result = 6; // Save file exists
 			delete file;
-		} else if (_game.id == GID_LOOM && _game.platform == Common::kPlatformFMTowns && slot == 0) {
-			// LOOM Towns explicitly sets the result to 6 if the selected slot is 0
+		} else if (_game.id == GID_LOOM && _game.platform == Common::kPlatformFMTowns && slot == 0 && atLeastOneSaveExists) {
+			// LOOM Towns explicitly sets the result to 6 if the selected slot is 0;
+			// also, it needs to have at least one savegame available, otherwise it would lead
+			// to the game reaching towards a non-existent string, and crashing as a consequence.
 			result = 6;
 		} else
 			result = (_game.id == GID_LOOM && _game.platform == Common::kPlatformFMTowns) ? 8 : 7; // Save file does not exist
 		}
+
 		break;
 	default:
 		error("o4_saveLoadGame: unknown subopcode %d", _opcode);


Commit: 0f93142ac9a6d92e16b3e7a3d16cdb2cdf72be80
    https://github.com/scummvm/scummvm/commit/0f93142ac9a6d92e16b3e7a3d16cdb2cdf72be80
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-11-28T23:21:45+01:00

Commit Message:
SCUMM: MI1 (Sega CD): Fix message banner colors

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index c2916f8df55..d8025bbecb0 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -131,6 +131,16 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		bottomLineColor = 8;
 		leftLineColor = 15;
 		rightLineColor = 8;
+	} else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD) {
+		// AFAIK, the original Sega CD interpreter doesn't have message banners, it just
+		// shows the main menu box (e.g. when pausing). In here, we can show the banner,
+		// but let's use the main menu box colors to avoid using unintended colors.
+		normalFillColor = getBannerColor(4);
+		normalTextColor = getBannerColor(2);
+		topLineColor = getBannerColor(13);
+		bottomLineColor = getBannerColor(14);
+		leftLineColor = getBannerColor(15);
+		rightLineColor = getBannerColor(16);
 	} else {
 		int palOffset = (_game.version == 8) ? 0 : 11;
 		normalFillColor = getBannerColor(6 * bannerId + 15 + palOffset);




More information about the Scummvm-git-logs mailing list