[Scummvm-git-logs] scummvm master -> e0a2dccd77955ac250115884dc330a2b3323ac55

athrxx noreply at scummvm.org
Thu Sep 8 17:11:18 UTC 2022


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

Summary:
9ef023b11c SCUMM: GUI: Refactor internal GUI code
d1b73e1ffe SCUMM: GUI: Add functional main GUI banners for v5-6-7
457bcb67db SCUMM: GUI: Implement the majority of the v7 Main Menu
2417448791 SCUMM: Change _defaultTalkDelay to _defaultTextSpeed
ddb54b30a4 SCUMM: GUI: Implement saving and loading routines for the old style menu
8ec54a8a26 SCUMM: GUI: Fix GUI rendering in rooms with vertical scrolling
6e96d5f853 SCUMM: GUI: Fix warning
ef8797e65f SCUMM: GUI: Fix text color rendering glitch after getting out of the menu
8356072add SCUMM: GUI: Fix a color glitch when loading a game during a SMUSH movie
16661b2109 GRAPHICS: Add function to create thumbnail without binding it to a output stream
b881a3f600 SCUMM: GUI: Create proper thumbnail for savegames created within the original menu
914ec0084a SCUMM: GUI: Change the load page title of the menu only with a valid savegame
194555c3a7 SCUMM: GUI: Implement v6 GUI and Menu
025d25a1f1 SCUMM: GUI: Fix pre-v7 text rendering over GUI
ee3084bb93 SCUMM: GUI: Fix using nullptr byte array
9bd0a40ea2 SCUMM: GUI: Implement the volume and speed sliders for v6
261978a137 SCUMM: GUI: Games under v7 shouldn't close the menu on failed queryQuit()
a79b55e3f0 SCUMM: GUI: Fix cursor related v7 GUI crash
9bca06429f SCUMM: GUI: Implement v5 GUI and Menu
f7c8b670d8 SCUMM: GUI: Replace non-ASCII characters with portable variations
a56bf5c4e1 SCUMM: GUI: Implement voice mode settings for Indy4 Talkie
eadacafd1b SCUMM: Fix warnings
251d6ab20d SCUMM: Fix parenthesis warning in input.cpp
222bb5c2fa SCUMM: DETECTION: Fix detection for MI2 non-interactive demo
43c6896c53 SCUMM: GUI: Disable original GUI for MI2 non-interactive demo
36dce20400 SCUMM: GUI: Allow screenshots to be taken without clearing banners
a431385a4f SCUMM: GUI: Fix cursor transparency issues in v6
76db64e365 SCUMM: GUI: Fix Amiga menu content
491232a2a2 SCUMM: (GUI) - fix memory leaks
28e1b022ce SCUMM: (GUI) - avoid buffer overflow in convertMessageToString
fa8cff6248 SCUMM: (GUI) - initialize vars
ce4ed0bbf1 SCUMM: (COMI) - rename _savegameThumbnail
6f81942133 SCUMM: (GUI) - replace some strcpy calls with Common::strlcpy
b37ad8d06e SCUMM: (v6/EGA) - fix mouse cursor being dithered/scaled more than once
9c2e357172 SCUMM: GUI: Fix v6 cursor handling
880c78b023 SCUMM: GUI: Implement v4 GUI and menu
6d4de4e527 SCUMM: DETECTION: Add GUIO_ORIGINALGUI flag to v4 games
158a347c94 SCUMM: GUI: Allow ALT-X combination on games which supported it
b19e8dd609 SCUMM: GUI: Fix COMI demo string regression
5ef621e27d SCUMM: GUI: Allow the user to open the GMM whilst on the original menu
afd34eaf2d SCUMM: GUI: Fix unused variable warning
7c1e8df9a3 SCUMM: GUI: Fix CGA palette for v4
7c3418c028 SCUMM: GUI: Fix arrows appearing where they shouldn't on v7
a62ce28eb4 SCUMM: GUI: Fix verbs disappearing in LOOM VGA
649c6a9f11 SCUMM: GUI: Restore shake effect after exiting a GUI prompt or menu
af45365e4f SCUMM: make some vars const
71f73fd8ae SCUMM: (GUI) - modify dialogs for CJK font support
13663bcb6f SCUMM: GUI: Fix v7 menu components positioning for non-CJK versions
62af2cff9b SCUMM: GUI: Fix _curGrabbedCursor memory leak
68ff04184f SCUMM: remove leftover/garbage code
f05d770c69 SCUMM: (DIG/CJK) - implement special arrow buttons
9e53af16c7 SCUMM: GUI: Fix savegame replace prompt regression
c8ba69ed9a SCUMM: GUI: Make quit prompt behavior more consistent
daebac23fb SCUMM: GUI: Notify the backend to bring up virtual keyboard on user prompts
537e6043f2 SCUMM: (GUI) - add mouse wheel support to save/load dialog
7cf77ce865 SCUMM: fix rtl feature
c09ae8edce SCUMM: GUI: Implement draggable sliders for v6-v7 menus
ae88c0be13 SCUMM: GUI: Fix v6 controls unavailable in floppy versions appearing when they shouldn't
913eada820 SCUMM: (GUI) - minor improvement to mouse wheel handling
5c47ccd478 SCUMM: Allow setting voice mode for SE Talkie games
c71d6d19cd SCUMM: (MI1/FM-TOWNS) - adjust bogus values to avoid assert
bb343ad6bd SCUMM: Fix nullptr access
1c51cf6396 SCUMM: GUI: Save and restore the verb surface before and after showing GUI elements
80a8b3cb17 SCUMM: GUI: Simplify the saving/restoring routines for the screen surfaces
a71e03444e SCUMM: GUI: Fix menu closing after failed replace savestate prompt
3475e94b6c SCUMM: GUI: Remove unnecessary call to the cursor restoring routine
e0a2dccd77 SCUMM: GUI: Save shake effect in showOldStyleBannerAndPause()


Commit: 9ef023b11c88df273c97b6c1c6ca933030d00e47
    https://github.com/scummvm/scummvm/commit/9ef023b11c88df273c97b6c1c6ca933030d00e47
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Refactor internal GUI code

Changed paths:
    engines/scumm/gfx.cpp
    engines/scumm/gfx_gui.cpp
    engines/scumm/input.cpp
    engines/scumm/resource.h
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v7.h
    engines/scumm/scumm_v8.h


diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index d8c3de85c79..394397c836a 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -1425,7 +1425,7 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) {
 	if ((vs = findVirtScreen(y)) == nullptr)
 		return;
 
-	if (_game.version == 8) {
+	if (_game.version == 8 || _game.id == GID_DIG) {
 		width = _screenWidth + 8;
 		height = _screenHeight;
 		int effX2 = x2;
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index cbac418d159..a1eb8616b92 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -20,7 +20,7 @@
  */
 
 #include "scumm/scumm.h"
-#include "scumm/scumm_v7.h"
+#include "scumm/scumm_v8.h"
 #include "scumm/gfx.h"
 #include "scumm/dialogs.h"
 #include "scumm/charset.h"
@@ -31,8 +31,7 @@
 
 namespace Scumm {
 
-#ifdef ENABLE_SCUMM_7_8
-void ScummEngine_v7::initBanners() {
+void ScummEngine::initBanners() {
 	setPalColor(7, 0x5A, 0x5A, 0x5A);
 	setPalColor(8, 0x46, 0x46, 0x46);
 	setPalColor(15, 0x8C, 0x8C, 0x8C);
@@ -71,7 +70,7 @@ void ScummEngine_v7::initBanners() {
 	setBannerColors(31, 0x54, 0x54, 0x54);
 }
 
-Common::KeyState ScummEngine_v7::showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...) {
+Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...) {
 	char bannerMsg[512];
 	char localizedMsg[512];
 	char localizedY[512];
@@ -80,8 +79,7 @@ Common::KeyState ScummEngine_v7::showBannerAndPause(int bannerId, int32 waitTime
 	int startingPointX, startingPointY;
 	int xPos, yPos;
 	int rightLineColor, leftLineColor, bottomLineColor, topLineColor;
-	int primaryLineColor, primaryFillColor;
-	InfoDialog d(this, 0);
+	int normalTextColor, normalFillColor;
 
 	// Fetch the translated string for the message...
 	convertMessageToString((const byte *)msg, (byte *)localizedMsg, sizeof(localizedMsg));
@@ -101,8 +99,8 @@ Common::KeyState ScummEngine_v7::showBannerAndPause(int bannerId, int32 waitTime
 	PauseToken pt = pauseEngine();
 
 	// Gather the colors needed for the banner
-	primaryFillColor = getBannerColor(6 * bannerId + 15);
-	primaryLineColor = getBannerColor(6 * bannerId + 14);
+	normalFillColor = getBannerColor(6 * bannerId + 15);
+	normalTextColor = getBannerColor(6 * bannerId + 14);
 	topLineColor = getBannerColor(6 * bannerId + 16);
 	bottomLineColor = getBannerColor(6 * bannerId + 17);
 	leftLineColor = getBannerColor(6 * bannerId + 18);
@@ -116,7 +114,7 @@ Common::KeyState ScummEngine_v7::showBannerAndPause(int bannerId, int32 waitTime
 	// Take all the necessary measurements for the box which
 	// will contain the string...
 	bool isCOMIDemo = (_game.id == GID_CMI && (_game.features & GF_DEMO) != 0);
-	bannerMsgHeight = (isCOMIDemo ? _textV7->getStringHeight("ABC \x80\x78 \xb0\x78") : _textV7->getStringHeight(bannerMsg)) + 5;
+	bannerMsgHeight = (isCOMIDemo ? _textV7->getStringHeight("ABC \x80\x78 \xb0\x78) : _textV7->getStringHeight(bannerMsg)) + 5;
 	bannerMsgWidth = _textV7->getStringWidth(bannerMsg);
 	if (bannerMsgWidth < 100)
 		bannerMsgWidth = 100;
@@ -140,7 +138,7 @@ Common::KeyState ScummEngine_v7::showBannerAndPause(int bannerId, int32 waitTime
 	}
 
 	// Set up the GUI control, specifying all the related colors, the message and the position...
-	setUpInternalGUIControl(0, primaryFillColor, primaryLineColor,
+	setUpInternalGUIControl(0, normalFillColor, normalTextColor,
 							topLineColor, bottomLineColor, leftLineColor, rightLineColor, 0, 0,
 							startingPointX, startingPointY, xPos, yPos,
 							bannerMsg, true);
@@ -166,7 +164,7 @@ Common::KeyState ScummEngine_v7::showBannerAndPause(int bannerId, int32 waitTime
 		_charset->setCurID(oldId);
 
 	// Fetch the localized confirmation letter and substitute it with the 'y' of 'yes'
-	convertMessageToString((const byte *)d.getPlainEngineString(29), (byte *)localizedY, sizeof(localizedY));
+	convertMessageToString((const byte *)getGUIString(gsYesKey), (byte *)localizedY, sizeof(localizedY));
 
 	if (tolower(localizedY[0]) == ks.ascii || toupper((localizedY[0]) == ks.ascii))
 		ks = Common::KEYCODE_y;
@@ -174,7 +172,7 @@ Common::KeyState ScummEngine_v7::showBannerAndPause(int bannerId, int32 waitTime
 	return ks;
 }
 
-void ScummEngine_v7::clearBanner() {
+void ScummEngine::clearBanner() {
 	// Restore the GFX content which was under the banner,
 	// and then mark that part of the screen as dirty.
 	if (_bannerMem) {
@@ -198,7 +196,7 @@ void ScummEngine_v7::clearBanner() {
 	}
 }
 
-void ScummEngine_v7::setBannerColors(int bannerId, byte r, byte g, byte b) {
+void ScummEngine::setBannerColors(int bannerId, byte r, byte g, byte b) {
 	if (bannerId < 0 || bannerId > 50) {
 		debug(1, "ScummEngine::setBannerColors(): invalid slot %d out of range (min %d, max %d)", bannerId, 0, 50);
 		return;
@@ -208,18 +206,14 @@ void ScummEngine_v7::setBannerColors(int bannerId, byte r, byte g, byte b) {
 }
 
 int ScummEngine_v7::getBannerColor(int bannerId) {
-	byte r, g, b;
 	byte *palette = isSmushActive() ? _splayer->getVideoPalette() : _currentPalette;
-	r = (_bannerColors[bannerId] >> 0) & 0xFF;
-	g = (_bannerColors[bannerId] >> 8) & 0xFF;
-	b = (_bannerColors[bannerId] >> 16) & 0xFF;
-	return getPaletteColorFromRGB(palette, r, g, b);
+	return ScummEngine::getBannerColor(bannerId, palette);
 }
 
-void ScummEngine_v7::setUpInternalGUIControl(int id, int primaryFillColor, int primaryLineColor,
-											 int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
-											 int secondaryLineColor, int secondaryFillColor,
-											 int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag) {
+void ScummEngine::setUpInternalGUIControl(int id, int normalFillColor, int normalTextColor,
+										  int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
+										  int highlightedTextColor, int highlightedFillColor,
+										  int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag) {
 
 	int effX, effY;
 	InternalGUIControl *ctrl;
@@ -237,21 +231,21 @@ void ScummEngine_v7::setUpInternalGUIControl(int id, int primaryFillColor, int p
 	ctrl->yPos = effY;
 	ctrl->label = label;
 	ctrl->centerText = centerFlag;
-	ctrl->primaryFillColor = primaryFillColor;
+	ctrl->normalFillColor = normalFillColor;
 	ctrl->topLineColor = topLineColor;
 	ctrl->bottomLineColor = bottomLineColor;
 	ctrl->leftLineColor = leftLineColor;
 	ctrl->rightLineColor = rightLineColor;
-	ctrl->primaryLineColor = primaryLineColor;
-	ctrl->secondaryLineColor = secondaryLineColor;
-	ctrl->secondaryFillColor = secondaryFillColor;
+	ctrl->normalTextColor = normalTextColor;
+	ctrl->highlightedTextColor = highlightedTextColor;
+	ctrl->highlightedFillColor = highlightedFillColor;
 }
 
-void ScummEngine_v7::drawInternalGUIControl(int id, bool useSecondaryColor) {
+void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 	InternalGUIControl *ctrl;
 	int relCentX, relCentY, textHeight;
 	int x, y, textXPos, textYPos;
-	int lineColor, fillColor;
+	int textColor, fillColor;
 	int boxSizeX, boxSizeY;
 
 	bool centerFlag;
@@ -267,7 +261,7 @@ void ScummEngine_v7::drawInternalGUIControl(int id, bool useSecondaryColor) {
 		boxSizeX = x - ctrl->relativeCenterX;
 		boxSizeY = y - relCentY;
 
-		fillColor = useSecondaryColor ? ctrl->secondaryFillColor : ctrl->primaryFillColor;
+		fillColor = highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor;
 
 		// Draw the main box...
 		drawBox(relCentX + 1, relCentY + 1, boxSizeX - 2, boxSizeY - 2, fillColor);
@@ -286,7 +280,7 @@ void ScummEngine_v7::drawInternalGUIControl(int id, bool useSecondaryColor) {
 		// Calculate the positioning for the text
 		int oldId = _charset->getCurID();
 		_charset->setCurID(1);
-		textHeight = _textV7->getStringHeight(buttonString);
+		textHeight = getGUIStringHeight(buttonString);
 		centerFlag = ctrl->centerText;
 
 		if (centerFlag)
@@ -297,17 +291,17 @@ void ScummEngine_v7::drawInternalGUIControl(int id, bool useSecondaryColor) {
 		textYPos = relCentY + (boxSizeY - textHeight) / 2 + 1;
 
 		// Finally, choose the color and draw the text message
-		if (useSecondaryColor)
-			lineColor = ctrl->secondaryLineColor;
+		if (highlightColor)
+			textColor = ctrl->highlightedTextColor;
 		else
-			lineColor = ctrl->primaryLineColor;
+			textColor = ctrl->normalTextColor;
 
 		if (ctrl->label)
 			strcpy(buttonString, ctrl->label);
 		else
 			strcpy(buttonString, "null button");
 
-		drawTextImmediately((const byte *)buttonString, textXPos, textYPos, lineColor, 1, (TextStyleFlags)centerFlag);
+		drawGUIText(buttonString, textXPos, textYPos, textColor, centerFlag);
 
 		// Restore the previous charset
 		if (oldId)
@@ -315,7 +309,7 @@ void ScummEngine_v7::drawInternalGUIControl(int id, bool useSecondaryColor) {
 	}
 }
 
-int ScummEngine_v7::getInternalGUIControlFromCoordinates(int x, int y) {
+int ScummEngine::getInternalGUIControlFromCoordinates(int x, int y) {
 	int id = 0;
 	while (_internalGUIControls[id].relativeCenterX == -1 ||
 		   _internalGUIControls[id].relativeCenterX > x ||
@@ -330,184 +324,443 @@ int ScummEngine_v7::getInternalGUIControlFromCoordinates(int x, int y) {
 	return id;
 }
 
-void ScummEngine_v7::confirmExitDialog() {
+
+#ifdef ENABLE_SCUMM_7_8
+void ScummEngine_v7::queryQuit() {
 	if (isUsingOriginalGUI()) {
-		int boxWidth, strWidth;
-		int ctrlId;
-		char yesLabelPtr[512];
-		char noLabelPtr[512];
-		char msgLabelPtr[512];
-		byte *curGrabbedCursor;
-		int curCursorWidth, curCursorHeight, curCursorHotspotX, curCursorHotspotY, curCursorState;
-
-		InfoDialog d(this, 0);
-
-		// "Are you sure you want to quit?"
-		convertMessageToString((const byte *)d.getPlainEngineString(22), (byte *)msgLabelPtr, sizeof(msgLabelPtr));
-		// "Yes"
-		convertMessageToString((const byte *)d.getPlainEngineString(23), (byte *)yesLabelPtr, sizeof(yesLabelPtr));
-		// "No"
-		convertMessageToString((const byte *)d.getPlainEngineString(24), (byte *)noLabelPtr, sizeof(noLabelPtr));
-
-		// Pause the engine...
-		PauseToken pt = pauseEngine();
-
-		// Backup the current cursor graphics and parameters
-		// and set up the internal v8 cursor...
-		curGrabbedCursor = (byte *)malloc(sizeof(_grabbedCursor));
-		memcpy(curGrabbedCursor, _grabbedCursor, sizeof(_grabbedCursor));
-		curCursorState = isSmushActive() ? 0 : _cursor.state;
-		curCursorWidth = _cursor.width;
-		curCursorHeight = _cursor.height;
-		curCursorHotspotX = _cursor.hotspotX;
-		curCursorHotspotY = _cursor.hotspotY;
-		setDefaultCursor();
-		CursorMan.showMouse(true);
-
-		// Backup the current charsetId, since we're going to switch
-		// to charsetId == 1 and start taking measurements for the box...
-		int oldId = _charset->getCurID();
-		_charset->setCurID(1);
+		if (_game.version == 8 && !(_game.features & GF_DEMO)) {
+			int boxWidth, strWidth;
+			int ctrlId;
+			char yesLabelPtr[512];
+			char noLabelPtr[512];
+			char msgLabelPtr[512];
+			byte *curGrabbedCursor;
+			int curCursorWidth, curCursorHeight, curCursorHotspotX, curCursorHotspotY, curCursorState;
+
+			// Force the cursor to be ON...
+			int8 oldCursorState = _cursor.state;
+			_cursor.state = 1;
+			CursorMan.showMouse(_cursor.state > 0);
+
+			// "Are you sure you want to quit?"
+			convertMessageToString((const byte *)getGUIString(gsQuitPrompt), (byte *)msgLabelPtr, sizeof(msgLabelPtr));
+			// "Yes"
+			convertMessageToString((const byte *)getGUIString(gsYes), (byte *)yesLabelPtr, sizeof(yesLabelPtr));
+			// "No"
+			convertMessageToString((const byte *)getGUIString(gsNo), (byte *)noLabelPtr, sizeof(noLabelPtr));
+
+			// Pause the engine...
+			PauseToken pt = pauseEngine();
+
+			// Backup the current cursor graphics and parameters
+			// and set up the internal v8 cursor...
+			curGrabbedCursor = (byte *)malloc(sizeof(_grabbedCursor));
+			memcpy(curGrabbedCursor, _grabbedCursor, sizeof(_grabbedCursor));
+			curCursorState = isSmushActive() ? 0 : _cursor.state;
+			curCursorWidth = _cursor.width;
+			curCursorHeight = _cursor.height;
+			curCursorHotspotX = _cursor.hotspotX;
+			curCursorHotspotY = _cursor.hotspotY;
+			setDefaultCursor();
+			CursorMan.showMouse(true);
+
+			// Backup the current charsetId, since we're going to switch
+			// to charsetId == 1 and start taking measurements for the box...
+			int oldId = _charset->getCurID();
+			_charset->setCurID(1);
+
+			boxWidth = ((getGUIStringWidth(msgLabelPtr) + 32) & 0xFFF0) + 8;
+			if (boxWidth <= 400)
+				boxWidth = 400;
+
+			// Set up and draw the main box
+			setUpInternalGUIControl(
+				0,
+				getBannerColor(33),
+				getBannerColor(32),
+				getBannerColor(34),
+				getBannerColor(35),
+				getBannerColor(36),
+				getBannerColor(37),
+				0,
+				0,
+				320 - boxWidth / 2,
+				190,
+				boxWidth / 2 + 319,
+				-90,
+				_emptyMsg,
+				true);
+
+			// Save the pixels which will be overwritten by the dialog,
+			// so that we can restore them later. Note that the interpreter
+			// doesn't do this, but we have to...
+			if (!_bannerMem && !isSmushActive()) {
+				_bannerMemSize = _screenWidth * _screenHeight;
+				_bannerMem = (byte *)malloc(_bannerMemSize * sizeof(byte));
+				if (_bannerMem)
+					memcpy(
+						_bannerMem,
+						_virtscr[kMainVirtScreen].getPixels(0, _screenTop),
+						_bannerMemSize);
+			}
+
+			drawInternalGUIControl(0, 0);
+
+			// The text is drawn as a separate entity
+			drawTextImmediately((const byte *)msgLabelPtr, 320, 200, getBannerColor(32), 1, (TextStyleFlags) true);
+
+			// Now set up and draw the Yes and No buttons...
+			if (getGUIStringWidth(noLabelPtr) <= getGUIStringWidth(yesLabelPtr)) {
+				strWidth = getGUIStringWidth(yesLabelPtr);
+			} else {
+				strWidth = getGUIStringWidth(noLabelPtr);
+			}
+
+			if (strWidth <= 120)
+				strWidth = 120;
+
+			setUpInternalGUIControl(
+				0,
+				getBannerColor(45),
+				getBannerColor(44),
+				getBannerColor(46),
+				getBannerColor(47),
+				getBannerColor(48),
+				getBannerColor(49),
+				0,
+				0,
+				420 - (strWidth / 2),
+				240, -strWidth,
+				-30,
+				noLabelPtr,
+				true);
+
+			drawInternalGUIControl(0, 0);
+
+			setUpInternalGUIControl(
+				0,
+				getBannerColor(39),
+				getBannerColor(38),
+				getBannerColor(40),
+				getBannerColor(41),
+				getBannerColor(42),
+				getBannerColor(43),
+				0,
+				0,
+				220 - (strWidth / 2),
+				240,
+				-strWidth,
+				-30,
+				yesLabelPtr,
+				true);
+
+			drawInternalGUIControl(0, 0);
+
+			// Done, draw everything to screen!
+			ScummEngine::drawDirtyScreenParts();
 
-		boxWidth = ((_textV7->getStringWidth(msgLabelPtr) + 32) & 0xFFF0) + 8;
-		if (boxWidth <= 400)
-			boxWidth = 400;
-
-		// Set up and draw the main box
-		setUpInternalGUIControl(
-			0,
-			getBannerColor(33),
-			getBannerColor(32),
-			getBannerColor(34),
-			getBannerColor(35),
-			getBannerColor(36),
-			getBannerColor(37),
-			0,
-			0,
-			320 - boxWidth / 2,
-			190,
-			boxWidth / 2 + 319,
-			-90,
-			_emptyMsg,
-			true);
-
-		// Save the pixels which will be overwritten by the dialog,
-		// so that we can restore them later. Note that the interpreter
-		// doesn't do this, but we have to...
-		if (!_bannerMem && !isSmushActive()) {
-			_bannerMemSize = _screenWidth * _screenHeight;
-			_bannerMem = (byte *)malloc(_bannerMemSize * sizeof(byte));
-			if (_bannerMem)
+			// Stay in the dialog while we keep pressing CTRL-C...
+			Common::KeyState ks;
+			bool leftBtnPressed = false, rightBtnPressed = false;
+			do {
+				clearClickedStatus();
+				ks = Common::KEYCODE_INVALID;
+				waitForBannerInput(-1, ks, leftBtnPressed, rightBtnPressed);
+			} while (ks.keycode == Common::KEYCODE_LCTRL ||
+					 ks.keycode == Common::KEYCODE_RCTRL ||
+					 (ks.keycode == Common::KEYCODE_c && ks.hasFlags(Common::KBD_CTRL)));
+
+			ctrlId = getInternalGUIControlFromCoordinates(_mouse.x, _mouse.y);
+			if ((leftBtnPressed && ctrlId == 0) || (toupper(ks.ascii) == yesLabelPtr[0]))
+				quitGame();
+
+			// Restore the previous cursor...
+			_cursor.state = curCursorState;
+			CursorMan.showMouse(_cursor.state > 0);
+			setCursorHotspot(curCursorHotspotX, curCursorHotspotY);
+			setCursorFromBuffer(curGrabbedCursor, curCursorWidth, curCursorHeight, curCursorWidth);
+			free(curGrabbedCursor);
+
+			// The interpreter makes us wait 45 full frames;
+			// let's wait half that time...
+			waitForTimer(45 * 2);
+
+			// Again, he interpreter does not explicitly restore the screen
+			// after finishing displaying this query dialog, but we have to...
+			if (_bannerMem && !isSmushActive()) {
 				memcpy(
-					_bannerMem,
 					_virtscr[kMainVirtScreen].getPixels(0, _screenTop),
+					_bannerMem,
 					_bannerMemSize);
-		}
+				free(_bannerMem);
+				_bannerMem = nullptr;
 
-		drawInternalGUIControl(0, 0);
+				markRectAsDirty(_virtscr[kMainVirtScreen].number, 0, _screenWidth + 8, _screenTop, _screenHeight + _screenTop);
+				ScummEngine::drawDirtyScreenParts();
+				_system->updateScreen();
+			}
 
-		// The text is drawn as a separate entity
-		drawTextImmediately((const byte *)msgLabelPtr, 320, 200, getBannerColor(32), 1, (TextStyleFlags) true);
+			// Finally, resume the engine, clear the input state, and restore the charset.
+			pt.clear();
+			clearClickedStatus();
+			if (oldId)
+				_charset->setCurID(oldId);
 
-		// Now set up and draw the Yes and No buttons...
-		if (_textV7->getStringWidth(noLabelPtr) <= _textV7->getStringWidth(yesLabelPtr)) {
-			strWidth = _textV7->getStringWidth(yesLabelPtr);
+			// Restore the old cursor state...
+			_cursor.state = oldCursorState;
+			CursorMan.showMouse(_cursor.state > 0);
 		} else {
-			strWidth = _textV7->getStringWidth(noLabelPtr);
+			ScummEngine::queryQuit();
 		}
+	} else {
+		ScummEngine::confirmExitDialog();
+	}
+}
 
-		if (strWidth <= 120)
-			strWidth = 120;
-
-		setUpInternalGUIControl(
-			0,
-			getBannerColor(45),
-			getBannerColor(44),
-			getBannerColor(46),
-			getBannerColor(47),
-			getBannerColor(48),
-			getBannerColor(49),
-			0,
-			0,
-			420 - (strWidth / 2),
-			240, -strWidth,
-			-30,
-			noLabelPtr,
-			true);
-
-		drawInternalGUIControl(0, 0);
-
-		setUpInternalGUIControl(
-			0,
-			getBannerColor(39),
-			getBannerColor(38),
-			getBannerColor(40),
-			getBannerColor(41),
-			getBannerColor(42),
-			getBannerColor(43),
-			0,
-			0,
-			220 - (strWidth / 2),
-			240,
-			-strWidth,
-			-30,
-			yesLabelPtr,
-			true);
-
-		drawInternalGUIControl(0, 0);
-
-		// Done, draw everything to screen!
-		ScummEngine::drawDirtyScreenParts();
-
-		// Stay in the dialog while we keep pressing CTRL-C...
-		Common::KeyState ks;
-		bool leftBtnPressed = false, rightBtnPressed = false;
-		do {
-			clearClickedStatus();
-			ks = Common::KEYCODE_INVALID;
-			waitForBannerInput(-1, ks, leftBtnPressed, rightBtnPressed);
-		} while (ks.keycode == Common::KEYCODE_LCTRL ||
-				 ks.keycode == Common::KEYCODE_RCTRL ||
-				 (ks.keycode == Common::KEYCODE_c && ks.hasFlags(Common::KBD_CTRL)));
-
-		ctrlId = getInternalGUIControlFromCoordinates(_mouse.x, _mouse.y);
-		if ((leftBtnPressed && ctrlId == 0) || (toupper(ks.ascii) == yesLabelPtr[0]))
-			quitGame();
-
-		// Restore the previous cursor...
-		_cursor.state = curCursorState;
-		CursorMan.showMouse(_cursor.state > 0);
-		setCursorHotspot(curCursorHotspotX, curCursorHotspotY);
-		setCursorFromBuffer(curGrabbedCursor, curCursorWidth, curCursorHeight, curCursorWidth);
-		free(curGrabbedCursor);
-
-		// The interpreter makes us wait 45 full frames;
-		// let's wait half that time...
-		waitForTimer(45 * 2);
-
-		// Again, he interpreter does not explicitly restore the screen
-		// after finishing displaying this query dialog, but we have to...
-		if (_bannerMem && !isSmushActive()) {
-			memcpy(
-				_virtscr[kMainVirtScreen].getPixels(0, _screenTop),
-				_bannerMem,
-				_bannerMemSize);
-			free(_bannerMem);
-			_bannerMem = nullptr;
+const char *ScummEngine_v8::getGUIString(int stringId) {
+	InfoDialog d(this, 0);
+	int resStringId = -1;
+
+	switch (stringId) {
+	case gsPause:
+		resStringId = 4;
+		break;
+	case gsQuitPrompt:
+		resStringId = (_game.features & GF_DEMO) ? 30 : 22;
+		break;
+	case gsYes:
+		resStringId = 23;
+		break;
+	case gsNo:
+		resStringId = 24;
+		break;
+	case gsIMuseBuffer:
+		resStringId = 25;
+		break;
+	case gsVoiceAndText:
+		resStringId = 26;
+		break;
+	case gsTextDisplayOnly:
+		resStringId = 27;
+		break;
+	case gsVoiceOnly:
+		resStringId = 28;
+		break;
+	case gsYesKey:
+		resStringId = 29;
+		break;
+	case gsTextSpeed:
+		resStringId = 31;
+		break;
+	case gsMusicVolume:
+		resStringId = 32;
+		break;
+	case gsVoiceVolume:
+		resStringId = 33;
+		break;
+	case gsSfxVolume:
+		resStringId = 34;
+		break;
+	default:
+		return "";
+	}
 
-			markRectAsDirty(_virtscr[kMainVirtScreen].number, 0, _screenWidth + 8, _screenTop, _screenHeight + _screenTop);
-			ScummEngine::drawDirtyScreenParts();
-			_system->updateScreen();
-		}
+	if (resStringId > 0)
+		return d.getPlainEngineString(resStringId);
+	else
+		return "";
+}
 
-		// Finally, resume the engine, clear the input state, and restore the charset.
-		pt.clear();
-		clearClickedStatus();
-		if (oldId)
-			_charset->setCurID(oldId);
-	} else {
-		ScummEngine::confirmExitDialog();
+const char *ScummEngine_v7::getGUIString(int stringId) {
+	InfoDialog d(this, 0);
+	int resStringId = -1;
+
+	switch (stringId) {
+	case gsPause:
+		break;
+	case gsVersion:
+		break;
+	case gsTextSpeed:
+		break;
+	case gsRestart:
+		break;
+	case gsQuitPrompt:
+		break;
+	case gsSave:
+		break;
+	case gsLoad:
+		break;
+	case gsPlay:
+		break;
+	case gsCancel:
+		break;
+	case gsQuit:
+		break;
+	case gsOK:
+		break;
+	case gsMustName:
+		break;
+	case gsGameNotSaved:
+		break;
+	case gsGameNotLoaded:
+		break;
+	case gsSaving:
+		break;
+	case gsLoading:
+		break;
+	case gsNamePrompt:
+		break;
+	case gsSelectLoadPrompt:
+		break;
+	case gsReplacePrompt:
+		break;
+	case gsYes:
+		break;
+	case gsNo:
+		break;
+	case gsIMuseBuffer:
+		break;
+	case gsVoiceAndText:
+		break;
+	case gsTextDisplayOnly:
+		break;
+	case gsYesKey:
+		break;
+	case gsMusicVolume:
+		break;
+	case gsVoiceVolume:
+		break;
+	case gsSfxVolume:
+		break;
+	default:
+		return "";
 	}
+
+	if (resStringId > 0)
+		return d.getPlainEngineString(resStringId);
+	else
+		return "";
+}
+
+int ScummEngine_v7::getGUIStringHeight(const char *str) {
+	return _textV7->getStringHeight(str);
+}
+
+int ScummEngine_v7::getGUIStringWidth(const char *str) {
+	return _textV7->getStringWidth(str);
 }
+
+void ScummEngine_v7::drawGUIText(const char *buttonString, int textXPos, int textYPos, int textColor, bool centerFlag) {
+	drawTextImmediately((const byte *)buttonString, textXPos, textYPos, textColor, 1, (TextStyleFlags)centerFlag);
+}
+
 #endif
+
+int ScummEngine::getBannerColor(int bannerId, byte *palette) {
+	byte r, g, b;
+	r = (_bannerColors[bannerId] >> 0) & 0xFF;
+	g = (_bannerColors[bannerId] >> 8) & 0xFF;
+	b = (_bannerColors[bannerId] >> 16) & 0xFF;
+	return getPaletteColorFromRGB(palette, r, g, b);
+}
+
+void ScummEngine::queryQuit() {
+	// "Are you sure you want to quit?  (Y-N)"
+	Common::KeyState ks = showBannerAndPause(0, -1, getGUIString(gsQuitPrompt));
+	if (ks.keycode == Common::KEYCODE_y) {
+		quitGame();
+	}
+}
+
+int ScummEngine::getGUIStringHeight(const char *str) {
+	return _charset->getFontHeight();
+}
+
+int ScummEngine::getGUIStringWidth(const char *str) {
+	return _charset->getStringWidth(0, (const byte *)str);
 }
+
+void ScummEngine::drawGUIText(const char *buttonString, int textXPos, int textYPos, int textColor, bool centerFlag) {
+	_string[4].ypos = textYPos;
+	_string[4].xpos = textXPos;
+	_string[4].right = _screenWidth - 1;
+	_string[4].center = centerFlag;
+	_string[4].color = textColor;
+	_string[4].charset = 1;
+	drawString(4, (const byte *)buttonString);
+}
+
+const char *ScummEngine::getGUIString(int stringId) {
+	InfoDialog d(this, 0);
+	int resStringId = -1;
+
+	switch (stringId) {
+	case gsPause:
+		break;
+	case gsVersion:
+		break;
+	case gsTextSpeed:
+		break;
+	case gsRestart:
+		break;
+	case gsQuitPrompt:
+		break;
+	case gsSave:
+		break;
+	case gsLoad:
+		break;
+	case gsPlay:
+		break;
+	case gsCancel:
+		break;
+	case gsQuit:
+		break;
+	case gsOK:
+		break;
+	case gsMustName:
+		break;
+	case gsGameNotSaved:
+		break;
+	case gsGameNotLoaded:
+		break;
+	case gsSaving:
+		break;
+	case gsLoading:
+		break;
+	case gsNamePrompt:
+		break;
+	case gsSelectLoadPrompt:
+		break;
+	case gsReplacePrompt:
+		break;
+	case gsYes:
+		break;
+	case gsNo:
+		break;
+	case gsIMuseBuffer:
+		break;
+	case gsVoiceAndText:
+		break;
+	case gsTextDisplayOnly:
+		break;
+	case gsYesKey:
+		break;
+	case gsMusicVolume:
+		break;
+	case gsVoiceVolume:
+		break;
+	case gsSfxVolume:
+		break;
+	case gsHeap:
+		return "Heap %d";
+	default:
+		return "";
+	}
+
+	if (resStringId > 0)
+		return d.getPlainEngineString(resStringId);
+	else
+		return "";
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 9fb7c2ead59..a0d5dfba346 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -398,8 +398,6 @@ void ScummEngine::processInput() {
 #ifdef ENABLE_SCUMM_7_8
 void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 	if (isUsingOriginalGUI()) {
-		// Set up an InfoDialog object for fetching the internal strings.
-		InfoDialog d(this, 0);
 		char tempStr[64];
 
 		if (lastKeyHit.keycode == Common::KEYCODE_INVALID)
@@ -428,7 +426,7 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 			_cursor.state = 0;
 			CursorMan.showMouse(_cursor.state > 0);
 			// "Game Paused.  Press SPACE to Continue."
-			showBannerAndPause(0, -1, d.getPlainEngineString(4));
+			showBannerAndPause(0, -1, getGUIString(gsPause));
 			_cursor.state = oldCursorState;
 			return;
 		}
@@ -443,24 +441,7 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 		}
 
 		if (lastKeyHit.keycode == Common::KEYCODE_c && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-			if (_game.features & GF_DEMO) {
-				// "Are you sure you want to quit?  (Y-N)"
-				Common::KeyState ks = showBannerAndPause(0, -1, d.getPlainEngineString(30));
-				if (ks.keycode == Common::KEYCODE_y) {
-					quitGame();
-				}
-			} else {
-				// Force the cursor to be ON...
-				int8 oldCursorState = _cursor.state;
-				_cursor.state = 1;
-				CursorMan.showMouse(_cursor.state > 0);
-
-				confirmExitDialog();
-
-				// Restore the old cursor state...
-				_cursor.state = oldCursorState;
-				CursorMan.showMouse(_cursor.state > 0);
-			}
+			queryQuit();
 			return;
 		}
 
@@ -474,13 +455,13 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 
 			switch (voiceMode) {
 			case 0: // "Voice Only"
-				showBannerAndPause(0, 120, d.getPlainEngineString(28));
+				showBannerAndPause(0, 120, getGUIString(gsVoiceOnly));
 				break;
 			case 1: // "Voice and Text"
-				showBannerAndPause(0, 120, d.getPlainEngineString(26));
+				showBannerAndPause(0, 120, getGUIString(gsVoiceAndText));
 				break;
 			default: // "Text Display Only"
-				showBannerAndPause(0, 120, d.getPlainEngineString(27));
+				showBannerAndPause(0, 120, getGUIString(gsTextDisplayOnly));
 			}
 
 			ConfMan.setInt("original_gui_text_status", voiceMode);
@@ -509,7 +490,7 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 		if (lastKeyHit.keycode == Common::KEYCODE_b && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 			int curBufferCount = _imuseDigital->roundRobinSetBufferCount();
 			// "iMuse buffer count changed to %d"
-			showBannerAndPause(0, 90, d.getPlainEngineString(25), curBufferCount);
+			showBannerAndPause(0, 90, getGUIString(gsIMuseBuffer), curBufferCount);
 			return;
 		}
 
@@ -533,7 +514,7 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 							volume = 127;
 					}
 
-					strcpy(tempStr, d.getPlainEngineString(32));
+					strcpy(tempStr, getGUIString(gsMusicVolume));
 					char *ptrToChar = strchr(tempStr, '=');
 					memset(ptrToChar, '\v', 9);
 					ptrToChar[volume / 15] = '\f';
@@ -571,7 +552,7 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 							volume = 127;
 					}
 
-					strcpy(tempStr, d.getPlainEngineString(33));
+					strcpy(tempStr, getGUIString(gsVoiceVolume));
 					char *ptrToChar = strchr(tempStr, '=');
 					memset(ptrToChar, '\v', 9);
 					ptrToChar[volume / 15] = '\f';
@@ -609,7 +590,7 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 							volume = 127;
 					}
 
-					strcpy(tempStr, d.getPlainEngineString(34));
+					strcpy(tempStr, getGUIString(gsSfxVolume));
 					char *ptrToChar = strchr(tempStr, '=');
 					memset(ptrToChar, '\v', 9);
 					ptrToChar[volume / 15] = '\f';
@@ -649,7 +630,7 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 							VAR(VAR_CHARINC) = 9;
 					}
 
-					strcpy(tempStr, d.getPlainEngineString(31));
+					strcpy(tempStr, getGUIString(gsTextSpeed));
 					char *ptrToChar = strchr(tempStr, '=');
 					memset(ptrToChar, '\v', 10);
 					ptrToChar[9 - VAR(VAR_CHARINC)] = '\f';
@@ -721,8 +702,10 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 		ScummEngine_v6::processKeyboard(lastKeyHit);
 	}
 }
+#endif
+
 
-void ScummEngine_v7::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked) {
+void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked) {
 	bool validKey = false;
 
 	if (waitTime && waitTime != -1) {
@@ -761,8 +744,6 @@ void ScummEngine_v7::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bo
 	}
 }
 
-#endif
-
 void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) {
 	if (lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 		SubtitleSettingsDialog dialog(this, _voiceMode);
diff --git a/engines/scumm/resource.h b/engines/scumm/resource.h
index fe4d0628d69..6f9c09017a9 100644
--- a/engines/scumm/resource.h
+++ b/engines/scumm/resource.h
@@ -180,6 +180,7 @@ public:
 	~ResourceManager();
 
 	void setHeapThreshold(int min, int max);
+	uint32 getHeapSize() { return _allocatedSize; }
 
 	void allocResTypeData(ResType type, uint32 tag, int num, ResTypeMode mode);
 	void freeResources();
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 28408d4addd..1c318e34f2c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -848,6 +848,10 @@ Common::Error ScummEngine::init() {
 
 	const Common::FSNode gameDataDir(ConfMan.get("path"));
 
+	ConfMan.registerDefault("original_gui", true);
+	if (ConfMan.hasKey("original_gui", _targetName)) {
+		_useOriginalGUI = ConfMan.getBool("original_gui");
+	}
 	_enableEnhancements = ConfMan.getBool("enable_enhancements");
 	_enableAudioOverride = ConfMan.getBool("audio_override");
 
@@ -1389,11 +1393,6 @@ void ScummEngine::setupScumm(const Common::String &macResourceFile) {
 #ifdef ENABLE_SCUMM_7_8
 void ScummEngine_v7::setupScumm(const Common::String &macResourceFile) {
 
-	ConfMan.registerDefault("original_gui", true);
-	if (ConfMan.hasKey("original_gui", _targetName)) {
-		_useOriginalGUI = ConfMan.getBool("original_gui");
-	}
-
 	// The object line toggle is always synchronized from the main game to
 	// our internal Game Options; at startup we do the opposite, since an user
 	// might change the toggle just before starting up the game...
@@ -2090,7 +2089,7 @@ void ScummEngine::setupMusic(int midi, const Common::String &macInstrumentFile)
 }
 
 void ScummEngine::syncSoundSettings() {
-	if (isUsingOriginalGUI() && _game.version == 8) {
+	if (isUsingOriginalGUI() && _game.version > 6) {
 		if (ConfMan.hasKey("original_gui_text_status", _targetName)) {
 			_voiceMode = ConfMan.getInt("original_gui_text_status");
 		} else if (ConfMan.hasKey("subtitles", _targetName) && ConfMan.hasKey("speech_mute", _targetName)){
@@ -3109,7 +3108,7 @@ void ScummEngine::restart() {
 }
 
 bool ScummEngine::isUsingOriginalGUI() {
-	if (_game.version == 8)
+	if (_game.version > 6)
 		return _useOriginalGUI;
 
 	return false;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index db5a89fcbf4..3f80cef35ff 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -351,6 +351,60 @@ class ResourceManager;
 
 #define AMIGA_NTSC_VBLANK_RATE 240.0
 
+/**
+ * GUI strings categories.
+ */
+
+enum GUIString {
+	gsPause = 0,
+	gsVersion = 1,
+	gsTextSpeed = 2,
+	gsRestart = 3,
+	gsQuitPrompt = 4,
+	gsSave = 5,
+	gsLoad = 6,
+	gsPlay = 7,
+	gsCancel = 8,
+	gsQuit = 9,
+	gsOK = 10,
+	gsMustName = 11,
+	gsGameNotSaved = 12,
+	gsGameNotLoaded = 13,
+	gsSaving = 14,
+	gsLoading = 15,
+	gsNamePrompt = 16,
+	gsSelectLoadPrompt = 17,
+	gsReplacePrompt = 18,
+	gsYes = 20,
+	gsNo = 21,
+	gsIMuseBuffer = 22,
+	gsVoiceAndText = 23,
+	gsTextDisplayOnly = 24,
+	gsVoiceOnly = 25,
+	gsYesKey = 26,
+	gsMusicVolume = 27,
+	gsVoiceVolume = 28,
+	gsSfxVolume = 29,
+	gsHeap = 30
+};
+
+struct InternalGUIControl {
+	int relativeCenterX;
+	int relativeCenterY;
+	int xPos;
+	int yPos;
+	int normalFillColor;
+	int topLineColor;
+	int bottomLineColor;
+	int leftLineColor;
+	int rightLineColor;
+	int normalTextColor;
+	int highlightedTextColor;
+	int highlightedFillColor;
+	bool centerText;
+	char *label;
+};
+
 /**
  * Base class for all SCUMM engines.
  */
@@ -492,12 +546,40 @@ protected:
 	Dialog *_messageDialog = nullptr;
 	Dialog *_versionDialog = nullptr;
 
-	virtual void confirmExitDialog();
+	void confirmExitDialog();
 	void confirmRestartDialog();
 	void pauseDialog();
 	void messageDialog(const Common::U32String &message);
 	void versionDialog();
 
+	// Original GUI
+	int32 _bannerColors[50]; // Colors for the original GUI
+	byte *_bannerMem = nullptr;
+	uint32 _bannerMemSize = 0;
+	InternalGUIControl _internalGUIControls[30];
+	char _emptyMsg[1] = {'\0'};
+
+	void initBanners();
+	Common::KeyState showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...);
+	void clearBanner();
+	void setBannerColors(int bannerId, byte r, byte g, byte b);
+	virtual int getBannerColor(int bannerId) { return getBannerColor(bannerId, _currentPalette); }
+	int getBannerColor(int bannerId, byte *palette);
+	void setUpInternalGUIControl(int id, int normalFillColor, int normalTextColor,
+								 int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
+								 int highlightedTextColor, int highlightedFillColor,
+								 int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag);
+	void drawInternalGUIControl(int id, bool highlightColor);
+	int getInternalGUIControlFromCoordinates(int x, int y);
+	virtual bool isSmushActive() { return false; }
+
+	virtual void queryQuit();
+	virtual const char *getGUIString(int stringId);
+	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked);
+	virtual int getGUIStringHeight(const char *str);
+	virtual int getGUIStringWidth(const char *str);
+	virtual void drawGUIText(const char *buttonString, int textXPos, int textYPos, int textColor, bool centerFlag);
+
 public:
 	char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);
 
diff --git a/engines/scumm/scumm_v7.h b/engines/scumm/scumm_v7.h
index 43f79b05aa5..518ba9cfb9f 100644
--- a/engines/scumm/scumm_v7.h
+++ b/engines/scumm/scumm_v7.h
@@ -65,23 +65,6 @@ public:
 		int32 offset;
 	};
 
-	struct InternalGUIControl {
-		int relativeCenterX;
-		int relativeCenterY;
-		int xPos;
-		int yPos;
-		int primaryFillColor;
-		int topLineColor;
-		int bottomLineColor;
-		int leftLineColor;
-		int rightLineColor;
-		int primaryLineColor;
-		int secondaryLineColor;
-		int secondaryFillColor;
-		bool centerText;
-		char *label;
-	};
-
 protected:
 	TextRenderer_v7 *_textV7;
 	Common::Rect _defaultTextClipRect;
@@ -111,18 +94,12 @@ protected:
 	int _subtitleQueuePos;
 	SubtitleText _subtitleQueue[20];
 
-	int32 _bannerColors[50]; // Colors for the original GUI
-	byte *_bannerMem = nullptr;
-	uint32 _bannerMemSize = 0;
-	InternalGUIControl _internalGUIControls[30];
-	char _emptyMsg[1] = { '\0' };
-
 public:
 	void processSubtitleQueue();
 	void addSubtitleToQueue(const byte *text, const Common::Point &pos, byte color, byte charset, bool center, bool wrap);
 	void clearSubtitleQueue();
 	void CHARSET_1() override;
-	bool isSmushActive() { return _smushActive; }
+	bool isSmushActive() override { return _smushActive; }
 	void removeBlastTexts() override;
 	void restoreBlastTextsRects();
 
@@ -165,19 +142,12 @@ protected:
 	void loadLanguageBundle() override;
 	void playSpeech(const byte *ptr);
 
-	void initBanners();
-	Common::KeyState showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...);
-	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked);
-	void clearBanner();
-	void setBannerColors(int bannerId, byte r, byte g, byte b);
-	int getBannerColor(int bannerId);
-	void setUpInternalGUIControl(int id, int primaryFillColor, int primaryLineColor,
-								 int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
-								 int secondaryLineColor, int secondaryFillColor,
-								 int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag);
-	void drawInternalGUIControl(int id, bool useSecondaryColor);
-	int getInternalGUIControlFromCoordinates(int x, int y);
-	void confirmExitDialog() override;
+	void queryQuit() override;
+	int getBannerColor(int bannerId) override;
+	const char *getGUIString(int stringId) override;
+	int getGUIStringHeight(const char *str) override;
+	int getGUIStringWidth(const char *str) override;
+	void drawGUIText(const char *buttonString, int textXPos, int textYPos, int textColor, bool centerFlag) override;
 
 	void setDefaultCursor() override;
 
diff --git a/engines/scumm/scumm_v8.h b/engines/scumm/scumm_v8.h
index 5e90bfdd9e6..196f136b2d7 100644
--- a/engines/scumm/scumm_v8.h
+++ b/engines/scumm/scumm_v8.h
@@ -95,6 +95,8 @@ protected:
 	bool fetchInternalSaveStateThumbnail(int slotId, bool isHeapSave);
 	uint32 *fetchScummVMSaveStateThumbnail(int slotId, bool isHeapSave, int brightness);
 
+	const char *getGUIString(int stringId) override;
+
 	/* Version 8 script opcodes */
 	void o8_mod();
 	void o8_wait();


Commit: d1b73e1ffe1bfb7c304a7d3e16cdda335a129129
    https://github.com/scummvm/scummvm/commit/d1b73e1ffe1bfb7c304a7d3e16cdda335a129129
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Add functional main GUI banners for v5-6-7

Changed paths:
    engines/scumm/detection_tables.h
    engines/scumm/dialogs.cpp
    engines/scumm/gfx.cpp
    engines/scumm/gfx_gui.cpp
    engines/scumm/input.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v6.h
    engines/scumm/string.cpp


diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 46d61af7435..12be1af7437 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -191,35 +191,35 @@ static const GameSettings gameVariantsTable[] = {
 	{"monkey", "EGA",      "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_16COLOR,     Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_ENHANCEMENTS)},
 	{"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR,                        GF_16COLOR,     Common::kPlatformAtariST, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
 	{"monkey", "Demo",     "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB,            GF_16COLOR | GF_DEMO,     Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
-	{"monkey", "CD",           0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS, UNK, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
-	{"monkey", "Mac",    0, GID_MONKEY,     5, 0, MDT_ADLIB,                        0, UNK, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
-	{"monkey", "FM-TOWNS",     0, GID_MONKEY,     5, 0, MDT_TOWNS,                        GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS)},
-	{"monkey", "SEGA",         0, GID_MONKEY,     5, 0, MDT_NONE,                         GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
-	{"monkey", "SE Talkie",    0, GID_MONKEY,     5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_AUDIOTRACKS, UNK, GUIO0()},
-
-	{"monkey2", "", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO2(GUIO_NOSPEECH, GUIO_ENHANCEMENTS)},
-	{"monkey2", "Amiga", 0, GID_MONKEY2,  5, 0, MDT_AMIGA, 0, Common::kPlatformAmiga, GUIO3(GUIO_NOSPEECH, GUIO_MIDIAMIGA, GUIO_ENHANCEMENTS)},
-	{"monkey2", "FM-TOWNS", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO6(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS)},
-	{"monkey2", "SE Talkie",0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()},
-
-	{"atlantis", "", 0, GID_INDY4,    5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_ENHANCEMENTS)},
-	{"atlantis", "Steam", "steam", GID_INDY4,    5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_ENHANCEMENTS)},
-	{"atlantis", "Floppy", 0, GID_INDY4,    5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO2(GUIO_NOSPEECH, GUIO_ENHANCEMENTS)},
-	{"atlantis", "Amiga", 0, GID_INDY4,  5, 0, MDT_AMIGA, 0, Common::kPlatformAmiga, GUIO3(GUIO_NOSPEECH, GUIO_MIDIAMIGA, GUIO_ENHANCEMENTS)},
-	{"atlantis", "FM-TOWNS", 0, GID_INDY4,    5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO5(GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS)},
-
-	{"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO1(GUIO_ENHANCEMENTS)},
-	{"tentacle", "Floppy", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO2(GUIO_NOSPEECH, GUIO_ENHANCEMENTS)},
-
-	{"samnmax",  "", 0, GID_SAMNMAX,  6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO1(GUIO_ENHANCEMENTS)},
-	{"samnmax",  "Floppy", 0, GID_SAMNMAX,  6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO2(GUIO_NOSPEECH, GUIO_ENHANCEMENTS)},
-
-	{"ft",   "", 0, GID_FT,  7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
-	{"ft",   "Demo", 0, GID_FT,  7, 0, MDT_NONE, GF_DEMO, UNK, GUIO1(GUIO_NOMIDI)},
-
-	{"dig",  "", 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
-	{"dig",  "Demo", 0, GID_DIG, 7, 0, MDT_NONE, GF_DEMO, UNK, GUIO1(GUIO_NOMIDI)},
-	{"dig",  "Steam", "steam", GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)},
+	{"monkey", "CD",           0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS, UNK, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey", "Mac",    0, GID_MONKEY,     5, 0, MDT_ADLIB,                        0, UNK, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey", "FM-TOWNS",     0, GID_MONKEY,     5, 0, MDT_TOWNS,                        GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey", "SEGA",         0, GID_MONKEY,     5, 0, MDT_NONE,                         GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey", "SE Talkie",    0, GID_MONKEY,     5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_AUDIOTRACKS, UNK, GUIO1(GUIO_ORIGINALGUI)},
+
+	{"monkey2", "", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO3(GUIO_NOSPEECH, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey2", "Amiga", 0, GID_MONKEY2,  5, 0, MDT_AMIGA, 0, Common::kPlatformAmiga, GUIO4(GUIO_NOSPEECH, GUIO_MIDIAMIGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey2", "FM-TOWNS", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO7(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey2", "SE Talkie", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_ORIGINALGUI)},
+
+	{"atlantis", "", 0, GID_INDY4,    5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO2(GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"atlantis", "Steam", "steam", GID_INDY4,    5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO2(GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"atlantis", "Floppy", 0, GID_INDY4,    5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO3(GUIO_NOSPEECH, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"atlantis", "Amiga", 0, GID_INDY4,  5, 0, MDT_AMIGA, 0, Common::kPlatformAmiga, GUIO4(GUIO_NOSPEECH, GUIO_MIDIAMIGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"atlantis", "FM-TOWNS", 0, GID_INDY4,    5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO6(GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+
+	{"tentacle", "", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO2(GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"tentacle", "Floppy", 0, GID_TENTACLE, 6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO3(GUIO_NOSPEECH, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+
+	{"samnmax",  "", 0, GID_SAMNMAX,  6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO2(GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"samnmax",  "Floppy", 0, GID_SAMNMAX,  6, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_GM, GF_USE_KEY, UNK, GUIO3(GUIO_NOSPEECH, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+
+	{"ft",   "", 0, GID_FT,  7, 0, MDT_NONE, 0, UNK, GUIO2(GUIO_NOMIDI, GUIO_ORIGINALGUI)},
+	{"ft",   "Demo", 0, GID_FT,  7, 0, MDT_NONE, GF_DEMO, UNK, GUIO2(GUIO_NOMIDI, GUIO_ORIGINALGUI)},
+
+	{"dig",  "", 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO2(GUIO_NOMIDI, GUIO_ORIGINALGUI)},
+	{"dig",  "Demo", 0, GID_DIG, 7, 0, MDT_NONE, GF_DEMO, UNK, GUIO2(GUIO_NOMIDI, GUIO_ORIGINALGUI)},
+	{"dig",  "Steam", "steam", GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO2(GUIO_NOMIDI, GUIO_ORIGINALGUI)},
 
 	{"comi", "", 0, GID_CMI, 8, 0, MDT_NONE, 0, Common::kPlatformWindows, GUIO3(GUIO_NOMIDI, GUIO_NOASPECT, GUIO_ORIGINALGUI)},
 	{"comi", "Demo", 0, GID_CMI, 8, 0, MDT_NONE, GF_DEMO, Common::kPlatformWindows, GUIO3(GUIO_NOMIDI, GUIO_NOASPECT, GUIO_ORIGINALGUI)},
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 6bc4d629673..707fd3db17b 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -83,7 +83,8 @@ static const ResString string_map_table_v8[] = {
 	{0, "/NEW.23/Text Speed  Slow  ==========  Fast"},
 	{0, "/NEW.24/Music Volume  Low  =========  High"},
 	{0, "/NEW.25/Voice Volume  Low  =========  High"},
-	{0, "/NEW.26/Sfx Volume  Low  =========  High"}
+	{0, "/NEW.26/Sfx Volume  Low  =========  High"},
+	{0, "Heap %dK"} // Non-translatable string
 };
 
 static const ResString string_map_table_v7[] = {
@@ -106,9 +107,8 @@ static const ResString string_map_table_v7[] = {
 	{79, "/BOOT.017/Saving '%s'"},
 	{80, "/BOOT.018/Loading '%s'"},
 	{76, "/BOOT.019/Name your SAVE game"},
-	{77, "/BOOT.020/Select a game to LOAD"}
-
-	/* This is the complete string map for v7
+	{77, "/BOOT.020/Select a game to LOAD"},
+	// Original GUI strings
 	{68, "/BOOT.007/c:\\dig"},
 	{69, "/BOOT.021/The Dig"},
 	{70, "/BOOT.008/Save"},
@@ -135,13 +135,18 @@ static const ResString string_map_table_v7[] = {
 	{93, "/BOOT.025/disabled"},
 	{94, "/BOOT.026/Text speed"},
 	{95, "/BOOT.027/Display Text"},
-	{96, "The Dig v1.0"},
-	{138, "/BOOT.028/Spooled Music"),
+	{96, "game name and version"},
+	{138, "/BOOT.028/Spooled Music"},
 	{139, "/BOOT.029/Do you want to replace this saved game?  (Y/N)"},
-	{141, "Voice Only"},
-	{142, "Voice and Text"},
-	{143, "Text Display Only"}, */
-
+	{141, "/NEW.020/Voice Only"},
+	{142, "/NEW.021/Voice and Text"},
+	{143, "/NEW.022/Text Display Only"},
+	{145, "/NEW.023/Text Speed   Slow  ==========  Fast"},
+	{147, "/NEW.024/Music Volume    Low  =========  High"},
+	{149, "/NEW.025/Voice Volume    Low  =========  High"},
+	{151, "/NEW.026/SFX Volume    Low  =========  High"},
+	{144, "Heap %dK"},
+	{0, "iMuse buffer count changed to %d"} // Not in the original
 };
 
 static const ResString string_map_table_v6[] = {
@@ -411,19 +416,33 @@ void InfoDialog::reflowLayout() {
 }
 
 const char *InfoDialog::getPlainEngineString(int stringno) {
+	//char buf[256];
+	const char *result;
+
 	if (stringno == 0)
 		return nullptr;
 
-	if (_vm->_game.version == 8)
+	if (_vm->_game.version == 8) {
 		return (const char *)string_map_table_v8[stringno - 1].string;
-	else if (_vm->_game.version == 7)
-		return (const char *)_vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
-	else if (_vm->_game.version == 6)
-		return (const char *)_vm->getStringAddressVar(string_map_table_v6[stringno - 1].num);
-	else if (_vm->_game.version >= 3)
-		return (const char *)_vm->getStringAddress(getStaticResString(_vm->_language, stringno - 1).num);
-	else
-		return (const char *)(getStaticResString(_vm->_language, stringno - 1).string);
+	} else if (_vm->_game.version == 7) {
+		result = (const char *)_vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
+
+		if (!result) {
+			result = (const char *)_vm->VAR(string_map_table_v7[stringno - 1].num);
+		}
+
+		if (!result) {
+			result = (const char *)string_map_table_v7[stringno - 1].string;
+		}
+	} else if (_vm->_game.version == 6) {
+		result = (const char *)_vm->getStringAddressVar(string_map_table_v6[stringno - 1].num);
+	} else if (_vm->_game.version >= 3) {
+		result = (const char *)_vm->getStringAddress(string_map_table_v345[stringno - 1].num);
+	} else {
+		result = (const char *)(string_map_table_v345[stringno - 1].string);
+	}
+
+	return result;
 }
 
 void decodeV2String(Common::Language lang, Common::String &str) {
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 394397c836a..9532489f208 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -1581,6 +1581,11 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) {
 }
 
 void ScummEngine::drawLine(int x1, int y1, int x2, int y2, int color) {
+	if (_game.platform == Common::kPlatformFMTowns) {
+		drawBox(x1, y1, x2, y2, color);
+		return;
+	}
+
 	int effColor, black, white;
 	int effX1, effY1;
 	int width, height, widthAccumulator, heightAccumulator, horizontalStrips, originalHeight;
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index a1eb8616b92..eeec4a8c1e5 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -77,6 +77,7 @@ 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;
@@ -95,16 +96,22 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	vsnprintf(bannerMsg, sizeof(bannerMsg), localizedMsg, va);
 	va_end(va);
 
+	// Fetch the localized confirmation letter and substitute it with the 'y' of 'yes'
+	if (_game.version == 8) {
+		convertMessageToString((const byte *)getGUIString(gsYesKey), (byte *)localizedY, sizeof(localizedY));
+	}
+
 	// Pause the engine
 	PauseToken pt = pauseEngine();
 
 	// Gather the colors needed for the banner
-	normalFillColor = getBannerColor(6 * bannerId + 15);
-	normalTextColor = getBannerColor(6 * bannerId + 14);
-	topLineColor = getBannerColor(6 * bannerId + 16);
-	bottomLineColor = getBannerColor(6 * bannerId + 17);
-	leftLineColor = getBannerColor(6 * bannerId + 18);
-	rightLineColor = getBannerColor(6 * bannerId + 19);
+	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);
 
 	// Backup the current charsetId, since we're going to switch
 	// to charsetId == 1...
@@ -120,21 +127,64 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		bannerMsgWidth = 100;
 
 	roundedWidth = (((bannerMsgWidth + 15) & 0xFFF0) + 8) / 2;
-	startingPointX = _screenWidth / 2 - roundedWidth - 4;
-	startingPointY = _screenHeight / 2 - 10;
-	xPos = _screenWidth / 2 + roundedWidth + 3;
-	yPos = 1 - bannerMsgHeight;
+	if (_game.version < 7) {
+		roundedWidth = bannerMsgWidth / 2;
+	}
+
+	if (_game.version >= 7 && _game.id != GID_FT) {
+		startingPointX = _screenWidth / 2 - roundedWidth - 4;
+		startingPointY = _screenHeight / 2 - 10;
+		xPos = _screenWidth / 2 + roundedWidth + 3;
+		yPos = 1 - bannerMsgHeight;
+		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 = 1; // Bogus value, since it is unused
+		yPos = 1; // Bogus value, since it is unused
+		bannerSaveYStart = 78;
+	} else {
+		startingPointX = 156 - roundedWidth;
+		startingPointY = ((_game.version < 7) ? 80 : _screenTop + 90);
+		xPos = roundedWidth + 163 + ((_game.version < 7) ? 1 : 0);
+		yPos = -12;
+		bannerSaveYStart = startingPointY - ((_game.version < 7) ? 2 : 0);
+	}
 
 	// 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 * (_screenWidth + 8);
-		_bannerMem = (byte *)malloc(bannerMsgHeight * (_screenWidth + 8) * sizeof(byte));
-		if (_bannerMem)
+		_bannerMem = (byte *)malloc(_bannerMemSize * sizeof(byte));
+		if (_bannerMem) {
+			// 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
+
 			memcpy(
 				_bannerMem,
-				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[(_screenWidth + 8) * (_screenHeight / 2 - 10)],
+				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * bannerSaveYStart],
 				_bannerMemSize);
+		}
 	}
 
 	// Set up the GUI control, specifying all the related colors, the message and the position...
@@ -163,11 +213,10 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	if (oldId)
 		_charset->setCurID(oldId);
 
-	// Fetch the localized confirmation letter and substitute it with the 'y' of 'yes'
-	convertMessageToString((const byte *)getGUIString(gsYesKey), (byte *)localizedY, sizeof(localizedY));
-
-	if (tolower(localizedY[0]) == ks.ascii || toupper((localizedY[0]) == ks.ascii))
-		ks = Common::KEYCODE_y;
+	if (_game.version == 8) {
+		if (tolower(localizedY[0]) == ks.ascii || toupper(localizedY[0]) == ks.ascii)
+			ks = Common::KEYCODE_y;
+	}
 
 	return ks;
 }
@@ -176,23 +225,52 @@ 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;
 		// 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
 		// screen for next frame.
 		if (!isSmushActive()) {
+			int startingPointY;
+			if (_game.version >= 7 && _game.id != GID_FT) {
+				startingPointY = _screenHeight / 2 - 10;
+			} else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformFMTowns) {
+				startingPointY = 78;
+			} else {
+				startingPointY = ((_game.version < 7) ? 80 - 2 : _screenTop + 90);
+			}
+
+			// 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) {
+				startingPointY *= _textSurfaceMultiplier;
+				rowSize *= _textSurfaceMultiplier;
+				memcpy(
+					&((byte *)_textSurface.getBasePtr(0, _screenTop * _textSurfaceMultiplier))[rowSize * startingPointY],
+					_textSurfBannerMem,
+					_textSurfBannerMemSize);
+
+				// We're going to use these same values for restoring the
+				// virtual screen surface, so let's un-multiply them...
+				rowSize /= _textSurfaceMultiplier;
+				startingPointY /= _textSurfaceMultiplier;
+			}
+#endif
 			memcpy(
-				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[(_screenWidth + 8) * (_screenHeight / 2 - 10)],
+				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * startingPointY],
 				_bannerMem,
 				_bannerMemSize);
 
-			markRectAsDirty(_virtscr[kMainVirtScreen].number, 0, _screenWidth + 8, _screenTop, _screenHeight + _screenTop);
+			markRectAsDirty(_virtscr[kMainVirtScreen].number, 0, rowSize, _screenTop, _screenHeight + _screenTop);
 			ScummEngine::drawDirtyScreenParts();
 			_system->updateScreen();
 		}
 
 		free(_bannerMem);
 		_bannerMem = nullptr;
+
+		free(_textSurfBannerMem);
+		_textSurfBannerMem = nullptr;
 	}
 }
 
@@ -205,11 +283,6 @@ void ScummEngine::setBannerColors(int bannerId, byte r, byte g, byte b) {
 	_bannerColors[bannerId] = r | (b << 16) | (g << 8);
 }
 
-int ScummEngine_v7::getBannerColor(int bannerId) {
-	byte *palette = isSmushActive() ? _splayer->getVideoPalette() : _currentPalette;
-	return ScummEngine::getBannerColor(bannerId, palette);
-}
-
 void ScummEngine::setUpInternalGUIControl(int id, int normalFillColor, int normalTextColor,
 										  int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
 										  int highlightedTextColor, int highlightedFillColor,
@@ -247,6 +320,7 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 	int x, y, textXPos, textYPos;
 	int textColor, fillColor;
 	int boxSizeX, boxSizeY;
+	int offset = (_game.version >= 7 && _game.id != GID_FT) ? 2 : 1;
 
 	bool centerFlag;
 	char buttonString[512];
@@ -258,37 +332,54 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 		x = ctrl->xPos;
 		y = ctrl->yPos;
 
-		boxSizeX = x - ctrl->relativeCenterX;
-		boxSizeY = y - relCentY;
+		boxSizeX = x - ((_game.version >= 7 && _game.id != GID_FT) ? ctrl->relativeCenterX : 0);
+		boxSizeY = y - ((_game.version >= 7 && _game.id != GID_FT) ? relCentY : 0);
 
 		fillColor = highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor;
 
-		// Draw the main box...
-		drawBox(relCentX + 1, relCentY + 1, boxSizeX - 2, boxSizeY - 2, fillColor);
-
-		// 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);
+		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, 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);
+			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);
+		} else {
+			// Draw the main box...
+			drawBox(relCentX + 1, relCentY + 1, boxSizeX - offset, boxSizeY - offset, fillColor);
+
+			// 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);
+		}
 
 		// Calculate the positioning for the text
 		int oldId = _charset->getCurID();
 		_charset->setCurID(1);
-		textHeight = getGUIStringHeight(buttonString);
+
 		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(buttonString);
 
-		if (centerFlag)
-			textXPos = relCentX + boxSizeX / 2;
-		else
-			textXPos = relCentX + 2;
+			if (centerFlag)
+				textXPos = relCentX + (x - ctrl->relativeCenterX) / 2;
+			else
+				textXPos = relCentX + 2;
 
-		textYPos = relCentY + (boxSizeY - textHeight) / 2 + 1;
+			textYPos = relCentY + ((y - relCentY) - textHeight) / 2 + 1;
+		}
 
 		// Finally, choose the color and draw the text message
 		if (highlightColor)
@@ -561,6 +652,9 @@ const char *ScummEngine_v8::getGUIString(int stringId) {
 	case gsSfxVolume:
 		resStringId = 34;
 		break;
+	case gsHeap:
+		resStringId = 35;
+		break;
 	default:
 		return "";
 	}
@@ -577,40 +671,61 @@ const char *ScummEngine_v7::getGUIString(int stringId) {
 
 	switch (stringId) {
 	case gsPause:
+		resStringId = 4;
 		break;
 	case gsVersion:
-		break;
-	case gsTextSpeed:
+		resStringId = 47;
 		break;
 	case gsRestart:
+		resStringId = 5;
 		break;
 	case gsQuitPrompt:
+		resStringId = 6;
 		break;
 	case gsSave:
+		resStringId = 7;
 		break;
 	case gsLoad:
+		resStringId = 8;
 		break;
 	case gsPlay:
+		resStringId = 9;
 		break;
 	case gsCancel:
+		resStringId = 10;
 		break;
 	case gsQuit:
+		resStringId = 11;
 		break;
 	case gsOK:
+		resStringId = 12;
 		break;
 	case gsMustName:
+		resStringId = 14;
 		break;
 	case gsGameNotSaved:
+		resStringId = 15;
 		break;
 	case gsGameNotLoaded:
+		resStringId = 16;
 		break;
 	case gsSaving:
+		resStringId = 17;
 		break;
 	case gsLoading:
+		resStringId = 18;
 		break;
 	case gsNamePrompt:
+		resStringId = 19;
 		break;
 	case gsSelectLoadPrompt:
+		resStringId = 20;
+		break;
+	case gsSavePath:
+		resStringId = 21;
+		break;
+	case gsTitle:
+		resStringId = 22;
 		break;
 	case gsReplacePrompt:
 		break;
@@ -618,19 +733,32 @@ const char *ScummEngine_v7::getGUIString(int stringId) {
 		break;
 	case gsNo:
 		break;
-	case gsIMuseBuffer:
+	case gsVoiceOnly:
+		resStringId = 50;
 		break;
 	case gsVoiceAndText:
+		resStringId = 51;
 		break;
 	case gsTextDisplayOnly:
+		resStringId = 52;
 		break;
-	case gsYesKey:
+	case gsTextSpeed:
+		resStringId = 53;
 		break;
 	case gsMusicVolume:
+		resStringId = 54;
 		break;
 	case gsVoiceVolume:
+		resStringId = 55;
 		break;
 	case gsSfxVolume:
+		resStringId = 56;
+		break;
+	case gsHeap:
+		resStringId = 57;
+		break;
+	case gsIMuseBuffer:
+		resStringId = 58;
 		break;
 	default:
 		return "";
@@ -654,21 +782,70 @@ void ScummEngine_v7::drawGUIText(const char *buttonString, int textXPos, int tex
 	drawTextImmediately((const byte *)buttonString, textXPos, textYPos, textColor, 1, (TextStyleFlags)centerFlag);
 }
 
+int ScummEngine_v7::getBannerColor(int bannerId) {
+	if (_game.version == 8) {
+		byte *palette = isSmushActive() ? _splayer->getVideoPalette() : _currentPalette;
+		byte r, g, b;
+		r = (_bannerColors[bannerId] >> 0) & 0xFF;
+		g = (_bannerColors[bannerId] >> 8) & 0xFF;
+		b = (_bannerColors[bannerId] >> 16) & 0xFF;
+		return getPaletteColorFromRGB(palette, r, g, b);
+	}
+
+	int color = readArray(88, 0, bannerId);
+	if (isSmushActive()) {
+		color = (int)getPaletteColorFromRGB(_splayer->getVideoPalette(),
+											_currentPalette[3 * color + 0],
+											_currentPalette[3 * color + 1],
+											_currentPalette[3 * color + 2]);
+	}
+
+	return color;
+}
 #endif
 
-int ScummEngine::getBannerColor(int bannerId, byte *palette) {
-	byte r, g, b;
-	r = (_bannerColors[bannerId] >> 0) & 0xFF;
-	g = (_bannerColors[bannerId] >> 8) & 0xFF;
-	b = (_bannerColors[bannerId] >> 16) & 0xFF;
-	return getPaletteColorFromRGB(palette, r, g, b);
+int ScummEngine_v6::getBannerColor(int bannerId) {
+	return readArray(110, 0, bannerId);
+}
+
+int ScummEngine::getBannerColor(int bannerId) {
+	byte *arrAddr = getResourceAddress(rtString, 21);
+	return (int)arrAddr[bannerId];
 }
 
 void ScummEngine::queryQuit() {
-	// "Are you sure you want to quit?  (Y-N)"
-	Common::KeyState ks = showBannerAndPause(0, -1, getGUIString(gsQuitPrompt));
-	if (ks.keycode == Common::KEYCODE_y) {
-		quitGame();
+	char msgLabelPtr[512];
+	char localizedYesKey;
+
+	convertMessageToString((const byte *)getGUIString(gsQuitPrompt), (byte *)msgLabelPtr, sizeof(msgLabelPtr));
+	if (msgLabelPtr[0] != '\0') {
+		localizedYesKey = msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1];
+		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
+
+		// "Are you sure you want to quit?  (Y-N)"
+		Common::KeyState ks = showBannerAndPause(0, -1, msgLabelPtr);
+
+		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) {
+			quitGame();
+		}
+	}
+}
+
+void ScummEngine::queryRestart() {
+	char msgLabelPtr[512];
+	char localizedYesKey;
+
+	convertMessageToString((const byte *)getGUIString(gsRestart), (byte *)msgLabelPtr, sizeof(msgLabelPtr));
+	if (msgLabelPtr[0] != '\0') {
+		localizedYesKey = msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1];
+		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
+
+		// "Are you sure you want to quit?  (Y-N)"
+		Common::KeyState ks = showBannerAndPause(0, -1, msgLabelPtr);
+
+		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) {
+			restart();
+		}
 	}
 }
 
@@ -690,46 +867,87 @@ void ScummEngine::drawGUIText(const char *buttonString, int textXPos, int textYP
 	drawString(4, (const byte *)buttonString);
 }
 
-const char *ScummEngine::getGUIString(int stringId) {
+void ScummEngine::getSliderString(int stringId, int value, char *sliderString, int size) {
+	char *ptrToChar;
+	char tempStr[256];
+
+	strcpy(tempStr, getGUIString(stringId));
+	convertMessageToString((const byte *)tempStr, (byte *)sliderString, size);
+
+	ptrToChar = strchr(sliderString, '=');
+
+	if (!ptrToChar) {
+		ptrToChar = strstr(sliderString, "xxx");
+	}
+
+	if (ptrToChar) {
+		if (stringId == gsTextSpeed) {
+			memset(ptrToChar, '\v', 10);
+			ptrToChar[9 - value] = '\f';
+		} else {
+			memset(ptrToChar, '\v', 9);
+			ptrToChar[value / 15] = '\f';
+		}
+	}
+}
+
+const char *ScummEngine_v6::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
 
 	switch (stringId) {
 	case gsPause:
-		break;
-	case gsVersion:
+		resStringId = 4;
 		break;
 	case gsTextSpeed:
 		break;
 	case gsRestart:
+		resStringId = 5;
 		break;
 	case gsQuitPrompt:
+		resStringId = 6;
 		break;
 	case gsSave:
+		resStringId = 7;
 		break;
 	case gsLoad:
+		resStringId = 8;
 		break;
 	case gsPlay:
+		resStringId = 9;
 		break;
 	case gsCancel:
+		resStringId = 10;
 		break;
 	case gsQuit:
+		resStringId = 11;
 		break;
 	case gsOK:
+		resStringId = 12;
 		break;
 	case gsMustName:
+		resStringId = 14;
 		break;
 	case gsGameNotSaved:
+		resStringId = 15;
 		break;
 	case gsGameNotLoaded:
+		resStringId = 16;
 		break;
 	case gsSaving:
+		resStringId = 17;
 		break;
 	case gsLoading:
+		resStringId = 18;
 		break;
 	case gsNamePrompt:
+		resStringId = 19;
 		break;
 	case gsSelectLoadPrompt:
+		resStringId = 20;
+		break;
+	case gsTitle:
+		resStringId = 21;
 		break;
 	case gsReplacePrompt:
 		break;
@@ -752,7 +970,95 @@ const char *ScummEngine::getGUIString(int stringId) {
 	case gsSfxVolume:
 		break;
 	case gsHeap:
-		return "Heap %d";
+		return "Heap %dK";
+	default:
+		return "";
+	}
+
+	if (resStringId > 0)
+		return d.getPlainEngineString(resStringId);
+	else
+		return "";
+}
+
+const char *ScummEngine::getGUIString(int stringId) {
+	InfoDialog d(this, 0);
+	int resStringId = -1;
+
+	switch (stringId) {
+	case gsPause:
+		resStringId = 4;
+		break;
+	case gsVersion:
+		break;
+	case gsTextSpeed:
+		break;
+	case gsRestart:
+		resStringId = 5;
+		break;
+	case gsQuitPrompt:
+		resStringId = 6;
+		break;
+	case gsSave:
+		resStringId = 7;
+		break;
+	case gsLoad:
+		resStringId = 8;
+		break;
+	case gsPlay:
+		resStringId = 9;
+		break;
+	case gsCancel:
+		resStringId = 10;
+		break;
+	case gsQuit:
+		resStringId = 11;
+		break;
+	case gsOK:
+		resStringId = 12;
+		break;
+	case gsMustName:
+		resStringId = 13;
+		break;
+	case gsGameNotSaved:
+		resStringId = 14;
+		break;
+	case gsGameNotLoaded:
+		resStringId = 15;
+		break;
+	case gsSaving:
+		resStringId = 16;
+		break;
+	case gsLoading:
+		resStringId = 17;
+		break;
+	case gsNamePrompt:
+		resStringId = 18;
+		break;
+	case gsSelectLoadPrompt:
+		resStringId = 19;
+		break;
+	case gsReplacePrompt:
+		break;
+	case gsYes:
+		break;
+	case gsNo:
+		break;
+	case gsVoiceAndText:
+		break;
+	case gsTextDisplayOnly:
+		break;
+	case gsMusicVolume:
+		break;
+	case gsVoiceVolume:
+		break;
+	case gsSfxVolume:
+		break;
+	case gsHeap:
+		return "Heap %dK";
+	case gsTitle:
+		resStringId = 20;
+		break;
 	default:
 		return "";
 	}
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index a0d5dfba346..beef7632228 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -398,8 +398,6 @@ void ScummEngine::processInput() {
 #ifdef ENABLE_SCUMM_7_8
 void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 	if (isUsingOriginalGUI()) {
-		char tempStr[64];
-
 		if (lastKeyHit.keycode == Common::KEYCODE_INVALID)
 			return;
 
@@ -418,74 +416,21 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 				runScript(_keyScriptNo, 0, 0, 0);
 			return;
 		}
+	}
 
-		if (lastKeyHit.keycode == VAR(VAR_PAUSE_KEY) ||
-			(lastKeyHit.keycode == Common::KEYCODE_SPACE && _game.features & GF_DEMO)) {
-			// Force the cursor OFF...
-			int8 oldCursorState = _cursor.state;
-			_cursor.state = 0;
-			CursorMan.showMouse(_cursor.state > 0);
-			// "Game Paused.  Press SPACE to Continue."
-			showBannerAndPause(0, -1, getGUIString(gsPause));
-			_cursor.state = oldCursorState;
-			return;
-		}
-
-		if (VAR(VAR_VERSION_KEY) != 0 &&
-			lastKeyHit.keycode == Common::KEYCODE_v && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-			showBannerAndPause(0, -1, _dataFileVersionString);
-			// This is not the string being used by the interpreter, which is instead hardcoded
-			// in the executable. The one used here is found in the data files.
-			showBannerAndPause(0, -1, _engineVersionString);
-			return;
-		}
-
-		if (lastKeyHit.keycode == Common::KEYCODE_c && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-			queryQuit();
-			return;
-		}
-
-		if (lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-			int voiceMode = VAR(VAR_VOICE_MODE);
-
-			voiceMode++;
-			if (voiceMode >= 3) {
-				voiceMode = 0;
-			}
+	// F1 (the trigger for the original save/load dialog) is mapped to F5
+	if (!(_game.features & GF_DEMO) && lastKeyHit.keycode == Common::KEYCODE_F1 && lastKeyHit.hasFlags(0)) {
+		lastKeyHit = Common::KeyState(Common::KEYCODE_F5, 319);
+	}
 
-			switch (voiceMode) {
-			case 0: // "Voice Only"
-				showBannerAndPause(0, 120, getGUIString(gsVoiceOnly));
-				break;
-			case 1: // "Voice and Text"
-				showBannerAndPause(0, 120, getGUIString(gsVoiceAndText));
-				break;
-			default: // "Text Display Only"
-				showBannerAndPause(0, 120, getGUIString(gsTextDisplayOnly));
-			}
+	// Fall back to V7 behavior...
+	ScummEngine_v7::processKeyboard(lastKeyHit);
 
-			ConfMan.setInt("original_gui_text_status", voiceMode);
-			switch (voiceMode) {
-			case 0:
-				ConfMan.setBool("speech_mute", false);
-				ConfMan.setBool("subtitles", false);
-				break;
-			case 1:
-				ConfMan.setBool("speech_mute", false);
-				ConfMan.setBool("subtitles", true);
-				break;
-			case 2:
-				ConfMan.setBool("speech_mute", true);
-				ConfMan.setBool("subtitles", true);
-				break;
-			default:
-				break;
-			}
+}
 
-			ConfMan.flushToDisk();
-			syncSoundSettings();
-			return;
-		}
+void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
+	if (isUsingOriginalGUI()) {
+		char sliderString[256];
 
 		if (lastKeyHit.keycode == Common::KEYCODE_b && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 			int curBufferCount = _imuseDigital->roundRobinSetBufferCount();
@@ -494,7 +439,7 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 			return;
 		}
 
-		if (_game.features & GF_DEMO) {
+		if (_game.version != 8 || (_game.version == 8 && (_game.features & GF_DEMO))) {
 			// "Music Volume  Low  =========  High"
 			if (lastKeyHit.keycode == Common::KEYCODE_o || lastKeyHit.keycode == Common::KEYCODE_p) {
 				Common::KeyState ks = lastKeyHit;
@@ -514,12 +459,8 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 							volume = 127;
 					}
 
-					strcpy(tempStr, getGUIString(gsMusicVolume));
-					char *ptrToChar = strchr(tempStr, '=');
-					memset(ptrToChar, '\v', 9);
-					ptrToChar[volume / 15] = '\f';
-
-					showBannerAndPause(0, 0, tempStr);
+					getSliderString(gsMusicVolume, volume, sliderString, sizeof(sliderString));
+					showBannerAndPause(0, 0, sliderString);
 					ks = Common::KEYCODE_INVALID;
 					bool leftBtnPressed = false, rightBtnPressed = false;
 					waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
@@ -552,12 +493,8 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 							volume = 127;
 					}
 
-					strcpy(tempStr, getGUIString(gsVoiceVolume));
-					char *ptrToChar = strchr(tempStr, '=');
-					memset(ptrToChar, '\v', 9);
-					ptrToChar[volume / 15] = '\f';
-
-					showBannerAndPause(0, 0, tempStr);
+					getSliderString(gsVoiceVolume, volume, sliderString, sizeof(sliderString));
+					showBannerAndPause(0, 0, sliderString);
 					ks = Common::KEYCODE_INVALID;
 					bool leftBtnPressed = false, rightBtnPressed = false;
 					waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
@@ -590,12 +527,8 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 							volume = 127;
 					}
 
-					strcpy(tempStr, getGUIString(gsSfxVolume));
-					char *ptrToChar = strchr(tempStr, '=');
-					memset(ptrToChar, '\v', 9);
-					ptrToChar[volume / 15] = '\f';
-
-					showBannerAndPause(0, 0, tempStr);
+					getSliderString(gsSfxVolume, volume, sliderString, sizeof(sliderString));
+					showBannerAndPause(0, 0, sliderString);
 					ks = Common::KEYCODE_INVALID;
 					bool leftBtnPressed = false, rightBtnPressed = false;
 					waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
@@ -630,12 +563,8 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 							VAR(VAR_CHARINC) = 9;
 					}
 
-					strcpy(tempStr, getGUIString(gsTextSpeed));
-					char *ptrToChar = strchr(tempStr, '=');
-					memset(ptrToChar, '\v', 10);
-					ptrToChar[9 - VAR(VAR_CHARINC)] = '\f';
-
-					showBannerAndPause(0, 0, tempStr);
+					getSliderString(gsTextSpeed, VAR(VAR_CHARINC), sliderString, sizeof(sliderString));
+					showBannerAndPause(0, 0, sliderString);
 					ks = Common::KEYCODE_INVALID;
 					bool leftBtnPressed = false, rightBtnPressed = false;
 					waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
@@ -650,17 +579,6 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 		}
 	}
 
-	// F1 (the trigger for the original save/load dialog) is mapped to F5
-	if (!(_game.features & GF_DEMO) && lastKeyHit.keycode == Common::KEYCODE_F1 && lastKeyHit.hasFlags(0)) {
-		lastKeyHit = Common::KeyState(Common::KEYCODE_F5, 319);
-	}
-
-	// Fall back to V7 behavior...
-	ScummEngine_v7::processKeyboard(lastKeyHit);
-
-}
-
-void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 	const bool cutsceneExitKeyEnabled = (VAR_CUTSCENEEXIT_KEY == 0xFF || VAR(VAR_CUTSCENEEXIT_KEY) != 0);
 
 	// VAR_VERSION_KEY (usually ctrl-v) is used in COMI, Dig and FT to trigger
@@ -669,7 +587,8 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 	// versionDialog for it. Dig/FT version strings are partly hard coded, too.
 	if (_game.id != GID_CMI && 0 != VAR(VAR_VERSION_KEY) &&
 	    lastKeyHit.keycode == Common::KEYCODE_v && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-		versionDialog();
+		if (!isUsingOriginalGUI())
+			versionDialog();
 
 	} else if (cutsceneExitKeyEnabled && lastKeyHit.keycode == Common::KEYCODE_ESCAPE) {
 		// Skip cutscene (or active SMUSH video).
@@ -745,32 +664,98 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 }
 
 void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) {
-	if (lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-		SubtitleSettingsDialog dialog(this, _voiceMode);
-		_voiceMode = runDialog(dialog);
-
-		switch (_voiceMode) {
-		case 0:
-			ConfMan.setBool("speech_mute", false);
-			ConfMan.setBool("subtitles", false);
-			break;
-		case 1:
-			ConfMan.setBool("speech_mute", false);
-			ConfMan.setBool("subtitles", true);
-			break;
-		case 2:
-			ConfMan.setBool("speech_mute", true);
-			ConfMan.setBool("subtitles", true);
-			break;
-		default:
-			break;
+	if (isUsingOriginalGUI()) {
+		if (VAR_VERSION_KEY != 0xFF && VAR(VAR_VERSION_KEY) != 0 &&
+			lastKeyHit.keycode == Common::KEYCODE_v && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+			if (_game.version == 8) {
+				showBannerAndPause(0, -1, _dataFileVersionString);
+				// This is not the string being used by the interpreter, which is instead hardcoded
+				// in the executable. The one used here is found in the data files.
+				showBannerAndPause(0, -1, _engineVersionString);
+
+				if (_game.features & GF_DEMO)
+					showBannerAndPause(0, -1, "iMuse(tm) initialized");
+			} else if (_game.version == 7) {
+				showBannerAndPause(0, -1, getGUIString(gsVersion));
+				showBannerAndPause(0, -1, "Scripts compiled %s", _dataFileVersionString);
+				showBannerAndPause(0, -1, "SPU(tm) version %s", _engineVersionString);
+				showBannerAndPause(0, -1, "iMuse(tm) initialized");
+			}
+
+			return;
 		}
 
-		// We need to sync the current sound settings here to make sure that
-		// we actually update the mute state of speech properly.
-		syncSoundSettings();
 
-		return;
+		if (lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+			int voiceMode = VAR(VAR_VOICE_MODE);
+
+			voiceMode++;
+			if (voiceMode >= 3) {
+				voiceMode = 0;
+			}
+
+			switch (voiceMode) {
+			case 0: // "Voice Only"
+				showBannerAndPause(0, 120, getGUIString(gsVoiceOnly));
+				break;
+			case 1: // "Voice and Text"
+				showBannerAndPause(0, 120, getGUIString(gsVoiceAndText));
+				break;
+			default: // "Text Display Only"
+				showBannerAndPause(0, 120, getGUIString(gsTextDisplayOnly));
+			}
+
+			ConfMan.setInt("original_gui_text_status", voiceMode);
+			switch (voiceMode) {
+			case 0:
+				ConfMan.setBool("speech_mute", false);
+				ConfMan.setBool("subtitles", false);
+				break;
+			case 1:
+				ConfMan.setBool("speech_mute", false);
+				ConfMan.setBool("subtitles", true);
+				break;
+			case 2:
+				ConfMan.setBool("speech_mute", true);
+				ConfMan.setBool("subtitles", true);
+				break;
+			default:
+				break;
+			}
+
+			ConfMan.flushToDisk();
+			syncSoundSettings();
+			return;
+		}
+
+	} else {
+		if (lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+			SubtitleSettingsDialog dialog(this, _voiceMode);
+			_voiceMode = runDialog(dialog);
+
+			switch (_voiceMode) {
+			case 0:
+				ConfMan.setBool("speech_mute", false);
+				ConfMan.setBool("subtitles", false);
+				break;
+			case 1:
+				ConfMan.setBool("speech_mute", false);
+				ConfMan.setBool("subtitles", true);
+				break;
+			case 2:
+				ConfMan.setBool("speech_mute", true);
+				ConfMan.setBool("subtitles", true);
+				break;
+			default:
+				break;
+			}
+
+			// We need to sync the current sound settings here to make sure that
+			// we actually update the mute state of speech properly.
+			syncSoundSettings();
+
+			return;
+		}
 	}
 
 	// Fall back to default behavior
@@ -864,6 +849,35 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 	if (_game.platform == Common::kPlatformFMTowns)
 		restartKeyEnabled = true;
 
+	if (isUsingOriginalGUI()) {
+		if (pauseKeyEnabled && (lastKeyHit.ascii == VAR(VAR_PAUSE_KEY) ||
+			(lastKeyHit.keycode == Common::KEYCODE_SPACE && _game.features & GF_DEMO))) {
+			// Force the cursor OFF...
+			int8 oldCursorState = _cursor.state;
+			_cursor.state = 0;
+			CursorMan.showMouse(_cursor.state > 0);
+			// "Game Paused.  Press SPACE to Continue."
+			showBannerAndPause(0, -1, getGUIString(gsPause));
+			_cursor.state = oldCursorState;
+			return;
+		}
+
+		if (restartKeyEnabled && (lastKeyHit.ascii == VAR(VAR_RESTART_KEY))) {
+			queryRestart();
+			return;
+		}
+
+		if (lastKeyHit.keycode == Common::KEYCODE_k && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+			showBannerAndPause(0, 120, getGUIString(gsHeap), _res->getHeapSize() / 1024);
+			return;
+		}
+
+		if (lastKeyHit.keycode == Common::KEYCODE_c && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+			queryQuit();
+			return;
+		}
+	}
+
 	// For games which use VAR_MAINMENU_KEY, disable the mainmenu key if
 	// requested by the scripts. We make an exception for COMI (i.e.
 	// forcefully always enable it there), as that always disables it.
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 1c318e34f2c..81511232761 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -3108,7 +3108,7 @@ void ScummEngine::restart() {
 }
 
 bool ScummEngine::isUsingOriginalGUI() {
-	if (_game.version > 6)
+	if (_game.version > 4)
 		return _useOriginalGUI;
 
 	return false;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 3f80cef35ff..3635537e398 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -385,7 +385,9 @@ enum GUIString {
 	gsMusicVolume = 27,
 	gsVoiceVolume = 28,
 	gsSfxVolume = 29,
-	gsHeap = 30
+	gsHeap = 30,
+	gsSavePath = 31,
+	gsTitle = 32
 };
 
 struct InternalGUIControl {
@@ -556,6 +558,11 @@ protected:
 	int32 _bannerColors[50]; // Colors for the original GUI
 	byte *_bannerMem = nullptr;
 	uint32 _bannerMemSize = 0;
+
+	// The followings are needed for MI1 FM-Towns
+	byte *_textSurfBannerMem = nullptr;
+	uint32 _textSurfBannerMemSize = 0;
+
 	InternalGUIControl _internalGUIControls[30];
 	char _emptyMsg[1] = {'\0'};
 
@@ -563,8 +570,9 @@ protected:
 	Common::KeyState showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...);
 	void clearBanner();
 	void setBannerColors(int bannerId, byte r, byte g, byte b);
-	virtual int getBannerColor(int bannerId) { return getBannerColor(bannerId, _currentPalette); }
-	int getBannerColor(int bannerId, byte *palette);
+	//virtual int getBannerColor(int bannerId) { return getBannerColor(bannerId, _currentPalette); }
+	//int getBannerColor(int bannerId, byte *palette);
+	virtual int getBannerColor(int bannerId);
 	void setUpInternalGUIControl(int id, int normalFillColor, int normalTextColor,
 								 int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
 								 int highlightedTextColor, int highlightedFillColor,
@@ -574,11 +582,13 @@ protected:
 	virtual bool isSmushActive() { return false; }
 
 	virtual void queryQuit();
+	virtual void queryRestart();
 	virtual const char *getGUIString(int stringId);
 	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked);
 	virtual int getGUIStringHeight(const char *str);
 	virtual int getGUIStringWidth(const char *str);
 	virtual void drawGUIText(const char *buttonString, int textXPos, int textYPos, int textColor, bool centerFlag);
+	void getSliderString(int stringId, int value, char *sliderString, int size);
 
 public:
 	char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index 512c3850b7c..a010af2f1e3 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -163,6 +163,9 @@ protected:
 
 	void clearDrawQueues() override;
 
+	int getBannerColor(int bannerId) override;
+	const char *getGUIString(int stringId) override;
+
 public:
 	bool akos_increaseAnims(const byte *akos, Actor *a);
 	bool akos_increaseAnim(Actor *a, int i, const byte *aksq, const uint16 *akfo, int numakfo);
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index b233dc4e874..2a79c4da053 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -153,8 +153,13 @@ void ScummEngine::showMessageDialog(const byte *msg) {
 	if (_string[3].color == 0)
 		_string[3].color = 4;
 
-	InfoDialog dialog(this, Common::U32String((char *)buf));
-	VAR(VAR_KEYPRESS) = runDialog(dialog);
+	if (isUsingOriginalGUI()) {
+		VAR(VAR_KEYPRESS) = showBannerAndPause(0, -1, (const char *)msg).ascii;
+	} else {
+		InfoDialog dialog(this, Common::U32String((char *)buf));
+		VAR(VAR_KEYPRESS) = runDialog(dialog);
+	}
+
 }
 
 #pragma mark -


Commit: 457bcb67dbfc7f86de3e5139c5f8b4b659cedd4a
    https://github.com/scummvm/scummvm/commit/457bcb67dbfc7f86de3e5139c5f8b4b659cedd4a
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Implement the majority of the v7 Main Menu

Changed paths:
    engines/scumm/cursor.cpp
    engines/scumm/dialogs.cpp
    engines/scumm/gfx.cpp
    engines/scumm/gfx_gui.cpp
    engines/scumm/imuse_digi/dimuse_engine.cpp
    engines/scumm/imuse_digi/dimuse_engine.h
    engines/scumm/imuse_digi/dimuse_scripts.cpp
    engines/scumm/input.cpp
    engines/scumm/script.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v6.h
    engines/scumm/scumm_v7.h
    engines/scumm/scumm_v8.h
    engines/scumm/sound.cpp
    engines/scumm/sound.h


diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index 1048a50c985..9fbd974d944 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -91,6 +91,21 @@ 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 default_v7_cursor[] = {
+	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
+	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
+	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
+	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
+	0x00,0x00,0x00,0x00, 0x01,0x01,0x01, 0x00,0x00,0x00,0x00,
+	0x0F,0x0F,0x0F,0x0F, 0x01,0x01,0x01, 0x0F,0x0F,0x0F,0x0F,
+	0x00,0x00,0x00,0x00, 0x01,0x01,0x01, 0x00,0x00,0x00,0x00,
+	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
+	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
+	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
+	0x01,0x01,0x01,0x01, 0x00,0x0F,0x00, 0x01,0x01,0x01,0x01,
+	0x00,0x00,0x00,
+};
+
 static const byte default_v8_cursor[] = {
 	0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
 	0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE, 0x00,0x0F,0x0F,0x00, 0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
@@ -147,7 +162,7 @@ void ScummEngine_v6::setCursorTransparency(int a) {
 	} else {
 		for (i = 0; i < size; i++)
 			if (_grabbedCursor[i] == (byte)a)
-				_grabbedCursor[i] = 0xFF;
+				_grabbedCursor[i] = 0x01;
 	}
 
 	updateCursor();
@@ -188,6 +203,38 @@ void ScummEngine_v6::setDefaultCursor() {
 
 #ifdef ENABLE_SCUMM_7_8
 void ScummEngine_v7::setDefaultCursor() {
+	byte *palette = isSmushActive() ? _splayer->getVideoPalette() : _currentPalette;
+	byte cursorBuffer[124];
+	byte cursorPixel;
+	int black, white, inverseRgbIdx;
+	int rgbIdx = 0;
+
+	do {
+		black = getPaletteColorFromRGB(palette, rgbIdx, rgbIdx, rgbIdx);
+		++rgbIdx;
+	} while (black == 1 && rgbIdx != 100);
+	rgbIdx = 0;
+
+	do {
+		inverseRgbIdx = 0xFF - rgbIdx++;
+		white = getPaletteColorFromRGB(palette, inverseRgbIdx, inverseRgbIdx, inverseRgbIdx);
+	} while (white == 1 && rgbIdx != 100);
+
+	for (int i = 0; i < ARRAYSIZE(default_v7_cursor); i++) {
+		cursorPixel = default_v7_cursor[i];
+
+		if (cursorPixel == 0x0F)
+			cursorPixel = white;
+
+		cursorBuffer[i] = (byte)(cursorPixel & 0xFF);
+	}
+
+	setCursorHotspot(5, 5);
+	setCursorFromBuffer(cursorBuffer, 11, 11, 11);
+	setCursorTransparency(0x01);
+}
+
+void ScummEngine_v8::setDefaultCursor() {
 	byte *palette = isSmushActive() ? _splayer->getVideoPalette() : _currentPalette;
 	byte cursorBuffer[400];
 	byte cursorPixel;
@@ -230,20 +277,32 @@ void ScummEngine_v7::setDefaultCursor() {
 	setCursorTransparency(0xFE);
 }
 
-void ScummEngine_v8::setCursorTransparency(int a) {
+void ScummEngine_v7::setCursorTransparency(int a) {
 	int i, size;
 
 	size = _cursor.width * _cursor.height;
 
-	for (i = 0; i < size; i++)
-		if (_grabbedCursor[i] == (byte)a)
-			_grabbedCursor[i] = isSmushActive() ? 0xFE : 0xFF;
+	for (i = 0; i < size; i++) {
+		if (_grabbedCursor[i] == (byte)a) {
+			if (_game.version == 8) {
+				_grabbedCursor[i] = isSmushActive() ? 0xFE : 0xFF;
+			} else {
+				_grabbedCursor[i] = isSmushActive() ? 0x01 : 0xFF;
+			}
+		}
+	}
 
 	updateCursor();
 }
 
-void ScummEngine_v8::updateCursor() {
-	int transColor = isSmushActive() ? 0xFE : 0xFF;
+void ScummEngine_v7::updateCursor() {
+	int transColor;
+	if (_game.version == 8) {
+		transColor = isSmushActive() ? 0xFE : 0xFF;
+	} else {
+		transColor = isSmushActive() ? 0x01 : 0xFF;
+	}
+
 #ifdef USE_RGB_COLOR
 	Graphics::PixelFormat format = _system->getScreenFormat();
 	CursorMan.replaceCursor(_grabbedCursor, _cursor.width, _cursor.height,
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 707fd3db17b..799dea3fc5c 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -136,8 +136,8 @@ static const ResString string_map_table_v7[] = {
 	{94, "/BOOT.026/Text speed"},
 	{95, "/BOOT.027/Display Text"},
 	{96, "game name and version"},
-	{138, "/BOOT.028/Spooled Music"},
-	{139, "/BOOT.029/Do you want to replace this saved game?  (Y/N)"},
+	{137, "/BOOT.028/Spooled Music"},
+	{138, "/BOOT.029/Do you want to replace this saved game?  (Y/N)"},
 	{141, "/NEW.020/Voice Only"},
 	{142, "/NEW.021/Voice and Text"},
 	{143, "/NEW.022/Text Display Only"},
@@ -416,7 +416,6 @@ void InfoDialog::reflowLayout() {
 }
 
 const char *InfoDialog::getPlainEngineString(int stringno) {
-	//char buf[256];
 	const char *result;
 
 	if (stringno == 0)
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 9532489f208..c1df566d8c9 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -1425,7 +1425,7 @@ void ScummEngine::drawBox(int x, int y, int x2, int y2, int color) {
 	if ((vs = findVirtScreen(y)) == nullptr)
 		return;
 
-	if (_game.version == 8 || _game.id == GID_DIG) {
+	if (_game.version == 8) {
 		width = _screenWidth + 8;
 		height = _screenHeight;
 		int effX2 = x2;
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index eeec4a8c1e5..876411166f3 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -26,6 +26,7 @@
 #include "scumm/charset.h"
 #include "scumm/string_v7.h"
 #include "scumm/smush/smush_player.h"
+#include "scumm/imuse_digi/dimuse_engine.h"
 
 #include "graphics/cursorman.h"
 
@@ -131,7 +132,7 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		roundedWidth = bannerMsgWidth / 2;
 	}
 
-	if (_game.version >= 7 && _game.id != GID_FT) {
+	if (_game.version == 8) {
 		startingPointX = _screenWidth / 2 - roundedWidth - 4;
 		startingPointY = _screenHeight / 2 - 10;
 		xPos = _screenWidth / 2 + roundedWidth + 3;
@@ -191,7 +192,7 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	setUpInternalGUIControl(0, normalFillColor, normalTextColor,
 							topLineColor, bottomLineColor, leftLineColor, rightLineColor, 0, 0,
 							startingPointX, startingPointY, xPos, yPos,
-							bannerMsg, true);
+							bannerMsg, true, true);
 
 	// Draw it!
 	drawInternalGUIControl(0, 0);
@@ -232,7 +233,7 @@ void ScummEngine::clearBanner() {
 		// screen for next frame.
 		if (!isSmushActive()) {
 			int startingPointY;
-			if (_game.version >= 7 && _game.id != GID_FT) {
+			if (_game.version == 8) {
 				startingPointY = _screenHeight / 2 - 10;
 			} else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformFMTowns) {
 				startingPointY = 78;
@@ -286,7 +287,7 @@ void ScummEngine::setBannerColors(int bannerId, byte r, byte g, byte b) {
 void ScummEngine::setUpInternalGUIControl(int id, int normalFillColor, int normalTextColor,
 										  int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
 										  int highlightedTextColor, int highlightedFillColor,
-										  int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag) {
+										  int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag, bool doubleLinesFlag) {
 
 	int effX, effY;
 	InternalGUIControl *ctrl;
@@ -312,6 +313,7 @@ void ScummEngine::setUpInternalGUIControl(int id, int normalFillColor, int norma
 	ctrl->normalTextColor = normalTextColor;
 	ctrl->highlightedTextColor = highlightedTextColor;
 	ctrl->highlightedFillColor = highlightedFillColor;
+	ctrl->doubleLinesFlag = doubleLinesFlag;
 }
 
 void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
@@ -320,7 +322,7 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 	int x, y, textXPos, textYPos;
 	int textColor, fillColor;
 	int boxSizeX, boxSizeY;
-	int offset = (_game.version >= 7 && _game.id != GID_FT) ? 2 : 1;
+	int offset = (_game.version == 8) ? 2 : 1;
 
 	bool centerFlag;
 	char buttonString[512];
@@ -332,8 +334,8 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 		x = ctrl->xPos;
 		y = ctrl->yPos;
 
-		boxSizeX = x - ((_game.version >= 7 && _game.id != GID_FT) ? ctrl->relativeCenterX : 0);
-		boxSizeY = y - ((_game.version >= 7 && _game.id != GID_FT) ? relCentY : 0);
+		boxSizeX = x - ((_game.version == 8) ? ctrl->relativeCenterX : 0);
+		boxSizeY = y - ((_game.version == 8) ? relCentY : 0);
 
 		fillColor = highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor;
 
@@ -346,19 +348,28 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 			drawLine(relCentX, 81, relCentX, 90, ctrl->leftLineColor);
 			drawLine(relCentY, 81, relCentY, 90, ctrl->rightLineColor);
 		} else {
-			// Draw the main box...
-			drawBox(relCentX + 1, relCentY + 1, boxSizeX - offset, boxSizeY - offset, fillColor);
-
-			// 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);
+			if (ctrl->doubleLinesFlag) {
+				// Draw the main box...
+				drawBox(relCentX + 1, relCentY + 1, boxSizeX - offset, boxSizeY - offset, fillColor);
+
+				// 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 {
+				drawBox(relCentX, relCentY, x, y, (highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor));
+
+				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);
+			}
 		}
 
 		// Calculate the positioning for the text
@@ -392,7 +403,10 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 		else
 			strcpy(buttonString, "null button");
 
-		drawGUIText(buttonString, textXPos, textYPos, textColor, centerFlag);
+		int tmpRight = _string[5].right;
+		_string[5].right = _screenWidth - 1;
+		drawGUIText(buttonString, textXPos, textYPos, _screenWidth - 1, textColor, centerFlag);
+		_string[5].right = tmpRight;
 
 		// Restore the previous charset
 		if (oldId)
@@ -480,6 +494,7 @@ void ScummEngine_v7::queryQuit() {
 				boxWidth / 2 + 319,
 				-90,
 				_emptyMsg,
+				true,
 				true);
 
 			// Save the pixels which will be overwritten by the dialog,
@@ -524,6 +539,7 @@ void ScummEngine_v7::queryQuit() {
 				240, -strWidth,
 				-30,
 				noLabelPtr,
+				true,
 				true);
 
 			drawInternalGUIControl(0, 0);
@@ -543,6 +559,7 @@ void ScummEngine_v7::queryQuit() {
 				-strWidth,
 				-30,
 				yesLabelPtr,
+				true,
 				true);
 
 			drawInternalGUIControl(0, 0);
@@ -616,6 +633,9 @@ const char *ScummEngine_v8::getGUIString(int stringId) {
 	case gsPause:
 		resStringId = 4;
 		break;
+	case gsRestart:
+		resStringId = 5;
+		break;
 	case gsQuitPrompt:
 		resStringId = (_game.features & GF_DEMO) ? 30 : 22;
 		break;
@@ -640,16 +660,16 @@ const char *ScummEngine_v8::getGUIString(int stringId) {
 	case gsYesKey:
 		resStringId = 29;
 		break;
-	case gsTextSpeed:
+	case gsTextSpeedSlider:
 		resStringId = 31;
 		break;
-	case gsMusicVolume:
+	case gsMusicVolumeSlider:
 		resStringId = 32;
 		break;
-	case gsVoiceVolume:
+	case gsVoiceVolumeSlider:
 		resStringId = 33;
 		break;
-	case gsSfxVolume:
+	case gsSfxVolumeSlider:
 		resStringId = 34;
 		break;
 	case gsHeap:
@@ -673,9 +693,6 @@ const char *ScummEngine_v7::getGUIString(int stringId) {
 	case gsPause:
 		resStringId = 4;
 		break;
-	case gsVersion:
-		resStringId = 47;
-		break;
 	case gsRestart:
 		resStringId = 5;
 		break;
@@ -727,12 +744,37 @@ const char *ScummEngine_v7::getGUIString(int stringId) {
 	case gsTitle:
 		resStringId = 22;
 		break;
-	case gsReplacePrompt:
-		break;
 	case gsYes:
 		break;
 	case gsNo:
 		break;
+	case gsMusic:
+		resStringId = 41;
+		break;
+	case gsVoice:
+		resStringId = 42;
+		break;
+	case gsSfx:
+		resStringId = 43;
+		break;
+	case gsDisabled:
+		resStringId = 44;
+		break;
+	case gsTextSpeed:
+		resStringId = 45;
+		break;
+	case gsDisplayText:
+		resStringId = 46;
+		break;
+	case gsVersion:
+		resStringId = 47;
+		break;
+	case gsSpooledMusic:
+		resStringId = 48;
+		break;
+	case gsReplacePrompt:
+		resStringId = 49;
+		break;
 	case gsVoiceOnly:
 		resStringId = 50;
 		break;
@@ -742,16 +784,16 @@ const char *ScummEngine_v7::getGUIString(int stringId) {
 	case gsTextDisplayOnly:
 		resStringId = 52;
 		break;
-	case gsTextSpeed:
+	case gsTextSpeedSlider:
 		resStringId = 53;
 		break;
-	case gsMusicVolume:
+	case gsMusicVolumeSlider:
 		resStringId = 54;
 		break;
-	case gsVoiceVolume:
+	case gsVoiceVolumeSlider:
 		resStringId = 55;
 		break;
-	case gsSfxVolume:
+	case gsSfxVolumeSlider:
 		resStringId = 56;
 		break;
 	case gsHeap:
@@ -778,10 +820,48 @@ int ScummEngine_v7::getGUIStringWidth(const char *str) {
 	return _textV7->getStringWidth(str);
 }
 
-void ScummEngine_v7::drawGUIText(const char *buttonString, int textXPos, int textYPos, int textColor, bool centerFlag) {
+void ScummEngine_v7::drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag) {
 	drawTextImmediately((const byte *)buttonString, textXPos, textYPos, textColor, 1, (TextStyleFlags)centerFlag);
 }
 
+int ScummEngine_v7::getMusicVolume() {
+	//setMusicVolume(ConfMan.getInt("music_volume") / 2);
+	return CLIP<int>(ConfMan.getInt("music_volume") / 2, 0, 127); //_imuseDigital->diMUSEGetMusicGroupVol();
+}
+
+int ScummEngine_v7::getSpeechVolume() {
+	//setMusicVolume(ConfMan.getInt("speech_volume") / 2);
+	return CLIP<int>(ConfMan.getInt("speech_volume") / 2, 0, 127); //_imuseDigital->diMUSEGetVoiceGroupVol();
+}
+
+int ScummEngine_v7::getSFXVolume() {
+	//setMusicVolume(ConfMan.getInt("sfx_volume") / 2);
+	return CLIP<int>(ConfMan.getInt("sfx_volume") / 2, 0, 127); //_imuseDigital->diMUSEGetSFXGroupVol();
+}
+
+void ScummEngine_v7::setMusicVolume(int volume) {
+	_imuseDigital->diMUSESetMusicGroupVol(CLIP<int>(volume, 0, 127));
+	ScummEngine::setMusicVolume(CLIP<int>(volume, 0, 127));
+}
+
+void ScummEngine_v7::setSpeechVolume(int volume) {
+	ScummEngine::setSpeechVolume(CLIP<int>(volume, 0, 127));
+	_imuseDigital->diMUSESetVoiceGroupVol(CLIP<int>(volume, 0, 127));
+}
+
+void ScummEngine_v7::setSFXVolume(int volume) {
+	ScummEngine::setSFXVolume(CLIP<int>(volume, 0, 127));
+	_imuseDigital->diMUSESetSFXGroupVol(CLIP<int>(volume, 0, 127));
+}
+
+void ScummEngine_v7::toggleVoiceMode() {
+	ScummEngine::toggleVoiceMode();
+	if (VAR_VOICE_MODE != 0xFF) {
+		_splayer->setChanFlag(0, VAR(VAR_VOICE_MODE) != 0);
+		_splayer->setChanFlag(2, VAR(VAR_VOICE_MODE) != 2);
+	}
+}
+
 int ScummEngine_v7::getBannerColor(int bannerId) {
 	if (_game.version == 8) {
 		byte *palette = isSmushActive() ? _splayer->getVideoPalette() : _currentPalette;
@@ -813,6 +893,32 @@ int ScummEngine::getBannerColor(int bannerId) {
 	return (int)arrAddr[bannerId];
 }
 
+void ScummEngine::toggleVoiceMode() {
+	if (VAR_VOICE_MODE != 0xFF) {
+		VAR(VAR_VOICE_MODE) = (VAR(VAR_VOICE_MODE) != 1) ? 1 : 0;
+		ConfMan.setInt("original_gui_text_status", VAR(VAR_VOICE_MODE));
+		ConfMan.setBool("speech_mute", VAR(VAR_VOICE_MODE) == 2);
+		ConfMan.setBool("subtitles", VAR(VAR_VOICE_MODE) > 0);
+		syncSoundSettings();
+		ConfMan.flushToDisk();
+	}
+}
+
+void ScummEngine::setMusicVolume(int volume) {
+	ConfMan.setInt("music_volume", volume * 2);
+	ConfMan.flushToDisk();
+}
+
+void ScummEngine::setSpeechVolume(int volume) {
+	ConfMan.setInt("speech_volume", volume * 2);
+	ConfMan.flushToDisk();
+}
+
+void ScummEngine::setSFXVolume(int volume) {
+	ConfMan.setInt("sfx_volume", volume * 2);
+	ConfMan.flushToDisk();
+}
+
 void ScummEngine::queryQuit() {
 	char msgLabelPtr[512];
 	char localizedYesKey;
@@ -826,6 +932,7 @@ void ScummEngine::queryQuit() {
 		Common::KeyState ks = showBannerAndPause(0, -1, msgLabelPtr);
 
 		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) {
+			_quitByButton = true;
 			quitGame();
 		}
 	}
@@ -840,15 +947,782 @@ void ScummEngine::queryRestart() {
 		localizedYesKey = msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1];
 		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
 
-		// "Are you sure you want to quit?  (Y-N)"
+		// "Are you sure you want to restart?  (Y/N)"
 		Common::KeyState ks = showBannerAndPause(0, -1, msgLabelPtr);
 
-		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) {
+		if ((tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) ||
+			(_game.version == 8 && ks.keycode == Common::KEYCODE_y)) {
 			restart();
 		}
 	}
 }
 
+// This function is actually not a thing in the original, it's here to
+// make things a little bit more modern and avoid making the menu feel
+// artificially slow.
+bool ScummEngine::shouldHighlightAndWait(int clickedControl) {
+	return ((clickedControl >= GUI_CTRL_SAVE_BUTTON && clickedControl <= GUI_CTRL_PATH_BUTTON) ||
+			(clickedControl == GUI_CTRL_DISPLAY_TEXT_CHECKBOX ||
+			 clickedControl == GUI_CTRL_SPOOLED_MUSIC_CHECKBOX));
+}
+
+void ScummEngine::showMainMenu() {
+	char saveScreenTitle[512];
+	byte *curGrabbedCursor = nullptr;
+	int curCursorWidth = -1;
+	int curCursorHeight = -1;
+	int curCursorHotspotX = -1;
+	int curCursorHotspotY = -1;
+	int curCursorState = -1;
+	int args[NUM_SCRIPT_LOCAL];
+	bool leftMsClicked = false, rightMsClicked = false;
+	int clickedControl = -1;
+	int curMouseX, curMouseY;
+
+	Common::KeyState ks;
+
+	// Pause the engine
+	PauseToken pt = pauseEngine();
+
+	// Run the entrance savescreen script, if available
+	if (VAR_SAVELOAD_SCRIPT != 0xFF)
+		runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, nullptr);
+
+	_saveSound = 1;
+	setShake(0);
+
+	_menuPage = GUI_PAGE_MAIN;
+	setUpMainMenuControls();
+	drawMainMenuControls();
+	convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+	drawMainMenuTitle(saveScreenTitle);
+	updateMainMenuControls();
+
+	// Force the cursor to be ON...
+	int8 oldCursorState = _cursor.state;
+	_cursor.state = 1;
+	CursorMan.showMouse(_cursor.state > 0);
+
+	if (_game.version > 5) {
+		// Backup the current cursor graphics and parameters
+		// and set up the main menu cursor...
+		curGrabbedCursor = (byte *)malloc(sizeof(_grabbedCursor));
+		if (curGrabbedCursor) {
+			memcpy(curGrabbedCursor, _grabbedCursor, sizeof(_grabbedCursor));
+			curCursorState = isSmushActive() ? 0 : _cursor.state;
+			curCursorWidth = _cursor.width;
+			curCursorHeight = _cursor.height;
+			curCursorHotspotX = _cursor.hotspotX;
+			curCursorHotspotY = _cursor.hotspotY;
+			setDefaultCursor();
+		}
+	}
+
+	CursorMan.showMouse(true);
+
+	// Notify that the menu is now active
+	_mainMenuIsActive = true;
+
+	// Clear keypresses and mouse presses
+	clearClickedStatus();
+
+	// Menu loop
+	while (!shouldQuit()) {
+		// Update the screen and the cursor while we're in the loop
+		waitForTimer(1);
+
+		// Wait for any left mouse button presses...
+		waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
+		rightMsClicked = false; // We don't care for this
+
+		if (leftMsClicked) {
+			curMouseX = _mouse.x;
+			curMouseY = _mouse.y;
+			clickedControl = getInternalGUIControlFromCoordinates(curMouseX, curMouseY);
+			clearClickedStatus();
+			leftMsClicked = false;
+			if (clickedControl != -1) {
+				if (clickedControl < GUI_CTRL_FIRST_SG || clickedControl > GUI_CTRL_LAST_SG) {
+					// Avoid highlighting the main container boxes :-)
+					if (clickedControl != GUI_CTRL_OUTER_BOX && clickedControl != GUI_CTRL_INNER_BOX) {
+						// Highlight the control
+						drawInternalGUIControl(clickedControl, 1);
+						ScummEngine::drawDirtyScreenParts();
+
+						// Wait a little bit (the original waited 120 quarter frames, which feels like molasses).
+						// We only perform this artificial wait for buttons; the original also did this for
+						// sliders but it feels artificially slow, and we don't want that here :-)
+						if (shouldHighlightAndWait(clickedControl))
+							waitForTimer(60);
+
+						// Dehighlight it
+						drawInternalGUIControl(clickedControl, 0);
+
+						// Execute the operation pertaining the clicked control
+						if (executeMainMenuOperation(clickedControl, curMouseX))
+							break;
+					}
+				}
+			}
+		}
+	}
+
+	if (shouldQuit() && !_quitByButton) {
+		getEventManager()->resetQuit();
+		getEventManager()->resetReturnToLauncher();
+		clearClickedStatus();
+		queryQuit();
+	}
+
+	_completeScreenRedraw = true;
+
+	// Run the exit savescreen script, if available
+	if (VAR_SAVELOAD_SCRIPT2 != 0xFF)
+		runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, args);
+
+	if (_game.version > 5 && curGrabbedCursor) {
+		// Restore the previous cursor...
+		_cursor.state = curCursorState;
+		CursorMan.showMouse(_cursor.state > 0);
+		setCursorHotspot(curCursorHotspotX, curCursorHotspotY);
+		setCursorFromBuffer(curGrabbedCursor, curCursorWidth, curCursorHeight, curCursorWidth);
+		free(curGrabbedCursor);
+		curGrabbedCursor = nullptr;
+	}
+
+	// Resume the engine
+	pt.clear();
+	clearClickedStatus();
+
+	// Restore the old cursor state...
+	_cursor.state = oldCursorState;
+	CursorMan.showMouse(_cursor.state > 0);
+}
+
+bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
+	char saveScreenTitle[512];
+	switch (op) {
+	case GUI_CTRL_SAVE_BUTTON:
+		_mainMenuSavegameLabel = 0;
+		//constructSavegameString();
+		_menuPage = GUI_PAGE_SAVE;
+		setUpMainMenuControls();
+		drawMainMenuControls();
+		ScummEngine::drawDirtyScreenParts();
+		break;
+	case GUI_CTRL_LOAD_BUTTON:
+		_mainMenuSavegameLabel = 0;
+		//constructSavegameString();
+		_menuPage = GUI_PAGE_LOAD;
+		setUpMainMenuControls();
+		drawMainMenuControls();
+		ScummEngine::drawDirtyScreenParts();
+		break;
+	case GUI_CTRL_PLAY_BUTTON:
+		return true;
+	case GUI_CTRL_QUIT_BUTTON:
+		queryQuit();
+		_quitByButton = shouldQuit();
+		return true;
+	case GUI_CTRL_OK_BUTTON:
+		break;
+	case GUI_CTRL_CANCEL_BUTTON:
+		_menuPage = GUI_PAGE_MAIN;
+		setUpMainMenuControls();
+		drawMainMenuControls();
+		convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+		drawMainMenuTitle(saveScreenTitle);
+		updateMainMenuControls();
+		ScummEngine::drawDirtyScreenParts();
+		break;
+	case GUI_CTRL_ARROW_UP_BUTTON:
+	case GUI_CTRL_ARROW_DOWN_BUTTON:
+	case GUI_CTRL_PATH_BUTTON:
+		// This apparently should't do anything
+		break;
+	case GUI_CTRL_MUSIC_SLIDER:
+		setMusicVolume(((mouseX - 111) << 7) / 87);
+		updateMainMenuControls();
+		ScummEngine::drawDirtyScreenParts();
+		break;
+	case GUI_CTRL_SPEECH_SLIDER:
+		setSpeechVolume(((mouseX - 111) << 7) / 87);
+		updateMainMenuControls();
+		ScummEngine::drawDirtyScreenParts();
+		break;
+	case GUI_CTRL_SFX_SLIDER:
+		setSFXVolume(((mouseX - 111) << 7) / 87);
+		updateMainMenuControls();
+		ScummEngine::drawDirtyScreenParts();
+		break;
+	case GUI_CTRL_TEXT_SPEED_SLIDER:
+		_defaultTalkDelay = CLIP<int>(9 - (mouseX - 108) / 9, 0, 9);
+		ConfMan.setInt("original_gui_text_speed", _defaultTalkDelay);
+		setTalkSpeed(9 - _defaultTalkDelay);
+		syncSoundSettings();
+		ConfMan.flushToDisk();
+		updateMainMenuControls();
+		ScummEngine::drawDirtyScreenParts();
+		break;
+	case GUI_CTRL_DISPLAY_TEXT_CHECKBOX:
+		toggleVoiceMode();
+		updateMainMenuControls();
+		ScummEngine::drawDirtyScreenParts();
+		break;
+	case GUI_CTRL_SPOOLED_MUSIC_CHECKBOX:
+		_spooledMusicIsToBeEnabled ^= 1;
+
+		// Just for safety, this should never be nullptr...
+		if (_imuseDigital) {
+			if (_spooledMusicIsToBeEnabled) {
+				_imuseDigital->diMUSEEnableSpooledMusic();
+			} else {
+				_imuseDigital->diMUSEDisableSpooledMusic();
+			}
+		}
+		updateMainMenuControls();
+		ScummEngine::drawDirtyScreenParts();
+		break;
+	default:
+		break;
+	}
+
+	return false;
+}
+
+void ScummEngine::setUpMainMenuControls() {
+	char *saveNames;
+	int yComponent, yConstant, yConstant2;
+
+	yComponent = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
+	yConstant = _screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop;
+	yConstant2 = _screenHeight / 2 + ((yComponent - 1) / 2) + _screenTop;
+
+	for (int i = 0; i < ARRAYSIZE(_internalGUIControls); i++) {
+		_internalGUIControls[i].relativeCenterX = -1;
+	}
+
+	// Outer box
+	setUpInternalGUIControl(GUI_CTRL_OUTER_BOX,
+		getBannerColor(4),
+		getBannerColor(2),
+		getBannerColor(13),
+		getBannerColor(14),
+		getBannerColor(15),
+		getBannerColor(16),
+		getBannerColor(6),
+		getBannerColor(4),
+		16,
+		yConstant,
+		303,
+		yConstant2,
+		_emptyMsg, 1, 1);
+
+	// Inner box
+	setUpInternalGUIControl(GUI_CTRL_INNER_BOX,
+		getBannerColor(4),
+		getBannerColor(5),
+		getBannerColor(18),
+		getBannerColor(17),
+		getBannerColor(20),
+		getBannerColor(19),
+		getBannerColor(6),
+		getBannerColor(7),
+		22,
+		yConstant + ((_game.id == GID_DIG && _useCJKMode) ? 21 : 13),
+		-183,
+		-102,
+		_emptyMsg, 1, 1);
+
+	if (_menuPage == GUI_PAGE_MAIN) {
+		if (_game.id == GID_FT) {
+			// Spooled music checkbox
+			setUpInternalGUIControl(GUI_CTRL_SPOOLED_MUSIC_CHECKBOX,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(18),
+				getBannerColor(17),
+				getBannerColor(20),
+				getBannerColor(19),
+				getBannerColor(11),
+				getBannerColor(12),
+				108,
+				_screenTop + 57,
+				-12,
+				-12,
+				_uncheckedBox, 1, 1);
+
+			// Music volume slider
+			setUpInternalGUIControl(GUI_CTRL_MUSIC_SLIDER,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(18),
+				getBannerColor(17),
+				getBannerColor(20),
+				getBannerColor(19),
+				getBannerColor(10),
+				getBannerColor(12),
+				108,
+				_screenTop + 71,
+				-90,
+				-12,
+				_uncheckedBox, 1, 1);
+
+			// Speech volume slider
+			setUpInternalGUIControl(GUI_CTRL_SPEECH_SLIDER,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(18),
+				getBannerColor(17),
+				getBannerColor(20),
+				getBannerColor(19),
+				getBannerColor(10),
+				getBannerColor(12),
+				108,
+				_screenTop + 85,
+				-90,
+				-12,
+				_uncheckedBox, 1, 1);
+
+			// SFX volume slider
+			setUpInternalGUIControl(GUI_CTRL_SFX_SLIDER,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(18),
+				getBannerColor(17),
+				getBannerColor(20),
+				getBannerColor(19),
+				getBannerColor(10),
+				getBannerColor(12),
+				108,
+				_screenTop + 99,
+				-90,
+				-12,
+				_uncheckedBox, 1, 1);
+		} else {
+			// Music volume slider
+			setUpInternalGUIControl(GUI_CTRL_MUSIC_SLIDER,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(18),
+				getBannerColor(17),
+				getBannerColor(20),
+				getBannerColor(19),
+				getBannerColor(10),
+				getBannerColor(12),
+				108,
+				yConstant + 25,
+				-90,
+				-12,
+				_uncheckedBox, 1, 1);
+
+			// Speech volume slider
+			setUpInternalGUIControl(GUI_CTRL_SPEECH_SLIDER,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(18),
+				getBannerColor(17),
+				getBannerColor(20),
+				getBannerColor(19),
+				getBannerColor(10),
+				getBannerColor(12),
+				108,
+				yConstant + 43,
+				-90,
+				-12,
+				_uncheckedBox, 1, 1);
+
+			// SFX volume slider
+			setUpInternalGUIControl(GUI_CTRL_SFX_SLIDER,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(18),
+				getBannerColor(17),
+				getBannerColor(20),
+				getBannerColor(19),
+				getBannerColor(10),
+				getBannerColor(12),
+				108,
+				yConstant + 61,
+				-90,
+				-12,
+				_uncheckedBox, 1, 1);
+		}
+
+		// Display text checkbox
+		setUpInternalGUIControl(GUI_CTRL_DISPLAY_TEXT_CHECKBOX,
+			getBannerColor(9),
+			getBannerColor(10),
+			getBannerColor(18),
+			getBannerColor(17),
+			getBannerColor(20),
+			getBannerColor(19),
+			getBannerColor(11),
+			getBannerColor(12),
+			108,
+			yConstant + 85,
+			-12,
+			-12,
+			_uncheckedBox, 1, 1);
+
+		// Text speed slider
+		setUpInternalGUIControl(GUI_CTRL_TEXT_SPEED_SLIDER,
+			getBannerColor(9),
+			getBannerColor(10),
+			getBannerColor(18),
+			getBannerColor(17),
+			getBannerColor(20),
+			getBannerColor(19),
+			getBannerColor(10),
+			getBannerColor(12),
+			108,
+			yConstant + 99,
+			-90,
+			-12,
+			_uncheckedBox, 1, 1);
+
+		// Save button
+		int saveButtonAnchorY = yConstant + 37;
+		setUpInternalGUIControl(GUI_CTRL_SAVE_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			235,
+			saveButtonAnchorY,
+			-60,
+			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			(char *)getGUIString(gsSave), 1, 1);
+
+		// Load button
+		int loadButtonAnchorY = yConstant +
+			((_game.id == GID_DIG && _useCJKMode) ? 18 : 12)
+			+ 40;
+		setUpInternalGUIControl(GUI_CTRL_LOAD_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			235,
+			loadButtonAnchorY,
+			-60,
+			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			(char *)getGUIString(gsLoad), 1, 1);
+
+		// Play button
+		int playButtonAnchorY = yConstant +
+			2 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12)
+			+ 43;
+		setUpInternalGUIControl(GUI_CTRL_PLAY_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			235,
+			playButtonAnchorY,
+			-60,
+			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			(char *)getGUIString(gsPlay), 1, 1);
+
+		// Quit button
+		int quitButtonAnchorY = yConstant +
+			3 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12)
+			+ 46;
+		setUpInternalGUIControl(GUI_CTRL_QUIT_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			235,
+			quitButtonAnchorY,
+			-60,
+			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			(char *)getGUIString(gsQuit), 1, 1);
+	}
+
+	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
+		// Arrow up button
+		setUpInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON,
+			getBannerColor(9),
+			getBannerColor(10),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(11),
+			getBannerColor(12),
+			209,
+			yConstant + ((_game.id == GID_DIG && _useCJKMode) ? 25 : 17),
+			-16,
+			-47,
+			_arrowUp, 1, 1);
+
+		// Arrow down button
+		setUpInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON,
+			getBannerColor(9),
+			getBannerColor(10),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(11),
+			getBannerColor(12),
+			209,
+			yConstant + ((_game.id == GID_DIG && _useCJKMode) ? 75 : 67),
+			-16,
+			-45,
+			_arrowDown, 1, 1);
+
+		if (_menuPage == GUI_PAGE_SAVE) {
+			// OK button
+			setUpInternalGUIControl(GUI_CTRL_OK_BUTTON,
+				getBannerColor(4),
+				getBannerColor(5),
+				getBannerColor(17),
+				getBannerColor(18),
+				getBannerColor(19),
+				getBannerColor(20),
+				getBannerColor(6),
+				getBannerColor(7),
+				235,
+				((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) + yConstant + 40,
+				-60,
+				((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+				(char *)getGUIString(gsOK), 1, 1);
+		}
+
+		// Cancel button
+		int cancelButtonAnchorY = 0;
+		if (_menuPage == GUI_PAGE_LOAD) {
+			cancelButtonAnchorY = _screenHeight / 2 +
+				(((_game.id == GID_DIG && _useCJKMode) ? 10 : 7) - yComponent / 2) +
+				_screenTop +
+				((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) +
+				40;
+		} else {
+			cancelButtonAnchorY = yConstant + 43 + 2 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12);
+		}
+		setUpInternalGUIControl(GUI_CTRL_CANCEL_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			235,
+			cancelButtonAnchorY,
+			-60,
+			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			(char *)getGUIString(gsCancel), 1, 1);
+
+		// Savegame names
+		saveNames = _savegameNames;
+		for (int i = GUI_CTRL_FIRST_SG, j = 11; i <= GUI_CTRL_LAST_SG; i++, j += 11) {
+			setUpInternalGUIControl(i,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(4),
+				getBannerColor(4),
+				getBannerColor(4),
+				getBannerColor(4),
+				getBannerColor(11),
+				getBannerColor(12),
+				24,
+				yConstant + j + ((_game.id == GID_DIG && _useCJKMode) ? 12 : 4),
+				-179,
+				-9,
+				saveNames, 0, 0);
+
+			saveNames += 40;
+		}
+	}
+}
+
+void ScummEngine::drawMainMenuControls() {
+	char namePrompt[256];
+	char loadPrompt[256];
+
+	// Outer box
+	drawInternalGUIControl(GUI_CTRL_OUTER_BOX, 0);
+
+	if (_menuPage == GUI_PAGE_MAIN) {
+		drawInternalGUIControl(GUI_CTRL_SAVE_BUTTON, 0); // Save button
+		drawInternalGUIControl(GUI_CTRL_LOAD_BUTTON, 0); // Load button
+		drawInternalGUIControl(GUI_CTRL_PLAY_BUTTON, 0); // Play button
+		drawInternalGUIControl(GUI_CTRL_QUIT_BUTTON, 0); // Quit button
+
+		drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0); // Inner box
+	}
+
+	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
+		drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0);     // Inner box
+		drawInternalGUIControl(GUI_CTRL_PATH_BUTTON, 0);   // Path button
+		drawInternalGUIControl(GUI_CTRL_OK_BUTTON, 0);     // Ok button
+		drawInternalGUIControl(GUI_CTRL_CANCEL_BUTTON, 0); // Cancel button
+
+		// Savegame names
+		for (int i = GUI_CTRL_FIRST_SG; i <= GUI_CTRL_LAST_SG; i++)
+			drawInternalGUIControl(i, 0);
+
+		drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);   // Arrow up button
+		drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button
+
+		if (_menuPage == GUI_PAGE_SAVE) {
+			convertMessageToString((const byte *)getGUIString(gsNamePrompt), (byte *)namePrompt, sizeof(namePrompt));
+			drawMainMenuTitle(namePrompt);
+		} else if (_menuPage == GUI_PAGE_LOAD) {
+			convertMessageToString((const byte *)getGUIString(gsSelectLoadPrompt), (byte *)loadPrompt, sizeof(loadPrompt));
+			drawMainMenuTitle(loadPrompt);
+		}
+	}
+
+	if (_mainMenuSavegameLabel)
+		drawInternalGUIControl(_mainMenuSavegameLabel, 1);
+
+	ScummEngine::drawDirtyScreenParts();
+	_system->updateScreen();
+}
+
+void ScummEngine::updateMainMenuControls() {
+	char msg[256];
+	int yComponent, yConstant;
+
+	yComponent = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
+	yConstant = _screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop;
+
+	strncpy(_mainMenuMusicSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuMusicSlider));
+	strncpy(_mainMenuSpeechSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuSpeechSlider));
+	strncpy(_mainMenuSfxSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuSfxSlider));
+	strncpy(_mainMenuTextSpeedSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuTextSpeedSlider));
+
+	_mainMenuMusicSlider[getMusicVolume() / 8] = '\f';
+	_mainMenuSpeechSlider[getSpeechVolume() / 8] = '\f';
+	_mainMenuSfxSlider[getSFXVolume() / 8] = '\f';
+
+	if (VAR_CHARINC != 0xFF)
+		_mainMenuTextSpeedSlider[15 - (15 * VAR(VAR_CHARINC) / 9)] = '\f';
+
+	_internalGUIControls[GUI_CTRL_MUSIC_SLIDER].label      = _mainMenuMusicSlider;
+	_internalGUIControls[GUI_CTRL_SPEECH_SLIDER].label     = _mainMenuSpeechSlider;
+	_internalGUIControls[GUI_CTRL_SFX_SLIDER].label        = _mainMenuSfxSlider;
+	_internalGUIControls[GUI_CTRL_TEXT_SPEED_SLIDER].label = _mainMenuTextSpeedSlider;
+
+	if (_sound->isAudioDisabled()) {
+		_internalGUIControls[GUI_CTRL_MUSIC_SLIDER].label  = (char *)getGUIString(gsDisabled);
+		_internalGUIControls[GUI_CTRL_SPEECH_SLIDER].label = (char *)getGUIString(gsDisabled);
+		_internalGUIControls[GUI_CTRL_SFX_SLIDER].label    = (char *)getGUIString(gsDisabled);
+	}
+
+	if (_spooledMusicIsToBeEnabled) {
+		_internalGUIControls[GUI_CTRL_SPOOLED_MUSIC_CHECKBOX].label = _checkedBox;
+	} else {
+		_internalGUIControls[GUI_CTRL_SPOOLED_MUSIC_CHECKBOX].label = _uncheckedBox;
+	}
+
+	_internalGUIControls[GUI_CTRL_DISPLAY_TEXT_CHECKBOX].label = _checkedBox;
+
+	if (VAR_VOICE_MODE != 0xFF && VAR(VAR_VOICE_MODE) == 0) {
+		_internalGUIControls[GUI_CTRL_DISPLAY_TEXT_CHECKBOX].label = _uncheckedBox;
+		_internalGUIControls[GUI_CTRL_TEXT_SPEED_SLIDER].label = (char *)getGUIString(gsDisabled);
+	}
+
+	drawInternalGUIControl(GUI_CTRL_MUSIC_SLIDER,  0); // Music slider
+	drawInternalGUIControl(GUI_CTRL_SPEECH_SLIDER, 0); // Speech slider
+	drawInternalGUIControl(GUI_CTRL_SFX_SLIDER,    0); // SFX slider
+
+	if (_game.id == GID_FT)
+		drawInternalGUIControl(GUI_CTRL_SPOOLED_MUSIC_CHECKBOX, 0); // Spooled music checkbox
+
+	drawInternalGUIControl(GUI_CTRL_DISPLAY_TEXT_CHECKBOX, 0); // Display text checkbox
+	drawInternalGUIControl(GUI_CTRL_TEXT_SPEED_SLIDER,     0); // Text speed slider
+
+	// Full Throttle has the "Spooled Music" checkbox,
+	// 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, 29, yConstant + 19, _screenWidth - 1, getBannerColor(2), false);
+
+		convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 29, yConstant + 33, _screenWidth - 1, getBannerColor(2), false);
+
+		convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 29, yConstant + 47, _screenWidth - 1, getBannerColor(2), false);
+	} else {
+		convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 29, yConstant + 25, _screenWidth - 1, getBannerColor(2), false);
+
+		convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 29, yConstant + 43, _screenWidth - 1, getBannerColor(2), false);
+	}
+
+	convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
+	drawGUIText(msg, 29, yConstant + 61, _screenWidth - 1, getBannerColor(2), false);
+
+	convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
+	drawGUIText(msg, 29, yConstant + 88, _screenWidth - 1, getBannerColor(2), false);
+
+	convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
+	drawGUIText(msg, 29, yConstant + 102, _screenWidth - 1, getBannerColor(2), false);
+
+	drawLine(23, yConstant + 77, 204, yConstant + 77, getBannerColor(17));
+	drawLine(23, yConstant + 78, 204, yConstant + 78, getBannerColor(4));
+	drawLine(23, yConstant + 79, 204, yConstant + 79, getBannerColor(4));
+	drawLine(23, yConstant + 80, 204, yConstant + 80, getBannerColor(18));
+
+	// The following line is in the Aaron Giles' interpreter of FT, based on the first DOS version;
+	// for some reason it doesn't get displayed in the DOS version, and it also overflows
+	// onto the internal panel lines, so let's just not draw it...
+	// drawLine(24, yConstant + 81, 204, yConstant + 81, getBannerColor(4));
+
+	ScummEngine::drawDirtyScreenParts();
+	_system->updateScreen();
+}
+
+void ScummEngine::drawMainMenuTitle(const char *title) {
+	int boxColor = getBannerColor(4);
+	int stringColor = getBannerColor(2);
+	if (_game.id == GID_DIG) {
+		int yComponent = _useCJKMode ? 130 : 121;
+
+		drawBox(18,
+			_screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop + 4,
+			301,
+			_screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop + 12,
+			boxColor);
+
+		drawGUIText(title,
+			159,
+			_screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop + 4,
+			_screenWidth - 1,
+			stringColor,
+			true);
+	} else {
+		drawBox(18, _screenTop + 44, 301, _screenTop + 52, boxColor);
+		drawGUIText(title, 159, _screenTop + 44, _screenWidth - 1, stringColor, true);
+	}
+
+	ScummEngine::drawDirtyScreenParts();
+	_system->updateScreen();
+}
+
 int ScummEngine::getGUIStringHeight(const char *str) {
 	return _charset->getFontHeight();
 }
@@ -857,14 +1731,18 @@ int ScummEngine::getGUIStringWidth(const char *str) {
 	return _charset->getStringWidth(0, (const byte *)str);
 }
 
-void ScummEngine::drawGUIText(const char *buttonString, int textXPos, int textYPos, int textColor, bool centerFlag) {
-	_string[4].ypos = textYPos;
-	_string[4].xpos = textXPos;
-	_string[4].right = _screenWidth - 1;
-	_string[4].center = centerFlag;
-	_string[4].color = textColor;
-	_string[4].charset = 1;
-	drawString(4, (const byte *)buttonString);
+void ScummEngine::drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag) {
+	int tmpRight = _string[5].right;
+
+	_string[5].xpos = textXPos;
+	_string[5].ypos = textYPos;
+	_string[5].right = rightRectClip;
+	_string[5].center = centerFlag;
+	_string[5].color = textColor;
+	_string[5].charset = 1;
+
+	drawString(5, (const byte *)buttonString);
+	_string[5].right = tmpRight;
 }
 
 void ScummEngine::getSliderString(int stringId, int value, char *sliderString, int size) {
@@ -881,7 +1759,7 @@ void ScummEngine::getSliderString(int stringId, int value, char *sliderString, i
 	}
 
 	if (ptrToChar) {
-		if (stringId == gsTextSpeed) {
+		if (stringId == gsTextSpeedSlider) {
 			memset(ptrToChar, '\v', 10);
 			ptrToChar[9 - value] = '\f';
 		} else {
@@ -899,7 +1777,7 @@ const char *ScummEngine_v6::getGUIString(int stringId) {
 	case gsPause:
 		resStringId = 4;
 		break;
-	case gsTextSpeed:
+	case gsTextSpeedSlider:
 		break;
 	case gsRestart:
 		resStringId = 5;
@@ -963,11 +1841,11 @@ const char *ScummEngine_v6::getGUIString(int stringId) {
 		break;
 	case gsYesKey:
 		break;
-	case gsMusicVolume:
+	case gsMusicVolumeSlider:
 		break;
-	case gsVoiceVolume:
+	case gsVoiceVolumeSlider:
 		break;
-	case gsSfxVolume:
+	case gsSfxVolumeSlider:
 		break;
 	case gsHeap:
 		return "Heap %dK";
@@ -991,7 +1869,7 @@ const char *ScummEngine::getGUIString(int stringId) {
 		break;
 	case gsVersion:
 		break;
-	case gsTextSpeed:
+	case gsTextSpeedSlider:
 		break;
 	case gsRestart:
 		resStringId = 5;
@@ -1048,11 +1926,11 @@ const char *ScummEngine::getGUIString(int stringId) {
 		break;
 	case gsTextDisplayOnly:
 		break;
-	case gsMusicVolume:
+	case gsMusicVolumeSlider:
 		break;
-	case gsVoiceVolume:
+	case gsVoiceVolumeSlider:
 		break;
-	case gsSfxVolume:
+	case gsSfxVolumeSlider:
 		break;
 	case gsHeap:
 		return "Heap %dK";
diff --git a/engines/scumm/imuse_digi/dimuse_engine.cpp b/engines/scumm/imuse_digi/dimuse_engine.cpp
index ab8c90df412..a7b38204578 100644
--- a/engines/scumm/imuse_digi/dimuse_engine.cpp
+++ b/engines/scumm/imuse_digi/dimuse_engine.cpp
@@ -74,6 +74,7 @@ IMuseDigital::IMuseDigital(ScummEngine_v7 *scumm, Audio::Mixer *mixer)
 	_stopSequenceFlag = 0;
 	_scriptInitializedFlag = 0;
 	_callbackInterruptFlag = 0;
+	_spooledMusicEnabled = true;
 
 	_radioChatterSFX = false;
 	_isEngineDisabled = false;
@@ -921,6 +922,17 @@ int IMuseDigital::diMUSESetAttribute(int attrIndex, int attrVal) {
 	return scriptParse(8, attrIndex, attrVal);
 }
 
+void IMuseDigital::diMUSEEnableSpooledMusic() {
+	_spooledMusicEnabled = true;
+}
+
+void IMuseDigital::diMUSEDisableSpooledMusic() {
+	_spooledMusicEnabled = true;
+	diMUSESetState(0);
+	diMUSESetSequence(0);
+	_spooledMusicEnabled = false;
+}
+
 // Debugger utility functions
 
 void IMuseDigital::listStates() {
diff --git a/engines/scumm/imuse_digi/dimuse_engine.h b/engines/scumm/imuse_digi/dimuse_engine.h
index b4eef033bfd..efe1e36cad1 100644
--- a/engines/scumm/imuse_digi/dimuse_engine.h
+++ b/engines/scumm/imuse_digi/dimuse_engine.h
@@ -110,6 +110,7 @@ private:
 	int _stopSequenceFlag;
 	int _scriptInitializedFlag;
 	char _emptyMarker[1];
+	bool _spooledMusicEnabled;
 
 	int _usecPerInt; // Microseconds between each callback (will be set to 50 Hz)
 	int _callbackInterruptFlag;
@@ -387,6 +388,8 @@ public:
 	int diMUSESetSequence(int soundId);
 	int diMUSESetCuePoint(int cueId);
 	int diMUSESetAttribute(int attrIndex, int attrVal);
+	void diMUSEEnableSpooledMusic();
+	void diMUSEDisableSpooledMusic();
 
 	// Utils
 	int addTrackToList(IMuseDigiTrack **listPtr, IMuseDigiTrack *listPtr_Item);
diff --git a/engines/scumm/imuse_digi/dimuse_scripts.cpp b/engines/scumm/imuse_digi/dimuse_scripts.cpp
index 5ce400f369f..a2d94af2573 100644
--- a/engines/scumm/imuse_digi/dimuse_scripts.cpp
+++ b/engines/scumm/imuse_digi/dimuse_scripts.cpp
@@ -427,6 +427,9 @@ void IMuseDigital::playFtMusic(const char *songName, int transitionType, int vol
 	int oldSoundId = 0;
 	int soundId;
 
+	if (!_spooledMusicEnabled)
+		return;
+
 	// Check for any music piece which is played as a SFX (without an associated stream)
 	// and fade it out
 	for (int i = diMUSEGetNextSound(0); i; i = diMUSEGetNextSound(i)) {
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index beef7632228..cc2e43a254e 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -431,6 +431,7 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 	if (isUsingOriginalGUI()) {
 		char sliderString[256];
+		PauseToken pt;
 
 		if (lastKeyHit.keycode == Common::KEYCODE_b && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 			int curBufferCount = _imuseDigital->roundRobinSetBufferCount();
@@ -444,8 +445,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 			if (lastKeyHit.keycode == Common::KEYCODE_o || lastKeyHit.keycode == Common::KEYCODE_p) {
 				Common::KeyState ks = lastKeyHit;
 
-				if (isSmushActive())
-					_mixer->pauseAll(true);
+				pt = pauseEngine();
 
 				int volume = _imuseDigital->diMUSEGetMusicGroupVol();
 				do {
@@ -459,17 +459,18 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 							volume = 127;
 					}
 
-					getSliderString(gsMusicVolume, volume, sliderString, sizeof(sliderString));
+					getSliderString(gsMusicVolumeSlider, volume, sliderString, sizeof(sliderString));
 					showBannerAndPause(0, 0, sliderString);
 					ks = Common::KEYCODE_INVALID;
 					bool leftBtnPressed = false, rightBtnPressed = false;
 					waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
 				} while (ks.keycode == Common::KEYCODE_o || ks.keycode == Common::KEYCODE_p);
 				clearBanner();
+
 				_imuseDigital->diMUSESetMusicGroupVol(volume);
+				ConfMan.setInt("music_volume", volume * 2);
 
-				if (isSmushActive())
-					_mixer->pauseAll(false);
+				pt.clear();
 
 				return;
 			}
@@ -478,8 +479,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 			if (lastKeyHit.keycode == Common::KEYCODE_k || lastKeyHit.keycode == Common::KEYCODE_l) {
 				Common::KeyState ks = lastKeyHit;
 
-				if (isSmushActive())
-					_mixer->pauseAll(true);
+				pt = pauseEngine();
 
 				int volume = _imuseDigital->diMUSEGetVoiceGroupVol();
 				do {
@@ -493,17 +493,18 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 							volume = 127;
 					}
 
-					getSliderString(gsVoiceVolume, volume, sliderString, sizeof(sliderString));
+					getSliderString(gsVoiceVolumeSlider, volume, sliderString, sizeof(sliderString));
 					showBannerAndPause(0, 0, sliderString);
 					ks = Common::KEYCODE_INVALID;
 					bool leftBtnPressed = false, rightBtnPressed = false;
 					waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
 				} while (ks.keycode == Common::KEYCODE_k || ks.keycode == Common::KEYCODE_l);
 				clearBanner();
+
 				_imuseDigital->diMUSESetVoiceGroupVol(volume);
+				ConfMan.setInt("speech_volume", volume * 2);
 
-				if (isSmushActive())
-					_mixer->pauseAll(false);
+				pt.clear();
 
 				return;
 			}
@@ -512,8 +513,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 			if (lastKeyHit.keycode == Common::KEYCODE_n || lastKeyHit.keycode == Common::KEYCODE_m) {
 				Common::KeyState ks = lastKeyHit;
 
-				if (isSmushActive())
-					_mixer->pauseAll(true);
+				pt = pauseEngine();
 
 				int volume = _imuseDigital->diMUSEGetSFXGroupVol();
 				do {
@@ -527,17 +527,18 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 							volume = 127;
 					}
 
-					getSliderString(gsSfxVolume, volume, sliderString, sizeof(sliderString));
+					getSliderString(gsSfxVolumeSlider, volume, sliderString, sizeof(sliderString));
 					showBannerAndPause(0, 0, sliderString);
 					ks = Common::KEYCODE_INVALID;
 					bool leftBtnPressed = false, rightBtnPressed = false;
 					waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
 				} while (ks.keycode == Common::KEYCODE_n || ks.keycode == Common::KEYCODE_m);
 				clearBanner();
+
 				_imuseDigital->diMUSESetSFXGroupVol(volume);
+				ConfMan.setInt("sfx_volume", volume * 2);
 
-				if (isSmushActive())
-					_mixer->pauseAll(false);
+				pt.clear();
 
 				return;
 			}
@@ -549,8 +550,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 
 				Common::KeyState ks = lastKeyHit;
 
-				if (isSmushActive())
-					_mixer->pauseAll(true);
+				pt = pauseEngine();
 
 				do {
 					if (ks.ascii == '+') {
@@ -563,7 +563,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 							VAR(VAR_CHARINC) = 9;
 					}
 
-					getSliderString(gsTextSpeed, VAR(VAR_CHARINC), sliderString, sizeof(sliderString));
+					getSliderString(gsTextSpeedSlider, VAR(VAR_CHARINC), sliderString, sizeof(sliderString));
 					showBannerAndPause(0, 0, sliderString);
 					ks = Common::KEYCODE_INVALID;
 					bool leftBtnPressed = false, rightBtnPressed = false;
@@ -571,8 +571,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 				} while (ks.ascii == '+' || ks.ascii == '-');
 				clearBanner();
 
-				if (isSmushActive())
-					_mixer->pauseAll(false);
+				pt.clear();
 
 				return;
 			}
@@ -585,10 +584,9 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 	// a version dialog, unless VAR_VERSION_KEY is set to 0. However, the COMI
 	// version string is hard coded in the engine, hence we don't invoke
 	// versionDialog for it. Dig/FT version strings are partly hard coded, too.
-	if (_game.id != GID_CMI && 0 != VAR(VAR_VERSION_KEY) &&
+	if (!isUsingOriginalGUI() && _game.id != GID_CMI && 0 != VAR(VAR_VERSION_KEY) &&
 	    lastKeyHit.keycode == Common::KEYCODE_v && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-		if (!isUsingOriginalGUI())
-			versionDialog();
+		versionDialog();
 
 	} else if (cutsceneExitKeyEnabled && lastKeyHit.keycode == Common::KEYCODE_ESCAPE) {
 		// Skip cutscene (or active SMUSH video).
@@ -850,7 +848,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		restartKeyEnabled = true;
 
 	if (isUsingOriginalGUI()) {
-		if (pauseKeyEnabled && (lastKeyHit.ascii == VAR(VAR_PAUSE_KEY) ||
+		if (VAR_PAUSE_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_PAUSE_KEY) ||
 			(lastKeyHit.keycode == Common::KEYCODE_SPACE && _game.features & GF_DEMO))) {
 			// Force the cursor OFF...
 			int8 oldCursorState = _cursor.state;
@@ -862,7 +860,9 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			return;
 		}
 
-		if (restartKeyEnabled && (lastKeyHit.ascii == VAR(VAR_RESTART_KEY))) {
+		if (VAR_RESTART_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_RESTART_KEY)) ||
+			((_game.id == GID_CMI && !(_game.features & GF_DEMO))
+				&& lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0))) {
 			queryRestart();
 			return;
 		}
@@ -876,6 +876,12 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			queryQuit();
 			return;
 		}
+
+		if (VAR_MAINMENU_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_MAINMENU_KEY) && lastKeyHit.hasFlags(0)) &&
+			_game.version > 6) {
+			showMainMenu();
+			return;
+		}
 	}
 
 	// For games which use VAR_MAINMENU_KEY, disable the mainmenu key if
diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp
index eb0a35d677e..993c6baee2d 100644
--- a/engines/scumm/script.cpp
+++ b/engines/scumm/script.cpp
@@ -641,10 +641,10 @@ void ScummEngine::writeVar(uint var, int value) {
 			// look at the target specific settings, assuming that any global
 			// value is likely to be bogus. See also bug #4008.
 			if (ConfMan.hasKey("talkspeed", _targetName)) {
-				value = getTalkSpeed();
+				value = 9 - getTalkSpeed();
 			} else {
 				// Save the new talkspeed value to ConfMan
-				setTalkSpeed(value);
+				setTalkSpeed(9 - value);
 			}
 		}
 
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 81511232761..3e9e06b0f39 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -164,6 +164,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
 
 	setTimerAndShakeFrequency();
 
+	memset(_savegameNames, 0, sizeof(_savegameNames));
+
 	camera.reset();
 	memset(_colorCycle, 0, sizeof(_colorCycle));
 	memset(_colorUsedByCycle, 0, sizeof(_colorUsedByCycle));
@@ -2122,6 +2124,14 @@ void ScummEngine::syncSoundSettings() {
 			// - 0 is the lowest text speed possible.
 			if (VAR_CHARINC != 0xFF)
 				VAR(VAR_CHARINC) = 9 - _defaultTalkDelay;
+		} else if (_game.version != 8) {
+			ConfMan.setInt("original_gui_text_speed", getTalkSpeed());
+		}
+
+		if (_game.version >= 7 && _imuseDigital) {
+			_imuseDigital->diMUSESetMusicGroupVol(ConfMan.getInt("music_volume") / 2);
+			_imuseDigital->diMUSESetVoiceGroupVol(ConfMan.getInt("speech_volume") / 2);
+			_imuseDigital->diMUSESetSFXGroupVol(ConfMan.getInt("sfx_volume") / 2);
 		}
 		return;
 	}
@@ -2657,7 +2667,7 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 				errMsg = _("Failed to save game to file:\n\n%s");
 
 			if (success && _saveTemporaryState && VAR_GAME_LOADED != 0xFF && _game.version <= 7)
-				VAR(VAR_GAME_LOADED) = 201;
+				VAR(VAR_GAME_LOADED) = GAME_PROPER_SAVE;
 
 			if (!_saveTemporaryState)
 				_lastSaveTime = _system->getMillis();
@@ -2667,7 +2677,7 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 				errMsg = _("Failed to load saved game from file:\n\n%s");
 
 			if (success && (_saveTemporaryState || _game.version == 8) && VAR_GAME_LOADED != 0xFF)
-				VAR(VAR_GAME_LOADED) = (_game.version == 8) ? 1 : 203;
+				VAR(VAR_GAME_LOADED) = (_game.version == 8) ? 1 : GAME_PROPER_LOAD;
 		}
 
 		if (!success) {
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 3635537e398..4f74d275ec2 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -352,13 +352,47 @@ class ResourceManager;
 #define AMIGA_NTSC_VBLANK_RATE 240.0
 
 /**
- * GUI strings categories.
+ * Game saving/loading outcome codes
  */
 
+#define GAME_PROPER_SAVE 201
+#define GAME_FAILED_SAVE 202
+#define GAME_PROPER_LOAD 203
+#define GAME_FAILED_LOAD 204
+
+/**
+ * GUI defines and enums.
+ */
+
+#define GUI_PAGE_MAIN 0
+#define GUI_PAGE_SAVE 1
+#define GUI_PAGE_LOAD 2
+
+#define GUI_CTRL_FIRST_SG               1
+#define GUI_CTRL_LAST_SG                9
+#define GUI_CTRL_SAVE_BUTTON            10
+#define GUI_CTRL_LOAD_BUTTON            11
+#define GUI_CTRL_PLAY_BUTTON            12
+#define GUI_CTRL_QUIT_BUTTON            13
+#define GUI_CTRL_OK_BUTTON              14
+#define GUI_CTRL_CANCEL_BUTTON          15
+#define GUI_CTRL_ARROW_UP_BUTTON        16
+#define GUI_CTRL_ARROW_DOWN_BUTTON      17
+#define GUI_CTRL_PATH_BUTTON            18
+#define GUI_CTRL_MUSIC_SLIDER           19
+#define GUI_CTRL_SPEECH_SLIDER          20
+#define GUI_CTRL_SFX_SLIDER             21
+#define GUI_CTRL_TEXT_SPEED_SLIDER      22
+#define GUI_CTRL_DISPLAY_TEXT_CHECKBOX  23
+#define GUI_CTRL_SPOOLED_MUSIC_CHECKBOX 24
+#define GUI_CTRL_OUTER_BOX              26
+#define GUI_CTRL_INNER_BOX              27
+
+
 enum GUIString {
 	gsPause = 0,
 	gsVersion = 1,
-	gsTextSpeed = 2,
+	gsTextSpeedSlider = 2,
 	gsRestart = 3,
 	gsQuitPrompt = 4,
 	gsSave = 5,
@@ -382,12 +416,19 @@ enum GUIString {
 	gsTextDisplayOnly = 24,
 	gsVoiceOnly = 25,
 	gsYesKey = 26,
-	gsMusicVolume = 27,
-	gsVoiceVolume = 28,
-	gsSfxVolume = 29,
+	gsMusicVolumeSlider = 27,
+	gsVoiceVolumeSlider = 28,
+	gsSfxVolumeSlider = 29,
 	gsHeap = 30,
 	gsSavePath = 31,
-	gsTitle = 32
+	gsTitle = 32,
+	gsDisabled = 33,
+	gsMusic = 34,
+	gsVoice = 35,
+	gsSfx = 36,
+	gsTextSpeed = 37,
+	gsDisplayText = 38,
+	gsSpooledMusic = 39
 };
 
 struct InternalGUIControl {
@@ -405,6 +446,7 @@ struct InternalGUIControl {
 	int highlightedFillColor;
 	bool centerText;
 	char *label;
+	bool doubleLinesFlag;
 };
 
 /**
@@ -537,6 +579,9 @@ protected:
 	virtual void setDefaultCursor() {};
 	virtual void setCursorTransparency(int a) {};
 	virtual void resetCursors() {}
+	virtual void setCursorHotspot(int x, int y) {}
+	virtual void setCursorFromBuffer(const byte *ptr, int width, int height, int pitch) {}
+
 
 public:
 	void pauseGame();
@@ -564,19 +609,34 @@ protected:
 	uint32 _textSurfBannerMemSize = 0;
 
 	InternalGUIControl _internalGUIControls[30];
+
+	// Special GUI strings
 	char _emptyMsg[1] = {'\0'};
+	char _uncheckedBox[2] = {' ', '\0'};
+	char _checkedBox[2] = {'x', '\0'};
+	char _arrowUp[2] = {'\x18', '\0'};
+	char _arrowDown[2] = {'\x19', '\0'};
+
+	char _savegameNames[40 * 10];
+	int _menuPage = 0;
+	int _mainMenuSavegameLabel = 1;
+	bool _mainMenuIsActive = false;
+	bool _quitByButton = false;
+	char _mainMenuMusicSlider[17];
+	char _mainMenuSpeechSlider[17];
+	char _mainMenuSfxSlider[17];
+	char _mainMenuTextSpeedSlider[17];
+	int _spooledMusicIsToBeEnabled = 1;
 
 	void initBanners();
 	Common::KeyState showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...);
 	void clearBanner();
 	void setBannerColors(int bannerId, byte r, byte g, byte b);
-	//virtual int getBannerColor(int bannerId) { return getBannerColor(bannerId, _currentPalette); }
-	//int getBannerColor(int bannerId, byte *palette);
 	virtual int getBannerColor(int bannerId);
 	void setUpInternalGUIControl(int id, int normalFillColor, int normalTextColor,
 								 int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
 								 int highlightedTextColor, int highlightedFillColor,
-								 int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag);
+								 int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag, bool unknownFlag);
 	void drawInternalGUIControl(int id, bool highlightColor);
 	int getInternalGUIControlFromCoordinates(int x, int y);
 	virtual bool isSmushActive() { return false; }
@@ -587,8 +647,24 @@ protected:
 	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked);
 	virtual int getGUIStringHeight(const char *str);
 	virtual int getGUIStringWidth(const char *str);
-	virtual void drawGUIText(const char *buttonString, int textXPos, int textYPos, int textColor, bool centerFlag);
+	virtual void drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag);
 	void getSliderString(int stringId, int value, char *sliderString, int size);
+	virtual int getMusicVolume() { return 0; }
+	virtual int getSpeechVolume() { return 0; }
+	virtual int getSFXVolume() { return 0; }
+	virtual void setMusicVolume(int volume);
+	virtual void setSpeechVolume(int volume);
+	virtual void setSFXVolume(int volume);
+	virtual void toggleVoiceMode();
+
+	void showMainMenu();
+	void setUpMainMenuControls();
+	void drawMainMenuControls();
+	void updateMainMenuControls();
+	void drawMainMenuTitle(const char *title);
+	bool executeMainMenuOperation(int op, int mouseX);
+	bool shouldHighlightAndWait(int clickedControl);
+
 
 public:
 	char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index a010af2f1e3..7b31de156a5 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -142,13 +142,13 @@ protected:
 
 	void setDefaultCursor() override;
 	void setCursorTransparency(int a) override;
-	void setCursorHotspot(int x, int y);
+	void setCursorHotspot(int x, int y) override;
 
 	virtual void setCursorFromImg(uint img, uint room, uint imgindex);
 	void useIm01Cursor(const byte *im, int w, int h);
 	void useBompCursor(const byte *im, int w, int h);
 	void grabCursor(int x, int y, int w, int h);
-	void setCursorFromBuffer(const byte *ptr, int width, int height, int pitch);
+	void setCursorFromBuffer(const byte *ptr, int width, int height, int pitch) override;
 	void ditherCursor();
 
 	virtual void drawBlastTexts() {}
diff --git a/engines/scumm/scumm_v7.h b/engines/scumm/scumm_v7.h
index 518ba9cfb9f..c8b98ba033b 100644
--- a/engines/scumm/scumm_v7.h
+++ b/engines/scumm/scumm_v7.h
@@ -147,9 +147,18 @@ protected:
 	const char *getGUIString(int stringId) override;
 	int getGUIStringHeight(const char *str) override;
 	int getGUIStringWidth(const char *str) override;
-	void drawGUIText(const char *buttonString, int textXPos, int textYPos, int textColor, bool centerFlag) override;
+	void drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag) override;
+	int getMusicVolume() override;
+	int getSpeechVolume() override;
+	int getSFXVolume() override;
+	void setMusicVolume(int volume) override;
+	void setSpeechVolume(int volume) override;
+	void setSFXVolume(int volume) override;
+	void toggleVoiceMode() override;
 
 	void setDefaultCursor() override;
+	void updateCursor() override;
+	void setCursorTransparency(int a) override;
 
 	void drawVerb(int verb, int mode) override;
 
diff --git a/engines/scumm/scumm_v8.h b/engines/scumm/scumm_v8.h
index 196f136b2d7..de3885b5433 100644
--- a/engines/scumm/scumm_v8.h
+++ b/engines/scumm/scumm_v8.h
@@ -84,8 +84,7 @@ protected:
 	int getObjectIdFromOBIM(const byte *obim) override;
 
 	void processKeyboard(Common::KeyState lastKeyHit) override;
-	void updateCursor() override;
-	void setCursorTransparency(int a) override;
+	void setDefaultCursor() override;
 	void desaturatePalette(int hueScale, int satScale, int lightScale, int startColor, int endColor);
 
 	void stampShotEnqueue(int slot, int boxX, int boxY, int boxWidth, int boxHeight, int brightness);
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 061b981ef89..34cd12c99cb 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -1566,6 +1566,14 @@ void Sound::restoreAfterLoad() {
 	}
 }
 
+bool Sound::isAudioDisabled() {
+	if (_vm->_game.version > 6) {
+		return _vm->_imuseDigital->isEngineDisabled();
+	}
+
+	return false;
+}
+
 #pragma mark -
 #pragma mark --- Sound resource handling ---
 #pragma mark -
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index ea44451a5e7..09befb94b16 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -162,6 +162,8 @@ public:
 	void saveLoadWithSerializer(Common::Serializer &ser) override;
 	void restoreAfterLoad();
 
+	bool isAudioDisabled();
+
 protected:
 	void setupSfxFile();
 	bool isSfxFinished() const;


Commit: 2417448791d9879ab207d1bbb51a03ad6d33f63c
    https://github.com/scummvm/scummvm/commit/2417448791d9879ab207d1bbb51a03ad6d33f63c
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: Change _defaultTalkDelay to _defaultTextSpeed

>From now on we're reasoning in terms of text speed, just like the interpreter does,
which means: delay == 9 - speed.
This allows us to sync the internal GUI and the ScummVM GUI more easily, and
allows for a better correspondence to the original interpreters.

Changed paths:
    engines/scumm/gfx_gui.cpp
    engines/scumm/input.cpp
    engines/scumm/saveload.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/string.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 876411166f3..b188dead47a 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1156,9 +1156,9 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 		ScummEngine::drawDirtyScreenParts();
 		break;
 	case GUI_CTRL_TEXT_SPEED_SLIDER:
-		_defaultTalkDelay = CLIP<int>(9 - (mouseX - 108) / 9, 0, 9);
-		ConfMan.setInt("original_gui_text_speed", _defaultTalkDelay);
-		setTalkSpeed(9 - _defaultTalkDelay);
+		_defaultTextSpeed = CLIP<int>((mouseX - 108) / 9, 0, 9);
+		ConfMan.setInt("original_gui_text_speed", _defaultTextSpeed);
+		setTalkSpeed(_defaultTextSpeed);
 		syncSoundSettings();
 		ConfMan.flushToDisk();
 		updateMainMenuControls();
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index cc2e43a254e..bac29ae0de1 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -563,6 +563,10 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 							VAR(VAR_CHARINC) = 9;
 					}
 
+					_defaultTextSpeed = 9 - VAR(VAR_CHARINC);
+					ConfMan.setInt("original_gui_text_speed", _defaultTextSpeed);
+					setTalkSpeed(_defaultTextSpeed);
+
 					getSliderString(gsTextSpeedSlider, VAR(VAR_CHARINC), sliderString, sizeof(sliderString));
 					showBannerAndPause(0, 0, sliderString);
 					ks = Common::KEYCODE_INVALID;
@@ -949,20 +953,20 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		syncSoundSettings();
 
 	} else if (optionKeysEnabled && (lastKeyHit.ascii == '-' || lastKeyHit.ascii == '+')) { // Change text speed
-		if (lastKeyHit.ascii == '+' && _defaultTalkDelay > 0)
-			_defaultTalkDelay--;
-		else if (lastKeyHit.ascii == '-' && _defaultTalkDelay < 9)
-			_defaultTalkDelay++;
+		if (lastKeyHit.ascii == '-' && _defaultTextSpeed > 0)
+			_defaultTextSpeed--;
+		else if (lastKeyHit.ascii == '+' && _defaultTextSpeed < 9)
+			_defaultTextSpeed++;
 
 		// Display the talk speed
-		ValueDisplayDialog dlg(_("Subtitle speed: "), 0, 9, 9 - _defaultTalkDelay, '+', '-');
-		_defaultTalkDelay = 9 - runDialog(dlg);
+		ValueDisplayDialog dlg(_("Subtitle speed: "), 0, 9, _defaultTextSpeed, '+', '-');
+		_defaultTextSpeed = runDialog(dlg);
 
 		// Save the new talkspeed value to ConfMan
-		setTalkSpeed(_defaultTalkDelay);
+		setTalkSpeed(_defaultTextSpeed);
 
 		if (VAR_CHARINC != 0xFF)
-			VAR(VAR_CHARINC) = _defaultTalkDelay;
+			VAR(VAR_CHARINC) = 9 - _defaultTextSpeed;
 
 	} else {
 
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 487f46a3480..080b0ec68d6 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -789,7 +789,7 @@ bool ScummEngine::loadState(int slot, bool compat, Common::String &filename) {
 		if (_game.version == 8)
 			_scummVars[VAR_CHARINC] = (_game.features & GF_DEMO) ? 3 : 1;
 		// Needed due to subtitle speed changes
-		_defaultTalkDelay /= 20;
+		_defaultTextSpeed /= 20;
 	}
 
 	// For a long time, we used incorrect locations for some camera related
@@ -1325,7 +1325,7 @@ void ScummEngine::saveLoadWithSerializer(Common::Serializer &s) {
 	s.syncAsByte(_useTalkAnims, VER(8));
 
 	s.syncAsSint16LE(_talkDelay, VER(8));
-	s.syncAsSint16LE(_defaultTalkDelay, VER(8));
+	s.syncAsSint16LE(_defaultTextSpeed, VER(8));
 	s.skip(2, VER(8), VER(27)); // _numInMsgStack
 	s.syncAsByte(_sentenceNum, VER(8));
 
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 3e9e06b0f39..6c16194881e 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1240,6 +1240,11 @@ Common::Error ScummEngine::init() {
 			ConfMan.setBool("subtitles", true);
 	}
 
+	// While most games set their own default talkspeed at start-up,
+	// some don't, so let's preventively set a default one.
+	if (!ConfMan.hasKey("talkspeed", _targetName))
+		setTalkSpeed(_defaultTextSpeed);
+
 	syncSoundSettings();
 
 	return Common::kNoError;
@@ -1674,7 +1679,7 @@ void ScummEngine::resetScumm() {
 	_varwatch = -1;
 	_screenStartStrip = 0;
 
-	_defaultTalkDelay = 3;
+	_defaultTextSpeed = 6;
 	_talkDelay = 0;
 	_keepText = false;
 	_nextLeft = 0;
@@ -2116,16 +2121,10 @@ void ScummEngine::syncSoundSettings() {
 				ConfMan.setInt("original_gui_text_speed", getTalkSpeed());
 			}
 
-			_defaultTalkDelay = ConfMan.getInt("original_gui_text_speed");
+			_defaultTextSpeed = ConfMan.getInt("original_gui_text_speed");
 
-			// In the original games the talk delay is represented as text speed,
-			// so we have to invert the value:
-			// - 9 is the highest text speed possible;
-			// - 0 is the lowest text speed possible.
 			if (VAR_CHARINC != 0xFF)
-				VAR(VAR_CHARINC) = 9 - _defaultTalkDelay;
-		} else if (_game.version != 8) {
-			ConfMan.setInt("original_gui_text_speed", getTalkSpeed());
+				VAR(VAR_CHARINC) = 9 - _defaultTextSpeed;
 		}
 
 		if (_game.version >= 7 && _imuseDigital) {
@@ -2168,14 +2167,10 @@ void ScummEngine::syncSoundSettings() {
 		VAR(VAR_VOICE_MODE) = _voiceMode;
 
 	if (ConfMan.hasKey("talkspeed", _targetName)) {
-		_defaultTalkDelay = getTalkSpeed();
+		_defaultTextSpeed = getTalkSpeed();
 
-		// In the original games the talk delay is represented as text speed,
-		// so we have to invert the value:
-		// - 9 is the highest text speed possible;
-		// - 0 is the lowest text speed possible.
 		if (VAR_CHARINC != 0xFF)
-			VAR(VAR_CHARINC) = 9 - _defaultTalkDelay;
+			VAR(VAR_CHARINC) = 9 - _defaultTextSpeed;
 	}
 
 	// Backyard Baseball 2003 uses a unique subtitle variable,
@@ -2871,7 +2866,7 @@ void ScummEngine_v5::scummLoop_handleSaveLoad() {
 
 		// For LOOM VGA Talkie, we restore the text glyphs on top of the note verbs
 		// and also restore the text description on top of the image of the selected
-		// object in the bottom right corner. 
+		// object in the bottom right corner.
 		// These text parts are not actually connected to the verbs (which are image
 		// verbs only). redrawVerbs() will not restore them. They require some script
 		// work. The original interpreter just sets this variable after loading.
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 4f74d275ec2..ba82305e47f 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1345,7 +1345,7 @@ protected:
 
 	bool _haveActorSpeechMsg = false;
 	bool _useTalkAnims = false;
-	uint16 _defaultTalkDelay = 0;
+	uint16 _defaultTextSpeed = 0;
 	int _saveSound = 0;
 	bool _native_mt32 = false;
 	bool _enable_gs = false;
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index 2a79c4da053..8e9e41f8ed7 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -790,7 +790,7 @@ void ScummEngine::CHARSET_1() {
 				restoreCharsetBg();
 		_msgCount = 0;
 	} else if (_game.version <= 2) {
-		_talkDelay += _msgCount * _defaultTalkDelay;
+		_talkDelay += _msgCount * _defaultTextSpeed;
 	}
 
 	if (_game.version > 3) {
@@ -892,7 +892,7 @@ void ScummEngine::CHARSET_1() {
 			mac_drawIndy3TextBox();
 
 		if (_game.version <= 2) {
-			_talkDelay += _defaultTalkDelay;
+			_talkDelay += _defaultTextSpeed;
 			VAR(VAR_CHARCOUNT)++;
 		} else {
 			_talkDelay += (int)VAR(VAR_CHARINC);


Commit: ddb54b30a4e3d1a60ad2851f81d08b7bc704f0c9
    https://github.com/scummvm/scummvm/commit/ddb54b30a4e3d1a60ad2851f81d08b7bc704f0c9
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Implement saving and loading routines for the old style menu

Changed paths:
    engines/scumm/gfx_gui.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v6.h
    engines/scumm/scumm_v7.h
    engines/scumm/smush/smush_player.h


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index b188dead47a..71d63f8d98e 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -382,14 +382,27 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 			textXPos = 160;
 			textYPos = 82;
 		} else {
-			textHeight = getGUIStringHeight(buttonString);
+			textHeight = getGUIStringHeight(ctrl->label);
 
 			if (centerFlag)
 				textXPos = relCentX + (x - ctrl->relativeCenterX) / 2;
 			else
 				textXPos = relCentX + 2;
 
-			textYPos = relCentY + ((y - relCentY) - textHeight) / 2 + 1;
+			if (_game.version == 8) {
+				textYPos = relCentY + ((y - relCentY) - textHeight) / 2 + 1;
+			} else {
+				int yOffset = 8;
+
+				if ((_game.id == GID_DIG && _useCJKMode) &&
+					((ctrl->label[0] >= 128 && ctrl->label[0] <= 159) ||
+					 (ctrl->label[0] >= 224 && ctrl->label[0] <= 253))) {
+					yOffset = 16;
+				}
+
+				textYPos = relCentY + (y - yOffset - relCentY + 2) / 2;
+			}
+
 		}
 
 		// Finally, choose the color and draw the text message
@@ -403,6 +416,10 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 		else
 			strcpy(buttonString, "null button");
 
+		if (_mainMenuSavegameLabel == id && _menuPage == GUI_PAGE_SAVE) {
+			strcat(buttonString, "_");
+		}
+
 		int tmpRight = _string[5].right;
 		_string[5].right = _screenWidth - 1;
 		drawGUIText(buttonString, textXPos, textYPos, _screenWidth - 1, textColor, centerFlag);
@@ -862,6 +879,13 @@ void ScummEngine_v7::toggleVoiceMode() {
 	}
 }
 
+void ScummEngine_v7::handleLoadDuringSmush() {
+	_saveLoadFlag = 2;
+	_saveLoadSlot = _mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9;
+	_splayer->release();
+	_splayer->resetAudioTracks();
+}
+
 int ScummEngine_v7::getBannerColor(int bannerId) {
 	if (_game.version == 8) {
 		byte *palette = isSmushActive() ? _splayer->getVideoPalette() : _currentPalette;
@@ -960,20 +984,138 @@ void ScummEngine::queryRestart() {
 // This function is actually not a thing in the original, it's here to
 // make things a little bit more modern and avoid making the menu feel
 // artificially slow.
-bool ScummEngine::shouldHighlightAndWait(int clickedControl) {
+bool ScummEngine::shouldHighlightLabelAndWait(int clickedControl) {
 	return ((clickedControl >= GUI_CTRL_SAVE_BUTTON && clickedControl <= GUI_CTRL_PATH_BUTTON) ||
 			(clickedControl == GUI_CTRL_DISPLAY_TEXT_CHECKBOX ||
 			 clickedControl == GUI_CTRL_SPOOLED_MUSIC_CHECKBOX));
 }
 
+void ScummEngine::fillSavegameLabels() {
+	bool availSaves[100];
+	listSavegames(availSaves, ARRAYSIZE(availSaves));
+	Common::String name;
+	for (int i = 0; i < 9; i++) {
+		int curSaveSlot = i + 1 + _curDisplayedSaveSlotPage * 9;
+		sprintf_s(_savegameNames[i].label, sizeof(_savegameNames[i].label), "%2d. ", curSaveSlot);
+
+		if (availSaves[curSaveSlot]) {
+			if (getSavegameName(curSaveSlot, name)) {
+				sprintf_s(_savegameNames[i].label, sizeof(_savegameNames[i].label), "%2d. %s", curSaveSlot, name.c_str());
+			} else {
+				// The original printed "WARNING... old savegame", but we do support old savegames :-)
+				sprintf_s(_savegameNames[i].label, sizeof(_savegameNames[i].label), "%2d. WARNING: wrong save version", curSaveSlot);
+			}
+		}
+	}
+}
+
+bool ScummEngine::canWriteGame(int slotId) {
+	bool saveList[100];
+	char msgLabelPtr[512];
+	char localizedYesKey;
+
+	listSavegames(saveList, ARRAYSIZE(saveList));
+	if (saveList[slotId]) {
+		convertMessageToString((const byte *)getGUIString(gsReplacePrompt), (byte *)msgLabelPtr, sizeof(msgLabelPtr));
+
+		// Fallback to a hardcoded string
+		if (msgLabelPtr[0] == '\0') {
+			strcpy(msgLabelPtr, "Do you want to replace this saved game?  (Y/N)Y");
+		}
+
+		localizedYesKey = msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1];
+		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
+
+		// "Do you want to replace this saved game?  (Y/N)"
+		Common::KeyState ks = showBannerAndPause(0, -1, msgLabelPtr);
+
+		return (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii);
+	}
+
+	return true;
+}
+
+bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked) {
+	while (true) {
+		waitForTimer(1);
+		waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
+		rightMsClicked = false;
+		if (ks.keycode == Common::KEYCODE_RETURN) {
+			clearClickedStatus();
+			executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1);
+			return true;
+		} else if (leftMsClicked) {
+			clearClickedStatus();
+			break;
+		}
+
+		// Handle special key presses
+		int curLen = strlen(_savegameNames[_mainMenuSavegameLabel - 1].label);
+		if (ks.keycode == Common::KEYCODE_BACKSPACE) {
+			 // Prevent the user from deleting the header (" 1. ")
+			if ((curLen) > 4) {
+				_savegameNames[_mainMenuSavegameLabel - 1].label[curLen - 1] = '\0';
+				drawInternalGUIControl(_mainMenuSavegameLabel, 1);
+				ScummEngine::drawDirtyScreenParts();
+				_system->updateScreen();
+			}
+		} else if (ks.ascii >= 32 && ks.ascii <= 122) { // Handle characters
+			if (curLen < 39) {
+				_savegameNames[_mainMenuSavegameLabel - 1].label[curLen] = ks.ascii;
+				_savegameNames[_mainMenuSavegameLabel - 1].label[curLen + 1] = '\0';
+				drawInternalGUIControl(_mainMenuSavegameLabel, 1);
+				ScummEngine::drawDirtyScreenParts();
+				_system->updateScreen();
+			}
+		}
+
+		clearClickedStatus();
+	}
+
+	return false;
+}
+
+void ScummEngine::saveCursorPreMenu() {
+	// Force the cursor to be ON...
+	_oldCursorState = _cursor.state;
+	_cursor.state = 1;
+	CursorMan.showMouse(_cursor.state > 0);
+
+	if (_game.version > 5) {
+		// Backup the current cursor graphics and parameters
+		// and set up the main menu cursor...
+		_curGrabbedCursor = (byte *)malloc(sizeof(_grabbedCursor));
+		if (_curGrabbedCursor) {
+			memcpy(_curGrabbedCursor, _grabbedCursor, sizeof(_grabbedCursor));
+			_curCursorState = isSmushActive() ? 0 : _cursor.state;
+			_curCursorWidth = _cursor.width;
+			_curCursorHeight = _cursor.height;
+			_curCursorHotspotX = _cursor.hotspotX;
+			_curCursorHotspotY = _cursor.hotspotY;
+			setDefaultCursor();
+		}
+	}
+
+	CursorMan.showMouse(true);
+}
+
+void ScummEngine::restoreCursorPostMenu() {
+	if (_game.version > 5 && _curGrabbedCursor) {
+		// Restore the previous cursor...
+		_cursor.state = _curCursorState;
+		CursorMan.showMouse(_cursor.state > 0);
+		setCursorHotspot(_curCursorHotspotX, _curCursorHotspotY);
+		setCursorFromBuffer(_curGrabbedCursor, _curCursorWidth, _curCursorHeight, _curCursorWidth);
+		free(_curGrabbedCursor);
+		_curGrabbedCursor = nullptr;
+	}
+
+	// Restore the old cursor state...
+	_cursor.state = _oldCursorState;
+}
+
 void ScummEngine::showMainMenu() {
 	char saveScreenTitle[512];
-	byte *curGrabbedCursor = nullptr;
-	int curCursorWidth = -1;
-	int curCursorHeight = -1;
-	int curCursorHotspotX = -1;
-	int curCursorHotspotY = -1;
-	int curCursorState = -1;
 	int args[NUM_SCRIPT_LOCAL];
 	bool leftMsClicked = false, rightMsClicked = false;
 	int clickedControl = -1;
@@ -981,6 +1123,8 @@ void ScummEngine::showMainMenu() {
 
 	Common::KeyState ks;
 
+	memset(args, 0, sizeof(args));
+
 	// Pause the engine
 	PauseToken pt = pauseEngine();
 
@@ -998,27 +1142,8 @@ void ScummEngine::showMainMenu() {
 	drawMainMenuTitle(saveScreenTitle);
 	updateMainMenuControls();
 
-	// Force the cursor to be ON...
-	int8 oldCursorState = _cursor.state;
-	_cursor.state = 1;
-	CursorMan.showMouse(_cursor.state > 0);
-
-	if (_game.version > 5) {
-		// Backup the current cursor graphics and parameters
-		// and set up the main menu cursor...
-		curGrabbedCursor = (byte *)malloc(sizeof(_grabbedCursor));
-		if (curGrabbedCursor) {
-			memcpy(curGrabbedCursor, _grabbedCursor, sizeof(_grabbedCursor));
-			curCursorState = isSmushActive() ? 0 : _cursor.state;
-			curCursorWidth = _cursor.width;
-			curCursorHeight = _cursor.height;
-			curCursorHotspotX = _cursor.hotspotX;
-			curCursorHotspotY = _cursor.hotspotY;
-			setDefaultCursor();
-		}
-	}
-
-	CursorMan.showMouse(true);
+	// Save the current cursor state...
+	saveCursorPreMenu();
 
 	// Notify that the menu is now active
 	_mainMenuIsActive = true;
@@ -1031,8 +1156,14 @@ void ScummEngine::showMainMenu() {
 		// Update the screen and the cursor while we're in the loop
 		waitForTimer(1);
 
-		// Wait for any left mouse button presses...
-		waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
+		if (_menuPage == GUI_PAGE_SAVE && _mainMenuSavegameLabel > 0) {
+			if (userWriteLabelRoutine(ks, leftMsClicked, rightMsClicked))
+				break;
+		} else {
+			// Wait for any left mouse button presses...
+			waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
+		}
+
 		rightMsClicked = false; // We don't care for this
 
 		if (leftMsClicked) {
@@ -1052,7 +1183,7 @@ void ScummEngine::showMainMenu() {
 						// Wait a little bit (the original waited 120 quarter frames, which feels like molasses).
 						// We only perform this artificial wait for buttons; the original also did this for
 						// sliders but it feels artificially slow, and we don't want that here :-)
-						if (shouldHighlightAndWait(clickedControl))
+						if (shouldHighlightLabelAndWait(clickedControl))
 							waitForTimer(60);
 
 						// Dehighlight it
@@ -1062,6 +1193,20 @@ void ScummEngine::showMainMenu() {
 						if (executeMainMenuOperation(clickedControl, curMouseX))
 							break;
 					}
+				} else {
+					int tmp = _mainMenuSavegameLabel;
+					_mainMenuSavegameLabel = clickedControl;
+
+					drawInternalGUIControl(tmp, 0);
+					drawInternalGUIControl(_mainMenuSavegameLabel, 1);
+
+					ScummEngine::drawDirtyScreenParts();
+					_system->updateScreen();
+
+					if (_menuPage == GUI_PAGE_LOAD) {
+						if (executeMainMenuOperation(GUI_CTRL_OK_BUTTON, curMouseX))
+							break;
+					}
 				}
 			}
 		}
@@ -1076,35 +1221,35 @@ void ScummEngine::showMainMenu() {
 
 	_completeScreenRedraw = true;
 
-	// Run the exit savescreen script, if available
-	if (VAR_SAVELOAD_SCRIPT2 != 0xFF)
-		runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, args);
+	// Restore the old cursor state only if we're not loading a game...
+	if (_saveScriptParam != GAME_PROPER_LOAD && _saveLoadFlag != 2) {
+		restoreCursorPostMenu();
+	} else if (_saveLoadFlag == 2) {
+		_cursor.state = 0;
+	}
 
-	if (_game.version > 5 && curGrabbedCursor) {
-		// Restore the previous cursor...
-		_cursor.state = curCursorState;
-		CursorMan.showMouse(_cursor.state > 0);
-		setCursorHotspot(curCursorHotspotX, curCursorHotspotY);
-		setCursorFromBuffer(curGrabbedCursor, curCursorWidth, curCursorHeight, curCursorWidth);
-		free(curGrabbedCursor);
-		curGrabbedCursor = nullptr;
+	// Run the exit savescreen script, if available
+	if (_saveScriptParam != 0) {
+		args[0] = _saveScriptParam;
+		if (VAR_SAVELOAD_SCRIPT2 != 0xFF) {
+			runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, args);
+			_saveScriptParam = 0;
+		}
 	}
 
 	// Resume the engine
 	pt.clear();
 	clearClickedStatus();
-
-	// Restore the old cursor state...
-	_cursor.state = oldCursorState;
-	CursorMan.showMouse(_cursor.state > 0);
 }
 
 bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 	char saveScreenTitle[512];
+	char formattedString[512];
+
 	switch (op) {
 	case GUI_CTRL_SAVE_BUTTON:
 		_mainMenuSavegameLabel = 0;
-		//constructSavegameString();
+		fillSavegameLabels();
 		_menuPage = GUI_PAGE_SAVE;
 		setUpMainMenuControls();
 		drawMainMenuControls();
@@ -1112,7 +1257,7 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 		break;
 	case GUI_CTRL_LOAD_BUTTON:
 		_mainMenuSavegameLabel = 0;
-		//constructSavegameString();
+		fillSavegameLabels();
 		_menuPage = GUI_PAGE_LOAD;
 		setUpMainMenuControls();
 		drawMainMenuControls();
@@ -1125,6 +1270,100 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 		_quitByButton = shouldQuit();
 		return true;
 	case GUI_CTRL_OK_BUTTON:
+		if (_menuPage == GUI_PAGE_SAVE) {
+			if (_mainMenuSavegameLabel > 0) {
+				convertMessageToString((const byte *)getGUIString(gsSaving), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+				sprintf_s(formattedString, sizeof(formattedString), saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[4]);
+				drawMainMenuTitle(formattedString);
+				ScummEngine::drawDirtyScreenParts();
+				_system->updateScreen();
+
+				waitForTimer(60);
+
+				Common::String dummyString;
+				_saveLoadDescription = &_savegameNames[_mainMenuSavegameLabel - 1].label[4];
+
+				if (canWriteGame(_mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9)) {
+					restoreCursorPostMenu();
+					if (saveState(_mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9, false, dummyString)) {
+						saveCursorPreMenu();
+						_saveScriptParam = GAME_PROPER_SAVE;
+						drawMainMenuControls();
+						return true;
+					}
+				} else {
+					saveCursorPreMenu();
+					convertMessageToString((const byte *)getGUIString(gsGameNotSaved), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+					if (_game.id == GID_DIG) {
+						showBannerAndPause(1, -1, saveScreenTitle);
+						drawMainMenuControls();
+					} else {
+						drawMainMenuTitle(saveScreenTitle);
+					}
+
+					ScummEngine::drawDirtyScreenParts();
+				}
+			} else {
+				convertMessageToString((const byte *)getGUIString(gsMustName), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+				drawMainMenuTitle(saveScreenTitle);
+				ScummEngine::drawDirtyScreenParts();
+			}
+
+			// The original, after doing the above, immediately redraws the menus,
+			// effectively overwriting the title we've just changed.
+			// In a DOS machine one could effectively see the changed title for a
+			// fraction of time, before reverting to the normale one.
+			// We, on the other hand, wouldn't be able to see changed title at all,
+			// so let's comment the following instruction :-)
+			//
+			//drawMainMenuControls();
+
+		} else if (_menuPage == GUI_PAGE_LOAD) {
+			if (_mainMenuSavegameLabel > 0) {
+				convertMessageToString((const byte *)getGUIString(gsLoading), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+				sprintf_s(formattedString, sizeof(formattedString), saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[4]);
+				drawMainMenuTitle(formattedString);
+				ScummEngine::drawDirtyScreenParts();
+				_system->updateScreen();
+
+				waitForTimer(60);
+
+				if (strlen(_savegameNames[_mainMenuSavegameLabel - 1].label) == 4) {
+					drawMainMenuControls();
+					ScummEngine::drawDirtyScreenParts();
+					break;
+				}
+
+				if (isSmushActive()) {
+					handleLoadDuringSmush();
+					return true;
+				}
+
+				if (loadState(_mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9, false)) {
+					if (!_spooledMusicIsToBeEnabled)
+						_imuseDigital->diMUSEDisableSpooledMusic();
+
+					setSkipVideo(0);
+					_saveScriptParam = GAME_PROPER_LOAD;
+					return true;
+				} else {
+					convertMessageToString((const byte *)getGUIString(gsGameNotLoaded), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+					if (_game.id == GID_DIG) {
+						showBannerAndPause(1, -1, saveScreenTitle);
+						drawMainMenuControls();
+					} else {
+						drawMainMenuTitle(saveScreenTitle);
+					}
+
+					ScummEngine::drawDirtyScreenParts();
+				}
+
+				// See the comment for the Save control
+				//
+				//drawMainMenuControls();
+			}
+		}
+
 		break;
 	case GUI_CTRL_CANCEL_BUTTON:
 		_menuPage = GUI_PAGE_MAIN;
@@ -1137,6 +1376,20 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 		break;
 	case GUI_CTRL_ARROW_UP_BUTTON:
 	case GUI_CTRL_ARROW_DOWN_BUTTON:
+		if (_menuPage != GUI_PAGE_MAIN) {
+			if (op == GUI_CTRL_ARROW_UP_BUTTON) {
+				_curDisplayedSaveSlotPage--;
+			} else {
+				_curDisplayedSaveSlotPage++;
+			}
+
+			_curDisplayedSaveSlotPage = CLIP<int>(_curDisplayedSaveSlotPage, 0, 10);
+			_mainMenuSavegameLabel = 0;
+			fillSavegameLabels();
+			drawMainMenuControls();
+			ScummEngine::drawDirtyScreenParts();
+		}
+		break;
 	case GUI_CTRL_PATH_BUTTON:
 		// This apparently should't do anything
 		break;
@@ -1191,7 +1444,6 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 }
 
 void ScummEngine::setUpMainMenuControls() {
-	char *saveNames;
 	int yComponent, yConstant, yConstant2;
 
 	yComponent = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
@@ -1534,7 +1786,6 @@ void ScummEngine::setUpMainMenuControls() {
 			(char *)getGUIString(gsCancel), 1, 1);
 
 		// Savegame names
-		saveNames = _savegameNames;
 		for (int i = GUI_CTRL_FIRST_SG, j = 11; i <= GUI_CTRL_LAST_SG; i++, j += 11) {
 			setUpInternalGUIControl(i,
 				getBannerColor(9),
@@ -1549,9 +1800,7 @@ void ScummEngine::setUpMainMenuControls() {
 				yConstant + j + ((_game.id == GID_DIG && _useCJKMode) ? 12 : 4),
 				-179,
 				-9,
-				saveNames, 0, 0);
-
-			saveNames += 40;
+				_savegameNames[i - 1].label, 0, 0);
 		}
 	}
 }
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 6c16194881e..66b1289124c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2658,8 +2658,11 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 		Common::String filename;
 		if (_saveLoadFlag == 1) {
 			success = saveState(_saveLoadSlot, _saveTemporaryState, filename);
-			if (!success)
+			if (!success) {
 				errMsg = _("Failed to save game to file:\n\n%s");
+				if (isUsingOriginalGUI() && VAR_GAME_LOADED != 0xFF && _game.version <= 7)
+					VAR(VAR_GAME_LOADED) = GAME_FAILED_SAVE;
+			}
 
 			if (success && _saveTemporaryState && VAR_GAME_LOADED != 0xFF && _game.version <= 7)
 				VAR(VAR_GAME_LOADED) = GAME_PROPER_SAVE;
@@ -2668,8 +2671,11 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 				_lastSaveTime = _system->getMillis();
 		} else {
 			success = loadState(_saveLoadSlot, _saveTemporaryState, filename);
-			if (!success)
+			if (!success) {
 				errMsg = _("Failed to load saved game from file:\n\n%s");
+				if (isUsingOriginalGUI() && VAR_GAME_LOADED != 0xFF && _game.version <= 7)
+					VAR(VAR_GAME_LOADED) = GAME_FAILED_LOAD;
+			}
 
 			if (success && (_saveTemporaryState || _game.version == 8) && VAR_GAME_LOADED != 0xFF)
 				VAR(VAR_GAME_LOADED) = (_game.version == 8) ? 1 : GAME_PROPER_LOAD;
@@ -2680,7 +2686,7 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 
 			GUI::MessageDialog dialog(buf);
 			runDialog(dialog);
-		} else if (_saveLoadFlag == 1 && _saveLoadSlot != 0 && !_saveTemporaryState) {
+		} else if (_saveLoadFlag == 1 && _saveLoadSlot != 0 && !_saveTemporaryState && !isUsingOriginalGUI()) {
 			// Display "Save successful" message, except for auto saves
 			Common::U32String buf = Common::U32String::format(_("Successfully saved game in file:\n\n%s"), filename.c_str());
 
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index ba82305e47f..25c98024fe4 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -449,6 +449,10 @@ struct InternalGUIControl {
 	bool doubleLinesFlag;
 };
 
+struct GUISaveGameLabel {
+	char label[40];
+};
+
 /**
  * Base class for all SCUMM engines.
  */
@@ -617,9 +621,10 @@ protected:
 	char _arrowUp[2] = {'\x18', '\0'};
 	char _arrowDown[2] = {'\x19', '\0'};
 
-	char _savegameNames[40 * 10];
+	GUISaveGameLabel _savegameNames[9];
 	int _menuPage = 0;
 	int _mainMenuSavegameLabel = 1;
+	int _curDisplayedSaveSlotPage = 0;
 	bool _mainMenuIsActive = false;
 	bool _quitByButton = false;
 	char _mainMenuMusicSlider[17];
@@ -627,6 +632,16 @@ protected:
 	char _mainMenuSfxSlider[17];
 	char _mainMenuTextSpeedSlider[17];
 	int _spooledMusicIsToBeEnabled = 1;
+	int _saveScriptParam = 0;
+
+	// Saved cursor pre and post GUI
+	byte *_curGrabbedCursor = nullptr;
+	int8 _oldCursorState = 0;
+	int _curCursorState = 0;
+	int _curCursorWidth = 0;
+	int _curCursorHeight = 0;
+	int _curCursorHotspotX = 0;
+	int _curCursorHotspotY = 0;
 
 	void initBanners();
 	Common::KeyState showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...);
@@ -656,6 +671,8 @@ protected:
 	virtual void setSpeechVolume(int volume);
 	virtual void setSFXVolume(int volume);
 	virtual void toggleVoiceMode();
+	virtual void handleLoadDuringSmush() {}
+	virtual void setSkipVideo(int value) {}
 
 	void showMainMenu();
 	void setUpMainMenuControls();
@@ -663,7 +680,12 @@ protected:
 	void updateMainMenuControls();
 	void drawMainMenuTitle(const char *title);
 	bool executeMainMenuOperation(int op, int mouseX);
-	bool shouldHighlightAndWait(int clickedControl);
+	bool shouldHighlightLabelAndWait(int clickedControl);
+	void fillSavegameLabels();
+	bool canWriteGame(int slotId);
+	bool userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked);
+	void saveCursorPreMenu();
+	void restoreCursorPostMenu();
 
 
 public:
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index 7b31de156a5..50dc55156c2 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -165,6 +165,7 @@ protected:
 
 	int getBannerColor(int bannerId) override;
 	const char *getGUIString(int stringId) override;
+	void setSkipVideo(int value) override { _skipVideo = value; }
 
 public:
 	bool akos_increaseAnims(const byte *akos, Actor *a);
diff --git a/engines/scumm/scumm_v7.h b/engines/scumm/scumm_v7.h
index c8b98ba033b..3f2bf605be6 100644
--- a/engines/scumm/scumm_v7.h
+++ b/engines/scumm/scumm_v7.h
@@ -155,6 +155,7 @@ protected:
 	void setSpeechVolume(int volume) override;
 	void setSFXVolume(int volume) override;
 	void toggleVoiceMode() override;
+	void handleLoadDuringSmush() override;
 
 	void setDefaultCursor() override;
 	void updateCursor() override;
diff --git a/engines/scumm/smush/smush_player.h b/engines/scumm/smush/smush_player.h
index a813c62a0d5..15559795798 100644
--- a/engines/scumm/smush/smush_player.h
+++ b/engines/scumm/smush/smush_player.h
@@ -181,6 +181,7 @@ public:
 	void processDispatches(int16 feedSize);
 	bool isAudioCallbackEnabled();
 	byte *getVideoPalette();
+	void resetAudioTracks();
 
 protected:
 	int _width, _height;
@@ -226,7 +227,6 @@ private:
 	void terminateAudio();
 	int isChanActive(int flagId);
 	int addAudioTrack(int32 trackBlockSize, int32 maxBlockSize);
-	void resetAudioTracks();
 	void setGainReductionParams(int16 gainReductionLowerBound, int16 gainReductionMultiplier);
 	void fillAudioTrackInfo(uint8 *srcBuf, uint16 *flagsAccumulator, uint32 size, int groupId, int vol, int pan, int16 flags, int trkId, int index, int maxFrames);
 	bool processAudioCodes(int idx, int32 &tmpFeedSize, int &mixVolume);


Commit: 8ec54a8a26a3a5cdaf4e8b86c67bb2abe372b1ff
    https://github.com/scummvm/scummvm/commit/8ec54a8a26a3a5cdaf4e8b86c67bb2abe372b1ff
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix GUI rendering in rooms with vertical scrolling

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 71d63f8d98e..8878a7dc800 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -147,7 +147,7 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		bannerSaveYStart = 78;
 	} else {
 		startingPointX = 156 - roundedWidth;
-		startingPointY = ((_game.version < 7) ? 80 : _screenTop + 90);
+		startingPointY = ((_game.version < 7) ? 80 : _screenHeight / 2 - 10);
 		xPos = roundedWidth + 163 + ((_game.version < 7) ? 1 : 0);
 		yPos = -12;
 		bannerSaveYStart = startingPointY - ((_game.version < 7) ? 2 : 0);
@@ -238,7 +238,7 @@ void ScummEngine::clearBanner() {
 			} else if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformFMTowns) {
 				startingPointY = 78;
 			} else {
-				startingPointY = ((_game.version < 7) ? 80 - 2 : _screenTop + 90);
+				startingPointY = ((_game.version < 7) ? 80 - 2 : _screenHeight / 2 - 10);
 			}
 
 			// FM-Towns games draw the banners on the text surface, so restore both surfaces...
@@ -323,6 +323,7 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 	int textColor, fillColor;
 	int boxSizeX, boxSizeY;
 	int offset = (_game.version == 8) ? 2 : 1;
+	int topComp = (_game.version < 8) ? _screenTop : 0;
 
 	bool centerFlag;
 	char buttonString[512];
@@ -350,7 +351,7 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 		} else {
 			if (ctrl->doubleLinesFlag) {
 				// Draw the main box...
-				drawBox(relCentX + 1, relCentY + 1, boxSizeX - offset, boxSizeY - offset, fillColor);
+				drawBox(relCentX + 1, relCentY + 1 + topComp, boxSizeX - offset, boxSizeY - offset + topComp, fillColor);
 
 				// 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);
@@ -363,7 +364,7 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 				drawLine(relCentX + 1, relCentY + 1, relCentX + 1, y - 1, ctrl->leftLineColor);
 				drawLine(x - 1, relCentY + 1, x - 1, y - 1, ctrl->rightLineColor);
 			} else {
-				drawBox(relCentX, relCentY, x, y, (highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor));
+				drawBox(relCentX, relCentY + topComp, x, y + topComp, (highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor));
 
 				drawLine(relCentX, relCentY, x, relCentY, ctrl->topLineColor);
 				drawLine(relCentX, y, x, y, ctrl->bottomLineColor);
@@ -1447,8 +1448,8 @@ void ScummEngine::setUpMainMenuControls() {
 	int yComponent, yConstant, yConstant2;
 
 	yComponent = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
-	yConstant = _screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop;
-	yConstant2 = _screenHeight / 2 + ((yComponent - 1) / 2) + _screenTop;
+	yConstant = _screenHeight / 2 - ((yComponent - 1) / 2);
+	yConstant2 = _screenHeight / 2 + ((yComponent - 1) / 2);
 
 	for (int i = 0; i < ARRAYSIZE(_internalGUIControls); i++) {
 		_internalGUIControls[i].relativeCenterX = -1;
@@ -1499,7 +1500,7 @@ void ScummEngine::setUpMainMenuControls() {
 				getBannerColor(11),
 				getBannerColor(12),
 				108,
-				_screenTop + 57,
+				57,
 				-12,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -1515,7 +1516,7 @@ void ScummEngine::setUpMainMenuControls() {
 				getBannerColor(10),
 				getBannerColor(12),
 				108,
-				_screenTop + 71,
+				71,
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -1531,7 +1532,7 @@ void ScummEngine::setUpMainMenuControls() {
 				getBannerColor(10),
 				getBannerColor(12),
 				108,
-				_screenTop + 85,
+				85,
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -1547,7 +1548,7 @@ void ScummEngine::setUpMainMenuControls() {
 				getBannerColor(10),
 				getBannerColor(12),
 				108,
-				_screenTop + 99,
+				99,
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -1764,7 +1765,6 @@ void ScummEngine::setUpMainMenuControls() {
 		if (_menuPage == GUI_PAGE_LOAD) {
 			cancelButtonAnchorY = _screenHeight / 2 +
 				(((_game.id == GID_DIG && _useCJKMode) ? 10 : 7) - yComponent / 2) +
-				_screenTop +
 				((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) +
 				40;
 		} else {
@@ -1855,7 +1855,7 @@ void ScummEngine::updateMainMenuControls() {
 	int yComponent, yConstant;
 
 	yComponent = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
-	yConstant = _screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop;
+	yConstant = _screenHeight / 2 - ((yComponent - 1) / 2);
 
 	strncpy(_mainMenuMusicSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuMusicSlider));
 	strncpy(_mainMenuSpeechSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuSpeechSlider));
@@ -1959,13 +1959,13 @@ void ScummEngine::drawMainMenuTitle(const char *title) {
 
 		drawGUIText(title,
 			159,
-			_screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop + 4,
+			_screenHeight / 2 - ((yComponent - 1) / 2) + 4,
 			_screenWidth - 1,
 			stringColor,
 			true);
 	} else {
 		drawBox(18, _screenTop + 44, 301, _screenTop + 52, boxColor);
-		drawGUIText(title, 159, _screenTop + 44, _screenWidth - 1, stringColor, true);
+		drawGUIText(title, 159, 44, _screenWidth - 1, stringColor, true);
 	}
 
 	ScummEngine::drawDirtyScreenParts();


Commit: 6e96d5f85312cbd690710ed9d737262e81f750b0
    https://github.com/scummvm/scummvm/commit/6e96d5f85312cbd690710ed9d737262e81f750b0
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix warning

Changed paths:
    engines/scumm/dialogs.cpp


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 799dea3fc5c..98daa44185e 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -426,10 +426,6 @@ const char *InfoDialog::getPlainEngineString(int stringno) {
 	} else if (_vm->_game.version == 7) {
 		result = (const char *)_vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
 
-		if (!result) {
-			result = (const char *)_vm->VAR(string_map_table_v7[stringno - 1].num);
-		}
-
 		if (!result) {
 			result = (const char *)string_map_table_v7[stringno - 1].string;
 		}


Commit: ef8797e65f804632f8906f7a6e47fddabea22718
    https://github.com/scummvm/scummvm/commit/ef8797e65f804632f8906f7a6e47fddabea22718
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix text color rendering glitch after getting out of the menu

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 8878a7dc800..22c42701736 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -953,7 +953,7 @@ void ScummEngine::queryQuit() {
 		localizedYesKey = msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1];
 		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
 
-		// "Are you sure you want to quit?  (Y-N)"
+		// "Are you sure you want to quit?  (Y/N)"
 		Common::KeyState ks = showBannerAndPause(0, -1, msgLabelPtr);
 
 		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) {
@@ -1220,6 +1220,8 @@ void ScummEngine::showMainMenu() {
 		queryQuit();
 	}
 
+	_mainMenuIsActive = false;
+
 	_completeScreenRedraw = true;
 
 	// Restore the old cursor state only if we're not loading a game...
@@ -1238,6 +1240,12 @@ void ScummEngine::showMainMenu() {
 		}
 	}
 
+	// A little bit of hackery: since we handle the main loop a little bit
+	// differently (basically we start from a different position, but the order
+	// remains the same), we call CHARSET_1() here to refresh the dialog texts
+	// immediately and avoid getting a frame in which their color is wrong...
+	CHARSET_1();
+
 	// Resume the engine
 	pt.clear();
 	clearClickedStatus();
@@ -1853,6 +1861,7 @@ void ScummEngine::drawMainMenuControls() {
 void ScummEngine::updateMainMenuControls() {
 	char msg[256];
 	int yComponent, yConstant;
+	int textColor = getBannerColor(2);
 
 	yComponent = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
 	yConstant = _screenHeight / 2 - ((yComponent - 1) / 2);
@@ -1907,29 +1916,29 @@ 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, 29, yConstant + 19, _screenWidth - 1, getBannerColor(2), false);
+		drawGUIText(msg, 29, yConstant + 19, _screenWidth - 1, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstant + 33, _screenWidth - 1, getBannerColor(2), false);
+		drawGUIText(msg, 29, yConstant + 33, _screenWidth - 1, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstant + 47, _screenWidth - 1, getBannerColor(2), false);
+		drawGUIText(msg, 29, yConstant + 47, _screenWidth - 1, textColor, false);
 	} else {
 		convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstant + 25, _screenWidth - 1, getBannerColor(2), false);
+		drawGUIText(msg, 29, yConstant + 25, _screenWidth - 1, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstant + 43, _screenWidth - 1, getBannerColor(2), false);
+		drawGUIText(msg, 29, yConstant + 43, _screenWidth - 1, textColor, false);
 	}
 
 	convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
-	drawGUIText(msg, 29, yConstant + 61, _screenWidth - 1, getBannerColor(2), false);
+	drawGUIText(msg, 29, yConstant + 61, _screenWidth - 1, textColor, false);
 
 	convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
-	drawGUIText(msg, 29, yConstant + 88, _screenWidth - 1, getBannerColor(2), false);
+	drawGUIText(msg, 29, yConstant + 88, _screenWidth - 1, textColor, false);
 
 	convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
-	drawGUIText(msg, 29, yConstant + 102, _screenWidth - 1, getBannerColor(2), false);
+	drawGUIText(msg, 29, yConstant + 102, _screenWidth - 1, textColor, false);
 
 	drawLine(23, yConstant + 77, 204, yConstant + 77, getBannerColor(17));
 	drawLine(23, yConstant + 78, 204, yConstant + 78, getBannerColor(4));


Commit: 8356072adde694735efcf57cf61b1ebd6825ed58
    https://github.com/scummvm/scummvm/commit/8356072adde694735efcf57cf61b1ebd6825ed58
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix a color glitch when loading a game during a SMUSH movie

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


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 22c42701736..2b1b084b041 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -881,10 +881,22 @@ void ScummEngine_v7::toggleVoiceMode() {
 }
 
 void ScummEngine_v7::handleLoadDuringSmush() {
+	// Notify the SMUSH player that we want to load a game...
 	_saveLoadFlag = 2;
 	_saveLoadSlot = _mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9;
-	_splayer->release();
-	_splayer->resetAudioTracks();
+
+	// Force screen to black to avoid glitches...
+	VirtScreen *vs = &_virtscr[kMainVirtScreen];
+	memset(vs->getPixels(0, 0), 0, vs->pitch * vs->h);
+	vs->setDirtyRange(0, vs->h);
+	ScummEngine::drawDirtyScreenParts();
+
+	// The original at this point does this, but we automatically
+	// handle the corresponding operations automatically in our
+	// SMUSH player...
+	//
+	//_splayer->release();
+	//_splayer->resetAudioTracks();
 }
 
 int ScummEngine_v7::getBannerColor(int bannerId) {
diff --git a/engines/scumm/smush/smush_player.h b/engines/scumm/smush/smush_player.h
index 15559795798..a813c62a0d5 100644
--- a/engines/scumm/smush/smush_player.h
+++ b/engines/scumm/smush/smush_player.h
@@ -181,7 +181,6 @@ public:
 	void processDispatches(int16 feedSize);
 	bool isAudioCallbackEnabled();
 	byte *getVideoPalette();
-	void resetAudioTracks();
 
 protected:
 	int _width, _height;
@@ -227,6 +226,7 @@ private:
 	void terminateAudio();
 	int isChanActive(int flagId);
 	int addAudioTrack(int32 trackBlockSize, int32 maxBlockSize);
+	void resetAudioTracks();
 	void setGainReductionParams(int16 gainReductionLowerBound, int16 gainReductionMultiplier);
 	void fillAudioTrackInfo(uint8 *srcBuf, uint16 *flagsAccumulator, uint32 size, int groupId, int vol, int pan, int16 flags, int trkId, int index, int maxFrames);
 	bool processAudioCodes(int idx, int32 &tmpFeedSize, int &mixVolume);


Commit: 16661b21095bb377b21f40adb487d45b866d2354
    https://github.com/scummvm/scummvm/commit/16661b21095bb377b21f40adb487d45b866d2354
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
GRAPHICS: Add function to create thumbnail without binding it to a output stream

Changed paths:
    graphics/thumbnail.cpp
    graphics/thumbnail.h


diff --git a/graphics/thumbnail.cpp b/graphics/thumbnail.cpp
index 126a20d9f36..210d8be8817 100644
--- a/graphics/thumbnail.cpp
+++ b/graphics/thumbnail.cpp
@@ -201,6 +201,18 @@ bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface *&thumbnail
 	return true;
 }
 
+bool createThumbnail(Graphics::Surface &thumb) {
+	if (thumb.getPixels())
+		thumb.free();
+
+	if (!createThumbnailFromScreen(&thumb)) {
+		warning("Couldn't create thumbnail from screen, aborting thumbnail save");
+		return false;
+	}
+
+	return true;
+}
+
 bool saveThumbnail(Common::WriteStream &out) {
 	Graphics::Surface thumb;
 
diff --git a/graphics/thumbnail.h b/graphics/thumbnail.h
index fbc360f0a0a..37c96f9e139 100644
--- a/graphics/thumbnail.h
+++ b/graphics/thumbnail.h
@@ -62,6 +62,11 @@ bool skipThumbnail(Common::SeekableReadStream &in);
  */
 bool loadThumbnail(Common::SeekableReadStream &in, Graphics::Surface *&thumbnail, bool skipThumbnail = false);
 
+/**
+ * Creates a thumbnail from screen contents.
+ */
+bool createThumbnail(Graphics::Surface &thumb);
+
 /**
  * Saves a thumbnail to the given write stream.
  * Automatically creates a thumbnail from screen contents.


Commit: b881a3f600e7da7c60657a44be9aadf489e00eed
    https://github.com/scummvm/scummvm/commit/b881a3f600e7da7c60657a44be9aadf489e00eed
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Create proper thumbnail for savegames created within the original menu

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


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 2b1b084b041..ffa5f86f887 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -29,6 +29,7 @@
 #include "scumm/imuse_digi/dimuse_engine.h"
 
 #include "graphics/cursorman.h"
+#include "graphics/thumbnail.h"
 
 namespace Scumm {
 
@@ -1138,6 +1139,9 @@ void ScummEngine::showMainMenu() {
 
 	memset(args, 0, sizeof(args));
 
+	// Generate the thumbnail, in case the game is saved
+	Graphics::createThumbnail(_savegameThumbnail);
+
 	// Pause the engine
 	PauseToken pt = pauseEngine();
 
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 080b0ec68d6..81d5caacfbf 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -497,7 +497,11 @@ bool ScummEngine::saveState(Common::WriteStream *out, bool writeHeader) {
 		saveSaveGameHeader(out, hdr);
 	}
 #if !defined(__DS__) && !defined(__N64__)
-	Graphics::saveThumbnail(*out);
+	if (isUsingOriginalGUI() && _mainMenuIsActive) {
+		Graphics::saveThumbnail(*out, _savegameThumbnail);
+	} else {
+		Graphics::saveThumbnail(*out);
+	}
 #endif
 	saveInfos(out);
 
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 25c98024fe4..e3833091b37 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -633,6 +633,7 @@ protected:
 	char _mainMenuTextSpeedSlider[17];
 	int _spooledMusicIsToBeEnabled = 1;
 	int _saveScriptParam = 0;
+	Graphics::Surface _savegameThumbnail;
 
 	// Saved cursor pre and post GUI
 	byte *_curGrabbedCursor = nullptr;


Commit: 914ec0084a83b163bd931982590cf9eb136be476
    https://github.com/scummvm/scummvm/commit/914ec0084a83b163bd931982590cf9eb136be476
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Change the load page title of the menu only with a valid savegame

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index ffa5f86f887..6ff3d32ad64 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1347,11 +1347,6 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 			if (_mainMenuSavegameLabel > 0) {
 				convertMessageToString((const byte *)getGUIString(gsLoading), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 				sprintf_s(formattedString, sizeof(formattedString), saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[4]);
-				drawMainMenuTitle(formattedString);
-				ScummEngine::drawDirtyScreenParts();
-				_system->updateScreen();
-
-				waitForTimer(60);
 
 				if (strlen(_savegameNames[_mainMenuSavegameLabel - 1].label) == 4) {
 					drawMainMenuControls();
@@ -1359,6 +1354,13 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 					break;
 				}
 
+				drawMainMenuTitle(formattedString);
+				ScummEngine::drawDirtyScreenParts();
+				_system->updateScreen();
+
+				waitForTimer(60);
+
+
 				if (isSmushActive()) {
 					handleLoadDuringSmush();
 					return true;


Commit: 194555c3a77dd6da5b9e488061da1e28f715eb59
    https://github.com/scummvm/scummvm/commit/194555c3a77dd6da5b9e488061da1e28f715eb59
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Implement v6 GUI and Menu

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


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 98daa44185e..e3cb8459fc1 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -170,7 +170,20 @@ static const ResString string_map_table_v6[] = {
 	{107, "Loading '%s'"},
 	{108, "Name your SAVE game"},
 	{109, "Select a game to LOAD"},
-	{117, "How may I serve you?"}
+	{117, "How may I serve you?"},
+	{80, "Text Speed"},
+	{81, "Display Text"},
+	{113, "Music"},
+	{114, "Voice"},
+	{115, "Sfx"},
+	{116, "disabled"},
+	{0, "Voice Only"},
+	{0, "Voice and Text"},
+	{0, "Text Display Only"},
+	{0, "Text Speed   Slow  ==========  Fast"},
+	{0, "Music Volume    Low  =========  High"},
+	{0, "Voice Volume    Low  =========  High"},
+	{0, "SFX Volume    Low  =========  High"},
 };
 
 #pragma mark -
@@ -431,6 +444,10 @@ const char *InfoDialog::getPlainEngineString(int stringno) {
 		}
 	} else if (_vm->_game.version == 6) {
 		result = (const char *)_vm->getStringAddressVar(string_map_table_v6[stringno - 1].num);
+
+		if (!result) {
+			result = (const char *)string_map_table_v6[stringno - 1].string;
+		}
 	} else if (_vm->_game.version >= 3) {
 		result = (const char *)_vm->getStringAddress(string_map_table_v345[stringno - 1].num);
 	} else {
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 6ff3d32ad64..2860fb62171 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -844,18 +844,15 @@ void ScummEngine_v7::drawGUIText(const char *buttonString, int textXPos, int tex
 }
 
 int ScummEngine_v7::getMusicVolume() {
-	//setMusicVolume(ConfMan.getInt("music_volume") / 2);
-	return CLIP<int>(ConfMan.getInt("music_volume") / 2, 0, 127); //_imuseDigital->diMUSEGetMusicGroupVol();
+	return CLIP<int>(ConfMan.getInt("music_volume") / 2, 0, 127);
 }
 
 int ScummEngine_v7::getSpeechVolume() {
-	//setMusicVolume(ConfMan.getInt("speech_volume") / 2);
-	return CLIP<int>(ConfMan.getInt("speech_volume") / 2, 0, 127); //_imuseDigital->diMUSEGetVoiceGroupVol();
+	return CLIP<int>(ConfMan.getInt("speech_volume") / 2, 0, 127);
 }
 
 int ScummEngine_v7::getSFXVolume() {
-	//setMusicVolume(ConfMan.getInt("sfx_volume") / 2);
-	return CLIP<int>(ConfMan.getInt("sfx_volume") / 2, 0, 127); //_imuseDigital->diMUSEGetSFXGroupVol();
+	return CLIP<int>(ConfMan.getInt("sfx_volume") / 2, 0, 127);
 }
 
 void ScummEngine_v7::setMusicVolume(int volume) {
@@ -943,20 +940,42 @@ void ScummEngine::toggleVoiceMode() {
 }
 
 void ScummEngine::setMusicVolume(int volume) {
+	volume = CLIP<int>(volume, 0, 127);
+	if (_game.version < 7)
+		_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume * 2);
 	ConfMan.setInt("music_volume", volume * 2);
 	ConfMan.flushToDisk();
 }
 
 void ScummEngine::setSpeechVolume(int volume) {
+	volume = CLIP<int>(volume, 0, 127);
+	if (_game.version < 7)
+		_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume * 2);
 	ConfMan.setInt("speech_volume", volume * 2);
 	ConfMan.flushToDisk();
 }
 
 void ScummEngine::setSFXVolume(int volume) {
+	volume = CLIP<int>(volume, 0, 127);
+	if (_game.version < 7)
+		_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume * 2);
 	ConfMan.setInt("sfx_volume", volume * 2);
 	ConfMan.flushToDisk();
 }
 
+int ScummEngine::getMusicVolume() {
+	return CLIP<int>(_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) / 2, 0, 127);
+}
+
+int ScummEngine::getSpeechVolume() {
+	return CLIP<int>(_mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2, 0, 127);
+}
+
+int ScummEngine::getSFXVolume() {
+	return CLIP<int>(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 2, 0, 127);
+}
+
+
 void ScummEngine::queryQuit() {
 	char msgLabelPtr[512];
 	char localizedYesKey;
@@ -1260,7 +1279,8 @@ void ScummEngine::showMainMenu() {
 	// differently (basically we start from a different position, but the order
 	// remains the same), we call CHARSET_1() here to refresh the dialog texts
 	// immediately and avoid getting a frame in which their color is wrong...
-	CHARSET_1();
+	if (_game.version == 7)
+		CHARSET_1();
 
 	// Resume the engine
 	pt.clear();
@@ -1415,28 +1435,33 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 			fillSavegameLabels();
 			drawMainMenuControls();
 			ScummEngine::drawDirtyScreenParts();
+		} else {
+			drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);
+			drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0);
+			ScummEngine::drawDirtyScreenParts();
 		}
+
 		break;
 	case GUI_CTRL_PATH_BUTTON:
 		// This apparently should't do anything
 		break;
 	case GUI_CTRL_MUSIC_SLIDER:
-		setMusicVolume(((mouseX - 111) << 7) / 87);
+		setMusicVolume(((mouseX - (_game.version == 7 ? 111 : 105)) << 7) / 87);
 		updateMainMenuControls();
 		ScummEngine::drawDirtyScreenParts();
 		break;
 	case GUI_CTRL_SPEECH_SLIDER:
-		setSpeechVolume(((mouseX - 111) << 7) / 87);
+		setSpeechVolume(((mouseX - (_game.version == 7 ? 111 : 105)) << 7) / 87);
 		updateMainMenuControls();
 		ScummEngine::drawDirtyScreenParts();
 		break;
 	case GUI_CTRL_SFX_SLIDER:
-		setSFXVolume(((mouseX - 111) << 7) / 87);
+		setSFXVolume(((mouseX - (_game.version == 7 ? 111 : 105)) << 7) / 87);
 		updateMainMenuControls();
 		ScummEngine::drawDirtyScreenParts();
 		break;
 	case GUI_CTRL_TEXT_SPEED_SLIDER:
-		_defaultTextSpeed = CLIP<int>((mouseX - 108) / 9, 0, 9);
+		_defaultTextSpeed = CLIP<int>((mouseX - (_game.version == 7 ? 108 : 102)) / 9, 0, 9);
 		ConfMan.setInt("original_gui_text_speed", _defaultTextSpeed);
 		setTalkSpeed(_defaultTextSpeed);
 		syncSoundSettings();
@@ -1471,11 +1496,19 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 }
 
 void ScummEngine::setUpMainMenuControls() {
-	int yComponent, yConstant, yConstant2;
 
-	yComponent = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
-	yConstant = _screenHeight / 2 - ((yComponent - 1) / 2);
-	yConstant2 = _screenHeight / 2 + ((yComponent - 1) / 2);
+}
+
+void ScummEngine_v6::setUpMainMenuControls() {
+	int yComponentV7, yConstantV7, yConstant2V7, yConstantV6;
+
+	// V7 auxiliary constants
+	yComponentV7 = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
+	yConstantV7 = _screenHeight / 2 - ((yComponentV7 - 1) / 2);
+	yConstant2V7 = _screenHeight / 2 + ((yComponentV7 - 1) / 2);
+
+	// V6 ausiliary constant
+	yConstantV6 = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
 
 	for (int i = 0; i < ARRAYSIZE(_internalGUIControls); i++) {
 		_internalGUIControls[i].relativeCenterX = -1;
@@ -1491,10 +1524,10 @@ void ScummEngine::setUpMainMenuControls() {
 		getBannerColor(16),
 		getBannerColor(6),
 		getBannerColor(4),
-		16,
-		yConstant,
-		303,
-		yConstant2,
+		(_game.version == 7 ? 16 : 20),
+		(_game.version == 7 ? yConstantV7 : yConstantV6 - 60),
+		(_game.version == 7 ? 303 : 300),
+		(_game.version == 7 ? yConstant2V7 : yConstantV6 + 60),
 		_emptyMsg, 1, 1);
 
 	// Inner box
@@ -1507,9 +1540,9 @@ void ScummEngine::setUpMainMenuControls() {
 		getBannerColor(19),
 		getBannerColor(6),
 		getBannerColor(7),
-		22,
-		yConstant + ((_game.id == GID_DIG && _useCJKMode) ? 21 : 13),
-		-183,
+		(_game.version == 7 ? 22 : 26),
+		(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 21 : 13) : yConstantV6 - 47),
+		(_game.version == 7 ? -183 : -176),
 		-102,
 		_emptyMsg, 1, 1);
 
@@ -1589,8 +1622,8 @@ void ScummEngine::setUpMainMenuControls() {
 				getBannerColor(19),
 				getBannerColor(10),
 				getBannerColor(12),
-				108,
-				yConstant + 25,
+				(_game.version == 7 ? 108 : 102),
+				(_game.version == 7 ? yConstantV7 + 25 : yConstantV6 - 39),
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -1605,8 +1638,8 @@ void ScummEngine::setUpMainMenuControls() {
 				getBannerColor(19),
 				getBannerColor(10),
 				getBannerColor(12),
-				108,
-				yConstant + 43,
+				(_game.version == 7 ? 108 : 102),
+				(_game.version == 7 ? yConstantV7 + 43 : yConstantV6 - 25),
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -1621,8 +1654,8 @@ void ScummEngine::setUpMainMenuControls() {
 				getBannerColor(19),
 				getBannerColor(10),
 				getBannerColor(12),
-				108,
-				yConstant + 61,
+				(_game.version == 7 ? 108 : 102),
+				(_game.version == 7 ? yConstantV7 + 61 : yConstantV6 - 11),
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -1638,8 +1671,8 @@ void ScummEngine::setUpMainMenuControls() {
 			getBannerColor(19),
 			getBannerColor(11),
 			getBannerColor(12),
-			108,
-			yConstant + 85,
+			(_game.version == 7 ? 108 : 102),
+			(_game.version == 7 ? yConstantV7 + 85 : yConstantV6 + 17),
 			-12,
 			-12,
 			_uncheckedBox, 1, 1);
@@ -1654,14 +1687,13 @@ void ScummEngine::setUpMainMenuControls() {
 			getBannerColor(19),
 			getBannerColor(10),
 			getBannerColor(12),
-			108,
-			yConstant + 99,
+			(_game.version == 7 ? 108 : 102),
+			(_game.version == 7 ? yConstantV7 + 99 : yConstantV6 + 31),
 			-90,
 			-12,
 			_uncheckedBox, 1, 1);
 
 		// Save button
-		int saveButtonAnchorY = yConstant + 37;
 		setUpInternalGUIControl(GUI_CTRL_SAVE_BUTTON,
 			getBannerColor(4),
 			getBannerColor(5),
@@ -1671,14 +1703,14 @@ void ScummEngine::setUpMainMenuControls() {
 			getBannerColor(20),
 			getBannerColor(6),
 			getBannerColor(7),
-			235,
-			saveButtonAnchorY,
+			(_game.version == 7 ? 235 : 232),
+			(_game.version == 7 ? yConstantV7 + 37 : yConstantV6 - 23),
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
 			(char *)getGUIString(gsSave), 1, 1);
 
 		// Load button
-		int loadButtonAnchorY = yConstant +
+		int loadButtonAnchorY = yConstantV7 +
 			((_game.id == GID_DIG && _useCJKMode) ? 18 : 12)
 			+ 40;
 		setUpInternalGUIControl(GUI_CTRL_LOAD_BUTTON,
@@ -1690,14 +1722,14 @@ void ScummEngine::setUpMainMenuControls() {
 			getBannerColor(20),
 			getBannerColor(6),
 			getBannerColor(7),
-			235,
-			loadButtonAnchorY,
+			(_game.version == 7 ? 235 : 232),
+			(_game.version == 7 ? loadButtonAnchorY : yConstantV6 - 8),
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
 			(char *)getGUIString(gsLoad), 1, 1);
 
 		// Play button
-		int playButtonAnchorY = yConstant +
+		int playButtonAnchorY = yConstantV7 +
 			2 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12)
 			+ 43;
 		setUpInternalGUIControl(GUI_CTRL_PLAY_BUTTON,
@@ -1709,14 +1741,14 @@ void ScummEngine::setUpMainMenuControls() {
 			getBannerColor(20),
 			getBannerColor(6),
 			getBannerColor(7),
-			235,
-			playButtonAnchorY,
+			(_game.version == 7 ? 235 : 232),
+			(_game.version == 7 ? playButtonAnchorY : yConstantV6 + 7),
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
 			(char *)getGUIString(gsPlay), 1, 1);
 
 		// Quit button
-		int quitButtonAnchorY = yConstant +
+		int quitButtonAnchorY = yConstantV7 +
 			3 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12)
 			+ 46;
 		setUpInternalGUIControl(GUI_CTRL_QUIT_BUTTON,
@@ -1728,48 +1760,49 @@ void ScummEngine::setUpMainMenuControls() {
 			getBannerColor(20),
 			getBannerColor(6),
 			getBannerColor(7),
-			235,
-			quitButtonAnchorY,
+			(_game.version == 7 ? 235 : 232),
+			(_game.version == 7 ? quitButtonAnchorY : yConstantV6 + 22),
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
 			(char *)getGUIString(gsQuit), 1, 1);
 	}
 
-	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
-		// Arrow up button
-		setUpInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON,
-			getBannerColor(9),
-			getBannerColor(10),
-			getBannerColor(17),
-			getBannerColor(18),
-			getBannerColor(19),
-			getBannerColor(20),
-			getBannerColor(11),
-			getBannerColor(12),
-			209,
-			yConstant + ((_game.id == GID_DIG && _useCJKMode) ? 25 : 17),
-			-16,
-			-47,
-			_arrowUp, 1, 1);
-
-		// Arrow down button
-		setUpInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON,
-			getBannerColor(9),
-			getBannerColor(10),
-			getBannerColor(17),
-			getBannerColor(18),
-			getBannerColor(19),
-			getBannerColor(20),
-			getBannerColor(11),
-			getBannerColor(12),
-			209,
-			yConstant + ((_game.id == GID_DIG && _useCJKMode) ? 75 : 67),
-			-16,
-			-45,
-			_arrowDown, 1, 1);
+	// Arrow up button
+	setUpInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON,
+		getBannerColor(9),
+		getBannerColor(10),
+		getBannerColor(17),
+		getBannerColor(18),
+		getBannerColor(19),
+		getBannerColor(20),
+		getBannerColor(11),
+		getBannerColor(12),
+		(_game.version == 7 ? 209 : 206),
+		(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 25 : 17) : yConstantV6 - 43),
+		-16,
+		-47,
+		_arrowUp, 1, 1);
+
+	// Arrow down button
+	setUpInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON,
+		getBannerColor(9),
+		getBannerColor(10),
+		getBannerColor(17),
+		getBannerColor(18),
+		getBannerColor(19),
+		getBannerColor(20),
+		getBannerColor(11),
+		getBannerColor(12),
+		(_game.version == 7 ? 209 : 206),
+		(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 75 : 67) : yConstantV6 + 7),
+		-16,
+		-45,
+		_arrowDown, 1, 1);
 
+	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
 		if (_menuPage == GUI_PAGE_SAVE) {
 			// OK button
+			int okButtonAnchorY = ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) + yConstantV7 + 40;
 			setUpInternalGUIControl(GUI_CTRL_OK_BUTTON,
 				getBannerColor(4),
 				getBannerColor(5),
@@ -1779,22 +1812,22 @@ void ScummEngine::setUpMainMenuControls() {
 				getBannerColor(20),
 				getBannerColor(6),
 				getBannerColor(7),
-				235,
-				((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) + yConstant + 40,
+				(_game.version == 7 ? 235 : 232),
+				(_game.version == 7 ? okButtonAnchorY : yConstantV6 - 8),
 				-60,
 				((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
 				(char *)getGUIString(gsOK), 1, 1);
 		}
 
 		// Cancel button
-		int cancelButtonAnchorY = 0;
+		int cancelButtonAnchorY;
 		if (_menuPage == GUI_PAGE_LOAD) {
 			cancelButtonAnchorY = _screenHeight / 2 +
-				(((_game.id == GID_DIG && _useCJKMode) ? 10 : 7) - yComponent / 2) +
+				(((_game.id == GID_DIG && _useCJKMode) ? 10 : 7) - yComponentV7 / 2) +
 				((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) +
 				40;
 		} else {
-			cancelButtonAnchorY = yConstant + 43 + 2 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12);
+			cancelButtonAnchorY = yConstantV7 + 43 + 2 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12);
 		}
 		setUpInternalGUIControl(GUI_CTRL_CANCEL_BUTTON,
 			getBannerColor(4),
@@ -1805,14 +1838,15 @@ void ScummEngine::setUpMainMenuControls() {
 			getBannerColor(20),
 			getBannerColor(6),
 			getBannerColor(7),
-			235,
-			cancelButtonAnchorY,
+			(_game.version == 7 ? 235 : 232),
+			(_game.version == 7 ? cancelButtonAnchorY : yConstantV6 - 1),
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
 			(char *)getGUIString(gsCancel), 1, 1);
 
 		// Savegame names
 		for (int i = GUI_CTRL_FIRST_SG, j = 11; i <= GUI_CTRL_LAST_SG; i++, j += 11) {
+			int curSaveLabelAnchorY = yConstantV7 + j + ((_game.id == GID_DIG && _useCJKMode) ? 12 : 4);
 			setUpInternalGUIControl(i,
 				getBannerColor(9),
 				getBannerColor(10),
@@ -1822,9 +1856,9 @@ void ScummEngine::setUpMainMenuControls() {
 				getBannerColor(4),
 				getBannerColor(11),
 				getBannerColor(12),
-				24,
-				yConstant + j + ((_game.id == GID_DIG && _useCJKMode) ? 12 : 4),
-				-179,
+				(_game.version == 7 ? 24 : 28),
+				(_game.version == 7 ? curSaveLabelAnchorY : yConstantV6 + j - 56),
+				(_game.version == 7 ? -179 : -172),
 				-9,
 				_savegameNames[i - 1].label, 0, 0);
 		}
@@ -1834,6 +1868,7 @@ void ScummEngine::setUpMainMenuControls() {
 void ScummEngine::drawMainMenuControls() {
 	char namePrompt[256];
 	char loadPrompt[256];
+	char insertDisk[256];
 
 	// Outer box
 	drawInternalGUIControl(GUI_CTRL_OUTER_BOX, 0);
@@ -1845,6 +1880,16 @@ void ScummEngine::drawMainMenuControls() {
 		drawInternalGUIControl(GUI_CTRL_QUIT_BUTTON, 0); // Quit button
 
 		drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0); // Inner box
+
+		if (_game.version == 6) {
+			drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);   // Arrow up button
+			drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button
+
+			if (VAR_FIXEDDISK != 0xFF && VAR(VAR_FIXEDDISK) == 0) {
+				convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)insertDisk, sizeof(insertDisk));
+				drawMainMenuTitle(insertDisk);
+			}
+		}
 	}
 
 	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
@@ -1877,12 +1922,19 @@ void ScummEngine::drawMainMenuControls() {
 }
 
 void ScummEngine::updateMainMenuControls() {
+	if (!strcmp(_game.variant, "Floppy"))
+		return;
+
 	char msg[256];
-	int yComponent, yConstant;
+	int yComponentV7, yConstantV7, yConstantV6;
 	int textColor = getBannerColor(2);
 
-	yComponent = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
-	yConstant = _screenHeight / 2 - ((yComponent - 1) / 2);
+	// V7 ausiliary constants
+	yComponentV7 = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
+	yConstantV7 = _screenHeight / 2 - ((yComponentV7 - 1) / 2);
+
+	// V6 ausiliary constant
+	yConstantV6 = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
 
 	strncpy(_mainMenuMusicSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuMusicSlider));
 	strncpy(_mainMenuSpeechSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuSpeechSlider));
@@ -1930,43 +1982,65 @@ void ScummEngine::updateMainMenuControls() {
 	drawInternalGUIControl(GUI_CTRL_DISPLAY_TEXT_CHECKBOX, 0); // Display text checkbox
 	drawInternalGUIControl(GUI_CTRL_TEXT_SPEED_SLIDER,     0); // Text speed slider
 
-	// Full Throttle has the "Spooled Music" checkbox,
-	// 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, 29, yConstant + 19, _screenWidth - 1, textColor, false);
+	if (_game.version == 7) {
+		// Full Throttle has the "Spooled Music" checkbox,
+		// 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, 29, yConstantV7 + 19, _screenWidth - 1, textColor, false);
 
-		convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstant + 33, _screenWidth - 1, textColor, false);
+			convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
+			drawGUIText(msg, 29, yConstantV7 + 33, _screenWidth - 1, textColor, false);
 
-		convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstant + 47, _screenWidth - 1, textColor, false);
+			convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
+			drawGUIText(msg, 29, yConstantV7 + 47, _screenWidth - 1, textColor, false);
+		} else {
+			convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
+			drawGUIText(msg, 29, yConstantV7 + 25, _screenWidth - 1, textColor, false);
+
+			convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
+			drawGUIText(msg, 29, yConstantV7 + 43, _screenWidth - 1, textColor, false);
+		}
+
+		convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 29, yConstantV7 + 61, _screenWidth - 1, textColor, false);
+
+		convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 29, yConstantV7 + 88, _screenWidth - 1, textColor, false);
+
+		convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 29, yConstantV7 + 102, _screenWidth - 1, textColor, false);
+
+		drawLine(23, yConstantV7 + 77, 204, yConstantV7 + 77, getBannerColor(17));
+		drawLine(23, yConstantV7 + 78, 204, yConstantV7 + 78, getBannerColor(4));
+		drawLine(23, yConstantV7 + 79, 204, yConstantV7 + 79, getBannerColor(4));
+		drawLine(23, yConstantV7 + 80, 204, yConstantV7 + 80, getBannerColor(18));
+
+		// The following line is from the Aaron Giles' interpreter of FT, based on the first DOS version;
+		// for some reason it doesn't get displayed in the DOS version, and it also overflows
+		// onto the internal panel lines, so let's just not draw it...
+		// drawLine(24, yConstantV7 + 81, 204, yConstantV7 + 81, getBannerColor(4));
 	} else {
 		convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstant + 25, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 33, yConstantV6 - 36, _screenWidth - 1, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstant + 43, _screenWidth - 1, textColor, false);
-	}
-
-	convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
-	drawGUIText(msg, 29, yConstant + 61, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 33, yConstantV6 - 22, _screenWidth - 1, textColor, false);
 
-	convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
-	drawGUIText(msg, 29, yConstant + 88, _screenWidth - 1, textColor, false);
+		convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 33, yConstantV6 - 8, _screenWidth - 1, textColor, false);
 
-	convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
-	drawGUIText(msg, 29, yConstant + 102, _screenWidth - 1, textColor, false);
+		convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 33, yConstantV6 + 19, _screenWidth - 1, textColor, false);
 
-	drawLine(23, yConstant + 77, 204, yConstant + 77, getBannerColor(17));
-	drawLine(23, yConstant + 78, 204, yConstant + 78, getBannerColor(4));
-	drawLine(23, yConstant + 79, 204, yConstant + 79, getBannerColor(4));
-	drawLine(23, yConstant + 80, 204, yConstant + 80, getBannerColor(18));
+		convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
+		drawGUIText(msg, 33, yConstantV6 + 34, _screenWidth - 1, textColor, false);
 
-	// The following line is in the Aaron Giles' interpreter of FT, based on the first DOS version;
-	// for some reason it doesn't get displayed in the DOS version, and it also overflows
-	// onto the internal panel lines, so let's just not draw it...
-	// drawLine(24, yConstant + 81, 204, yConstant + 81, getBannerColor(4));
+		drawLine(27, yConstantV6 + 8,  201, yConstantV6 + 8,  getBannerColor(17));
+		drawLine(27, yConstantV6 + 9,  201, yConstantV6 + 9,  getBannerColor(4));
+		drawLine(27, yConstantV6 + 10, 201, yConstantV6 + 10, getBannerColor(4));
+		drawLine(27, yConstantV6 + 11, 201, yConstantV6 + 11, getBannerColor(18));
+	}
 
 	ScummEngine::drawDirtyScreenParts();
 	_system->updateScreen();
@@ -1975,6 +2049,8 @@ void ScummEngine::updateMainMenuControls() {
 void ScummEngine::drawMainMenuTitle(const char *title) {
 	int boxColor = getBannerColor(4);
 	int stringColor = getBannerColor(2);
+	int yConstantV6 = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
+
 	if (_game.id == GID_DIG) {
 		int yComponent = _useCJKMode ? 130 : 121;
 
@@ -1990,9 +2066,12 @@ void ScummEngine::drawMainMenuTitle(const char *title) {
 			_screenWidth - 1,
 			stringColor,
 			true);
-	} else {
+	} else if (_game.version == 7) {
 		drawBox(18, _screenTop + 44, 301, _screenTop + 52, boxColor);
 		drawGUIText(title, 159, 44, _screenWidth - 1, stringColor, true);
+	} else {
+		drawBox(22, yConstantV6 - 56, 298, yConstantV6 - 48, boxColor);
+		drawGUIText(title, 160, yConstantV6 - 56, _screenWidth - 1, stringColor, true);
 	}
 
 	ScummEngine::drawDirtyScreenParts();
@@ -2053,8 +2132,6 @@ const char *ScummEngine_v6::getGUIString(int stringId) {
 	case gsPause:
 		resStringId = 4;
 		break;
-	case gsTextSpeedSlider:
-		break;
 	case gsRestart:
 		resStringId = 5;
 		break;
@@ -2079,6 +2156,9 @@ const char *ScummEngine_v6::getGUIString(int stringId) {
 	case gsOK:
 		resStringId = 12;
 		break;
+	case gsInsertSaveDisk:
+		resStringId = 13;
+		break;
 	case gsMustName:
 		resStringId = 14;
 		break;
@@ -2103,25 +2183,44 @@ const char *ScummEngine_v6::getGUIString(int stringId) {
 	case gsTitle:
 		resStringId = 21;
 		break;
-	case gsReplacePrompt:
+	case gsTextSpeed:
+		resStringId = 22;
 		break;
-	case gsYes:
+	case gsDisplayText:
+		resStringId = 23;
 		break;
-	case gsNo:
+	case gsMusic:
+		resStringId = 24;
 		break;
-	case gsIMuseBuffer:
+	case gsVoice:
+		resStringId = 25;
+		break;
+	case gsSfx:
+		resStringId = 26;
+		break;
+	case gsDisabled:
+		resStringId = 27;
+		break;
+	case gsVoiceOnly:
+		resStringId = 28;
 		break;
 	case gsVoiceAndText:
+		resStringId = 29;
 		break;
 	case gsTextDisplayOnly:
+		resStringId = 30;
 		break;
-	case gsYesKey:
+	case gsTextSpeedSlider:
+		resStringId = 31;
 		break;
 	case gsMusicVolumeSlider:
+		resStringId = 32;
 		break;
 	case gsVoiceVolumeSlider:
+		resStringId = 33;
 		break;
 	case gsSfxVolumeSlider:
+		resStringId = 34;
 		break;
 	case gsHeap:
 		return "Heap %dK";
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index bac29ae0de1..210faf46fc9 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -882,7 +882,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		}
 
 		if (VAR_MAINMENU_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_MAINMENU_KEY) && lastKeyHit.hasFlags(0)) &&
-			_game.version > 6) {
+			_game.version > 5) {
 			showMainMenu();
 			return;
 		}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index e3833091b37..70037f00dba 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -428,7 +428,8 @@ enum GUIString {
 	gsSfx = 36,
 	gsTextSpeed = 37,
 	gsDisplayText = 38,
-	gsSpooledMusic = 39
+	gsSpooledMusic = 39,
+	gsInsertSaveDisk = 40
 };
 
 struct InternalGUIControl {
@@ -665,9 +666,9 @@ protected:
 	virtual int getGUIStringWidth(const char *str);
 	virtual void drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag);
 	void getSliderString(int stringId, int value, char *sliderString, int size);
-	virtual int getMusicVolume() { return 0; }
-	virtual int getSpeechVolume() { return 0; }
-	virtual int getSFXVolume() { return 0; }
+	virtual int getMusicVolume();
+	virtual int getSpeechVolume();
+	virtual int getSFXVolume();
 	virtual void setMusicVolume(int volume);
 	virtual void setSpeechVolume(int volume);
 	virtual void setSFXVolume(int volume);
@@ -676,7 +677,7 @@ protected:
 	virtual void setSkipVideo(int value) {}
 
 	void showMainMenu();
-	void setUpMainMenuControls();
+	virtual void setUpMainMenuControls();
 	void drawMainMenuControls();
 	void updateMainMenuControls();
 	void drawMainMenuTitle(const char *title);
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index 50dc55156c2..c68bab7aba8 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -166,6 +166,7 @@ protected:
 	int getBannerColor(int bannerId) override;
 	const char *getGUIString(int stringId) override;
 	void setSkipVideo(int value) override { _skipVideo = value; }
+	void setUpMainMenuControls() override;
 
 public:
 	bool akos_increaseAnims(const byte *akos, Actor *a);


Commit: 025d25a1f17ab4be6838a9fea486e505fffba43c
    https://github.com/scummvm/scummvm/commit/025d25a1f17ab4be6838a9fea486e505fffba43c
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix pre-v7 text rendering over GUI

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


diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index c1df566d8c9..fc862e425f8 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -1255,7 +1255,8 @@ void ScummEngine::restoreCharsetBg() {
 	_nextLeft = _string[0].xpos;
 	_nextTop = _string[0].ypos + _screenTop;
 
-	if (_charset->_hasMask) {
+	if (_charset->_hasMask || _postGUICharMask) {
+		_postGUICharMask = false;
 		_charset->_hasMask = false;
 		_charset->_str.left = -1;
 		_charset->_left = -1;
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 2860fb62171..105442f1a20 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -103,6 +103,12 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		convertMessageToString((const byte *)getGUIString(gsYesKey), (byte *)localizedY, sizeof(localizedY));
 	}
 
+	// Backup the text surface...
+	if (_game.version < 7) {
+		saveTextSurfacePreGUI();
+		restoreCharsetBg();
+	}
+
 	// Pause the engine
 	PauseToken pt = pauseEngine();
 
@@ -209,6 +215,12 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		clearBanner();
 	}
 
+	// Restore the text surface...
+	if (_game.version < 7) {
+		restoreTextSurfacePostGUI();
+		_completeScreenRedraw = true;
+	}
+
 	// Finally, resume the engine, clear the input state, and restore the charset.
 	pt.clear();
 	clearClickedStatus();
@@ -928,6 +940,50 @@ int ScummEngine::getBannerColor(int bannerId) {
 	return (int)arrAddr[bannerId];
 }
 
+void ScummEngine::saveTextSurfacePreGUI() {
+	if (_game.version < 4 || _game.version > 6)
+		return;
+
+	_tempTextSurface = (byte *)malloc(_textSurface.w * _textSurface.h * sizeof(byte));
+
+	int x, y;
+	uint32 curPix;
+	for (int i = 0; i < _textSurface.h; i++) {
+		for (int j = 0; j < _textSurface.w; j++) {
+			x = j;
+			y = i;
+			curPix = _textSurface.getPixel(x, y);
+			_tempTextSurface[j + i * _textSurface.w] = curPix;
+			if (curPix != 0xFD)
+				_virtscr[kMainVirtScreen].setPixel(_virtscr[kMainVirtScreen].xstart + x, y, curPix);
+		}
+	}
+}
+
+void ScummEngine::restoreTextSurfacePostGUI() {
+	if (_game.version < 4 || _game.version > 6)
+		return;
+
+	int x, y;
+	uint32 curPix;
+	for (int i = 0; i < _textSurface.h; i++) {
+		for (int j = 0; j < _textSurface.w; j++) {
+			x = j;
+			y = i;
+			curPix = _tempTextSurface[j + i * _textSurface.w];
+			_textSurface.setPixel(x, y, curPix);
+		}
+	}
+
+	// Signal the restoreCharsetBg() function that there's text
+	// on the text surface, so it gets deleted the next time another
+	// text is displayed...
+	_postGUICharMask = true;
+
+	free(_tempTextSurface);
+	_tempTextSurface = nullptr;
+}
+
 void ScummEngine::toggleVoiceMode() {
 	if (VAR_VOICE_MODE != 0xFF) {
 		VAR(VAR_VOICE_MODE) = (VAR(VAR_VOICE_MODE) != 1) ? 1 : 0;
@@ -1069,13 +1125,15 @@ bool ScummEngine::canWriteGame(int slotId) {
 }
 
 bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked) {
+	bool hasLoadedState = false;
+
 	while (true) {
 		waitForTimer(1);
 		waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
 		rightMsClicked = false;
 		if (ks.keycode == Common::KEYCODE_RETURN) {
 			clearClickedStatus();
-			executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1);
+			executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1, hasLoadedState);
 			return true;
 		} else if (leftMsClicked) {
 			clearClickedStatus();
@@ -1153,6 +1211,7 @@ void ScummEngine::showMainMenu() {
 	bool leftMsClicked = false, rightMsClicked = false;
 	int clickedControl = -1;
 	int curMouseX, curMouseY;
+	bool hasLoadedState = false;
 
 	Common::KeyState ks;
 
@@ -1171,6 +1230,19 @@ void ScummEngine::showMainMenu() {
 	_saveSound = 1;
 	setShake(0);
 
+	if (_game.version < 7) {
+		// Below version 7, we draw texts on a separate surface which is then composited
+		// on top of the main one during ScummEngine::drawDirtyScreenParts().
+		// This results in texts overlapping on top of the menu; let's simulate the end result
+		// of the original by copying the text surface over the main one just before showing
+		// the menu...
+		saveTextSurfacePreGUI();
+
+		// 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.
+		restoreCharsetBg();
+	}
+
 	_menuPage = GUI_PAGE_MAIN;
 	setUpMainMenuControls();
 	drawMainMenuControls();
@@ -1226,7 +1298,7 @@ void ScummEngine::showMainMenu() {
 						drawInternalGUIControl(clickedControl, 0);
 
 						// Execute the operation pertaining the clicked control
-						if (executeMainMenuOperation(clickedControl, curMouseX))
+						if (executeMainMenuOperation(clickedControl, curMouseX, hasLoadedState))
 							break;
 					}
 				} else {
@@ -1240,7 +1312,7 @@ void ScummEngine::showMainMenu() {
 					_system->updateScreen();
 
 					if (_menuPage == GUI_PAGE_LOAD) {
-						if (executeMainMenuOperation(GUI_CTRL_OK_BUTTON, curMouseX))
+						if (executeMainMenuOperation(GUI_CTRL_OK_BUTTON, curMouseX, hasLoadedState))
 							break;
 					}
 				}
@@ -1282,12 +1354,15 @@ void ScummEngine::showMainMenu() {
 	if (_game.version == 7)
 		CHARSET_1();
 
+	if (_game.version < 7 && !hasLoadedState && !_quitByButton)
+		restoreTextSurfacePostGUI();
+
 	// Resume the engine
 	pt.clear();
 	clearClickedStatus();
 }
 
-bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
+bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedState) {
 	char saveScreenTitle[512];
 	char formattedString[512];
 
@@ -1312,7 +1387,6 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 		return true;
 	case GUI_CTRL_QUIT_BUTTON:
 		queryQuit();
-		_quitByButton = shouldQuit();
 		return true;
 	case GUI_CTRL_OK_BUTTON:
 		if (_menuPage == GUI_PAGE_SAVE) {
@@ -1386,7 +1460,13 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX) {
 					return true;
 				}
 
+				if (_game.version < 7) {
+					_postGUICharMask = true;
+				}
+
 				if (loadState(_mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9, false)) {
+					hasLoadedState = true;
+
 					if (!_spooledMusicIsToBeEnabled)
 						_imuseDigital->diMUSEDisableSpooledMusic();
 
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 70037f00dba..b0f70021f1b 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -635,6 +635,8 @@ protected:
 	int _spooledMusicIsToBeEnabled = 1;
 	int _saveScriptParam = 0;
 	Graphics::Surface _savegameThumbnail;
+	byte *_tempTextSurface;
+	bool _postGUICharMask = false;
 
 	// Saved cursor pre and post GUI
 	byte *_curGrabbedCursor = nullptr;
@@ -681,14 +683,15 @@ protected:
 	void drawMainMenuControls();
 	void updateMainMenuControls();
 	void drawMainMenuTitle(const char *title);
-	bool executeMainMenuOperation(int op, int mouseX);
+	bool executeMainMenuOperation(int op, int mouseX, bool &hasLoadedState);
 	bool shouldHighlightLabelAndWait(int clickedControl);
 	void fillSavegameLabels();
 	bool canWriteGame(int slotId);
 	bool userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked);
 	void saveCursorPreMenu();
 	void restoreCursorPostMenu();
-
+	void saveTextSurfacePreGUI();
+	void restoreTextSurfacePostGUI();
 
 public:
 	char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);


Commit: ee3084bb93b3741d9cb5ad21edf6018725ada7f6
    https://github.com/scummvm/scummvm/commit/ee3084bb93b3741d9cb5ad21edf6018725ada7f6
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix using nullptr byte array

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 105442f1a20..9282aad6750 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -963,25 +963,26 @@ void ScummEngine::saveTextSurfacePreGUI() {
 void ScummEngine::restoreTextSurfacePostGUI() {
 	if (_game.version < 4 || _game.version > 6)
 		return;
-
-	int x, y;
-	uint32 curPix;
-	for (int i = 0; i < _textSurface.h; i++) {
-		for (int j = 0; j < _textSurface.w; j++) {
-			x = j;
-			y = i;
-			curPix = _tempTextSurface[j + i * _textSurface.w];
-			_textSurface.setPixel(x, y, curPix);
+	if (_tempTextSurface) {
+		int x, y;
+		uint32 curPix;
+		for (int i = 0; i < _textSurface.h; i++) {
+			for (int j = 0; j < _textSurface.w; j++) {
+				x = j;
+				y = i;
+				curPix = _tempTextSurface[j + i * _textSurface.w];
+				_textSurface.setPixel(x, y, curPix);
+			}
 		}
-	}
 
-	// Signal the restoreCharsetBg() function that there's text
-	// on the text surface, so it gets deleted the next time another
-	// text is displayed...
-	_postGUICharMask = true;
+		// Signal the restoreCharsetBg() function that there's text
+		// on the text surface, so it gets deleted the next time another
+		// text is displayed...
+		_postGUICharMask = true;
 
-	free(_tempTextSurface);
-	_tempTextSurface = nullptr;
+		free(_tempTextSurface);
+		_tempTextSurface = nullptr;
+	}
 }
 
 void ScummEngine::toggleVoiceMode() {
@@ -1354,7 +1355,7 @@ void ScummEngine::showMainMenu() {
 	if (_game.version == 7)
 		CHARSET_1();
 
-	if (_game.version < 7 && !hasLoadedState && !_quitByButton)
+	if (_game.version < 7 && !hasLoadedState)
 		restoreTextSurfacePostGUI();
 
 	// Resume the engine


Commit: 9bd0a40ea2f01d7c2a57f650479e371e7e4d8b29
    https://github.com/scummvm/scummvm/commit/9bd0a40ea2f01d7c2a57f650479e371e7e4d8b29
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Implement the volume and speed sliders for v6

Also, make it necessary for volume sliders to press SHIFT

Changed paths:
    engines/scumm/input.cpp


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 210faf46fc9..04099efc701 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -430,24 +430,111 @@ void ScummEngine_v8::processKeyboard(Common::KeyState lastKeyHit) {
 
 void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 	if (isUsingOriginalGUI()) {
-		char sliderString[256];
-		PauseToken pt;
-
 		if (lastKeyHit.keycode == Common::KEYCODE_b && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 			int curBufferCount = _imuseDigital->roundRobinSetBufferCount();
 			// "iMuse buffer count changed to %d"
 			showBannerAndPause(0, 90, getGUIString(gsIMuseBuffer), curBufferCount);
 			return;
 		}
+	}
+
+	const bool cutsceneExitKeyEnabled = (VAR_CUTSCENEEXIT_KEY == 0xFF || VAR(VAR_CUTSCENEEXIT_KEY) != 0);
+
+	// VAR_VERSION_KEY (usually ctrl-v) is used in COMI, Dig and FT to trigger
+	// a version dialog, unless VAR_VERSION_KEY is set to 0. However, the COMI
+	// version string is hard coded in the engine, hence we don't invoke
+	// versionDialog for it. Dig/FT version strings are partly hard coded, too.
+	if (!isUsingOriginalGUI() && _game.id != GID_CMI && 0 != VAR(VAR_VERSION_KEY) &&
+	    lastKeyHit.keycode == Common::KEYCODE_v && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+		versionDialog();
+
+	} else if (cutsceneExitKeyEnabled && lastKeyHit.keycode == Common::KEYCODE_ESCAPE) {
+		// Skip cutscene (or active SMUSH video).
+		if (_smushActive) {
+			if (_game.id == GID_FT)
+				_insane->escapeKeyHandler();
+			else
+				_smushVideoShouldFinish = true;
+
+			// WORKAROUND bug #12022: For some reason, skipping the cutscene in which Ben fires up
+			// his bike (after retrieving the keys from the bartender), will outright skip the first
+			// bike fight sequence. Because of this, the script which handles playing ambient and wind SFX
+			// outside the bar is never stopped, so those SFX are unintentionally played throughout the
+			// rest of the game.
+			// This fix produces the intended behaviour from the original interpreter.
+			if (_game.id == GID_FT && _currentRoom == 6
+				&& (vm.slot[_currentScript].number == 65 || vm.slot[_currentScript].number == 64)) {
+				_skipVideo = false;
+			} else {
+				_skipVideo = true;
+			}
+		} else {
+			abortCutscene();
+		}
+
+		_mouseAndKeyboardStat = Common::ASCII_ESCAPE;
+
+	} else {
+		// Fall back to V6 behavior
+		ScummEngine_v6::processKeyboard(lastKeyHit);
+	}
+}
+#endif
+
+
+void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked) {
+	bool validKey = false;
+
+	if (waitTime && waitTime != -1) {
+		uint32 millis = _system->getMillis();
+		while (((_system->getMillis() - millis) * (_timerFrequency / 4) / 1000) < waitTime) {
+			waitForTimer(1); // Allow the engine to update the screen and fetch new inputs...
+			ks = _keyPressed;
+			leftBtnClicked = (_leftBtnPressed & msClicked) != 0;
+			rightBtnClicked = (_rightBtnPressed & msClicked) != 0;
+			if (ks.keycode != Common::KEYCODE_INVALID || leftBtnClicked || rightBtnClicked)
+				return;
+
+			if (shouldQuit())
+				return;
+		}
+	} else {
+		while (!validKey && !leftBtnClicked && !rightBtnClicked) {
+			waitForTimer(1); // Allow the engine to update the screen and fetch new inputs...
+			ks = _keyPressed;
+			leftBtnClicked = (_leftBtnPressed & msClicked) != 0;
+			rightBtnClicked = (_rightBtnPressed & msClicked) != 0;
+
+			if (shouldQuit())
+				return;
+
+			validKey = ks.keycode != Common::KEYCODE_INVALID &&
+					   ks.keycode != Common::KEYCODE_LCTRL   &&
+					   ks.keycode != Common::KEYCODE_RCTRL   &&
+					   ks.keycode != Common::KEYCODE_LSHIFT  &&
+					   ks.keycode != Common::KEYCODE_RSHIFT  &&
+					   ks.keycode != Common::KEYCODE_UP      &&
+					   ks.keycode != Common::KEYCODE_DOWN    &&
+					   ks.keycode != Common::KEYCODE_LEFT    &&
+					   ks.keycode != Common::KEYCODE_RIGHT;
+		}
+	}
+}
+
+void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) {
+	if (isUsingOriginalGUI()) {
+		char sliderString[256];
+		PauseToken pt;
 
 		if (_game.version != 8 || (_game.version == 8 && (_game.features & GF_DEMO))) {
 			// "Music Volume  Low  =========  High"
-			if (lastKeyHit.keycode == Common::KEYCODE_o || lastKeyHit.keycode == Common::KEYCODE_p) {
+			if (lastKeyHit.hasFlags(Common::KBD_SHIFT) &&
+				(lastKeyHit.keycode == Common::KEYCODE_o || lastKeyHit.keycode == Common::KEYCODE_p)) {
 				Common::KeyState ks = lastKeyHit;
 
 				pt = pauseEngine();
 
-				int volume = _imuseDigital->diMUSEGetMusicGroupVol();
+				int volume = (_game.version > 6) ? _imuseDigital->diMUSEGetMusicGroupVol() : getMusicVolume();
 				do {
 					if (ks.keycode == Common::KEYCODE_o) {
 						volume -= 16;
@@ -467,8 +554,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 				} while (ks.keycode == Common::KEYCODE_o || ks.keycode == Common::KEYCODE_p);
 				clearBanner();
 
-				_imuseDigital->diMUSESetMusicGroupVol(volume);
-				ConfMan.setInt("music_volume", volume * 2);
+				setMusicVolume(volume);
 
 				pt.clear();
 
@@ -476,12 +562,13 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 			}
 
 			// "Voice Volume  Low  =========  High"
-			if (lastKeyHit.keycode == Common::KEYCODE_k || lastKeyHit.keycode == Common::KEYCODE_l) {
+			if (lastKeyHit.hasFlags(Common::KBD_SHIFT) &&
+				(lastKeyHit.keycode == Common::KEYCODE_k || lastKeyHit.keycode == Common::KEYCODE_l)) {
 				Common::KeyState ks = lastKeyHit;
 
 				pt = pauseEngine();
 
-				int volume = _imuseDigital->diMUSEGetVoiceGroupVol();
+				int volume = (_game.version > 6) ? _imuseDigital->diMUSEGetVoiceGroupVol() : getSpeechVolume();
 				do {
 					if (ks.keycode == Common::KEYCODE_k) {
 						volume -= 16;
@@ -501,8 +588,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 				} while (ks.keycode == Common::KEYCODE_k || ks.keycode == Common::KEYCODE_l);
 				clearBanner();
 
-				_imuseDigital->diMUSESetVoiceGroupVol(volume);
-				ConfMan.setInt("speech_volume", volume * 2);
+				setSpeechVolume(volume);
 
 				pt.clear();
 
@@ -510,12 +596,13 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 			}
 
 			// "Sfx Volume  Low  =========  High"
-			if (lastKeyHit.keycode == Common::KEYCODE_n || lastKeyHit.keycode == Common::KEYCODE_m) {
+			if (lastKeyHit.hasFlags(Common::KBD_SHIFT) &&
+				(lastKeyHit.keycode == Common::KEYCODE_n || lastKeyHit.keycode == Common::KEYCODE_m)) {
 				Common::KeyState ks = lastKeyHit;
 
 				pt = pauseEngine();
 
-				int volume = _imuseDigital->diMUSEGetSFXGroupVol();
+				int volume = (_game.version > 6) ? _imuseDigital->diMUSEGetSFXGroupVol() : getSFXVolume();
 				do {
 					if (ks.keycode == Common::KEYCODE_n) {
 						volume -= 16;
@@ -535,8 +622,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 				} while (ks.keycode == Common::KEYCODE_n || ks.keycode == Common::KEYCODE_m);
 				clearBanner();
 
-				_imuseDigital->diMUSESetSFXGroupVol(volume);
-				ConfMan.setInt("sfx_volume", volume * 2);
+				setSFXVolume(volume);
 
 				pt.clear();
 
@@ -580,93 +666,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 				return;
 			}
 		}
-	}
-
-	const bool cutsceneExitKeyEnabled = (VAR_CUTSCENEEXIT_KEY == 0xFF || VAR(VAR_CUTSCENEEXIT_KEY) != 0);
 
-	// VAR_VERSION_KEY (usually ctrl-v) is used in COMI, Dig and FT to trigger
-	// a version dialog, unless VAR_VERSION_KEY is set to 0. However, the COMI
-	// version string is hard coded in the engine, hence we don't invoke
-	// versionDialog for it. Dig/FT version strings are partly hard coded, too.
-	if (!isUsingOriginalGUI() && _game.id != GID_CMI && 0 != VAR(VAR_VERSION_KEY) &&
-	    lastKeyHit.keycode == Common::KEYCODE_v && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-		versionDialog();
-
-	} else if (cutsceneExitKeyEnabled && lastKeyHit.keycode == Common::KEYCODE_ESCAPE) {
-		// Skip cutscene (or active SMUSH video).
-		if (_smushActive) {
-			if (_game.id == GID_FT)
-				_insane->escapeKeyHandler();
-			else
-				_smushVideoShouldFinish = true;
-
-			// WORKAROUND bug #12022: For some reason, skipping the cutscene in which Ben fires up
-			// his bike (after retrieving the keys from the bartender), will outright skip the first
-			// bike fight sequence. Because of this, the script which handles playing ambient and wind SFX
-			// outside the bar is never stopped, so those SFX are unintentionally played throughout the
-			// rest of the game.
-			// This fix produces the intended behaviour from the original interpreter.
-			if (_game.id == GID_FT && _currentRoom == 6
-				&& (vm.slot[_currentScript].number == 65 || vm.slot[_currentScript].number == 64)) {
-				_skipVideo = false;
-			} else {
-				_skipVideo = true;
-			}
-		} else {
-			abortCutscene();
-		}
-
-		_mouseAndKeyboardStat = Common::ASCII_ESCAPE;
-
-	} else {
-		// Fall back to V6 behavior
-		ScummEngine_v6::processKeyboard(lastKeyHit);
-	}
-}
-#endif
-
-
-void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked) {
-	bool validKey = false;
-
-	if (waitTime && waitTime != -1) {
-		uint32 millis = _system->getMillis();
-		while (((_system->getMillis() - millis) * (_timerFrequency / 4) / 1000) < waitTime) {
-			waitForTimer(1); // Allow the engine to update the screen and fetch new inputs...
-			ks = _keyPressed;
-			leftBtnClicked = (_leftBtnPressed & msClicked) != 0;
-			rightBtnClicked = (_rightBtnPressed & msClicked) != 0;
-			if (ks.keycode != Common::KEYCODE_INVALID || leftBtnClicked || rightBtnClicked)
-				return;
-
-			if (shouldQuit())
-				return;
-		}
-	} else {
-		while (!validKey && !leftBtnClicked && !rightBtnClicked) {
-			waitForTimer(1); // Allow the engine to update the screen and fetch new inputs...
-			ks = _keyPressed;
-			leftBtnClicked = (_leftBtnPressed & msClicked) != 0;
-			rightBtnClicked = (_rightBtnPressed & msClicked) != 0;
-
-			if (shouldQuit())
-				return;
-
-			validKey = ks.keycode != Common::KEYCODE_INVALID &&
-					   ks.keycode != Common::KEYCODE_LCTRL   &&
-					   ks.keycode != Common::KEYCODE_RCTRL   &&
-					   ks.keycode != Common::KEYCODE_LSHIFT  &&
-					   ks.keycode != Common::KEYCODE_RSHIFT  &&
-					   ks.keycode != Common::KEYCODE_UP      &&
-					   ks.keycode != Common::KEYCODE_DOWN    &&
-					   ks.keycode != Common::KEYCODE_LEFT    &&
-					   ks.keycode != Common::KEYCODE_RIGHT;
-		}
-	}
-}
-
-void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) {
-	if (isUsingOriginalGUI()) {
 		if (VAR_VERSION_KEY != 0xFF && VAR(VAR_VERSION_KEY) != 0 &&
 			lastKeyHit.keycode == Common::KEYCODE_v && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 			if (_game.version == 8) {


Commit: 261978a137aa02f2d9672cae7168ad4150688227
    https://github.com/scummvm/scummvm/commit/261978a137aa02f2d9672cae7168ad4150688227
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Games under v7 shouldn't close the menu on failed queryQuit()

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 9282aad6750..56047abc378 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -104,7 +104,7 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	}
 
 	// Backup the text surface...
-	if (_game.version < 7) {
+	if (_game.version < 7 && !_mainMenuIsActive) {
 		saveTextSurfacePreGUI();
 		restoreCharsetBg();
 	}
@@ -216,7 +216,7 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	}
 
 	// Restore the text surface...
-	if (_game.version < 7) {
+	if (_game.version < 7 && !_mainMenuIsActive) {
 		restoreTextSurfacePostGUI();
 		_completeScreenRedraw = true;
 	}
@@ -1388,7 +1388,9 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 		return true;
 	case GUI_CTRL_QUIT_BUTTON:
 		queryQuit();
-		return true;
+		if (_game.version == 7)
+			return true;
+		break;
 	case GUI_CTRL_OK_BUTTON:
 		if (_menuPage == GUI_PAGE_SAVE) {
 			if (_mainMenuSavegameLabel > 0) {


Commit: a79b55e3f014958d1eb6b55e0c1867499b6f46d3
    https://github.com/scummvm/scummvm/commit/a79b55e3f014958d1eb6b55e0c1867499b6f46d3
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix cursor related v7 GUI crash

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 56047abc378..162f744c61e 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1414,7 +1414,7 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 						return true;
 					}
 				} else {
-					saveCursorPreMenu();
+					restoreCursorPostMenu();
 					convertMessageToString((const byte *)getGUIString(gsGameNotSaved), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 					if (_game.id == GID_DIG) {
 						showBannerAndPause(1, -1, saveScreenTitle);


Commit: 9bca06429f4b8b80f55621b7ef18898b060d2b4d
    https://github.com/scummvm/scummvm/commit/9bca06429f4b8b80f55621b7ef18898b060d2b4d
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Implement v5 GUI and Menu

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


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index e3cb8459fc1..d15d1557f09 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -384,7 +384,7 @@ InfoDialog::InfoDialog(ScummEngine *scumm, int res)
 	_message = queryResString(res);
 
 	// Trim the hardcoded strings for the GUI Dialog. The extra spaces which some strings have might
-	// be needed for proper alignment within the original display, but not here... 
+	// be needed for proper alignment within the original display, but not here...
 	if (scumm->_game.version < 3)
 		_message.trim();
 
@@ -449,9 +449,13 @@ const char *InfoDialog::getPlainEngineString(int stringno) {
 			result = (const char *)string_map_table_v6[stringno - 1].string;
 		}
 	} else if (_vm->_game.version >= 3) {
-		result = (const char *)_vm->getStringAddress(string_map_table_v345[stringno - 1].num);
+		result = (const char *)_vm->getStringAddress(getStaticResString(_vm->_language, stringno - 1).num);
+
+		if (!result) {
+			result = (const char *)getStaticResString(_vm->_language, stringno - 1).string;
+		}
 	} else {
-		result = (const char *)(string_map_table_v345[stringno - 1].string);
+		result = (const char *)(getStaticResString(_vm->_language, stringno - 1).string);
 	}
 
 	return result;
@@ -614,9 +618,11 @@ const ResString &InfoDialog::getStaticResString(Common::Language lang, int strin
 			{6, """\x8e""r du s""\x84""ker p""\x86"" att du vill avsluta? (J/N)J"}
 		}
 	};
-	
+
 	// Added in SCUMM4. Only the numbers are used, so there
-	// is no need to provide language specific strings.
+	// is no need to provide language specific strings; there are
+	// some exceptions for which there's only an hardcoded English
+	// string.
 	static const ResString strMap2[] = {
 		{7, ("Save")},
 		{8, ("Load")},
@@ -632,12 +638,19 @@ const ResString &InfoDialog::getStaticResString(Common::Language lang, int strin
 		{18, ("Loading '%s'")},
 		{19, ("Name your SAVE game")},
 		{20, ("Select a game to LOAD")},
-		{28, ("Game title)")}
+		{28, ("Game title)")},
+
+		// Hardcoded in English for each localized version
+		{0, "Voice Only"},
+		{0, "Voice and Text"},
+		{0, "Text Display Only"},
+		{0, "Text Speed   Slow  ==========  Fast"},
+		{0, "Roland Volume    Low  =========  High"},
 	};
 
-	if (stringno >= ARRAYSIZE(strMap1)) {
-		stringno -= ARRAYSIZE(strMap1);
-		assert(stringno < ARRAYSIZE(strMap2));
+	if (stringno + 1 >= ARRAYSIZE(strMap1)) {
+		stringno -= ARRAYSIZE(strMap1) - 1;
+		assert(stringno + 1 < ARRAYSIZE(strMap2));
 		return strMap2[stringno];
 	}
 
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 162f744c61e..c87d7ca1438 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -104,8 +104,8 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	}
 
 	// Backup the text surface...
-	if (_game.version < 7 && !_mainMenuIsActive) {
-		saveTextSurfacePreGUI();
+	if (_game.version < 7 && !_mainMenuIsActive && _game.platform != Common::kPlatformFMTowns) {
+		saveSurfacesPreGUI();
 		restoreCharsetBg();
 	}
 
@@ -216,9 +216,8 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	}
 
 	// Restore the text surface...
-	if (_game.version < 7 && !_mainMenuIsActive) {
-		restoreTextSurfacePostGUI();
-		_completeScreenRedraw = true;
+	if (_game.version < 7 && !_mainMenuIsActive && _game.platform != Common::kPlatformFMTowns) {
+		restoreSurfacesPostGUI();
 	}
 
 	// Finally, resume the engine, clear the input state, and restore the charset.
@@ -940,37 +939,57 @@ int ScummEngine::getBannerColor(int bannerId) {
 	return (int)arrAddr[bannerId];
 }
 
-void ScummEngine::saveTextSurfacePreGUI() {
+void ScummEngine::saveSurfacesPreGUI() {
+	// Why are we saving not one but TWO surfaces? Bear with me:
+	// texts in v6 and below are drawn sometimes onto the main surface, while
+	// other times they are drawn onto the text surface.
+	//
+	// Now, the original interpreters just killed every text after the
+	// menu is closed; this includes dialog texts, plain printed strings and
+	// possibly more.
+	//
+	// We can do better than that! Let's save both the main and the text surfaces
+	// so that we can restore them later when we're done with the menu.
+
+	uint32 curPix;
+
 	if (_game.version < 4 || _game.version > 6)
 		return;
 
 	_tempTextSurface = (byte *)malloc(_textSurface.w * _textSurface.h * sizeof(byte));
+	_tempMainSurface = (byte *)malloc(_virtscr[kMainVirtScreen].w * _virtscr[kMainVirtScreen].h * sizeof(byte));
 
-	int x, y;
-	uint32 curPix;
-	for (int i = 0; i < _textSurface.h; i++) {
-		for (int j = 0; j < _textSurface.w; j++) {
-			x = j;
-			y = i;
-			curPix = _textSurface.getPixel(x, y);
-			_tempTextSurface[j + i * _textSurface.w] = curPix;
-			if (curPix != 0xFD)
-				_virtscr[kMainVirtScreen].setPixel(_virtscr[kMainVirtScreen].xstart + x, y, curPix);
+	if (_tempMainSurface) {
+		for (int y = 0; y < _virtscr[kMainVirtScreen].h; y++) {
+			for (int x = 0; x < _virtscr[kMainVirtScreen].w; x++) {
+				curPix = _virtscr[kMainVirtScreen].getPixel(x, y);
+				_tempMainSurface[x + y * _virtscr[kMainVirtScreen].w] = curPix;
+			}
+		}
+	}
+
+	if (_tempTextSurface) {
+		for (int y = 0; y < _textSurface.h; y++) {
+			for (int x = 0; x < _textSurface.w; x++) {
+				curPix = _textSurface.getPixel(x, y);
+				_tempTextSurface[x + y * _textSurface.w] = curPix;
+				if (curPix != 0xFD)
+					_virtscr[kMainVirtScreen].setPixel(_virtscr[kMainVirtScreen].xstart + x, y, curPix);
+			}
 		}
 	}
 }
 
-void ScummEngine::restoreTextSurfacePostGUI() {
+void ScummEngine::restoreSurfacesPostGUI() {
+	uint32 curPix;
+
 	if (_game.version < 4 || _game.version > 6)
 		return;
+
 	if (_tempTextSurface) {
-		int x, y;
-		uint32 curPix;
-		for (int i = 0; i < _textSurface.h; i++) {
-			for (int j = 0; j < _textSurface.w; j++) {
-				x = j;
-				y = i;
-				curPix = _tempTextSurface[j + i * _textSurface.w];
+		for (int y = 0; y < _textSurface.h; y++) {
+			for (int x = 0; x < _textSurface.w; x++) {
+				curPix = _tempTextSurface[x + y * _textSurface.w];
 				_textSurface.setPixel(x, y, curPix);
 			}
 		}
@@ -983,6 +1002,20 @@ void ScummEngine::restoreTextSurfacePostGUI() {
 		free(_tempTextSurface);
 		_tempTextSurface = nullptr;
 	}
+
+	if (_tempMainSurface) {
+		for (int y = 0; y < _virtscr[kMainVirtScreen].h; y++) {
+			for (int x = 0; x < _virtscr[kMainVirtScreen].w; x++) {
+				curPix = _tempMainSurface[x + y * _virtscr[kMainVirtScreen].w];
+				_virtscr[kMainVirtScreen].setPixel(x, y, curPix);
+			}
+		}
+
+		free(_tempMainSurface);
+		_tempMainSurface = nullptr;
+
+		_virtscr[kMainVirtScreen].setDirtyRange(0, _virtscr[kMainVirtScreen].h);
+	}
 }
 
 void ScummEngine::toggleVoiceMode() {
@@ -1086,14 +1119,14 @@ void ScummEngine::fillSavegameLabels() {
 	Common::String name;
 	for (int i = 0; i < 9; i++) {
 		int curSaveSlot = i + 1 + _curDisplayedSaveSlotPage * 9;
-		sprintf_s(_savegameNames[i].label, sizeof(_savegameNames[i].label), "%2d. ", curSaveSlot);
+		sprintf(_savegameNames[i].label, "%2d. ", curSaveSlot);
 
 		if (availSaves[curSaveSlot]) {
 			if (getSavegameName(curSaveSlot, name)) {
-				sprintf_s(_savegameNames[i].label, sizeof(_savegameNames[i].label), "%2d. %s", curSaveSlot, name.c_str());
+				sprintf(_savegameNames[i].label, "%2d. %s", curSaveSlot, name.c_str());
 			} else {
 				// The original printed "WARNING... old savegame", but we do support old savegames :-)
-				sprintf_s(_savegameNames[i].label, sizeof(_savegameNames[i].label), "%2d. WARNING: wrong save version", curSaveSlot);
+				sprintf(_savegameNames[i].label, "%2d. WARNING: wrong save version", curSaveSlot);
 			}
 		}
 	}
@@ -1104,6 +1137,9 @@ bool ScummEngine::canWriteGame(int slotId) {
 	char msgLabelPtr[512];
 	char localizedYesKey;
 
+	if (_game.version < 7)
+		return true;
+
 	listSavegames(saveList, ARRAYSIZE(saveList));
 	if (saveList[slotId]) {
 		convertMessageToString((const byte *)getGUIString(gsReplacePrompt), (byte *)msgLabelPtr, sizeof(msgLabelPtr));
@@ -1130,6 +1166,7 @@ bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicke
 
 	while (true) {
 		waitForTimer(1);
+
 		waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
 		rightMsClicked = false;
 		if (ks.keycode == Common::KEYCODE_RETURN) {
@@ -1237,7 +1274,7 @@ void ScummEngine::showMainMenu() {
 		// This results in texts overlapping on top of the menu; let's simulate the end result
 		// of the original by copying the text surface over the main one just before showing
 		// the menu...
-		saveTextSurfacePreGUI();
+		saveSurfacesPreGUI();
 
 		// 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.
@@ -1247,8 +1284,12 @@ void ScummEngine::showMainMenu() {
 	_menuPage = GUI_PAGE_MAIN;
 	setUpMainMenuControls();
 	drawMainMenuControls();
-	convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
-	drawMainMenuTitle(saveScreenTitle);
+
+	if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
+		convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+		drawMainMenuTitle(saveScreenTitle);
+	}
+
 	updateMainMenuControls();
 
 	// Save the current cursor state...
@@ -1269,18 +1310,18 @@ void ScummEngine::showMainMenu() {
 			if (userWriteLabelRoutine(ks, leftMsClicked, rightMsClicked))
 				break;
 		} else {
-			// Wait for any left mouse button presses...
+			// Wait for any mouse button presses...
 			waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
 		}
 
-		rightMsClicked = false; // We don't care for this
-
-		if (leftMsClicked) {
+		if (leftMsClicked || rightMsClicked) {
 			curMouseX = _mouse.x;
 			curMouseY = _mouse.y;
 			clickedControl = getInternalGUIControlFromCoordinates(curMouseX, curMouseY);
 			clearClickedStatus();
 			leftMsClicked = false;
+			rightMsClicked = false;
+
 			if (clickedControl != -1) {
 				if (clickedControl < GUI_CTRL_FIRST_SG || clickedControl > GUI_CTRL_LAST_SG) {
 					// Avoid highlighting the main container boxes :-)
@@ -1330,7 +1371,8 @@ void ScummEngine::showMainMenu() {
 
 	_mainMenuIsActive = false;
 
-	_completeScreenRedraw = true;
+	if (_game.version > 6)
+		_completeScreenRedraw = true;
 
 	// Restore the old cursor state only if we're not loading a game...
 	if (_saveScriptParam != GAME_PROPER_LOAD && _saveLoadFlag != 2) {
@@ -1356,7 +1398,7 @@ void ScummEngine::showMainMenu() {
 		CHARSET_1();
 
 	if (_game.version < 7 && !hasLoadedState)
-		restoreTextSurfacePostGUI();
+		restoreSurfacesPostGUI();
 
 	// Resume the engine
 	pt.clear();
@@ -1395,7 +1437,7 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 		if (_menuPage == GUI_PAGE_SAVE) {
 			if (_mainMenuSavegameLabel > 0) {
 				convertMessageToString((const byte *)getGUIString(gsSaving), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
-				sprintf_s(formattedString, sizeof(formattedString), saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[4]);
+				sprintf(formattedString, saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[4]);
 				drawMainMenuTitle(formattedString);
 				ScummEngine::drawDirtyScreenParts();
 				_system->updateScreen();
@@ -1443,7 +1485,7 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 		} else if (_menuPage == GUI_PAGE_LOAD) {
 			if (_mainMenuSavegameLabel > 0) {
 				convertMessageToString((const byte *)getGUIString(gsLoading), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
-				sprintf_s(formattedString, sizeof(formattedString), saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[4]);
+				sprintf(formattedString, saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[4]);
 
 				if (strlen(_savegameNames[_mainMenuSavegameLabel - 1].label) == 4) {
 					drawMainMenuControls();
@@ -1457,7 +1499,6 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 
 				waitForTimer(60);
 
-
 				if (isSmushActive()) {
 					handleLoadDuringSmush();
 					return true;
@@ -1499,8 +1540,12 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 		_menuPage = GUI_PAGE_MAIN;
 		setUpMainMenuControls();
 		drawMainMenuControls();
-		convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
-		drawMainMenuTitle(saveScreenTitle);
+
+		if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
+			convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+			drawMainMenuTitle(saveScreenTitle);
+		}
+
 		updateMainMenuControls();
 		ScummEngine::drawDirtyScreenParts();
 		break;
@@ -1579,7 +1624,199 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 }
 
 void ScummEngine::setUpMainMenuControls() {
+	int yConstant;
+
+	yConstant = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
+
+	for (int i = 0; i < ARRAYSIZE(_internalGUIControls); i++) {
+		_internalGUIControls[i].relativeCenterX = -1;
+	}
+
+	// Outer box
+	setUpInternalGUIControl(GUI_CTRL_OUTER_BOX,
+		getBannerColor(4),
+		getBannerColor(2),
+		getBannerColor(13),
+		getBannerColor(14),
+		getBannerColor(15),
+		getBannerColor(16),
+		getBannerColor(6),
+		getBannerColor(4),
+		20,
+		yConstant - 60,
+		300,
+		((yConstant + 60) < 0 ? -120 : yConstant + 60),
+		_emptyMsg, 1, 1);
+
+	// Inner box
+	setUpInternalGUIControl(GUI_CTRL_INNER_BOX,
+		getBannerColor(4),
+		getBannerColor(5),
+		getBannerColor(18),
+		getBannerColor(17),
+		getBannerColor(20),
+		getBannerColor(19),
+		getBannerColor(6),
+		getBannerColor(7),
+		26,
+		yConstant - 47,
+		212,
+		yConstant - 47 + 102,
+		_emptyMsg, 1, 1);
+
+	if (_menuPage == GUI_PAGE_MAIN) {
+		// Save button
+		setUpInternalGUIControl(GUI_CTRL_SAVE_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			242,
+			yConstant - 23,
+			292,
+			yConstant - 23 + 12,
+			(char *)getGUIString(gsSave), 1, 1);
+
+		// Load button
+		setUpInternalGUIControl(GUI_CTRL_LOAD_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			242,
+			yConstant - 8,
+			292,
+			yConstant - 8 + 12,
+			(char *)getGUIString(gsLoad), 1, 1);
+
+		// Play button
+		setUpInternalGUIControl(GUI_CTRL_PLAY_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			242,
+			yConstant + 7,
+			292,
+			yConstant + 19,
+			(char *)getGUIString(gsPlay), 1, 1);
+
+		// Quit button
+		setUpInternalGUIControl(GUI_CTRL_QUIT_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			242,
+			yConstant + 22,
+			292,
+			yConstant + 34,
+			(char *)getGUIString(gsQuit), 1, 1);
+	}
+
+	if (_menuPage != GUI_PAGE_MAIN || !(_game.id == GID_MONKEY2 || _game.id == GID_MONKEY)) {
+		// Arrow up button
+		setUpInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON,
+			getBannerColor(9),
+			getBannerColor(10),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(11),
+			getBannerColor(12),
+			216,
+			yConstant - 43,
+			232,
+			yConstant - 43 + 47,
+			_arrowUp, 1, 1);
+
+		// Arrow down button
+		setUpInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON,
+			getBannerColor(9),
+			getBannerColor(10),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(11),
+			getBannerColor(12),
+			216,
+			yConstant + 7,
+			232,
+			yConstant + 52,
+			_arrowDown, 1, 1);
+	}
+
+	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
+		if (_menuPage == GUI_PAGE_SAVE) {
+			// OK button
+			setUpInternalGUIControl(GUI_CTRL_OK_BUTTON,
+				getBannerColor(4),
+				getBannerColor(5),
+				getBannerColor(17),
+				getBannerColor(18),
+				getBannerColor(19),
+				getBannerColor(20),
+				getBannerColor(6),
+				getBannerColor(7),
+				242,
+				yConstant - 8,
+				292,
+				yConstant - 8 + 12,
+				(char *)getGUIString(gsOK), 1, 1);
+		}
+
+		// Cancel button
+		setUpInternalGUIControl(GUI_CTRL_CANCEL_BUTTON,
+			getBannerColor(4),
+			getBannerColor(5),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(6),
+			getBannerColor(7),
+			242,
+			(_menuPage == GUI_PAGE_LOAD ? yConstant - 1 : yConstant + 7),
+			292,
+			(_menuPage == GUI_PAGE_LOAD ? yConstant - 1 : yConstant + 7) + 12,
+			(char *)getGUIString(gsCancel), 1, 1);
 
+		// Savegame names
+		for (int i = GUI_CTRL_FIRST_SG, j = 0; i <= GUI_CTRL_LAST_SG; i++, j += 11) {
+			setUpInternalGUIControl(i,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(4),
+				getBannerColor(4),
+				getBannerColor(4),
+				getBannerColor(4),
+				getBannerColor(11),
+				getBannerColor(12),
+				28,
+				yConstant - 45 + j,
+				210,
+				-9,
+				_savegameNames[i - 1].label, 0, 0);
+		}
+	}
 }
 
 void ScummEngine_v6::setUpMainMenuControls() {
@@ -1905,12 +2142,20 @@ void ScummEngine_v6::setUpMainMenuControls() {
 		// Cancel button
 		int cancelButtonAnchorY;
 		if (_menuPage == GUI_PAGE_LOAD) {
-			cancelButtonAnchorY = _screenHeight / 2 +
-				(((_game.id == GID_DIG && _useCJKMode) ? 10 : 7) - yComponentV7 / 2) +
-				((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) +
-				40;
+			if (_game.version == 7) {
+				cancelButtonAnchorY = _screenHeight / 2 +
+					(((_game.id == GID_DIG && _useCJKMode) ? 10 : 7) - yComponentV7 / 2) +
+					((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) +
+					40;
+			} else {
+				cancelButtonAnchorY = yConstantV6 - 1;
+			}
 		} else {
-			cancelButtonAnchorY = yConstantV7 + 43 + 2 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12);
+			if (_game.version == 7) {
+				cancelButtonAnchorY = yConstantV7 + 43 + 2 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12);
+			} else {
+				cancelButtonAnchorY = yConstantV6 + 7;
+			}
 		}
 		setUpInternalGUIControl(GUI_CTRL_CANCEL_BUTTON,
 			getBannerColor(4),
@@ -1922,7 +2167,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(6),
 			getBannerColor(7),
 			(_game.version == 7 ? 235 : 232),
-			(_game.version == 7 ? cancelButtonAnchorY : yConstantV6 - 1),
+			cancelButtonAnchorY,
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
 			(char *)getGUIString(gsCancel), 1, 1);
@@ -1962,9 +2207,10 @@ void ScummEngine::drawMainMenuControls() {
 		drawInternalGUIControl(GUI_CTRL_PLAY_BUTTON, 0); // Play button
 		drawInternalGUIControl(GUI_CTRL_QUIT_BUTTON, 0); // Quit button
 
-		drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0); // Inner box
+		if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY)
+			drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0); // Inner box
 
-		if (_game.version == 6) {
+		if ((_game.version == 5 &&( _game.id != GID_MONKEY2 && _game.id != GID_MONKEY)) || _game.version == 6) {
 			drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);   // Arrow up button
 			drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button
 
@@ -2005,7 +2251,7 @@ void ScummEngine::drawMainMenuControls() {
 }
 
 void ScummEngine::updateMainMenuControls() {
-	if (!strcmp(_game.variant, "Floppy"))
+	if (!strcmp(_game.variant, "Floppy") || _game.version < 6)
 		return;
 
 	char msg[256];
@@ -2325,10 +2571,6 @@ const char *ScummEngine::getGUIString(int stringId) {
 	case gsPause:
 		resStringId = 4;
 		break;
-	case gsVersion:
-		break;
-	case gsTextSpeedSlider:
-		break;
 	case gsRestart:
 		resStringId = 5;
 		break;
@@ -2353,48 +2595,50 @@ const char *ScummEngine::getGUIString(int stringId) {
 	case gsOK:
 		resStringId = 12;
 		break;
-	case gsMustName:
+	case gsInsertSaveDisk:
 		resStringId = 13;
 		break;
-	case gsGameNotSaved:
+	case gsMustName:
 		resStringId = 14;
 		break;
-	case gsGameNotLoaded:
+	case gsGameNotSaved:
 		resStringId = 15;
 		break;
-	case gsSaving:
+	case gsGameNotLoaded:
 		resStringId = 16;
 		break;
-	case gsLoading:
+	case gsSaving:
 		resStringId = 17;
 		break;
-	case gsNamePrompt:
+	case gsLoading:
 		resStringId = 18;
 		break;
-	case gsSelectLoadPrompt:
+	case gsNamePrompt:
 		resStringId = 19;
 		break;
-	case gsReplacePrompt:
+	case gsSelectLoadPrompt:
+		resStringId = 20;
 		break;
-	case gsYes:
+	case gsTitle:
+		resStringId = 21;
 		break;
-	case gsNo:
+	case gsVoiceOnly:
+		resStringId = 22;
 		break;
 	case gsVoiceAndText:
+		resStringId = 23;
 		break;
 	case gsTextDisplayOnly:
+		resStringId = 24;
 		break;
-	case gsMusicVolumeSlider:
-		break;
-	case gsVoiceVolumeSlider:
+	case gsTextSpeedSlider:
+		resStringId = 25;
 		break;
-	case gsSfxVolumeSlider:
+	case gsMusicVolumeSlider:
+		resStringId = 26;
 		break;
 	case gsHeap:
 		return "Heap %dK";
-	case gsTitle:
-		resStringId = 20;
-		break;
 	default:
 		return "";
 	}
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 04099efc701..85c5323ed4e 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -489,6 +489,12 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 		uint32 millis = _system->getMillis();
 		while (((_system->getMillis() - millis) * (_timerFrequency / 4) / 1000) < waitTime) {
 			waitForTimer(1); // Allow the engine to update the screen and fetch new inputs...
+
+			if (_game.version < 7 && (_guiCursorAnimCounter++ & 16)) {
+				_guiCursorAnimCounter = 0;
+				animateCursor();
+			}
+
 			ks = _keyPressed;
 			leftBtnClicked = (_leftBtnPressed & msClicked) != 0;
 			rightBtnClicked = (_rightBtnPressed & msClicked) != 0;
@@ -501,6 +507,12 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 	} else {
 		while (!validKey && !leftBtnClicked && !rightBtnClicked) {
 			waitForTimer(1); // Allow the engine to update the screen and fetch new inputs...
+
+			if (_game.version < 7 && (_guiCursorAnimCounter++ & 16)) {
+				_guiCursorAnimCounter = 0;
+				animateCursor();
+			}
+
 			ks = _keyPressed;
 			leftBtnClicked = (_leftBtnPressed & msClicked) != 0;
 			rightBtnClicked = (_rightBtnPressed & msClicked) != 0;
@@ -628,43 +640,6 @@ void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) {
 
 				return;
 			}
-
-			// "Text Speed  Slow  ==========  Fast"
-			if (lastKeyHit.ascii == '+' || lastKeyHit.ascii == '-') {
-				if (VAR_CHARINC == 0xFF)
-					return;
-
-				Common::KeyState ks = lastKeyHit;
-
-				pt = pauseEngine();
-
-				do {
-					if (ks.ascii == '+') {
-						VAR(VAR_CHARINC) -= 1;
-						if (VAR(VAR_CHARINC) < 0)
-							VAR(VAR_CHARINC) = 0;
-					} else {
-						VAR(VAR_CHARINC) += 1;
-						if (VAR(VAR_CHARINC) > 9)
-							VAR(VAR_CHARINC) = 9;
-					}
-
-					_defaultTextSpeed = 9 - VAR(VAR_CHARINC);
-					ConfMan.setInt("original_gui_text_speed", _defaultTextSpeed);
-					setTalkSpeed(_defaultTextSpeed);
-
-					getSliderString(gsTextSpeedSlider, VAR(VAR_CHARINC), sliderString, sizeof(sliderString));
-					showBannerAndPause(0, 0, sliderString);
-					ks = Common::KEYCODE_INVALID;
-					bool leftBtnPressed = false, rightBtnPressed = false;
-					waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
-				} while (ks.ascii == '+' || ks.ascii == '-');
-				clearBanner();
-
-				pt.clear();
-
-				return;
-			}
 		}
 
 		if (VAR_VERSION_KEY != 0xFF && VAR(VAR_VERSION_KEY) != 0 &&
@@ -677,59 +652,16 @@ void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) {
 
 				if (_game.features & GF_DEMO)
 					showBannerAndPause(0, -1, "iMuse(tm) initialized");
+				return;
 			} else if (_game.version == 7) {
 				showBannerAndPause(0, -1, getGUIString(gsVersion));
 				showBannerAndPause(0, -1, "Scripts compiled %s", _dataFileVersionString);
 				showBannerAndPause(0, -1, "SPU(tm) version %s", _engineVersionString);
 				showBannerAndPause(0, -1, "iMuse(tm) initialized");
+				return;
 			}
-
-			return;
-		}
-
-
-		if (lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-			int voiceMode = VAR(VAR_VOICE_MODE);
-
-			voiceMode++;
-			if (voiceMode >= 3) {
-				voiceMode = 0;
-			}
-
-			switch (voiceMode) {
-			case 0: // "Voice Only"
-				showBannerAndPause(0, 120, getGUIString(gsVoiceOnly));
-				break;
-			case 1: // "Voice and Text"
-				showBannerAndPause(0, 120, getGUIString(gsVoiceAndText));
-				break;
-			default: // "Text Display Only"
-				showBannerAndPause(0, 120, getGUIString(gsTextDisplayOnly));
-			}
-
-			ConfMan.setInt("original_gui_text_status", voiceMode);
-			switch (voiceMode) {
-			case 0:
-				ConfMan.setBool("speech_mute", false);
-				ConfMan.setBool("subtitles", false);
-				break;
-			case 1:
-				ConfMan.setBool("speech_mute", false);
-				ConfMan.setBool("subtitles", true);
-				break;
-			case 2:
-				ConfMan.setBool("speech_mute", true);
-				ConfMan.setBool("subtitles", true);
-				break;
-			default:
-				break;
-			}
-
-			ConfMan.flushToDisk();
-			syncSoundSettings();
-			return;
+			// Older versions show this banner via scripts, so just let it fallback...
 		}
-
 	} else {
 		if (lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 			SubtitleSettingsDialog dialog(this, _voiceMode);
@@ -852,6 +784,9 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		restartKeyEnabled = true;
 
 	if (isUsingOriginalGUI()) {
+		char sliderString[256];
+		PauseToken pt;
+
 		if (VAR_PAUSE_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_PAUSE_KEY) ||
 			(lastKeyHit.keycode == Common::KEYCODE_SPACE && _game.features & GF_DEMO))) {
 			// Force the cursor OFF...
@@ -871,6 +806,89 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			return;
 		}
 
+		if (VAR_VOICE_MODE != 0xFF &&
+			(_game.version > 5 || (_game.id == GID_INDY4 &&
+				strcmp(_game.variant, "Floppy") && strcmp(_game.variant, "Amiga"))) &&
+			lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+			int voiceMode = VAR(VAR_VOICE_MODE);
+
+			voiceMode++;
+			if (voiceMode >= 3) {
+				voiceMode = 0;
+			}
+
+			switch (voiceMode) {
+			case 0: // "Voice Only"
+				showBannerAndPause(0, 120, getGUIString(gsVoiceOnly));
+				break;
+			case 1: // "Voice and Text"
+				showBannerAndPause(0, 120, getGUIString(gsVoiceAndText));
+				break;
+			default: // "Text Display Only"
+				showBannerAndPause(0, 120, getGUIString(gsTextDisplayOnly));
+			}
+
+			ConfMan.setInt("original_gui_text_status", voiceMode);
+			switch (voiceMode) {
+			case 0:
+				ConfMan.setBool("speech_mute", false);
+				ConfMan.setBool("subtitles", false);
+				break;
+			case 1:
+				ConfMan.setBool("speech_mute", false);
+				ConfMan.setBool("subtitles", true);
+				break;
+			case 2:
+				ConfMan.setBool("speech_mute", true);
+				ConfMan.setBool("subtitles", true);
+				break;
+			default:
+				break;
+			}
+
+			ConfMan.flushToDisk();
+			syncSoundSettings();
+			return;
+		}
+
+		// "Text Speed  Slow  ==========  Fast"
+		if (lastKeyHit.ascii == '+' || lastKeyHit.ascii == '-') {
+			if (VAR_CHARINC == 0xFF)
+				return;
+
+			Common::KeyState ks = lastKeyHit;
+
+			pt = pauseEngine();
+
+			do {
+				if (ks.ascii == '+') {
+					VAR(VAR_CHARINC) -= 1;
+					if (VAR(VAR_CHARINC) < 0)
+						VAR(VAR_CHARINC) = 0;
+				} else {
+					VAR(VAR_CHARINC) += 1;
+					if (VAR(VAR_CHARINC) > 9)
+						VAR(VAR_CHARINC) = 9;
+				}
+
+				_defaultTextSpeed = 9 - VAR(VAR_CHARINC);
+				ConfMan.setInt("original_gui_text_speed", _defaultTextSpeed);
+				setTalkSpeed(_defaultTextSpeed);
+
+				getSliderString(gsTextSpeedSlider, VAR(VAR_CHARINC), sliderString, sizeof(sliderString));
+				showBannerAndPause(0, 0, sliderString);
+				ks = Common::KEYCODE_INVALID;
+				bool leftBtnPressed = false, rightBtnPressed = false;
+				waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
+			} while (ks.ascii == '+' || ks.ascii == '-');
+			clearBanner();
+
+			pt.clear();
+
+			return;
+		}
+
+
 		if (lastKeyHit.keycode == Common::KEYCODE_k && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 			showBannerAndPause(0, 120, getGUIString(gsHeap), _res->getHeapSize() / 1024);
 			return;
@@ -881,8 +899,8 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			return;
 		}
 
-		if (VAR_MAINMENU_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_MAINMENU_KEY) && lastKeyHit.hasFlags(0)) &&
-			_game.version > 5) {
+		if (VAR_MAINMENU_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_MAINMENU_KEY) && lastKeyHit.hasFlags(0))
+			&& _game.platform != Common::kPlatformFMTowns) {
 			showMainMenu();
 			return;
 		}
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 66b1289124c..92098b04b01 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -3119,6 +3119,9 @@ void ScummEngine::restart() {
 }
 
 bool ScummEngine::isUsingOriginalGUI() {
+	if (_game.heversion != 0)
+		return false;
+
 	if (_game.version > 4)
 		return _useOriginalGUI;
 
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index b0f70021f1b..21ef3aa218d 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -634,8 +634,11 @@ protected:
 	char _mainMenuTextSpeedSlider[17];
 	int _spooledMusicIsToBeEnabled = 1;
 	int _saveScriptParam = 0;
+	int _guiCursorAnimCounter = 0;
+
 	Graphics::Surface _savegameThumbnail;
 	byte *_tempTextSurface;
+	byte *_tempMainSurface;
 	bool _postGUICharMask = false;
 
 	// Saved cursor pre and post GUI
@@ -690,8 +693,8 @@ protected:
 	bool userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked);
 	void saveCursorPreMenu();
 	void restoreCursorPostMenu();
-	void saveTextSurfacePreGUI();
-	void restoreTextSurfacePostGUI();
+	void saveSurfacesPreGUI();
+	void restoreSurfacesPostGUI();
 
 public:
 	char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);


Commit: f7c8b670d88297a883c232a9b14409cf5b9f8760
    https://github.com/scummvm/scummvm/commit/f7c8b670d88297a883c232a9b14409cf5b9f8760
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Replace non-ASCII characters with portable variations

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index c87d7ca1438..3699ec00306 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -129,8 +129,8 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	// Take all the necessary measurements for the box which
 	// will contain the string...
 	bool isCOMIDemo = (_game.id == GID_CMI && (_game.features & GF_DEMO) != 0);
-	bannerMsgHeight = (isCOMIDemo ? _textV7->getStringHeight("ABC \x80\x78 \xb0\x78) : _textV7->getStringHeight(bannerMsg)) + 5;
-	bannerMsgWidth = _textV7->getStringWidth(bannerMsg);
+	bannerMsgHeight = (isCOMIDemo ? getGUIStringHeight("ABC \x80\x78 \xb0\x78") : getGUIStringHeight(bannerMsg)) + 5;
+	bannerMsgWidth = getGUIStringWidth(bannerMsg);
 	if (bannerMsgWidth < 100)
 		bannerMsgWidth = 100;
 


Commit: a56bf5c4e149c2781bd9ade6a22b6bdd0ea8211d
    https://github.com/scummvm/scummvm/commit/a56bf5c4e149c2781bd9ade6a22b6bdd0ea8211d
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Implement voice mode settings for Indy4 Talkie

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


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 85c5323ed4e..4382ce75aa7 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -806,17 +806,21 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			return;
 		}
 
-		if (VAR_VOICE_MODE != 0xFF &&
-			(_game.version > 5 || (_game.id == GID_INDY4 &&
+		// Generally allow voice mode settings only for v6, 7 and 8.
+		// Also allow it for Indy4 Talkie, which does its own thing.
+		if ((VAR_VOICE_MODE != 0xFF || (_game.id == GID_INDY4 &&
 				strcmp(_game.variant, "Floppy") && strcmp(_game.variant, "Amiga"))) &&
-			lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
-			int voiceMode = VAR(VAR_VOICE_MODE);
+			(lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL))) {
+			int voiceMode = (_game.version == 5) ? _v5VoiceMode : VAR(VAR_VOICE_MODE);
 
 			voiceMode++;
 			if (voiceMode >= 3) {
 				voiceMode = 0;
 			}
 
+			if (_game.version == 5)
+				_v5VoiceMode = voiceMode;
+
 			switch (voiceMode) {
 			case 0: // "Voice Only"
 				showBannerAndPause(0, 120, getGUIString(gsVoiceOnly));
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 21ef3aa218d..f161f1e159f 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -635,6 +635,7 @@ protected:
 	int _spooledMusicIsToBeEnabled = 1;
 	int _saveScriptParam = 0;
 	int _guiCursorAnimCounter = 0;
+	int _v5VoiceMode = 0;
 
 	Graphics::Surface _savegameThumbnail;
 	byte *_tempTextSurface;


Commit: eadacafd1b953cabe00c64844e978f961bb7d1af
    https://github.com/scummvm/scummvm/commit/eadacafd1b953cabe00c64844e978f961bb7d1af
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: Fix warnings

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


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index d15d1557f09..6284761e2b9 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -184,6 +184,7 @@ static const ResString string_map_table_v6[] = {
 	{0, "Music Volume    Low  =========  High"},
 	{0, "Voice Volume    Low  =========  High"},
 	{0, "SFX Volume    Low  =========  High"},
+	{0, "Heap %dK"}
 };
 
 #pragma mark -
@@ -428,34 +429,34 @@ void InfoDialog::reflowLayout() {
 	_text->setSize(_w, _h);
 }
 
-const char *InfoDialog::getPlainEngineString(int stringno) {
-	const char *result;
+char *InfoDialog::getPlainEngineString(int stringno) {
+	char *result;
 
 	if (stringno == 0)
 		return nullptr;
 
 	if (_vm->_game.version == 8) {
-		return (const char *)string_map_table_v8[stringno - 1].string;
+		return (char *)string_map_table_v8[stringno - 1].string;
 	} else if (_vm->_game.version == 7) {
-		result = (const char *)_vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
+		result = (char *)_vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
 
 		if (!result) {
-			result = (const char *)string_map_table_v7[stringno - 1].string;
+			result = (char *)string_map_table_v7[stringno - 1].string;
 		}
 	} else if (_vm->_game.version == 6) {
-		result = (const char *)_vm->getStringAddressVar(string_map_table_v6[stringno - 1].num);
+		result = (char *)_vm->getStringAddressVar(string_map_table_v6[stringno - 1].num);
 
 		if (!result) {
-			result = (const char *)string_map_table_v6[stringno - 1].string;
+			result = (char *)string_map_table_v6[stringno - 1].string;
 		}
 	} else if (_vm->_game.version >= 3) {
-		result = (const char *)_vm->getStringAddress(getStaticResString(_vm->_language, stringno - 1).num);
+		result = (char *)_vm->getStringAddress(getStaticResString(_vm->_language, stringno - 1).num);
 
 		if (!result) {
-			result = (const char *)getStaticResString(_vm->_language, stringno - 1).string;
+			result = (char *)getStaticResString(_vm->_language, stringno - 1).string;
 		}
 	} else {
-		result = (const char *)(getStaticResString(_vm->_language, stringno - 1).string);
+		result = (char *)(getStaticResString(_vm->_language, stringno - 1).string);
 	}
 
 	return result;
@@ -646,6 +647,7 @@ 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"}
 	};
 
 	if (stringno + 1 >= ARRAYSIZE(strMap1)) {
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 2a9e12691e2..16d4a2ff736 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -96,7 +96,7 @@ public:
 	}
 
 	void reflowLayout() override;
-	const char *getPlainEngineString(int stringno);
+	char *getPlainEngineString(int stringno);
 
 protected:
 	// Query a string from the resources
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 3699ec00306..79400282c37 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -408,8 +408,8 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 				int yOffset = 8;
 
 				if ((_game.id == GID_DIG && _useCJKMode) &&
-					((ctrl->label[0] >= 128 && ctrl->label[0] <= 159) ||
-					 (ctrl->label[0] >= 224 && ctrl->label[0] <= 253))) {
+					(((byte)ctrl->label[0] >= 128 && (byte)ctrl->label[0] <= 159) ||
+					 ((byte)ctrl->label[0] >= 224 && (byte)ctrl->label[0] <= 253))) {
 					yOffset = 16;
 				}
 
@@ -655,7 +655,7 @@ void ScummEngine_v7::queryQuit() {
 	}
 }
 
-const char *ScummEngine_v8::getGUIString(int stringId) {
+char *ScummEngine_v8::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
 
@@ -706,16 +706,16 @@ const char *ScummEngine_v8::getGUIString(int stringId) {
 		resStringId = 35;
 		break;
 	default:
-		return "";
+		return _emptyMsg;
 	}
 
 	if (resStringId > 0)
 		return d.getPlainEngineString(resStringId);
 	else
-		return "";
+		return _emptyMsg;
 }
 
-const char *ScummEngine_v7::getGUIString(int stringId) {
+char *ScummEngine_v7::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
 
@@ -833,13 +833,13 @@ const char *ScummEngine_v7::getGUIString(int stringId) {
 		resStringId = 58;
 		break;
 	default:
-		return "";
+		return _emptyMsg;
 	}
 
 	if (resStringId > 0)
 		return d.getPlainEngineString(resStringId);
 	else
-		return "";
+		return _emptyMsg;
 }
 
 int ScummEngine_v7::getGUIStringHeight(const char *str) {
@@ -1679,7 +1679,7 @@ void ScummEngine::setUpMainMenuControls() {
 			yConstant - 23,
 			292,
 			yConstant - 23 + 12,
-			(char *)getGUIString(gsSave), 1, 1);
+			getGUIString(gsSave), 1, 1);
 
 		// Load button
 		setUpInternalGUIControl(GUI_CTRL_LOAD_BUTTON,
@@ -1695,7 +1695,7 @@ void ScummEngine::setUpMainMenuControls() {
 			yConstant - 8,
 			292,
 			yConstant - 8 + 12,
-			(char *)getGUIString(gsLoad), 1, 1);
+			getGUIString(gsLoad), 1, 1);
 
 		// Play button
 		setUpInternalGUIControl(GUI_CTRL_PLAY_BUTTON,
@@ -1711,7 +1711,7 @@ void ScummEngine::setUpMainMenuControls() {
 			yConstant + 7,
 			292,
 			yConstant + 19,
-			(char *)getGUIString(gsPlay), 1, 1);
+			getGUIString(gsPlay), 1, 1);
 
 		// Quit button
 		setUpInternalGUIControl(GUI_CTRL_QUIT_BUTTON,
@@ -1727,7 +1727,7 @@ void ScummEngine::setUpMainMenuControls() {
 			yConstant + 22,
 			292,
 			yConstant + 34,
-			(char *)getGUIString(gsQuit), 1, 1);
+			getGUIString(gsQuit), 1, 1);
 	}
 
 	if (_menuPage != GUI_PAGE_MAIN || !(_game.id == GID_MONKEY2 || _game.id == GID_MONKEY)) {
@@ -1780,7 +1780,7 @@ void ScummEngine::setUpMainMenuControls() {
 				yConstant - 8,
 				292,
 				yConstant - 8 + 12,
-				(char *)getGUIString(gsOK), 1, 1);
+				getGUIString(gsOK), 1, 1);
 		}
 
 		// Cancel button
@@ -1797,7 +1797,7 @@ void ScummEngine::setUpMainMenuControls() {
 			(_menuPage == GUI_PAGE_LOAD ? yConstant - 1 : yConstant + 7),
 			292,
 			(_menuPage == GUI_PAGE_LOAD ? yConstant - 1 : yConstant + 7) + 12,
-			(char *)getGUIString(gsCancel), 1, 1);
+			getGUIString(gsCancel), 1, 1);
 
 		// Savegame names
 		for (int i = GUI_CTRL_FIRST_SG, j = 0; i <= GUI_CTRL_LAST_SG; i++, j += 11) {
@@ -2027,7 +2027,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			(_game.version == 7 ? yConstantV7 + 37 : yConstantV6 - 23),
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
-			(char *)getGUIString(gsSave), 1, 1);
+			getGUIString(gsSave), 1, 1);
 
 		// Load button
 		int loadButtonAnchorY = yConstantV7 +
@@ -2046,7 +2046,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			(_game.version == 7 ? loadButtonAnchorY : yConstantV6 - 8),
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
-			(char *)getGUIString(gsLoad), 1, 1);
+			getGUIString(gsLoad), 1, 1);
 
 		// Play button
 		int playButtonAnchorY = yConstantV7 +
@@ -2065,7 +2065,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			(_game.version == 7 ? playButtonAnchorY : yConstantV6 + 7),
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
-			(char *)getGUIString(gsPlay), 1, 1);
+			getGUIString(gsPlay), 1, 1);
 
 		// Quit button
 		int quitButtonAnchorY = yConstantV7 +
@@ -2084,7 +2084,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			(_game.version == 7 ? quitButtonAnchorY : yConstantV6 + 22),
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
-			(char *)getGUIString(gsQuit), 1, 1);
+			getGUIString(gsQuit), 1, 1);
 	}
 
 	// Arrow up button
@@ -2136,7 +2136,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				(_game.version == 7 ? okButtonAnchorY : yConstantV6 - 8),
 				-60,
 				((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
-				(char *)getGUIString(gsOK), 1, 1);
+				getGUIString(gsOK), 1, 1);
 		}
 
 		// Cancel button
@@ -2170,7 +2170,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			cancelButtonAnchorY,
 			-60,
 			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
-			(char *)getGUIString(gsCancel), 1, 1);
+			getGUIString(gsCancel), 1, 1);
 
 		// Savegame names
 		for (int i = GUI_CTRL_FIRST_SG, j = 11; i <= GUI_CTRL_LAST_SG; i++, j += 11) {
@@ -2283,9 +2283,9 @@ void ScummEngine::updateMainMenuControls() {
 	_internalGUIControls[GUI_CTRL_TEXT_SPEED_SLIDER].label = _mainMenuTextSpeedSlider;
 
 	if (_sound->isAudioDisabled()) {
-		_internalGUIControls[GUI_CTRL_MUSIC_SLIDER].label  = (char *)getGUIString(gsDisabled);
-		_internalGUIControls[GUI_CTRL_SPEECH_SLIDER].label = (char *)getGUIString(gsDisabled);
-		_internalGUIControls[GUI_CTRL_SFX_SLIDER].label    = (char *)getGUIString(gsDisabled);
+		_internalGUIControls[GUI_CTRL_MUSIC_SLIDER].label  = getGUIString(gsDisabled);
+		_internalGUIControls[GUI_CTRL_SPEECH_SLIDER].label = getGUIString(gsDisabled);
+		_internalGUIControls[GUI_CTRL_SFX_SLIDER].label    = getGUIString(gsDisabled);
 	}
 
 	if (_spooledMusicIsToBeEnabled) {
@@ -2298,7 +2298,7 @@ void ScummEngine::updateMainMenuControls() {
 
 	if (VAR_VOICE_MODE != 0xFF && VAR(VAR_VOICE_MODE) == 0) {
 		_internalGUIControls[GUI_CTRL_DISPLAY_TEXT_CHECKBOX].label = _uncheckedBox;
-		_internalGUIControls[GUI_CTRL_TEXT_SPEED_SLIDER].label = (char *)getGUIString(gsDisabled);
+		_internalGUIControls[GUI_CTRL_TEXT_SPEED_SLIDER].label = getGUIString(gsDisabled);
 	}
 
 	drawInternalGUIControl(GUI_CTRL_MUSIC_SLIDER,  0); // Music slider
@@ -2453,7 +2453,7 @@ void ScummEngine::getSliderString(int stringId, int value, char *sliderString, i
 	}
 }
 
-const char *ScummEngine_v6::getGUIString(int stringId) {
+char *ScummEngine_v6::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
 
@@ -2552,18 +2552,19 @@ const char *ScummEngine_v6::getGUIString(int stringId) {
 		resStringId = 34;
 		break;
 	case gsHeap:
-		return "Heap %dK";
+		resStringId = 35;
+		break;
 	default:
-		return "";
+		return _emptyMsg;
 	}
 
 	if (resStringId > 0)
 		return d.getPlainEngineString(resStringId);
 	else
-		return "";
+		return _emptyMsg;
 }
 
-const char *ScummEngine::getGUIString(int stringId) {
+char *ScummEngine::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
 
@@ -2638,15 +2639,16 @@ const char *ScummEngine::getGUIString(int stringId) {
 		resStringId = 26;
 		break;
 	case gsHeap:
-		return "Heap %dK";
+		resStringId = 28;
+		break;
 	default:
-		return "";
+		return _emptyMsg;
 	}
 
 	if (resStringId > 0)
 		return d.getPlainEngineString(resStringId);
 	else
-		return "";
+		return _emptyMsg;
 }
 
 } // End of namespace Scumm
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 4382ce75aa7..336b0373a39 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -808,7 +808,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 
 		// Generally allow voice mode settings only for v6, 7 and 8.
 		// Also allow it for Indy4 Talkie, which does its own thing.
-		if ((VAR_VOICE_MODE != 0xFF || (_game.id == GID_INDY4 &&
+		if (((VAR_VOICE_MODE != 0xFF) || (_game.id == GID_INDY4 &&
 				strcmp(_game.variant, "Floppy") && strcmp(_game.variant, "Amiga"))) &&
 			(lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL))) {
 			int voiceMode = (_game.version == 5) ? _v5VoiceMode : VAR(VAR_VOICE_MODE);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index f161f1e159f..c10573d70ce 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -666,7 +666,7 @@ protected:
 
 	virtual void queryQuit();
 	virtual void queryRestart();
-	virtual const char *getGUIString(int stringId);
+	virtual char *getGUIString(int stringId);
 	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked);
 	virtual int getGUIStringHeight(const char *str);
 	virtual int getGUIStringWidth(const char *str);
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index c68bab7aba8..bdf76a5a8db 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -164,7 +164,7 @@ protected:
 	void clearDrawQueues() override;
 
 	int getBannerColor(int bannerId) override;
-	const char *getGUIString(int stringId) override;
+	char *getGUIString(int stringId) override;
 	void setSkipVideo(int value) override { _skipVideo = value; }
 	void setUpMainMenuControls() override;
 
diff --git a/engines/scumm/scumm_v7.h b/engines/scumm/scumm_v7.h
index 3f2bf605be6..bf4759ae975 100644
--- a/engines/scumm/scumm_v7.h
+++ b/engines/scumm/scumm_v7.h
@@ -144,7 +144,7 @@ protected:
 
 	void queryQuit() override;
 	int getBannerColor(int bannerId) override;
-	const char *getGUIString(int stringId) override;
+	char *getGUIString(int stringId) override;
 	int getGUIStringHeight(const char *str) override;
 	int getGUIStringWidth(const char *str) override;
 	void drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag) override;
diff --git a/engines/scumm/scumm_v8.h b/engines/scumm/scumm_v8.h
index de3885b5433..6085affe665 100644
--- a/engines/scumm/scumm_v8.h
+++ b/engines/scumm/scumm_v8.h
@@ -94,7 +94,7 @@ protected:
 	bool fetchInternalSaveStateThumbnail(int slotId, bool isHeapSave);
 	uint32 *fetchScummVMSaveStateThumbnail(int slotId, bool isHeapSave, int brightness);
 
-	const char *getGUIString(int stringId) override;
+	char *getGUIString(int stringId) override;
 
 	/* Version 8 script opcodes */
 	void o8_mod();


Commit: 251d6ab20d33ab2d8c72f4cc98a2b7a88f799cbe
    https://github.com/scummvm/scummvm/commit/251d6ab20d33ab2d8c72f4cc98a2b7a88f799cbe
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: Fix parenthesis warning in input.cpp

Changed paths:
    engines/scumm/input.cpp


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 336b0373a39..08d8c2cccec 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -787,7 +787,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		char sliderString[256];
 		PauseToken pt;
 
-		if (VAR_PAUSE_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_PAUSE_KEY) ||
+		if ((VAR_PAUSE_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_PAUSE_KEY)) ||
 			(lastKeyHit.keycode == Common::KEYCODE_SPACE && _game.features & GF_DEMO))) {
 			// Force the cursor OFF...
 			int8 oldCursorState = _cursor.state;
@@ -799,7 +799,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			return;
 		}
 
-		if (VAR_RESTART_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_RESTART_KEY)) ||
+		if ((VAR_RESTART_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_RESTART_KEY))) ||
 			((_game.id == GID_CMI && !(_game.features & GF_DEMO))
 				&& lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0))) {
 			queryRestart();


Commit: 222bb5c2fa336d95d00187582d101bb22ff1b2b5
    https://github.com/scummvm/scummvm/commit/222bb5c2fa336d95d00187582d101bb22ff1b2b5
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: DETECTION: Fix detection for MI2 non-interactive demo

Changed paths:
    devtools/scumm-md5.txt
    engines/scumm/detection_tables.h
    engines/scumm/scumm-md5.h


diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt
index f945eb32ce1..ffe6091a88e 100644
--- a/devtools/scumm-md5.txt
+++ b/devtools/scumm-md5.txt
@@ -272,7 +272,7 @@ monkey2	Monkey Island 2: LeChuck's Revenge
 	da09e666fc8f5b78d7b0ac65d1a3b56e	11135	en	FM-TOWNS	FM-TOWNS	-	-	dhewg, Andrea Petrucci
 	430bc518017b6fac046f58bab6baad5d	-1	jp	FM-TOWNS	FM-TOWNS	-	-	Antti Leimi, Andrea Petrucci
 
-	387a544b8b10b26912d8413bab63a853	9770	en	DOS	-	Demo	non-interactive, v2.5.1 9/30/91	khalek
+	387a544b8b10b26912d8413bab63a853	9770	en	DOS	Demo	Demo	non-interactive, v2.5.1 9/30/91	khalek
 	f4d20ab4ce19743a646cb48bd93aee72	10835	en	DOS	SE Talkie	Unofficial SE Talkie v0.2	lotharsm
 	a95baf7746f1be4985ad42126993a744	-1	ko	DOS	-	-	Fan translation	ScummVM-Kor
 	9f0a200df45c1c6c944cda21c134ff50	10835	he	DOS	SE Talkie	Unofficial SE Talkie v0.2	Hebrew fan translation
diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 12be1af7437..809cdf10137 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -198,6 +198,7 @@ static const GameSettings gameVariantsTable[] = {
 	{"monkey", "SE Talkie",    0, GID_MONKEY,     5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_AUDIOTRACKS, UNK, GUIO1(GUIO_ORIGINALGUI)},
 
 	{"monkey2", "", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO3(GUIO_NOSPEECH, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey2", "Demo", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_DEMO, UNK, GUIO2(GUIO_NOSPEECH, GUIO_ENHANCEMENTS)},
 	{"monkey2", "Amiga", 0, GID_MONKEY2,  5, 0, MDT_AMIGA, 0, Common::kPlatformAmiga, GUIO4(GUIO_NOSPEECH, GUIO_MIDIAMIGA, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
 	{"monkey2", "FM-TOWNS", 0, GID_MONKEY2,  5, 0, MDT_PCSPK | MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO7(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
 	{"monkey2", "SE Talkie", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_ORIGINALGUI)},
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index 2318b706da1..63c80cedf41 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -186,7 +186,7 @@ static const MD5Table md5table[] = {
 	{ "37f56ceb13e401a7ac7d9e6b37fecaf7", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformDOS },
 	{ "37ff1b308999c4cca7319edfcc1280a0", "puttputt", "HE 70", "Demo", 8269, Common::EN_ANY, Common::kPlatformWindows },
 	{ "3824e60cdf639d22f6df92a03dc4b131", "fbear", "HE 62", "", 7732, Common::EN_ANY, Common::kPlatformDOS },
-	{ "387a544b8b10b26912d8413bab63a853", "monkey2", "", "Demo", 9770, Common::EN_ANY, Common::kPlatformDOS },
+	{ "387a544b8b10b26912d8413bab63a853", "monkey2", "Demo", "Demo", 9770, Common::EN_ANY, Common::kPlatformDOS },
 	{ "3938ee1aa4433fca9d9308c9891172b1", "indyzak", "FM-TOWNS", "Demo", 7520, Common::EN_ANY, Common::kPlatformFMTowns },
 	{ "399b217b0c8d65d0398076da486363a9", "indy3", "VGA", "VGA", 6295, Common::DE_DEU, Common::kPlatformDOS },
 	{ "39cb9dec16fa16f38d79acd80effb059", "loom", "EGA", "EGA", -1, Common::UNK_LANG, Common::kPlatformAmiga },


Commit: 43c6896c53dcf2223fe18e63046cc669193a68f4
    https://github.com/scummvm/scummvm/commit/43c6896c53dcf2223fe18e63046cc669193a68f4
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Disable original GUI for MI2 non-interactive demo

Changed paths:
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 92098b04b01..c9849fd84ef 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -3119,6 +3119,9 @@ void ScummEngine::restart() {
 }
 
 bool ScummEngine::isUsingOriginalGUI() {
+	if (_game.id == GID_MONKEY2 && (_game.features & GF_DEMO))
+		return false;
+
 	if (_game.heversion != 0)
 		return false;
 


Commit: 36dce2040096cc18229895311ccacd2999375444
    https://github.com/scummvm/scummvm/commit/36dce2040096cc18229895311ccacd2999375444
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Allow screenshots to be taken without clearing banners

Changed paths:
    engines/scumm/input.cpp


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 08d8c2cccec..7ebde91c8a0 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -498,7 +498,13 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 			ks = _keyPressed;
 			leftBtnClicked = (_leftBtnPressed & msClicked) != 0;
 			rightBtnClicked = (_rightBtnPressed & msClicked) != 0;
-			if (ks.keycode != Common::KEYCODE_INVALID || leftBtnClicked || rightBtnClicked)
+
+			validKey = ks.keycode != Common::KEYCODE_INVALID &&
+					   ks.keycode != Common::KEYCODE_LALT    &&
+					   ks.keycode != Common::KEYCODE_RALT    &&
+					   !(ks.keycode == Common::KEYCODE_s && ks.hasFlags(Common::KBD_ALT));
+
+			if (validKey || leftBtnClicked || rightBtnClicked)
 				return;
 
 			if (shouldQuit())
@@ -520,7 +526,9 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 			if (shouldQuit())
 				return;
 
-			validKey = ks.keycode != Common::KEYCODE_INVALID &&
+ 			validKey = ks.keycode != Common::KEYCODE_INVALID &&
+					   ks.keycode != Common::KEYCODE_LALT    &&
+					   ks.keycode != Common::KEYCODE_RALT    &&
 					   ks.keycode != Common::KEYCODE_LCTRL   &&
 					   ks.keycode != Common::KEYCODE_RCTRL   &&
 					   ks.keycode != Common::KEYCODE_LSHIFT  &&
@@ -528,7 +536,8 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 					   ks.keycode != Common::KEYCODE_UP      &&
 					   ks.keycode != Common::KEYCODE_DOWN    &&
 					   ks.keycode != Common::KEYCODE_LEFT    &&
-					   ks.keycode != Common::KEYCODE_RIGHT;
+					   ks.keycode != Common::KEYCODE_RIGHT   &&
+					   !(ks.keycode == Common::KEYCODE_s && ks.hasFlags(Common::KBD_ALT));
 		}
 	}
 }


Commit: a431385a4fc01981c7b1a55ac709be0bdd7f51e0
    https://github.com/scummvm/scummvm/commit/a431385a4fc01981c7b1a55ac709be0bdd7f51e0
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix cursor transparency issues in v6

Changed paths:
    engines/scumm/cursor.cpp


diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index 9fbd974d944..35e574c9b44 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -162,7 +162,7 @@ void ScummEngine_v6::setCursorTransparency(int a) {
 	} else {
 		for (i = 0; i < size; i++)
 			if (_grabbedCursor[i] == (byte)a)
-				_grabbedCursor[i] = 0x01;
+				_grabbedCursor[i] = 0xFF;
 	}
 
 	updateCursor();


Commit: 76db64e36574218aad0bacba8792ab400149d0f5
    https://github.com/scummvm/scummvm/commit/76db64e36574218aad0bacba8792ab400149d0f5
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix Amiga menu content

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 79400282c37..2dfe04b1892 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1285,7 +1285,10 @@ void ScummEngine::showMainMenu() {
 	setUpMainMenuControls();
 	drawMainMenuControls();
 
-	if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
+	if (_game.platform == Common::kPlatformAmiga) {
+		convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+		drawMainMenuTitle(saveScreenTitle);
+	} else if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
 		convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 		drawMainMenuTitle(saveScreenTitle);
 	}
@@ -1541,7 +1544,10 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 		setUpMainMenuControls();
 		drawMainMenuControls();
 
-		if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
+		if (_game.platform == Common::kPlatformAmiga) {
+			convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
+			drawMainMenuTitle(saveScreenTitle);
+		} else if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
 			convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 			drawMainMenuTitle(saveScreenTitle);
 		}
@@ -2207,14 +2213,16 @@ void ScummEngine::drawMainMenuControls() {
 		drawInternalGUIControl(GUI_CTRL_PLAY_BUTTON, 0); // Play button
 		drawInternalGUIControl(GUI_CTRL_QUIT_BUTTON, 0); // Quit button
 
-		if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY)
+		if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY && _game.platform != Common::kPlatformAmiga)
 			drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0); // Inner box
 
-		if ((_game.version == 5 &&( _game.id != GID_MONKEY2 && _game.id != GID_MONKEY)) || _game.version == 6) {
+		if ((_game.version == 5 &&
+			(_game.id != GID_MONKEY2 && _game.id != GID_MONKEY && _game.platform != Common::kPlatformAmiga)) ||
+			_game.version == 6) {
 			drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);   // Arrow up button
 			drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button
 
-			if (VAR_FIXEDDISK != 0xFF && VAR(VAR_FIXEDDISK) == 0) {
+			if ((VAR_FIXEDDISK != 0xFF && VAR(VAR_FIXEDDISK) == 0) || _game.platform == Common::kPlatformAmiga) {
 				convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)insertDisk, sizeof(insertDisk));
 				drawMainMenuTitle(insertDisk);
 			}


Commit: 491232a2a2de9fb1e9fa3cae050e05c3dce3e571
    https://github.com/scummvm/scummvm/commit/491232a2a2de9fb1e9fa3cae050e05c3dce3e571
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (GUI) - fix memory leaks

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 2dfe04b1892..8391bbf97e7 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1400,8 +1400,16 @@ void ScummEngine::showMainMenu() {
 	if (_game.version == 7)
 		CHARSET_1();
 
-	if (_game.version < 7 && !hasLoadedState)
+	if (_game.version < 7 && !hasLoadedState) {
 		restoreSurfacesPostGUI();
+	} else {
+		free(_tempTextSurface);
+		_tempTextSurface = nullptr;
+		free(_tempMainSurface);
+		_tempMainSurface = nullptr;
+	}
+
+	_savegameThumbnail.free();
 
 	// Resume the engine
 	pt.clear();


Commit: 28e1b022ce6b80ab59f90fd025c9b16802be2d77
    https://github.com/scummvm/scummvm/commit/28e1b022ce6b80ab59f90fd025c9b16802be2d77
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (GUI) - avoid buffer overflow in convertMessageToString

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 8391bbf97e7..5807ea230a3 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -231,6 +231,10 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 			ks = Common::KEYCODE_y;
 	}
 
+	// Deactivate this, so it does not trigger as invalid click target inside
+	// getInternalGUIControlFromCoordinates() (which can cause serious errors)
+	_internalGUIControls[0].relativeCenterX = -1;
+
 	return ks;
 }
 


Commit: fa8cff62483910fc1d51836e15ec442148b5179e
    https://github.com/scummvm/scummvm/commit/fa8cff62483910fc1d51836e15ec442148b5179e
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (GUI) - initialize vars

(this is necessary after the mem leaks fix)

Changed paths:
    engines/scumm/scumm.h


diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index c10573d70ce..819f6a20cf3 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -638,8 +638,8 @@ protected:
 	int _v5VoiceMode = 0;
 
 	Graphics::Surface _savegameThumbnail;
-	byte *_tempTextSurface;
-	byte *_tempMainSurface;
+	byte *_tempTextSurface = nullptr;
+	byte *_tempMainSurface = nullptr;
 	bool _postGUICharMask = false;
 
 	// Saved cursor pre and post GUI


Commit: ce4ed0bbf1594762bb65cb562aa4cf6209b75c36
    https://github.com/scummvm/scummvm/commit/ce4ed0bbf1594762bb65cb562aa4cf6209b75c36
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (COMI) - rename _savegameThumbnail

The new GUI code has a variable of the exact same name in the base class scope. It does not cause issues for me, but I guess it would at least provoke a warning on some compiler. We really don't need to wait for that...

I also renamed the _savegameThumbnailPalette, just for consistency.

Changed paths:
    engines/scumm/saveload.cpp
    engines/scumm/scumm_v8.h


diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 81d5caacfbf..3aa36108e40 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -294,7 +294,7 @@ void ScummEngine_v8::stampScreenShot(int slot, int boxX, int boxY, int boxWidth,
 
 	if (foundInternalThumbnail) {
 		for (int i = 0; i < 256; i++) {
-			rgb = _savegameThumbnailPalette[i];
+			rgb = _savegameThumbnailV8Palette[i];
 			tmpPalette[i] = remapPaletteColor(
 				brightness * ((rgb & 0xFF)     >> 0)  / 0xFF,
 				brightness * ((rgb & 0xFF00)   >> 8)  / 0xFF,
@@ -338,7 +338,7 @@ void ScummEngine_v8::stampScreenShot(int slot, int boxX, int boxY, int boxWidth,
 			// Remember, the internal one is paletted, while the ScummVM one
 			// is blitted without going through a palette index...
 			if (foundInternalThumbnail) {
-				color = _savegameThumbnail[160 * (heightSlice / boxHeight) + (widthSlice / boxWidth)];
+				color = _savegameThumbnailV8[160 * (heightSlice / boxHeight) + (widthSlice / boxWidth)];
 				pixelColor = tmpPalette[color];
 			} else {
 				pixelColor = thumbSurface[160 * (heightSlice / boxHeight) + (widthSlice / boxWidth)];
@@ -373,12 +373,12 @@ void ScummEngine_v8::createInternalSaveStateThumbnail() {
 		}
 
 		for (int i = 0; i < 256; i++) {
-			_savegameThumbnailPalette[i] = getPackedRGBColorFromPalette(_currentPalette, i);
+			_savegameThumbnailV8Palette[i] = getPackedRGBColorFromPalette(_currentPalette, i);
 		}
 
 		for (int i = 0; i < 120; i++) {
 			for (int j = 0; j < 160; j++) {
-				_savegameThumbnail[i * 160 + j] = tempBitmap[4 * (i * _screenWidth + j)];
+				_savegameThumbnailV8[i * 160 + j] = tempBitmap[4 * (i * _screenWidth + j)];
 			}
 		}
 
@@ -425,8 +425,8 @@ bool ScummEngine_v8::fetchInternalSaveStateThumbnail(int slotId, bool isHeapSave
 	// Now do the actual loading
 	Common::Serializer ser(in, nullptr);
 	ser.setVersion(hdr.ver);
-	ser.syncArray(_savegameThumbnail, 19200, Common::Serializer::Byte, VER(106));
-	ser.syncArray(_savegameThumbnailPalette, 256, Common::Serializer::Uint32LE, VER(106));
+	ser.syncArray(_savegameThumbnailV8, 19200, Common::Serializer::Byte, VER(106));
+	ser.syncArray(_savegameThumbnailV8Palette, 256, Common::Serializer::Uint32LE, VER(106));
 
 	delete in;
 	return true;
@@ -1936,8 +1936,8 @@ void syncWithSerializer(Common::Serializer &s, ScummEngine_v7::SubtitleText &st)
 
 void ScummEngine_v8::saveLoadWithSerializer(Common::Serializer &s) {
 	// Save/load the savegame thumbnail for COMI
-	s.syncArray(_savegameThumbnail, 19200, Common::Serializer::Byte, VER(106));
-	s.syncArray(_savegameThumbnailPalette, 256, Common::Serializer::Uint32LE, VER(106));
+	s.syncArray(_savegameThumbnailV8, 19200, Common::Serializer::Byte, VER(106));
+	s.syncArray(_savegameThumbnailV8Palette, 256, Common::Serializer::Uint32LE, VER(106));
 
 	// Also save the banner colors for the GUI
 	s.syncArray(_bannerColors, 50, Common::Serializer::Uint32LE, VER(106));
diff --git a/engines/scumm/scumm_v8.h b/engines/scumm/scumm_v8.h
index 6085affe665..c74572a868a 100644
--- a/engines/scumm/scumm_v8.h
+++ b/engines/scumm/scumm_v8.h
@@ -46,8 +46,8 @@ protected:
 		int brightness;
 	};
 
-	int _savegameThumbnailPalette[256];
-	byte _savegameThumbnail[160 * 120]; // One fourth of the nominal 640x480 resolution
+	int _savegameThumbnailV8Palette[256];
+	byte _savegameThumbnailV8[160 * 120]; // One fourth of the nominal 640x480 resolution
 	StampShot _stampShots[20];
 	int _stampShotsInQueue = 0;
 


Commit: 6f8194213365103ce0b205d0c150a24a33f2873f
    https://github.com/scummvm/scummvm/commit/6f8194213365103ce0b205d0c150a24a33f2873f
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (GUI) - replace some strcpy calls with Common::strlcpy

Unfortunately, the Scumm engine is still full of strcpy calls, although we tried to get rid of these in many of the other engines. I'll try to kill the other (numerous) use cases, too, but that needn't go into this PR.

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 5807ea230a3..6427cb25be3 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -429,12 +429,12 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 			textColor = ctrl->normalTextColor;
 
 		if (ctrl->label)
-			strcpy(buttonString, ctrl->label);
+			Common::strlcpy(buttonString, ctrl->label, sizeof(buttonString));
 		else
-			strcpy(buttonString, "null button");
+			Common::strlcpy(buttonString, "null button", sizeof(buttonString));
 
 		if (_mainMenuSavegameLabel == id && _menuPage == GUI_PAGE_SAVE) {
-			strcat(buttonString, "_");
+			Common::strlcat(buttonString, "_", sizeof(buttonString));
 		}
 
 		int tmpRight = _string[5].right;
@@ -1150,7 +1150,7 @@ bool ScummEngine::canWriteGame(int slotId) {
 
 		// Fallback to a hardcoded string
 		if (msgLabelPtr[0] == '\0') {
-			strcpy(msgLabelPtr, "Do you want to replace this saved game?  (Y/N)Y");
+			Common::strlcpy(msgLabelPtr, "Do you want to replace this saved game?  (Y/N)Y", sizeof(msgLabelPtr));
 		}
 
 		localizedYesKey = msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1];
@@ -2453,7 +2453,7 @@ void ScummEngine::getSliderString(int stringId, int value, char *sliderString, i
 	char *ptrToChar;
 	char tempStr[256];
 
-	strcpy(tempStr, getGUIString(stringId));
+	Common::strlcpy(tempStr, getGUIString(stringId), sizeof(tempStr));
 	convertMessageToString((const byte *)tempStr, (byte *)sliderString, size);
 
 	ptrToChar = strchr(sliderString, '=');


Commit: b37ad8d06e52a617b14ccd01d877c74aff6c3f09
    https://github.com/scummvm/scummvm/commit/b37ad8d06e52a617b14ccd01d877c74aff6c3f09
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (v6/EGA) - fix mouse cursor being dithered/scaled more than once

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


diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index 35e574c9b44..39b27189dfb 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -319,12 +319,13 @@ void ScummEngine_v7::updateCursor() {
 }
 #endif
 
-void ScummEngine_v6::setCursorFromBuffer(const byte *ptr, int width, int height, int pitch) {
+void ScummEngine_v6::setCursorFromBuffer(const byte *ptr, int width, int height, int pitch, bool preventScale) {
 	uint size;
 	byte *dst;
 
+	bool needsDithering = (_enableEGADithering && !preventScale);
 	size = width * height * _bytesPerPixel;
-	if (_enableEGADithering)
+	if (needsDithering)
 		size <<= 2;
 	if (size > sizeof(_grabbedCursor))
 		error("grabCursor: grabbed cursor too big");
@@ -333,14 +334,14 @@ void ScummEngine_v6::setCursorFromBuffer(const byte *ptr, int width, int height,
 	_cursor.height = height;
 	_cursor.animate = 0;
 
-	dst = _enableEGADithering ? _compositeBuf : _grabbedCursor;
+	dst = needsDithering ? _compositeBuf : _grabbedCursor;
 	for (; height; height--) {
 		memcpy(dst, ptr, width * _bytesPerPixel);
 		dst += width * _bytesPerPixel;
 		ptr += pitch;
 	}
 
-	if (_enableEGADithering)
+	if (needsDithering)
 		ditherCursor();
 
 	updateCursor();
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 6427cb25be3..d7dc941b569 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1237,8 +1237,12 @@ void ScummEngine::restoreCursorPostMenu() {
 		// Restore the previous cursor...
 		_cursor.state = _curCursorState;
 		CursorMan.showMouse(_cursor.state > 0);
+		if (_enableEGADithering) {
+			_curCursorHotspotX >>= 1;
+			_curCursorHotspotY >>= 1;
+		}
 		setCursorHotspot(_curCursorHotspotX, _curCursorHotspotY);
-		setCursorFromBuffer(_curGrabbedCursor, _curCursorWidth, _curCursorHeight, _curCursorWidth);
+		setCursorFromBuffer(_curGrabbedCursor, _curCursorWidth, _curCursorHeight, _curCursorWidth, true);
 		free(_curGrabbedCursor);
 		_curGrabbedCursor = nullptr;
 	}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 819f6a20cf3..2672d793e76 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -585,7 +585,7 @@ protected:
 	virtual void setCursorTransparency(int a) {};
 	virtual void resetCursors() {}
 	virtual void setCursorHotspot(int x, int y) {}
-	virtual void setCursorFromBuffer(const byte *ptr, int width, int height, int pitch) {}
+	virtual void setCursorFromBuffer(const byte *ptr, int width, int height, int pitch, bool preventScale = false) {}
 
 
 public:
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index bdf76a5a8db..ebe3f646ab1 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -148,7 +148,7 @@ protected:
 	void useIm01Cursor(const byte *im, int w, int h);
 	void useBompCursor(const byte *im, int w, int h);
 	void grabCursor(int x, int y, int w, int h);
-	void setCursorFromBuffer(const byte *ptr, int width, int height, int pitch) override;
+	void setCursorFromBuffer(const byte *ptr, int width, int height, int pitch, bool preventScale = false) override;
 	void ditherCursor();
 
 	virtual void drawBlastTexts() {}


Commit: 9c2e357172e407f5f49ecf30d9b1ee8bbfcf7b65
    https://github.com/scummvm/scummvm/commit/9c2e357172e407f5f49ecf30d9b1ee8bbfcf7b65
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix v6 cursor handling

In v6 most of the cursor substitution is done via scripts.

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index d7dc941b569..49b4d7b96f2 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1214,7 +1214,7 @@ void ScummEngine::saveCursorPreMenu() {
 	_cursor.state = 1;
 	CursorMan.showMouse(_cursor.state > 0);
 
-	if (_game.version > 5) {
+	if (_game.version > 6) {
 		// Backup the current cursor graphics and parameters
 		// and set up the main menu cursor...
 		_curGrabbedCursor = (byte *)malloc(sizeof(_grabbedCursor));
@@ -1227,13 +1227,19 @@ void ScummEngine::saveCursorPreMenu() {
 			_curCursorHotspotY = _cursor.hotspotY;
 			setDefaultCursor();
 		}
+	} else if (_game.version == 6) {
+		// V6 handles cursor substitution via scripts, but it handles
+		// setting dimensions and hotspot here; since manually changing
+		// cursor parameters at this stage glitches the cursor itself,
+		// let's call this function without saving anything unlike above...
+		setDefaultCursor();
 	}
 
 	CursorMan.showMouse(true);
 }
 
 void ScummEngine::restoreCursorPostMenu() {
-	if (_game.version > 5 && _curGrabbedCursor) {
+	if (_game.version > 6 && _curGrabbedCursor) {
 		// Restore the previous cursor...
 		_cursor.state = _curCursorState;
 		CursorMan.showMouse(_cursor.state > 0);
@@ -1245,6 +1251,10 @@ void ScummEngine::restoreCursorPostMenu() {
 		setCursorFromBuffer(_curGrabbedCursor, _curCursorWidth, _curCursorHeight, _curCursorWidth, true);
 		free(_curGrabbedCursor);
 		_curGrabbedCursor = nullptr;
+	} else if (_game.version == 6) {
+		setCursorHotspot(_curCursorHotspotX, _curCursorHotspotY);
+		_cursor.width = _curCursorWidth;
+		_cursor.height = _curCursorHeight;
 	}
 
 	// Restore the old cursor state...
@@ -1393,7 +1403,7 @@ void ScummEngine::showMainMenu() {
 	}
 
 	// Run the exit savescreen script, if available
-	if (_saveScriptParam != 0) {
+	if (_saveScriptParam != 0 || _game.version == 6) {
 		args[0] = _saveScriptParam;
 		if (VAR_SAVELOAD_SCRIPT2 != 0xFF) {
 			runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, args);


Commit: 880c78b023e0fecd512ea730537e964a9558be8a
    https://github.com/scummvm/scummvm/commit/880c78b023e0fecd512ea730537e964a9558be8a
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Implement v4 GUI and menu

Changed paths:
    engines/scumm/gfx_gui.cpp
    engines/scumm/input.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v4.h
    engines/scumm/string.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 49b4d7b96f2..4f6e3165efb 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -20,6 +20,7 @@
  */
 
 #include "scumm/scumm.h"
+#include "scumm/scumm_v4.h"
 #include "scumm/scumm_v8.h"
 #include "scumm/gfx.h"
 #include "scumm/dialogs.h"
@@ -106,20 +107,30 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	// Backup the text surface...
 	if (_game.version < 7 && !_mainMenuIsActive && _game.platform != Common::kPlatformFMTowns) {
 		saveSurfacesPreGUI();
-		restoreCharsetBg();
+		if (_charset->_textScreenID == kMainVirtScreen && !(_game.version == 4 && _game.id == GID_LOOM))
+			restoreCharsetBg();
 	}
 
 	// Pause the engine
 	PauseToken pt = pauseEngine();
 
 	// Gather the colors needed for the banner
-	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 == 4) {
+		normalFillColor = 7;
+		normalTextColor = 0;
+		topLineColor = 15;
+		bottomLineColor = 8;
+		leftLineColor = 15;
+		rightLineColor = 8;
+	} else {
+		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);
+	}
 
 	// Backup the current charsetId, since we're going to switch
 	// to charsetId == 1...
@@ -238,6 +249,97 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	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) {
+		return showBannerAndPause(0, waitTime, msg);
+	}
+
+	char bannerMsg[512];
+	int bannerMsgWidth, bannerMsgHeight, roundedWidth;
+	int startingPointY;
+	int bannerSaveYStart;
+
+	// 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 the engine
+	PauseToken pt = pauseEngine();
+
+	// Backup the current charsetId, since we're going to switch
+	// to charsetId == 1...
+	int oldId = _charset->getCurID();
+	_charset->setCurID(1);
+
+	// Take all the necessary measurements for the box which
+	// will contain the string...
+	bannerMsgHeight = getGUIStringHeight(bannerMsg) + 3;
+	bannerMsgWidth = getGUIStringWidth(bannerMsg);
+	if (bannerMsgWidth < 100)
+		bannerMsgWidth = 100;
+
+	roundedWidth = bannerMsgWidth / 2;
+
+	startingPointY = 80;
+	bannerSaveYStart = startingPointY - 2;
+
+
+	// 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);
+		_bannerMem = (byte *)malloc(_bannerMemSize * sizeof(byte));
+		if (_bannerMem) {
+			memcpy(
+				_bannerMem,
+				&_virtscr[kMainVirtScreen].getPixels(0, _screenTop)[rowSize * bannerSaveYStart],
+				_bannerMemSize);
+		}
+	}
+
+	// Draw the GUI control
+	drawBox(0, startingPointY, _screenWidth - 1, startingPointY + bannerMsgHeight, 0);
+	drawBox(0, startingPointY, _screenWidth - 1, startingPointY, color);
+	drawBox(0, startingPointY + bannerMsgHeight, _screenWidth - 1, startingPointY + bannerMsgHeight, color);
+	drawGUIText(bannerMsg, _screenWidth / 2, startingPointY + 2, _screenWidth - 1, color, true);
+	ScummEngine::drawDirtyScreenParts();
+
+	// 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);
+		clearBanner();
+	}
+
+	// Restore the text surface...
+	if (!_mainMenuIsActive) {
+		restoreSurfacesPostGUI();
+	}
+
+	// Finally, resume the engine, clear the input state, and restore the charset.
+	pt.clear();
+	clearClickedStatus();
+	if (oldId)
+		_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;
+
+	return ks;
+}
+
 void ScummEngine::clearBanner() {
 	// Restore the GFX content which was under the banner,
 	// and then mark that part of the screen as dirty.
@@ -369,23 +471,47 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 				// Draw the main box...
 				drawBox(relCentX + 1, relCentY + 1 + topComp, boxSizeX - offset, boxSizeY - offset + topComp, fillColor);
 
-				// 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);
+				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 {
 				drawBox(relCentX, relCentY + topComp, x, y + topComp, (highlightColor ? ctrl->highlightedFillColor : ctrl->normalFillColor));
-
-				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);
+				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);
+				}
 			}
 		}
 
@@ -896,7 +1022,7 @@ void ScummEngine_v7::toggleVoiceMode() {
 void ScummEngine_v7::handleLoadDuringSmush() {
 	// Notify the SMUSH player that we want to load a game...
 	_saveLoadFlag = 2;
-	_saveLoadSlot = _mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9;
+	_saveLoadSlot = _mainMenuSavegameLabel - 1 + _curDisplayedSaveSlotPage * 9;
 
 	// Force screen to black to avoid glitches...
 	VirtScreen *vs = &_virtscr[kMainVirtScreen];
@@ -934,6 +1060,10 @@ int ScummEngine_v7::getBannerColor(int bannerId) {
 }
 #endif
 
+int ScummEngine_v4::getBannerColor(int bannerId) {
+	return _GUIPalette[bannerId - 6];
+}
+
 int ScummEngine_v6::getBannerColor(int bannerId) {
 	return readArray(110, 0, bannerId);
 }
@@ -960,7 +1090,7 @@ void ScummEngine::saveSurfacesPreGUI() {
 	if (_game.version < 4 || _game.version > 6)
 		return;
 
-	_tempTextSurface = (byte *)malloc(_textSurface.w * _textSurface.h * sizeof(byte));
+	_tempTextSurface = (byte *)malloc(_screenWidth * _screenHeight * sizeof(byte));
 	_tempMainSurface = (byte *)malloc(_virtscr[kMainVirtScreen].w * _virtscr[kMainVirtScreen].h * sizeof(byte));
 
 	if (_tempMainSurface) {
@@ -973,12 +1103,13 @@ void ScummEngine::saveSurfacesPreGUI() {
 	}
 
 	if (_tempTextSurface) {
-		for (int y = 0; y < _textSurface.h; y++) {
-			for (int x = 0; x < _textSurface.w; x++) {
+		for (int y = 0; y < _screenHeight; y++) {
+			for (int x = 0; x < _screenWidth; x++) {
 				curPix = _textSurface.getPixel(x, y);
-				_tempTextSurface[x + y * _textSurface.w] = curPix;
-				if (curPix != 0xFD)
+				_tempTextSurface[x + y * _screenWidth] = curPix;
+				if (curPix != 0xFD && !(_game.version == 4 && _game.id == GID_LOOM)) {
 					_virtscr[kMainVirtScreen].setPixel(_virtscr[kMainVirtScreen].xstart + x, y, curPix);
+				}
 			}
 		}
 	}
@@ -991,9 +1122,9 @@ void ScummEngine::restoreSurfacesPostGUI() {
 		return;
 
 	if (_tempTextSurface) {
-		for (int y = 0; y < _textSurface.h; y++) {
-			for (int x = 0; x < _textSurface.w; x++) {
-				curPix = _tempTextSurface[x + y * _textSurface.w];
+		for (int y = 0; y < _screenHeight; y++) {
+			for (int x = 0; x < _screenWidth; x++) {
+				curPix = _tempTextSurface[x + y * _screenWidth];
 				_textSurface.setPixel(x, y, curPix);
 			}
 		}
@@ -1080,7 +1211,11 @@ void ScummEngine::queryQuit() {
 		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
 
 		// "Are you sure you want to quit?  (Y/N)"
-		Common::KeyState ks = showBannerAndPause(0, -1, msgLabelPtr);
+		Common::KeyState ks;
+		if (_game.version > 4)
+			ks = showBannerAndPause(0, -1, msgLabelPtr);
+		else
+			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
 
 		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) {
 			_quitByButton = true;
@@ -1099,10 +1234,18 @@ void ScummEngine::queryRestart() {
 		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
 
 		// "Are you sure you want to restart?  (Y/N)"
-		Common::KeyState ks = showBannerAndPause(0, -1, msgLabelPtr);
+		Common::KeyState ks;
+		if (_game.version > 4)
+			ks = showBannerAndPause(0, -1, msgLabelPtr);
+		else
+			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
 
 		if ((tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) ||
 			(_game.version == 8 && ks.keycode == Common::KEYCODE_y)) {
+
+			if (_game.version < 5)
+				restoreCharsetBg();
+
 			restart();
 		}
 	}
@@ -1121,17 +1264,34 @@ void ScummEngine::fillSavegameLabels() {
 	bool availSaves[100];
 	listSavegames(availSaves, ARRAYSIZE(availSaves));
 	Common::String name;
+	int curSaveSlot;
+	bool isLoomVga = (_game.id == GID_LOOM && _game.version == 4);
+
 	for (int i = 0; i < 9; i++) {
-		int curSaveSlot = i + 1 + _curDisplayedSaveSlotPage * 9;
-		sprintf(_savegameNames[i].label, "%2d. ", curSaveSlot);
+		curSaveSlot = i + (isLoomVga ? _firstSaveStateOfList : _curDisplayedSaveSlotPage * 9);
+		if (_game.version > 4 || (_game.version == 4 && _game.id == GID_LOOM)) {
+			sprintf(_savegameNames[i].label, "%2d. ", curSaveSlot + 1);
+		} else {
+			_savegameNames[i].label[0] = '\0';
+		}
 
 		if (availSaves[curSaveSlot]) {
-			if (getSavegameName(curSaveSlot, name)) {
-				sprintf(_savegameNames[i].label, "%2d. %s", curSaveSlot, name.c_str());
+			if (_game.version > 4 || (_game.version == 4 && _game.id == GID_LOOM)) {
+				if (getSavegameName(curSaveSlot, name)) {
+					sprintf(_savegameNames[i].label, "%2d. %s", curSaveSlot + 1, name.c_str());
+				} else {
+					// The original printed "WARNING... old savegame", but we do support old savegames :-)
+					sprintf(_savegameNames[i].label, "%2d. WARNING: wrong save version", curSaveSlot + 1);
+				}
 			} else {
-				// The original printed "WARNING... old savegame", but we do support old savegames :-)
-				sprintf(_savegameNames[i].label, "%2d. WARNING: wrong save version", curSaveSlot);
+				if (getSavegameName(curSaveSlot, name)) {
+					sprintf(_savegameNames[i].label, "%s", name.c_str());
+				} else {
+					// The original printed "WARNING... old savegame", but we do support old savegames :-)
+					sprintf(_savegameNames[i].label, "%s", "WARNING: wrong save version");
+				}
 			}
+
 		}
 	}
 }
@@ -1167,15 +1327,15 @@ bool ScummEngine::canWriteGame(int slotId) {
 
 bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked) {
 	bool hasLoadedState = false;
-
-	while (true) {
+	int firstChar = (_game.version == 4 && _game.id != GID_LOOM) ? 0 : 4;
+	while (!shouldQuit()) {
 		waitForTimer(1);
 
 		waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
 		rightMsClicked = false;
 		if (ks.keycode == Common::KEYCODE_RETURN) {
 			clearClickedStatus();
-			executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1, hasLoadedState);
+			executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1, -1, hasLoadedState);
 			return true;
 		} else if (leftMsClicked) {
 			clearClickedStatus();
@@ -1186,7 +1346,7 @@ bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicke
 		int curLen = strlen(_savegameNames[_mainMenuSavegameLabel - 1].label);
 		if (ks.keycode == Common::KEYCODE_BACKSPACE) {
 			 // Prevent the user from deleting the header (" 1. ")
-			if ((curLen) > 4) {
+			if (curLen > firstChar) {
 				_savegameNames[_mainMenuSavegameLabel - 1].label[curLen - 1] = '\0';
 				drawInternalGUIControl(_mainMenuSavegameLabel, 1);
 				ScummEngine::drawDirtyScreenParts();
@@ -1296,7 +1456,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.
-		restoreCharsetBg();
+		if (_charset->_textScreenID == kMainVirtScreen && !(_game.version == 4 && _game.id == GID_LOOM))
+			restoreCharsetBg();
 	}
 
 	_menuPage = GUI_PAGE_MAIN;
@@ -1306,7 +1467,7 @@ void ScummEngine::showMainMenu() {
 	if (_game.platform == Common::kPlatformAmiga) {
 		convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 		drawMainMenuTitle(saveScreenTitle);
-	} else if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
+	} else if (_game.version > 4 && _game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
 		convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 		drawMainMenuTitle(saveScreenTitle);
 	}
@@ -1361,7 +1522,7 @@ void ScummEngine::showMainMenu() {
 						drawInternalGUIControl(clickedControl, 0);
 
 						// Execute the operation pertaining the clicked control
-						if (executeMainMenuOperation(clickedControl, curMouseX, hasLoadedState))
+						if (executeMainMenuOperation(clickedControl, curMouseX, curMouseY, hasLoadedState))
 							break;
 					}
 				} else {
@@ -1369,13 +1530,18 @@ void ScummEngine::showMainMenu() {
 					_mainMenuSavegameLabel = clickedControl;
 
 					drawInternalGUIControl(tmp, 0);
+
+					// For v4 we activated the first slot by default; deactivate it...
+					if (_game.version == 4 && _game.id != GID_LOOM)
+						drawInternalGUIControl(GUI_CTRL_FIRST_SG, 0);
+
 					drawInternalGUIControl(_mainMenuSavegameLabel, 1);
 
 					ScummEngine::drawDirtyScreenParts();
 					_system->updateScreen();
 
-					if (_menuPage == GUI_PAGE_LOAD) {
-						if (executeMainMenuOperation(GUI_CTRL_OK_BUTTON, curMouseX, hasLoadedState))
+					if (_menuPage == GUI_PAGE_LOAD && (_game.version != 4 || _game.id == GID_LOOM)) {
+						if (executeMainMenuOperation(GUI_CTRL_OK_BUTTON, curMouseX, curMouseY, hasLoadedState))
 							break;
 					}
 				}
@@ -1434,9 +1600,12 @@ void ScummEngine::showMainMenu() {
 	clearClickedStatus();
 }
 
-bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedState) {
+bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool &hasLoadedState) {
 	char saveScreenTitle[512];
 	char formattedString[512];
+	int curSlot;
+	bool isLoomVga = (_game.id == GID_LOOM && _game.version == 4);
+	size_t labelSkip = (_game.version == 4 && _game.id != GID_LOOM) ? 0 : 4;
 
 	switch (op) {
 	case GUI_CTRL_SAVE_BUTTON:
@@ -1464,9 +1633,10 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 		break;
 	case GUI_CTRL_OK_BUTTON:
 		if (_menuPage == GUI_PAGE_SAVE) {
-			if (_mainMenuSavegameLabel > 0) {
+			// We check for an empty label since v4 might generate that...
+			if (_mainMenuSavegameLabel > 0 && _savegameNames[_mainMenuSavegameLabel - 1].label[labelSkip] != '\0') {
 				convertMessageToString((const byte *)getGUIString(gsSaving), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
-				sprintf(formattedString, saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[4]);
+				sprintf(formattedString, saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[labelSkip]);
 				drawMainMenuTitle(formattedString);
 				ScummEngine::drawDirtyScreenParts();
 				_system->updateScreen();
@@ -1474,11 +1644,12 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 				waitForTimer(60);
 
 				Common::String dummyString;
-				_saveLoadDescription = &_savegameNames[_mainMenuSavegameLabel - 1].label[4];
+				_saveLoadDescription = &_savegameNames[_mainMenuSavegameLabel - 1].label[labelSkip];
 
-				if (canWriteGame(_mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9)) {
+				curSlot = _mainMenuSavegameLabel + (isLoomVga ? _firstSaveStateOfList : _curDisplayedSaveSlotPage * 9);
+				if (canWriteGame(curSlot)) {
 					restoreCursorPostMenu();
-					if (saveState(_mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9, false, dummyString)) {
+					if (saveState(curSlot - 1, false, dummyString)) {
 						saveCursorPreMenu();
 						_saveScriptParam = GAME_PROPER_SAVE;
 						drawMainMenuControls();
@@ -1514,9 +1685,9 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 		} else if (_menuPage == GUI_PAGE_LOAD) {
 			if (_mainMenuSavegameLabel > 0) {
 				convertMessageToString((const byte *)getGUIString(gsLoading), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
-				sprintf(formattedString, saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[4]);
+				sprintf(formattedString, saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[labelSkip]);
 
-				if (strlen(_savegameNames[_mainMenuSavegameLabel - 1].label) == 4) {
+				if (strlen(_savegameNames[_mainMenuSavegameLabel - 1].label) == labelSkip) {
 					drawMainMenuControls();
 					ScummEngine::drawDirtyScreenParts();
 					break;
@@ -1537,7 +1708,8 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 					_postGUICharMask = true;
 				}
 
-				if (loadState(_mainMenuSavegameLabel + _curDisplayedSaveSlotPage * 9, false)) {
+				curSlot = _mainMenuSavegameLabel + (isLoomVga ? _firstSaveStateOfList : _curDisplayedSaveSlotPage * 9);
+				if (loadState(curSlot - 1, false)) {
 					hasLoadedState = true;
 
 					if (!_spooledMusicIsToBeEnabled)
@@ -1573,7 +1745,7 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 		if (_game.platform == Common::kPlatformAmiga) {
 			convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 			drawMainMenuTitle(saveScreenTitle);
-		} else if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
+		} else if (_game.version > 4 && _game.id != GID_MONKEY2 && _game.id != GID_MONKEY) {
 			convertMessageToString((const byte *)getGUIString(gsTitle), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 			drawMainMenuTitle(saveScreenTitle);
 		}
@@ -1584,13 +1756,26 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 	case GUI_CTRL_ARROW_UP_BUTTON:
 	case GUI_CTRL_ARROW_DOWN_BUTTON:
 		if (_menuPage != GUI_PAGE_MAIN) {
-			if (op == GUI_CTRL_ARROW_UP_BUTTON) {
-				_curDisplayedSaveSlotPage--;
+			if (!isLoomVga) {
+				if (op == GUI_CTRL_ARROW_UP_BUTTON) {
+					_curDisplayedSaveSlotPage--;
+				} else {
+					_curDisplayedSaveSlotPage++;
+				}
+
+				_curDisplayedSaveSlotPage = CLIP<int>(_curDisplayedSaveSlotPage, 0, 10);
 			} else {
-				_curDisplayedSaveSlotPage++;
+				// LOOM VGA uses its own system to scroll the savegame list, based
+				// on high or low the arrow button is pressed...
+				if (op == GUI_CTRL_ARROW_UP_BUTTON) {
+					_firstSaveStateOfList -= ((_virtscr[kMainVirtScreen].h / 2) - mouseY + _virtscr[kMainVirtScreen].topline + 54) / 14;
+				} else {
+					_firstSaveStateOfList += (mouseY - (_virtscr[kMainVirtScreen].h / 2) - _virtscr[kMainVirtScreen].topline + 45) / 14;
+				}
+
+				_firstSaveStateOfList = CLIP<int>(_firstSaveStateOfList, 0, 90);
 			}
 
-			_curDisplayedSaveSlotPage = CLIP<int>(_curDisplayedSaveSlotPage, 0, 10);
 			_mainMenuSavegameLabel = 0;
 			fillSavegameLabels();
 			drawMainMenuControls();
@@ -1655,8 +1840,156 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, bool &hasLoadedSt
 	return false;
 }
 
+void ScummEngine_v4::setUpMainMenuControls() {
+	if (_game.id == GID_LOOM && _game.version == 4) {
+		ScummEngine::setUpMainMenuControls();
+		return;
+	}
+
+	int yConstant = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
+
+	for (int i = 0; i < ARRAYSIZE(_internalGUIControls); i++) {
+		_internalGUIControls[i].relativeCenterX = -1;
+	}
+
+	// Outer box
+	setUpInternalGUIControl(GUI_CTRL_OUTER_BOX,
+		getBannerColor(6),
+		getBannerColor(6),
+		getBannerColor(7),
+		getBannerColor(7),
+		getBannerColor(7),
+		getBannerColor(7),
+		getBannerColor(7),
+		getBannerColor(6),
+		20,
+		yConstant - 58,
+		300,
+		yConstant + 58,
+		_emptyMsg, 0, 0);
+
+	if (_menuPage == GUI_PAGE_MAIN) {
+		// Save button
+		setUpInternalGUIControl(GUI_CTRL_SAVE_BUTTON,
+			getBannerColor(10),
+			getBannerColor(11),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(12),
+			getBannerColor(13),
+			242,
+			yConstant - 25,
+			-50,
+			-12,
+			getGUIString(gsSave), 1, 1);
+
+		// Load button
+		setUpInternalGUIControl(GUI_CTRL_LOAD_BUTTON,
+			getBannerColor(10),
+			getBannerColor(11),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(12),
+			getBannerColor(13),
+			242,
+			yConstant - 11,
+			-50,
+			-12,
+			getGUIString(gsLoad), 1, 1);
+
+		// Play button
+		setUpInternalGUIControl(GUI_CTRL_PLAY_BUTTON,
+			getBannerColor(10),
+			getBannerColor(11),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(12),
+			getBannerColor(13),
+			242,
+			yConstant + 3,
+			-50,
+			-12,
+			getGUIString(gsPlay), 1, 1);
+
+		// Quit button
+		setUpInternalGUIControl(GUI_CTRL_QUIT_BUTTON,
+			getBannerColor(10),
+			getBannerColor(11),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(12),
+			getBannerColor(13),
+			242,
+			yConstant + 17,
+			-50,
+			-12,
+			getGUIString(gsQuit), 1, 1);
+	}
+
+	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
+		// OK button
+		setUpInternalGUIControl(GUI_CTRL_OK_BUTTON,
+			getBannerColor(10),
+			getBannerColor(11),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(12),
+			getBannerColor(13),
+			242,
+			yConstant - 11,
+			-50,
+			-12,
+			getGUIString(gsOK), 1, 1);
+
+		// Cancel button
+		setUpInternalGUIControl(GUI_CTRL_CANCEL_BUTTON,
+			getBannerColor(10),
+			getBannerColor(11),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(9),
+			getBannerColor(12),
+			getBannerColor(13),
+			242,
+			yConstant + 3,
+			-50,
+			-12,
+			getGUIString(gsCancel), 1, 1);
+
+		// Savegame names
+		for (int i = GUI_CTRL_FIRST_SG, j = 11; i <= GUI_CTRL_LAST_SG; i++, j += 11) {
+			setUpInternalGUIControl(i,
+				getBannerColor(15),
+				getBannerColor(16),
+				getBannerColor(14),
+				getBannerColor(14),
+				getBannerColor(14),
+				getBannerColor(14),
+				getBannerColor(17),
+				getBannerColor(18),
+				28,
+				yConstant - 56 + j,
+				-206,
+				-9,
+				_savegameNames[i - 1].label, 0, 0);
+		}
+	}
+}
+
 void ScummEngine::setUpMainMenuControls() {
 	int yConstant;
+	bool isLoomVGA = (_game.id == GID_LOOM && _game.version == 4);
 
 	yConstant = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
 
@@ -1666,14 +1999,14 @@ void ScummEngine::setUpMainMenuControls() {
 
 	// Outer box
 	setUpInternalGUIControl(GUI_CTRL_OUTER_BOX,
-		getBannerColor(4),
-		getBannerColor(2),
-		getBannerColor(13),
-		getBannerColor(14),
-		getBannerColor(15),
-		getBannerColor(16),
-		getBannerColor(6),
-		getBannerColor(4),
+		isLoomVGA ? 7  : getBannerColor(4),
+		isLoomVGA ? 0  : getBannerColor(2),
+		isLoomVGA ? 15 : getBannerColor(13),
+		isLoomVGA ? 8  : getBannerColor(14),
+		isLoomVGA ? 15 : getBannerColor(15),
+		isLoomVGA ? 8  : getBannerColor(16),
+		isLoomVGA ? 14 : getBannerColor(6),
+		isLoomVGA ? 1  : getBannerColor(4),
 		20,
 		yConstant - 60,
 		300,
@@ -1682,32 +2015,32 @@ void ScummEngine::setUpMainMenuControls() {
 
 	// Inner box
 	setUpInternalGUIControl(GUI_CTRL_INNER_BOX,
-		getBannerColor(4),
-		getBannerColor(5),
-		getBannerColor(18),
-		getBannerColor(17),
-		getBannerColor(20),
-		getBannerColor(19),
-		getBannerColor(6),
-		getBannerColor(7),
+		isLoomVGA ? 7  : getBannerColor(4),
+		isLoomVGA ? 0  : getBannerColor(5),
+		isLoomVGA ? 8  : getBannerColor(18),
+		isLoomVGA ? 15 : getBannerColor(17),
+		isLoomVGA ? 8  : getBannerColor(20),
+		isLoomVGA ? 15 : getBannerColor(19),
+		isLoomVGA ? 14 : getBannerColor(6),
+		isLoomVGA ? 1  : getBannerColor(7),
 		26,
 		yConstant - 47,
-		212,
+		212 - (isLoomVGA ? 10 : 0),
 		yConstant - 47 + 102,
 		_emptyMsg, 1, 1);
 
 	if (_menuPage == GUI_PAGE_MAIN) {
 		// Save button
 		setUpInternalGUIControl(GUI_CTRL_SAVE_BUTTON,
-			getBannerColor(4),
-			getBannerColor(5),
-			getBannerColor(17),
-			getBannerColor(18),
-			getBannerColor(19),
-			getBannerColor(20),
-			getBannerColor(6),
-			getBannerColor(7),
-			242,
+			isLoomVGA ? 7  : getBannerColor(4),
+			isLoomVGA ? 0  : getBannerColor(5),
+			isLoomVGA ? 15 : getBannerColor(17),
+			isLoomVGA ? 8  : getBannerColor(18),
+			isLoomVGA ? 15 : getBannerColor(19),
+			isLoomVGA ? 8  : getBannerColor(20),
+			isLoomVGA ? 14 : getBannerColor(6),
+			isLoomVGA ? 1  : getBannerColor(7),
+			242 - (isLoomVGA ? 10 : 0),
 			yConstant - 23,
 			292,
 			yConstant - 23 + 12,
@@ -1715,15 +2048,15 @@ void ScummEngine::setUpMainMenuControls() {
 
 		// Load button
 		setUpInternalGUIControl(GUI_CTRL_LOAD_BUTTON,
-			getBannerColor(4),
-			getBannerColor(5),
-			getBannerColor(17),
-			getBannerColor(18),
-			getBannerColor(19),
-			getBannerColor(20),
-			getBannerColor(6),
-			getBannerColor(7),
-			242,
+			isLoomVGA ? 7  : getBannerColor(4),
+			isLoomVGA ? 0  : getBannerColor(5),
+			isLoomVGA ? 15 : getBannerColor(17),
+			isLoomVGA ? 8  : getBannerColor(18),
+			isLoomVGA ? 15 : getBannerColor(19),
+			isLoomVGA ? 8  : getBannerColor(20),
+			isLoomVGA ? 14 : getBannerColor(6),
+			isLoomVGA ? 1  : getBannerColor(7),
+			242 - (isLoomVGA ? 10 : 0),
 			yConstant - 8,
 			292,
 			yConstant - 8 + 12,
@@ -1731,15 +2064,15 @@ void ScummEngine::setUpMainMenuControls() {
 
 		// Play button
 		setUpInternalGUIControl(GUI_CTRL_PLAY_BUTTON,
-			getBannerColor(4),
-			getBannerColor(5),
-			getBannerColor(17),
-			getBannerColor(18),
-			getBannerColor(19),
-			getBannerColor(20),
-			getBannerColor(6),
-			getBannerColor(7),
-			242,
+			isLoomVGA ? 7  : getBannerColor(4),
+			isLoomVGA ? 0  : getBannerColor(5),
+			isLoomVGA ? 15 : getBannerColor(17),
+			isLoomVGA ? 8  : getBannerColor(18),
+			isLoomVGA ? 15 : getBannerColor(19),
+			isLoomVGA ? 8  : getBannerColor(20),
+			isLoomVGA ? 14 : getBannerColor(6),
+			isLoomVGA ? 1  : getBannerColor(7),
+			242 - (isLoomVGA ? 10 : 0),
 			yConstant + 7,
 			292,
 			yConstant + 19,
@@ -1747,15 +2080,15 @@ void ScummEngine::setUpMainMenuControls() {
 
 		// Quit button
 		setUpInternalGUIControl(GUI_CTRL_QUIT_BUTTON,
-			getBannerColor(4),
-			getBannerColor(5),
-			getBannerColor(17),
-			getBannerColor(18),
-			getBannerColor(19),
-			getBannerColor(20),
-			getBannerColor(6),
-			getBannerColor(7),
-			242,
+			isLoomVGA ? 7  : getBannerColor(4),
+			isLoomVGA ? 0  : getBannerColor(5),
+			isLoomVGA ? 15 : getBannerColor(17),
+			isLoomVGA ? 8  : getBannerColor(18),
+			isLoomVGA ? 15 : getBannerColor(19),
+			isLoomVGA ? 8  : getBannerColor(20),
+			isLoomVGA ? 14 : getBannerColor(6),
+			isLoomVGA ? 1  : getBannerColor(7),
+			242 - (isLoomVGA ? 10 : 0),
 			yConstant + 22,
 			292,
 			yConstant + 34,
@@ -1765,33 +2098,33 @@ void ScummEngine::setUpMainMenuControls() {
 	if (_menuPage != GUI_PAGE_MAIN || !(_game.id == GID_MONKEY2 || _game.id == GID_MONKEY)) {
 		// Arrow up button
 		setUpInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON,
-			getBannerColor(9),
-			getBannerColor(10),
-			getBannerColor(17),
-			getBannerColor(18),
-			getBannerColor(19),
-			getBannerColor(20),
-			getBannerColor(11),
-			getBannerColor(12),
-			216,
+			isLoomVGA ? 7  : getBannerColor(9),
+			isLoomVGA ? 0  : getBannerColor(10),
+			isLoomVGA ? 15 : getBannerColor(17),
+			isLoomVGA ? 8  : getBannerColor(18),
+			isLoomVGA ? 15 : getBannerColor(19),
+			isLoomVGA ? 8  : getBannerColor(20),
+			isLoomVGA ? 14 : getBannerColor(11),
+			isLoomVGA ? 1  : getBannerColor(12),
+			216 - (isLoomVGA ? 10 : 0),
 			yConstant - 43,
-			232,
+			232 - (isLoomVGA ? 10 : 0),
 			yConstant - 43 + 47,
 			_arrowUp, 1, 1);
 
 		// Arrow down button
 		setUpInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON,
-			getBannerColor(9),
-			getBannerColor(10),
-			getBannerColor(17),
-			getBannerColor(18),
-			getBannerColor(19),
-			getBannerColor(20),
-			getBannerColor(11),
-			getBannerColor(12),
-			216,
+			isLoomVGA ? 7  : getBannerColor(9),
+			isLoomVGA ? 0  : getBannerColor(10),
+			isLoomVGA ? 15 : getBannerColor(17),
+			isLoomVGA ? 8  : getBannerColor(18),
+			isLoomVGA ? 15 : getBannerColor(19),
+			isLoomVGA ? 8  : getBannerColor(20),
+			isLoomVGA ? 14 : getBannerColor(11),
+			isLoomVGA ? 1  : getBannerColor(12),
+			216 - (isLoomVGA ? 10 : 0),
 			yConstant + 7,
-			232,
+			232 - (isLoomVGA ? 10 : 0),
 			yConstant + 52,
 			_arrowDown, 1, 1);
 	}
@@ -1800,15 +2133,15 @@ void ScummEngine::setUpMainMenuControls() {
 		if (_menuPage == GUI_PAGE_SAVE) {
 			// OK button
 			setUpInternalGUIControl(GUI_CTRL_OK_BUTTON,
-				getBannerColor(4),
-				getBannerColor(5),
-				getBannerColor(17),
-				getBannerColor(18),
-				getBannerColor(19),
-				getBannerColor(20),
-				getBannerColor(6),
-				getBannerColor(7),
-				242,
+				isLoomVGA ? 7  : getBannerColor(4),
+				isLoomVGA ? 0  : getBannerColor(5),
+				isLoomVGA ? 15 : getBannerColor(17),
+				isLoomVGA ? 8  : getBannerColor(18),
+				isLoomVGA ? 15 : getBannerColor(19),
+				isLoomVGA ? 8  : getBannerColor(20),
+				isLoomVGA ? 14 : getBannerColor(6),
+				isLoomVGA ? 1  : getBannerColor(7),
+				242 - (isLoomVGA ? 10 : 0),
 				yConstant - 8,
 				292,
 				yConstant - 8 + 12,
@@ -1817,15 +2150,15 @@ void ScummEngine::setUpMainMenuControls() {
 
 		// Cancel button
 		setUpInternalGUIControl(GUI_CTRL_CANCEL_BUTTON,
-			getBannerColor(4),
-			getBannerColor(5),
-			getBannerColor(17),
-			getBannerColor(18),
-			getBannerColor(19),
-			getBannerColor(20),
-			getBannerColor(6),
-			getBannerColor(7),
-			242,
+			isLoomVGA ? 7  : getBannerColor(4),
+			isLoomVGA ? 0  : getBannerColor(5),
+			isLoomVGA ? 15 : getBannerColor(17),
+			isLoomVGA ? 8  : getBannerColor(18),
+			isLoomVGA ? 15 : getBannerColor(19),
+			isLoomVGA ? 8  : getBannerColor(20),
+			isLoomVGA ? 14 : getBannerColor(6),
+			isLoomVGA ? 1  : getBannerColor(7),
+			242 - (isLoomVGA ? 10 : 0),
 			(_menuPage == GUI_PAGE_LOAD ? yConstant - 1 : yConstant + 7),
 			292,
 			(_menuPage == GUI_PAGE_LOAD ? yConstant - 1 : yConstant + 7) + 12,
@@ -1834,17 +2167,17 @@ void ScummEngine::setUpMainMenuControls() {
 		// Savegame names
 		for (int i = GUI_CTRL_FIRST_SG, j = 0; i <= GUI_CTRL_LAST_SG; i++, j += 11) {
 			setUpInternalGUIControl(i,
-				getBannerColor(9),
-				getBannerColor(10),
-				getBannerColor(4),
-				getBannerColor(4),
-				getBannerColor(4),
-				getBannerColor(4),
-				getBannerColor(11),
-				getBannerColor(12),
+				isLoomVGA ? 7  : getBannerColor(9),
+				isLoomVGA ? 0  : getBannerColor(10),
+				isLoomVGA ? 7  : getBannerColor(4),
+				isLoomVGA ? 7  : getBannerColor(4),
+				isLoomVGA ? 7  : getBannerColor(4),
+				isLoomVGA ? 7  : getBannerColor(4),
+				isLoomVGA ? 14 : getBannerColor(11),
+				isLoomVGA ? 1  : getBannerColor(12),
 				28,
 				yConstant - 45 + j,
-				210,
+				210 - (isLoomVGA ? 10 : 0),
 				-9,
 				_savegameNames[i - 1].label, 0, 0);
 		}
@@ -2239,7 +2572,9 @@ void ScummEngine::drawMainMenuControls() {
 		drawInternalGUIControl(GUI_CTRL_PLAY_BUTTON, 0); // Play button
 		drawInternalGUIControl(GUI_CTRL_QUIT_BUTTON, 0); // Quit button
 
-		if (_game.id != GID_MONKEY2 && _game.id != GID_MONKEY && _game.platform != Common::kPlatformAmiga)
+		if (_game.version > 4 &&
+			_game.id != GID_MONKEY2 && _game.id != GID_MONKEY &&
+			_game.platform != Common::kPlatformAmiga)
 			drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0); // Inner box
 
 		if ((_game.version == 5 &&
@@ -2247,26 +2582,35 @@ void ScummEngine::drawMainMenuControls() {
 			_game.version == 6) {
 			drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);   // Arrow up button
 			drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button
+		}
 
-			if ((VAR_FIXEDDISK != 0xFF && VAR(VAR_FIXEDDISK) == 0) || _game.platform == Common::kPlatformAmiga) {
-				convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)insertDisk, sizeof(insertDisk));
-				drawMainMenuTitle(insertDisk);
-			}
+		if ((VAR_FIXEDDISK != 0xFF && VAR(VAR_FIXEDDISK) == 0) || _game.platform == Common::kPlatformAmiga) {
+			convertMessageToString((const byte *)getGUIString(gsInsertSaveDisk), (byte *)insertDisk, sizeof(insertDisk));
+			drawMainMenuTitle(insertDisk);
 		}
 	}
 
 	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
-		drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0);     // Inner box
+		if (_game.version > 4 || (_game.version == 4 && _game.id == GID_LOOM))
+			drawInternalGUIControl(GUI_CTRL_INNER_BOX, 0);     // Inner box
+
 		drawInternalGUIControl(GUI_CTRL_PATH_BUTTON, 0);   // Path button
 		drawInternalGUIControl(GUI_CTRL_OK_BUTTON, 0);     // Ok button
 		drawInternalGUIControl(GUI_CTRL_CANCEL_BUTTON, 0); // Cancel button
 
 		// Savegame names
-		for (int i = GUI_CTRL_FIRST_SG; i <= GUI_CTRL_LAST_SG; i++)
-			drawInternalGUIControl(i, 0);
+		for (int i = GUI_CTRL_FIRST_SG; i <= GUI_CTRL_LAST_SG; i++) {
+			if ((_game.version == 4 && _game.id != GID_LOOM) && _mainMenuSavegameLabel == 0 && i == 1)
+				drawInternalGUIControl(i, 1);
+			else
+				drawInternalGUIControl(i, 0);
+		}
+
 
-		drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);   // Arrow up button
-		drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button
+		if (_game.version > 4 || (_game.version == 4 && _game.id == GID_LOOM)) {
+			drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);   // Arrow up button
+			drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button
+		}
 
 		if (_menuPage == GUI_PAGE_SAVE) {
 			convertMessageToString((const byte *)getGUIString(gsNamePrompt), (byte *)namePrompt, sizeof(namePrompt));
@@ -2285,7 +2629,7 @@ void ScummEngine::drawMainMenuControls() {
 }
 
 void ScummEngine::updateMainMenuControls() {
-	if (!strcmp(_game.variant, "Floppy") || _game.version < 6)
+	if ((_game.variant && !strcmp(_game.variant, "Floppy")) || _game.version < 6)
 		return;
 
 	char msg[256];
@@ -2410,10 +2754,22 @@ void ScummEngine::updateMainMenuControls() {
 }
 
 void ScummEngine::drawMainMenuTitle(const char *title) {
-	int boxColor = getBannerColor(4);
-	int stringColor = getBannerColor(2);
+	int boxColor, stringColor;
 	int yConstantV6 = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
 
+	if (_game.version == 4) {
+		if (_game.id == GID_LOOM) {
+			boxColor = 7;
+			stringColor = 0;
+		} else {
+			boxColor = getBannerColor(6);
+			stringColor = getBannerColor(8);
+		}
+	} else {
+		boxColor = getBannerColor(4);
+		stringColor = getBannerColor(2);
+	}
+
 	if (_game.id == GID_DIG) {
 		int yComponent = _useCJKMode ? 130 : 121;
 
@@ -2432,6 +2788,14 @@ void ScummEngine::drawMainMenuTitle(const char *title) {
 	} else if (_game.version == 7) {
 		drawBox(18, _screenTop + 44, 301, _screenTop + 52, boxColor);
 		drawGUIText(title, 159, 44, _screenWidth - 1, stringColor, true);
+	} else if (_game.version == 4) {
+		if (_game.id == GID_LOOM) {
+			drawBox(22, yConstantV6 - 57, 298, yConstantV6 - 49, boxColor);
+			drawGUIText(title, 160, yConstantV6 - 57, _screenWidth - 1, stringColor, true);
+		} else {
+			drawBox(21, yConstantV6 - 55, 299, yConstantV6 - 47, boxColor);
+			drawGUIText(title, 160, yConstantV6 - 55, _screenWidth - 1, stringColor, true);
+		}
 	} else {
 		drawBox(22, yConstantV6 - 56, 298, yConstantV6 - 48, boxColor);
 		drawGUIText(title, 160, yConstantV6 - 56, _screenWidth - 1, stringColor, true);
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 7ebde91c8a0..768f22e2606 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -796,14 +796,18 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		char sliderString[256];
 		PauseToken pt;
 
-		if ((VAR_PAUSE_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_PAUSE_KEY)) ||
-			(lastKeyHit.keycode == Common::KEYCODE_SPACE && _game.features & GF_DEMO))) {
+		if ((VAR_PAUSE_KEY != 0xFF && (lastKeyHit.ascii == VAR(VAR_PAUSE_KEY))) ||
+			(lastKeyHit.keycode == Common::KEYCODE_SPACE && _game.features & GF_DEMO)) {
 			// Force the cursor OFF...
 			int8 oldCursorState = _cursor.state;
 			_cursor.state = 0;
 			CursorMan.showMouse(_cursor.state > 0);
 			// "Game Paused.  Press SPACE to Continue."
-			showBannerAndPause(0, -1, getGUIString(gsPause));
+			if (_game.version > 4)
+				showBannerAndPause(0, -1, getGUIString(gsPause));
+			else
+				showOldStyleBannerAndPause(getGUIString(gsPause), 12, -1);
+
 			_cursor.state = oldCursorState;
 			return;
 		}
@@ -865,7 +869,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		}
 
 		// "Text Speed  Slow  ==========  Fast"
-		if (lastKeyHit.ascii == '+' || lastKeyHit.ascii == '-') {
+		if (_game.version > 3 && (lastKeyHit.ascii == '+' || lastKeyHit.ascii == '-')) {
 			if (VAR_CHARINC == 0xFF)
 				return;
 
@@ -889,7 +893,11 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 				setTalkSpeed(_defaultTextSpeed);
 
 				getSliderString(gsTextSpeedSlider, VAR(VAR_CHARINC), sliderString, sizeof(sliderString));
-				showBannerAndPause(0, 0, sliderString);
+				if (_game.version > 4)
+					showBannerAndPause(0, 0, sliderString);
+				else
+					showOldStyleBannerAndPause(sliderString, 9, 0);
+
 				ks = Common::KEYCODE_INVALID;
 				bool leftBtnPressed = false, rightBtnPressed = false;
 				waitForBannerInput(60, ks, leftBtnPressed, rightBtnPressed);
@@ -902,7 +910,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		}
 
 
-		if (lastKeyHit.keycode == Common::KEYCODE_k && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+		if (_game.version > 4 && lastKeyHit.keycode == Common::KEYCODE_k && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
 			showBannerAndPause(0, 120, getGUIString(gsHeap), _res->getHeapSize() / 1024);
 			return;
 		}
@@ -917,6 +925,47 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			showMainMenu();
 			return;
 		}
+
+		if (_game.version == 4) {
+			if (lastKeyHit.keycode == Common::KEYCODE_r && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+				_snapScroll ^= 1;
+				if (_snapScroll) {
+					showOldStyleBannerAndPause("Horizontal Screen Snap", 9, 90);
+				} else {
+					showOldStyleBannerAndPause("Horizontal Screen Scroll", 9, 90);
+				}
+
+				if (VAR_CAMERA_FAST_X != 0xFF)
+					VAR(VAR_CAMERA_FAST_X) = _snapScroll;
+
+				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);
+				return;
+			}
+
+			if (lastKeyHit.keycode == Common::KEYCODE_m && lastKeyHit.hasFlags(Common::KBD_SHIFT)) {
+				showOldStyleBannerAndPause("Mouse Mode", 2, 90);
+				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);
+				}
+
+				return;
+			}
+
+		}
 	}
 
 	// For games which use VAR_MAINMENU_KEY, disable the mainmenu key if
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index c9849fd84ef..c757dd33b13 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -3125,7 +3125,7 @@ bool ScummEngine::isUsingOriginalGUI() {
 	if (_game.heversion != 0)
 		return false;
 
-	if (_game.version > 4)
+	if (_game.version > 3)
 		return _useOriginalGUI;
 
 	return false;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 2672d793e76..6135c770efd 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -626,6 +626,7 @@ protected:
 	int _menuPage = 0;
 	int _mainMenuSavegameLabel = 1;
 	int _curDisplayedSaveSlotPage = 0;
+	int _firstSaveStateOfList = 0; // For LOOM VGA
 	bool _mainMenuIsActive = false;
 	bool _quitByButton = false;
 	char _mainMenuMusicSlider[17];
@@ -636,6 +637,7 @@ protected:
 	int _saveScriptParam = 0;
 	int _guiCursorAnimCounter = 0;
 	int _v5VoiceMode = 0;
+	int _internalSpeakerSoundsAreOn = 1;
 
 	Graphics::Surface _savegameThumbnail;
 	byte *_tempTextSurface = nullptr;
@@ -653,6 +655,7 @@ protected:
 
 	void initBanners();
 	Common::KeyState showBannerAndPause(int bannerId, int32 waitTime, const char *msg, ...);
+	Common::KeyState showOldStyleBannerAndPause(const char *msg, int color, int32 waitTime);
 	void clearBanner();
 	void setBannerColors(int bannerId, byte r, byte g, byte b);
 	virtual int getBannerColor(int bannerId);
@@ -687,7 +690,7 @@ protected:
 	void drawMainMenuControls();
 	void updateMainMenuControls();
 	void drawMainMenuTitle(const char *title);
-	bool executeMainMenuOperation(int op, int mouseX, bool &hasLoadedState);
+	bool executeMainMenuOperation(int op, int mouseX, int mouseY, bool &hasLoadedState);
 	bool shouldHighlightLabelAndWait(int clickedControl);
 	void fillSavegameLabels();
 	bool canWriteGame(int slotId);
diff --git a/engines/scumm/scumm_v4.h b/engines/scumm/scumm_v4.h
index e33e40fe636..309832d203a 100644
--- a/engines/scumm/scumm_v4.h
+++ b/engines/scumm/scumm_v4.h
@@ -51,6 +51,8 @@ public:
 	void resetScumm() override;
 
 protected:
+	int _GUIPalette[13] = {0x00, 0x01, 0x0B, 0x03, 0x00, 0x0B, 0x0B, 0x03, 0x01, 0x00, 0x01, 0x0B, 0x09};
+
 	void setupOpcodes() override;
 
 	int readResTypeList(ResType type) override;
@@ -68,6 +70,9 @@ protected:
 	void loadIQPoints(byte *ptr, int size);
 	void updateIQPoints();
 
+	int getBannerColor(int bannerId) override;
+	void setUpMainMenuControls() override;
+
 	/* Version 4 script opcodes */
 	void o4_ifState();
 	void o4_ifNotState();
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index 8e9e41f8ed7..db6f2d31e5d 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -154,7 +154,10 @@ void ScummEngine::showMessageDialog(const byte *msg) {
 		_string[3].color = 4;
 
 	if (isUsingOriginalGUI()) {
-		VAR(VAR_KEYPRESS) = showBannerAndPause(0, -1, (const char *)msg).ascii;
+		if (_game.version > 4)
+			VAR(VAR_KEYPRESS) = showBannerAndPause(0, -1, (const char *)msg).ascii;
+		else
+			VAR(VAR_KEYPRESS) = showOldStyleBannerAndPause((const char *)msg, _string[3].color, -1).ascii;
 	} else {
 		InfoDialog dialog(this, Common::U32String((char *)buf));
 		VAR(VAR_KEYPRESS) = runDialog(dialog);
@@ -2022,7 +2025,7 @@ Common::CodePage ScummEngine::getDialogCodePage() const {
 			return Common::kDos862;
 		default:
 			return Common::kWindows1255;
-		}	
+		}
 	default:
 		return (_game.version > 7) ? Common::kWindows1252 : Common::kDos850;
 	}


Commit: 6d4de4e5277214d96adb7ea11442c087ee3bdaf3
    https://github.com/scummvm/scummvm/commit/6d4de4e5277214d96adb7ea11442c087ee3bdaf3
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: DETECTION: Add GUIO_ORIGINALGUI flag to v4 games

Changed paths:
    engines/scumm/detection_tables.h


diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h
index 809cdf10137..57eaf07aaf8 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -180,17 +180,17 @@ static const GameSettings gameVariantsTable[] = {
 	{"loom", "No AdLib", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS,                        0, UNK, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
 	{"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", "VGA",      "vga", GID_LOOM, 4, 0, MDT_NONE,                         GF_AUDIOTRACKS,             Common::kPlatformDOS, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
-	{"loom", "Steam",  "steam", GID_LOOM, 4, 0, MDT_NONE,                         GF_AUDIOTRACKS,  UNK, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
+	{"loom", "VGA",      "vga", GID_LOOM, 4, 0, MDT_NONE,                         GF_AUDIOTRACKS,             Common::kPlatformDOS, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"loom", "Steam",  "steam", GID_LOOM, 4, 0, MDT_NONE,                         GF_AUDIOTRACKS,  UNK, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, 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, GUIO1(GUIO_NOSPEECH)},
 
-	{"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_16COLOR, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
+	{"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_16COLOR, Common::kPlatformDOS, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ORIGINALGUI)},
 
-	{"monkey", "VGA",      "vga", GID_MONKEY_VGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO2(GUIO_NOSPEECH, GUIO_ENHANCEMENTS)},
-	{"monkey", "VGA Demo",      "vga", GID_MONKEY_VGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_DEMO, UNK, GUIO1(GUIO_NOSPEECH)},
-	{"monkey", "EGA",      "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_16COLOR,     Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_ENHANCEMENTS)},
-	{"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR,                        GF_16COLOR,     Common::kPlatformAtariST, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS)},
-	{"monkey", "Demo",     "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB,            GF_16COLOR | GF_DEMO,     Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
+	{"monkey", "VGA",      "vga", GID_MONKEY_VGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO3(GUIO_NOSPEECH, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey", "VGA Demo", "vga", GID_MONKEY_VGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_DEMO, UNK, GUIO2(GUIO_NOSPEECH, GUIO_ORIGINALGUI)},
+	{"monkey", "EGA",      "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_16COLOR,     Common::kPlatformDOS, GUIO3(GUIO_NOSPEECH, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR,                        GF_16COLOR,     Common::kPlatformAtariST, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
+	{"monkey", "Demo",     "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB,            GF_16COLOR | GF_DEMO,     Common::kPlatformDOS, GUIO3(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ORIGINALGUI)},
 	{"monkey", "CD",           0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS, UNK, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
 	{"monkey", "Mac",    0, GID_MONKEY,     5, 0, MDT_ADLIB,                        0, UNK, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},
 	{"monkey", "FM-TOWNS",     0, GID_MONKEY,     5, 0, MDT_TOWNS,                        GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO6(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_TRIM_FMTOWNS_TO_200_PIXELS, GUIO_ENHANCEMENTS, GUIO_ORIGINALGUI)},


Commit: 158a347c9479e3f6ee7026362a6721f3102101d9
    https://github.com/scummvm/scummvm/commit/158a347c9479e3f6ee7026362a6721f3102101d9
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Allow ALT-X combination on games which supported it

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 4f6e3165efb..d32f928c8e5 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1217,7 +1217,9 @@ void ScummEngine::queryQuit() {
 		else
 			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
 
-		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) {
+		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii ||
+			(ks.keycode == Common::KEYCODE_c && ks.hasFlags(Common::KBD_CTRL)) ||
+			(ks.keycode == Common::KEYCODE_x && ks.hasFlags(Common::KBD_ALT))) {
 			_quitByButton = true;
 			quitGame();
 		}
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 768f22e2606..7fb55dda97c 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -124,13 +124,13 @@ void ScummEngine::parseEvent(Common::Event event) {
 		} else if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_s) {
 			_res->resourceStats();
 		} else if (event.kbd.hasFlags(Common::KBD_ALT) && event.kbd.keycode == Common::KEYCODE_x) {
-			// TODO: Some SCUMM games quit when Alt-x is pressed. However, not
-			// all of them seem to exhibit this behavior. LordHoto found that
-			// the Loom manual does not mention this hotkey. On the other hand
-			// the Sam&Max manual mentions that Alt-x does so on "most"
-			// platforms. We should really check which games exhibit this
-			// behavior and only use it for them.
-			quitGame();
+			if (_game.version < 8) {
+				if (isUsingOriginalGUI()) {
+					_keyPressed = event.kbd;
+				} else {
+					quitGame();
+				}
+			}
 		} else {
 			// Normal key press, pass on to the game.
 			_keyPressed = event.kbd;
@@ -915,7 +915,8 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 			return;
 		}
 
-		if (lastKeyHit.keycode == Common::KEYCODE_c && lastKeyHit.hasFlags(Common::KBD_CTRL)) {
+		if ((lastKeyHit.keycode == Common::KEYCODE_c && lastKeyHit.hasFlags(Common::KBD_CTRL)) ||
+			(lastKeyHit.keycode == Common::KEYCODE_x && lastKeyHit.hasFlags(Common::KBD_ALT))) {
 			queryQuit();
 			return;
 		}


Commit: b19e8dd6098c938136e174b1bc4f0724f36099cb
    https://github.com/scummvm/scummvm/commit/b19e8dd6098c938136e174b1bc4f0724f36099cb
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix COMI demo string regression

Changed paths:
    engines/scumm/dialogs.cpp


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 6284761e2b9..e2b12474f9e 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -79,7 +79,7 @@ static const ResString string_map_table_v8[] = {
 	{0, "/BT_105/Text Display Only"},
 	{0, "/BT_103/Voice Only"},
 	{0, "/SYST300/y"},
-	{0, "/BOOT.005/Are you sure you want to quit?  (Y-N)"}, // Demo strings
+	{0, "/BOOT.005/Are you sure you want to quit?  (Y-N)Y"}, // Demo strings
 	{0, "/NEW.23/Text Speed  Slow  ==========  Fast"},
 	{0, "/NEW.24/Music Volume  Low  =========  High"},
 	{0, "/NEW.25/Voice Volume  Low  =========  High"},


Commit: 5ef621e27daf52284fe1f0f5dc417fec04d0d59e
    https://github.com/scummvm/scummvm/commit/5ef621e27daf52284fe1f0f5dc417fec04d0d59e
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Allow the user to open the GMM whilst on the original menu

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


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 7fb55dda97c..e1d96c73290 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -238,6 +238,11 @@ void ScummEngine::parseEvent(Common::Event event) {
 			_keyPressed = Common::KeyState(Common::KEYCODE_6, 54);	// '6'
 		break;
 
+	case Common::EVENT_MAINMENU:
+		// Let the user open the GMM when the menu is active.
+		if (isUsingOriginalGUI() && _mainMenuIsActive)
+			openMainMenuDialog();
+		break;
 	default:
 		break;
 	}
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 3aa36108e40..936e56f5b86 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -99,7 +99,9 @@ bool ScummEngine::canLoadGameStateCurrently() {
 	if (_game.id == GID_CMI)
 		return true;
 
-	return (VAR_MAINMENU_KEY == 0xFF || VAR(VAR_MAINMENU_KEY) != 0);
+	bool isOriginalMenuActive = isUsingOriginalGUI() && _mainMenuIsActive;
+
+	return (VAR_MAINMENU_KEY == 0xFF || VAR(VAR_MAINMENU_KEY) != 0) && !isOriginalMenuActive;
 }
 
 Common::Error ScummEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
@@ -144,9 +146,11 @@ bool ScummEngine::canSaveGameStateCurrently() {
 		return _currentRoom != 92;
 #endif
 
+	bool isOriginalMenuActive = isUsingOriginalGUI() && _mainMenuIsActive;
+
 	// 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));
+	return (VAR_MAINMENU_KEY == 0xFF || (VAR(VAR_MAINMENU_KEY) != 0 && _currentRoom != 0)) && !isOriginalMenuActive;
 }
 
 


Commit: afd34eaf2d5e7348edc25a3392c0634aa5e83859
    https://github.com/scummvm/scummvm/commit/afd34eaf2d5e7348edc25a3392c0634aa5e83859
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix unused variable warning

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index d32f928c8e5..b70c79ae773 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -256,7 +256,7 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	}
 
 	char bannerMsg[512];
-	int bannerMsgWidth, bannerMsgHeight, roundedWidth;
+	int bannerMsgWidth, bannerMsgHeight;
 	int startingPointY;
 	int bannerSaveYStart;
 
@@ -285,8 +285,6 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	if (bannerMsgWidth < 100)
 		bannerMsgWidth = 100;
 
-	roundedWidth = bannerMsgWidth / 2;
-
 	startingPointY = 80;
 	bannerSaveYStart = startingPointY - 2;
 


Commit: 7c1e8df9a347b979b0dff50297e573eb840a545c
    https://github.com/scummvm/scummvm/commit/7c1e8df9a347b979b0dff50297e573eb840a545c
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix CGA palette for v4

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


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index b70c79ae773..40dfd754fe9 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1059,7 +1059,9 @@ int ScummEngine_v7::getBannerColor(int bannerId) {
 #endif
 
 int ScummEngine_v4::getBannerColor(int bannerId) {
-	return _GUIPalette[bannerId - 6];
+	byte *palette = (_renderMode == Common::kRenderCGA) ? _GUIPaletteCGA : _GUIPalette;
+
+	return (int)palette[bannerId - 6];
 }
 
 int ScummEngine_v6::getBannerColor(int bannerId) {
diff --git a/engines/scumm/scumm_v4.h b/engines/scumm/scumm_v4.h
index 309832d203a..a675bebfe48 100644
--- a/engines/scumm/scumm_v4.h
+++ b/engines/scumm/scumm_v4.h
@@ -51,7 +51,8 @@ public:
 	void resetScumm() override;
 
 protected:
-	int _GUIPalette[13] = {0x00, 0x01, 0x0B, 0x03, 0x00, 0x0B, 0x0B, 0x03, 0x01, 0x00, 0x01, 0x0B, 0x09};
+	byte _GUIPalette[13]    = {0x00, 0x01, 0x0B, 0x03, 0x00, 0x0B, 0x0B, 0x03, 0x01, 0x00, 0x01, 0x0B, 0x09};
+	byte _GUIPaletteCGA[13] = {0x00, 0x03, 0x0B, 0x03, 0x00, 0x0B, 0x0B, 0x0F, 0x03, 0x00, 0x0B, 0x0B, 0x05};
 
 	void setupOpcodes() override;
 


Commit: 7c3418c028cc07fdef93b3c1fc3b3933df11af75
    https://github.com/scummvm/scummvm/commit/7c3418c028cc07fdef93b3c1fc3b3933df11af75
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix arrows appearing where they shouldn't on v7

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 40dfd754fe9..58d96d138a9 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -2454,37 +2454,39 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getGUIString(gsQuit), 1, 1);
 	}
 
-	// Arrow up button
-	setUpInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON,
-		getBannerColor(9),
-		getBannerColor(10),
-		getBannerColor(17),
-		getBannerColor(18),
-		getBannerColor(19),
-		getBannerColor(20),
-		getBannerColor(11),
-		getBannerColor(12),
-		(_game.version == 7 ? 209 : 206),
-		(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 25 : 17) : yConstantV6 - 43),
-		-16,
-		-47,
-		_arrowUp, 1, 1);
-
-	// Arrow down button
-	setUpInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON,
-		getBannerColor(9),
-		getBannerColor(10),
-		getBannerColor(17),
-		getBannerColor(18),
-		getBannerColor(19),
-		getBannerColor(20),
-		getBannerColor(11),
-		getBannerColor(12),
-		(_game.version == 7 ? 209 : 206),
-		(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 75 : 67) : yConstantV6 + 7),
-		-16,
-		-45,
-		_arrowDown, 1, 1);
+	if (_game.version == 6 || _menuPage != GUI_PAGE_MAIN) {
+		// Arrow up button
+		setUpInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON,
+			getBannerColor(9),
+			getBannerColor(10),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(11),
+			getBannerColor(12),
+			(_game.version == 7 ? 209 : 206),
+			(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 25 : 17) : yConstantV6 - 43),
+			-16,
+			-47,
+			_arrowUp, 1, 1);
+
+		// Arrow down button
+		setUpInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON,
+			getBannerColor(9),
+			getBannerColor(10),
+			getBannerColor(17),
+			getBannerColor(18),
+			getBannerColor(19),
+			getBannerColor(20),
+			getBannerColor(11),
+			getBannerColor(12),
+			(_game.version == 7 ? 209 : 206),
+			(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 75 : 67) : yConstantV6 + 7),
+			-16,
+			-45,
+			_arrowDown, 1, 1);
+	}
 
 	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
 		if (_menuPage == GUI_PAGE_SAVE) {


Commit: a62ce28eb4cbac33a7b2c37195e14a7d9fad090b
    https://github.com/scummvm/scummvm/commit/a62ce28eb4cbac33a7b2c37195e14a7d9fad090b
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix verbs disappearing in LOOM VGA

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 58d96d138a9..18386edeab0 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1132,7 +1132,8 @@ 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...
-		_postGUICharMask = true;
+		if (_game.version != 4 || _game.id != GID_LOOM)
+			_postGUICharMask = true;
 
 		free(_tempTextSurface);
 		_tempTextSurface = nullptr;
@@ -1706,7 +1707,7 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool
 					return true;
 				}
 
-				if (_game.version < 7) {
+				if ((_game.version != 4 || _game.id != GID_LOOM) && _game.version < 7) {
 					_postGUICharMask = true;
 				}
 


Commit: 649c6a9f11e99907d03d49b786e3a0584a4cd840
    https://github.com/scummvm/scummvm/commit/649c6a9f11e99907d03d49b786e3a0584a4cd840
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Restore shake effect after exiting a GUI prompt or menu

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 18386edeab0..0607694ce96 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -111,6 +111,10 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 			restoreCharsetBg();
 	}
 
+	// Pause shake effect
+	_shakeTempSavedState = _shakeEnabled;
+	setShake(0);
+
 	// Pause the engine
 	PauseToken pt = pauseEngine();
 
@@ -389,6 +393,9 @@ void ScummEngine::clearBanner() {
 		free(_textSurfBannerMem);
 		_textSurfBannerMem = nullptr;
 	}
+
+	// Restore shake effect
+	setShake(_shakeTempSavedState);
 }
 
 void ScummEngine::setBannerColors(int bannerId, byte r, byte g, byte b) {
@@ -1447,6 +1454,7 @@ void ScummEngine::showMainMenu() {
 		runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, nullptr);
 
 	_saveSound = 1;
+	_shakeTempSavedState = _shakeEnabled;
 	setShake(0);
 
 	if (_game.version < 7) {
@@ -1589,6 +1597,9 @@ void ScummEngine::showMainMenu() {
 
 	if (_game.version < 7 && !hasLoadedState) {
 		restoreSurfacesPostGUI();
+
+		// Restore shake effect
+		setShake(_shakeTempSavedState);
 	} else {
 		free(_tempTextSurface);
 		_tempTextSurface = nullptr;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 6135c770efd..12e677b8832 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1317,6 +1317,7 @@ public:
 
 protected:
 	bool _shakeEnabled = false;
+	bool _shakeTempSavedState = false; // For saving and restoring before and after GUI calls
 	uint _shakeFrame = 0;
 	uint32 _shakeNextTick = 0;
 	uint32 _shakeTickCounter = 0;


Commit: af45365e4f64190d8b2fdab31c3ca0ffebf1166a
    https://github.com/scummvm/scummvm/commit/af45365e4f64190d8b2fdab31c3ca0ffebf1166a
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: make some vars const

Changed paths:
    engines/scumm/dialogs.cpp
    engines/scumm/dialogs.h
    engines/scumm/gfx_gui.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v4.h
    engines/scumm/scumm_v6.h
    engines/scumm/scumm_v7.h
    engines/scumm/scumm_v8.h


diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index e2b12474f9e..329a35e1dfc 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -429,34 +429,34 @@ void InfoDialog::reflowLayout() {
 	_text->setSize(_w, _h);
 }
 
-char *InfoDialog::getPlainEngineString(int stringno) {
-	char *result;
+const char *InfoDialog::getPlainEngineString(int stringno) {
+	const char *result;
 
 	if (stringno == 0)
 		return nullptr;
 
 	if (_vm->_game.version == 8) {
-		return (char *)string_map_table_v8[stringno - 1].string;
+		return string_map_table_v8[stringno - 1].string;
 	} else if (_vm->_game.version == 7) {
-		result = (char *)_vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
+		result = (const char *)_vm->getStringAddressVar(string_map_table_v7[stringno - 1].num);
 
 		if (!result) {
-			result = (char *)string_map_table_v7[stringno - 1].string;
+			result = string_map_table_v7[stringno - 1].string;
 		}
 	} else if (_vm->_game.version == 6) {
-		result = (char *)_vm->getStringAddressVar(string_map_table_v6[stringno - 1].num);
+		result = (const char *)_vm->getStringAddressVar(string_map_table_v6[stringno - 1].num);
 
 		if (!result) {
-			result = (char *)string_map_table_v6[stringno - 1].string;
+			result = string_map_table_v6[stringno - 1].string;
 		}
 	} else if (_vm->_game.version >= 3) {
-		result = (char *)_vm->getStringAddress(getStaticResString(_vm->_language, stringno - 1).num);
+		result = (const char *)_vm->getStringAddress(getStaticResString(_vm->_language, stringno - 1).num);
 
 		if (!result) {
-			result = (char *)getStaticResString(_vm->_language, stringno - 1).string;
+			result = getStaticResString(_vm->_language, stringno - 1).string;
 		}
 	} else {
-		result = (char *)(getStaticResString(_vm->_language, stringno - 1).string);
+		result = getStaticResString(_vm->_language, stringno - 1).string;
 	}
 
 	return result;
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 16d4a2ff736..2a9e12691e2 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -96,7 +96,7 @@ public:
 	}
 
 	void reflowLayout() override;
-	char *getPlainEngineString(int stringno);
+	const char *getPlainEngineString(int stringno);
 
 protected:
 	// Query a string from the resources
diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 0607694ce96..774253b9831 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -410,7 +410,7 @@ void ScummEngine::setBannerColors(int bannerId, byte r, byte g, byte b) {
 void ScummEngine::setUpInternalGUIControl(int id, int normalFillColor, int normalTextColor,
 										  int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
 										  int highlightedTextColor, int highlightedFillColor,
-										  int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag, bool doubleLinesFlag) {
+										  int anchorPointX, int anchorPointY, int x, int y, const char *label, bool centerFlag, bool doubleLinesFlag) {
 
 	int effX, effY;
 	InternalGUIControl *ctrl;
@@ -790,7 +790,7 @@ void ScummEngine_v7::queryQuit() {
 	}
 }
 
-char *ScummEngine_v8::getGUIString(int stringId) {
+const char *ScummEngine_v8::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
 
@@ -850,7 +850,7 @@ char *ScummEngine_v8::getGUIString(int stringId) {
 		return _emptyMsg;
 }
 
-char *ScummEngine_v7::getGUIString(int stringId) {
+const char *ScummEngine_v7::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
 
@@ -1066,7 +1066,7 @@ int ScummEngine_v7::getBannerColor(int bannerId) {
 #endif
 
 int ScummEngine_v4::getBannerColor(int bannerId) {
-	byte *palette = (_renderMode == Common::kRenderCGA) ? _GUIPaletteCGA : _GUIPalette;
+	const byte *palette = (_renderMode == Common::kRenderCGA) ? _GUIPaletteCGA : _GUIPalette;
 
 	return (int)palette[bannerId - 6];
 }
@@ -2867,7 +2867,7 @@ void ScummEngine::getSliderString(int stringId, int value, char *sliderString, i
 	}
 }
 
-char *ScummEngine_v6::getGUIString(int stringId) {
+const char *ScummEngine_v6::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
 
@@ -2978,7 +2978,7 @@ char *ScummEngine_v6::getGUIString(int stringId) {
 		return _emptyMsg;
 }
 
-char *ScummEngine::getGUIString(int stringId) {
+const char *ScummEngine::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
 
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 12e677b8832..41e40bf8c33 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -446,7 +446,7 @@ struct InternalGUIControl {
 	int highlightedTextColor;
 	int highlightedFillColor;
 	bool centerText;
-	char *label;
+	const char *label;
 	bool doubleLinesFlag;
 };
 
@@ -616,11 +616,11 @@ protected:
 	InternalGUIControl _internalGUIControls[30];
 
 	// Special GUI strings
-	char _emptyMsg[1] = {'\0'};
-	char _uncheckedBox[2] = {' ', '\0'};
-	char _checkedBox[2] = {'x', '\0'};
-	char _arrowUp[2] = {'\x18', '\0'};
-	char _arrowDown[2] = {'\x19', '\0'};
+	const char _emptyMsg[1] = {'\0'};
+	const char _uncheckedBox[2] = {' ', '\0'};
+	const char _checkedBox[2] = {'x', '\0'};
+	const char _arrowUp[2] = {'\x18', '\0'};
+	const char _arrowDown[2] = {'\x19', '\0'};
 
 	GUISaveGameLabel _savegameNames[9];
 	int _menuPage = 0;
@@ -662,14 +662,14 @@ protected:
 	void setUpInternalGUIControl(int id, int normalFillColor, int normalTextColor,
 								 int topLineColor, int bottomLineColor, int leftLineColor, int rightLineColor,
 								 int highlightedTextColor, int highlightedFillColor,
-								 int anchorPointX, int anchorPointY, int x, int y, char *label, bool centerFlag, bool unknownFlag);
+								 int anchorPointX, int anchorPointY, int x, int y, const char *label, bool centerFlag, bool unknownFlag);
 	void drawInternalGUIControl(int id, bool highlightColor);
 	int getInternalGUIControlFromCoordinates(int x, int y);
 	virtual bool isSmushActive() { return false; }
 
 	virtual void queryQuit();
 	virtual void queryRestart();
-	virtual char *getGUIString(int stringId);
+	virtual const char *getGUIString(int stringId);
 	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked);
 	virtual int getGUIStringHeight(const char *str);
 	virtual int getGUIStringWidth(const char *str);
diff --git a/engines/scumm/scumm_v4.h b/engines/scumm/scumm_v4.h
index a675bebfe48..b7b07e3d594 100644
--- a/engines/scumm/scumm_v4.h
+++ b/engines/scumm/scumm_v4.h
@@ -51,8 +51,8 @@ public:
 	void resetScumm() override;
 
 protected:
-	byte _GUIPalette[13]    = {0x00, 0x01, 0x0B, 0x03, 0x00, 0x0B, 0x0B, 0x03, 0x01, 0x00, 0x01, 0x0B, 0x09};
-	byte _GUIPaletteCGA[13] = {0x00, 0x03, 0x0B, 0x03, 0x00, 0x0B, 0x0B, 0x0F, 0x03, 0x00, 0x0B, 0x0B, 0x05};
+	const byte _GUIPalette[13]    = {0x00, 0x01, 0x0B, 0x03, 0x00, 0x0B, 0x0B, 0x03, 0x01, 0x00, 0x01, 0x0B, 0x09};
+	const byte _GUIPaletteCGA[13] = {0x00, 0x03, 0x0B, 0x03, 0x00, 0x0B, 0x0B, 0x0F, 0x03, 0x00, 0x0B, 0x0B, 0x05};
 
 	void setupOpcodes() override;
 
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index ebe3f646ab1..c3c3dedb062 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -164,7 +164,7 @@ protected:
 	void clearDrawQueues() override;
 
 	int getBannerColor(int bannerId) override;
-	char *getGUIString(int stringId) override;
+	const char *getGUIString(int stringId) override;
 	void setSkipVideo(int value) override { _skipVideo = value; }
 	void setUpMainMenuControls() override;
 
diff --git a/engines/scumm/scumm_v7.h b/engines/scumm/scumm_v7.h
index bf4759ae975..3f2bf605be6 100644
--- a/engines/scumm/scumm_v7.h
+++ b/engines/scumm/scumm_v7.h
@@ -144,7 +144,7 @@ protected:
 
 	void queryQuit() override;
 	int getBannerColor(int bannerId) override;
-	char *getGUIString(int stringId) override;
+	const char *getGUIString(int stringId) override;
 	int getGUIStringHeight(const char *str) override;
 	int getGUIStringWidth(const char *str) override;
 	void drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag) override;
diff --git a/engines/scumm/scumm_v8.h b/engines/scumm/scumm_v8.h
index c74572a868a..5b992d1b265 100644
--- a/engines/scumm/scumm_v8.h
+++ b/engines/scumm/scumm_v8.h
@@ -94,7 +94,7 @@ protected:
 	bool fetchInternalSaveStateThumbnail(int slotId, bool isHeapSave);
 	uint32 *fetchScummVMSaveStateThumbnail(int slotId, bool isHeapSave, int brightness);
 
-	char *getGUIString(int stringId) override;
+	const char *getGUIString(int stringId) override;
 
 	/* Version 8 script opcodes */
 	void o8_mod();


Commit: 71f73fd8aebbfce9df3caf83792ecfa2bba9a385
    https://github.com/scummvm/scummvm/commit/71f73fd8aebbfce9df3caf83792ecfa2bba9a385
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (GUI) - modify dialogs for CJK font support

This replaces the fixed vertical coordinates with coordinates based on the font
height (taken from the original CJK DIG interpreter).

It also influences the appearance of the non-CJK dialog, but not necessarily for
the worse (and the one we had is again different from the one in the original
7.3.5/7.5.0 interpreters, so there really is not one definite dialog).

There is more in this commit, like:
- clippint the save names at the end of the line
- getting rid of all sprintfs and similiar cleanup to be better in line with our
coding conventions.

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


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 774253b9831..8afbf0d9cc9 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -144,7 +144,8 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	// Take all the necessary measurements for the box which
 	// will contain the string...
 	bool isCOMIDemo = (_game.id == GID_CMI && (_game.features & GF_DEMO) != 0);
-	bannerMsgHeight = (isCOMIDemo ? getGUIStringHeight("ABC \x80\x78 \xb0\x78") : getGUIStringHeight(bannerMsg)) + 5;
+	bannerMsgHeight = ((_game.id == GID_DIG || isCOMIDemo) ? getGUIStringHeight("ABC \x80\x78 \xb0\x78") : getGUIStringHeight(bannerMsg)) + 5;
+
 	bannerMsgWidth = getGUIStringWidth(bannerMsg);
 	if (bannerMsgWidth < 100)
 		bannerMsgWidth = 100;
@@ -171,7 +172,7 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		startingPointX = 156 - roundedWidth;
 		startingPointY = ((_game.version < 7) ? 80 : _screenHeight / 2 - 10);
 		xPos = roundedWidth + 163 + ((_game.version < 7) ? 1 : 0);
-		yPos = -12;
+		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);
 	}
 
@@ -311,7 +312,7 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	drawBox(0, startingPointY, _screenWidth - 1, startingPointY + bannerMsgHeight, 0);
 	drawBox(0, startingPointY, _screenWidth - 1, startingPointY, color);
 	drawBox(0, startingPointY + bannerMsgHeight, _screenWidth - 1, startingPointY + bannerMsgHeight, color);
-	drawGUIText(bannerMsg, _screenWidth / 2, startingPointY + 2, _screenWidth - 1, color, true);
+	drawGUIText(bannerMsg, 0, _screenWidth / 2, startingPointY + 2, color, true);
 	ScummEngine::drawDirtyScreenParts();
 
 	// Wait until the engine receives a new Keyboard or Mouse input,
@@ -445,7 +446,7 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 	int x, y, textXPos, textYPos;
 	int textColor, fillColor;
 	int boxSizeX, boxSizeY;
-	int offset = (_game.version == 8) ? 2 : 1;
+	int offset = (_game.version == 8 || _game.id == GID_DIG) ? 2 : 1;
 	int topComp = (_game.version < 8) ? _screenTop : 0;
 
 	bool centerFlag;
@@ -530,27 +531,17 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 			textXPos = 160;
 			textYPos = 82;
 		} else {
-			textHeight = getGUIStringHeight(ctrl->label);
+			textHeight = getGUIStringHeight(ctrl->label.c_str());
 
 			if (centerFlag)
 				textXPos = relCentX + (x - ctrl->relativeCenterX) / 2;
 			else
 				textXPos = relCentX + 2;
-
-			if (_game.version == 8) {
-				textYPos = relCentY + ((y - relCentY) - textHeight) / 2 + 1;
-			} else {
-				int yOffset = 8;
-
-				if ((_game.id == GID_DIG && _useCJKMode) &&
-					(((byte)ctrl->label[0] >= 128 && (byte)ctrl->label[0] <= 159) ||
-					 ((byte)ctrl->label[0] >= 224 && (byte)ctrl->label[0] <= 253))) {
-					yOffset = 16;
-				}
-
-				textYPos = relCentY + (y - yOffset - relCentY + 2) / 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
@@ -559,10 +550,7 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 		else
 			textColor = ctrl->normalTextColor;
 
-		if (ctrl->label)
-			Common::strlcpy(buttonString, ctrl->label, sizeof(buttonString));
-		else
-			Common::strlcpy(buttonString, "null button", sizeof(buttonString));
+		Common::strlcpy(buttonString, ctrl->label.c_str(), sizeof(buttonString));
 
 		if (_mainMenuSavegameLabel == id && _menuPage == GUI_PAGE_SAVE) {
 			Common::strlcat(buttonString, "_", sizeof(buttonString));
@@ -570,7 +558,12 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 
 		int tmpRight = _string[5].right;
 		_string[5].right = _screenWidth - 1;
-		drawGUIText(buttonString, textXPos, textYPos, _screenWidth - 1, textColor, centerFlag);
+
+		// The original CJK DIG interpreter limits the clipping to the save slots. Other elements
+		// seem to (theoretically) be allowed to draw text wherever they want...
+		bool isSaveSlot = (id >= 1 && id <= 9);
+		Common::Rect clipRect(relCentX, relCentY, x, y);
+		drawGUIText(buttonString, isSaveSlot ? &clipRect : 0, textXPos, textYPos, textColor, centerFlag);
 		_string[5].right = tmpRight;
 
 		// Restore the previous charset
@@ -678,7 +671,7 @@ void ScummEngine_v7::queryQuit() {
 			drawInternalGUIControl(0, 0);
 
 			// The text is drawn as a separate entity
-			drawTextImmediately((const byte *)msgLabelPtr, 320, 200, getBannerColor(32), 1, (TextStyleFlags) true);
+			drawTextImmediately((const byte *)msgLabelPtr, &_defaultTextClipRect, 320, 200, getBannerColor(32), 1, (TextStyleFlags) true);
 
 			// Now set up and draw the Yes and No buttons...
 			if (getGUIStringWidth(noLabelPtr) <= getGUIStringWidth(yesLabelPtr)) {
@@ -853,6 +846,7 @@ const char *ScummEngine_v8::getGUIString(int stringId) {
 const char *ScummEngine_v7::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
+	resStringId = VAR(stringId);
 
 	switch (stringId) {
 	case gsPause:
@@ -971,10 +965,14 @@ const char *ScummEngine_v7::getGUIString(int stringId) {
 		return _emptyMsg;
 	}
 
-	if (resStringId > 0)
-		return d.getPlainEngineString(resStringId);
-	else
-		return _emptyMsg;
+	const char *res =  (resStringId > 0) ? d.getPlainEngineString(resStringId) : _emptyMsg;
+
+	if (_game.id == GID_DIG) {
+		convertMessageToString((const byte*)res, _guiStringTransBuff, 512);
+		res = (const char*)_guiStringTransBuff;
+	}
+
+	return res;
 }
 
 int ScummEngine_v7::getGUIStringHeight(const char *str) {
@@ -985,8 +983,8 @@ int ScummEngine_v7::getGUIStringWidth(const char *str) {
 	return _textV7->getStringWidth(str);
 }
 
-void ScummEngine_v7::drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag) {
-	drawTextImmediately((const byte *)buttonString, textXPos, textYPos, textColor, 1, (TextStyleFlags)centerFlag);
+void ScummEngine_v7::drawGUIText(const char *buttonString, Common::Rect *clipRect, int textXPos, int textYPos, int textColor, bool centerFlag) {
+	drawTextImmediately((const byte *)buttonString, clipRect, textXPos, textYPos, textColor, 1, (TextStyleFlags)centerFlag);
 }
 
 int ScummEngine_v7::getMusicVolume() {
@@ -1208,7 +1206,6 @@ int ScummEngine::getSFXVolume() {
 	return CLIP<int>(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 2, 0, 127);
 }
 
-
 void ScummEngine::queryQuit() {
 	char msgLabelPtr[512];
 	char localizedYesKey;
@@ -1276,32 +1273,32 @@ void ScummEngine::fillSavegameLabels() {
 	Common::String name;
 	int curSaveSlot;
 	bool isLoomVga = (_game.id == GID_LOOM && _game.version == 4);
+	_savegameNames.clear();
 
 	for (int i = 0; i < 9; i++) {
 		curSaveSlot = i + (isLoomVga ? _firstSaveStateOfList : _curDisplayedSaveSlotPage * 9);
 		if (_game.version > 4 || (_game.version == 4 && _game.id == GID_LOOM)) {
-			sprintf(_savegameNames[i].label, "%2d. ", curSaveSlot + 1);
-		} else {
-			_savegameNames[i].label[0] = '\0';
-		}
-
-		if (availSaves[curSaveSlot]) {
-			if (_game.version > 4 || (_game.version == 4 && _game.id == GID_LOOM)) {
+			if (availSaves[curSaveSlot]) {
 				if (getSavegameName(curSaveSlot, name)) {
-					sprintf(_savegameNames[i].label, "%2d. %s", curSaveSlot + 1, name.c_str());
+					_savegameNames.push_back(Common::String::format("%2d. %s", curSaveSlot + 1, name.c_str()));
 				} else {
 					// The original printed "WARNING... old savegame", but we do support old savegames :-)
-					sprintf(_savegameNames[i].label, "%2d. WARNING: wrong save version", curSaveSlot + 1);
+					_savegameNames.push_back(Common::String::format("%2d. WARNING: wrong save version", curSaveSlot + 1));
 				}
 			} else {
+				_savegameNames.push_back(Common::String::format("%2d. ", curSaveSlot + 1));
+			}
+		} else {
+			if (availSaves[curSaveSlot]) {
 				if (getSavegameName(curSaveSlot, name)) {
-					sprintf(_savegameNames[i].label, "%s", name.c_str());
+					_savegameNames.push_back(Common::String::format("%s", name.c_str()));
 				} else {
 					// The original printed "WARNING... old savegame", but we do support old savegames :-)
-					sprintf(_savegameNames[i].label, "%s", "WARNING: wrong save version");
+					_savegameNames.push_back(Common::String::format("%s", "WARNING: wrong save version"));
 				}
+			} else {
+				_savegameNames.push_back(Common::String());
 			}
-
 		}
 	}
 }
@@ -1353,19 +1350,20 @@ bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicke
 		}
 
 		// Handle special key presses
-		int curLen = strlen(_savegameNames[_mainMenuSavegameLabel - 1].label);
+		int curLen = _savegameNames[_mainMenuSavegameLabel - 1].size();
 		if (ks.keycode == Common::KEYCODE_BACKSPACE) {
 			 // Prevent the user from deleting the header (" 1. ")
 			if (curLen > firstChar) {
-				_savegameNames[_mainMenuSavegameLabel - 1].label[curLen - 1] = '\0';
+				_savegameNames[_mainMenuSavegameLabel - 1].deleteLastChar();
+				_internalGUIControls[_mainMenuSavegameLabel].label = _savegameNames[_mainMenuSavegameLabel - 1];
 				drawInternalGUIControl(_mainMenuSavegameLabel, 1);
 				ScummEngine::drawDirtyScreenParts();
 				_system->updateScreen();
 			}
 		} else if (ks.ascii >= 32 && ks.ascii <= 122) { // Handle characters
 			if (curLen < 39) {
-				_savegameNames[_mainMenuSavegameLabel - 1].label[curLen] = ks.ascii;
-				_savegameNames[_mainMenuSavegameLabel - 1].label[curLen + 1] = '\0';
+				_savegameNames[_mainMenuSavegameLabel - 1] += (char)ks.ascii;
+				_internalGUIControls[_mainMenuSavegameLabel].label = _savegameNames[_mainMenuSavegameLabel - 1];
 				drawInternalGUIControl(_mainMenuSavegameLabel, 1);
 				ScummEngine::drawDirtyScreenParts();
 				_system->updateScreen();
@@ -1616,7 +1614,7 @@ void ScummEngine::showMainMenu() {
 
 bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool &hasLoadedState) {
 	char saveScreenTitle[512];
-	char formattedString[512];
+	Common::String formattedString;
 	int curSlot;
 	bool isLoomVga = (_game.id == GID_LOOM && _game.version == 4);
 	size_t labelSkip = (_game.version == 4 && _game.id != GID_LOOM) ? 0 : 4;
@@ -1648,17 +1646,17 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool
 	case GUI_CTRL_OK_BUTTON:
 		if (_menuPage == GUI_PAGE_SAVE) {
 			// We check for an empty label since v4 might generate that...
-			if (_mainMenuSavegameLabel > 0 && _savegameNames[_mainMenuSavegameLabel - 1].label[labelSkip] != '\0') {
+			if (_mainMenuSavegameLabel > 0 && !_savegameNames[_mainMenuSavegameLabel - 1].substr(labelSkip).empty()) {
 				convertMessageToString((const byte *)getGUIString(gsSaving), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
-				sprintf(formattedString, saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[labelSkip]);
-				drawMainMenuTitle(formattedString);
+				formattedString = Common::String::format(saveScreenTitle, _savegameNames[_mainMenuSavegameLabel - 1].substr(labelSkip).c_str());
+				drawMainMenuTitle(formattedString.c_str());
 				ScummEngine::drawDirtyScreenParts();
 				_system->updateScreen();
 
 				waitForTimer(60);
 
 				Common::String dummyString;
-				_saveLoadDescription = &_savegameNames[_mainMenuSavegameLabel - 1].label[labelSkip];
+				_saveLoadDescription = _savegameNames[_mainMenuSavegameLabel - 1].substr(labelSkip);
 
 				curSlot = _mainMenuSavegameLabel + (isLoomVga ? _firstSaveStateOfList : _curDisplayedSaveSlotPage * 9);
 				if (canWriteGame(curSlot)) {
@@ -1699,15 +1697,15 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool
 		} else if (_menuPage == GUI_PAGE_LOAD) {
 			if (_mainMenuSavegameLabel > 0) {
 				convertMessageToString((const byte *)getGUIString(gsLoading), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
-				sprintf(formattedString, saveScreenTitle, &_savegameNames[_mainMenuSavegameLabel - 1].label[labelSkip]);
+				formattedString = Common::String::format(saveScreenTitle, _savegameNames[_mainMenuSavegameLabel - 1].substr(labelSkip).c_str());
 
-				if (strlen(_savegameNames[_mainMenuSavegameLabel - 1].label) == labelSkip) {
+				if (_savegameNames[_mainMenuSavegameLabel - 1].size() == labelSkip) {
 					drawMainMenuControls();
 					ScummEngine::drawDirtyScreenParts();
 					break;
 				}
 
-				drawMainMenuTitle(formattedString);
+				drawMainMenuTitle(formattedString.c_str());
 				ScummEngine::drawDirtyScreenParts();
 				_system->updateScreen();
 
@@ -1792,6 +1790,11 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool
 
 			_mainMenuSavegameLabel = 0;
 			fillSavegameLabels();
+
+			// Update the control labels with the newly changed savegame names
+			for (int i = GUI_CTRL_FIRST_SG; i <= GUI_CTRL_LAST_SG; i++)
+				_internalGUIControls[i].label = _savegameNames[i - 1];
+
 			drawMainMenuControls();
 			ScummEngine::drawDirtyScreenParts();
 		} else {
@@ -1996,7 +1999,7 @@ void ScummEngine_v4::setUpMainMenuControls() {
 				yConstant - 56 + j,
 				-206,
 				-9,
-				_savegameNames[i - 1].label, 0, 0);
+				_savegameNames[i - 1].c_str(), 0, 0);
 		}
 	}
 }
@@ -2193,20 +2196,23 @@ void ScummEngine::setUpMainMenuControls() {
 				yConstant - 45 + j,
 				210 - (isLoomVGA ? 10 : 0),
 				-9,
-				_savegameNames[i - 1].label, 0, 0);
+				_savegameNames[i - 1].c_str(), 0, 0);
 		}
 	}
 }
 
 void ScummEngine_v6::setUpMainMenuControls() {
-	int yComponentV7, yConstantV7, yConstant2V7, yConstantV6;
+	int yConstantV6;
 
 	// V7 auxiliary constants
-	yComponentV7 = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
-	yConstantV7 = _screenHeight / 2 - ((yComponentV7 - 1) / 2);
-	yConstant2V7 = _screenHeight / 2 + ((yComponentV7 - 1) / 2);
+	int cid = _charset->getCurID();
+	_charset->setCurID(1);
+	int lh = getGUIStringHeight("ABC \x80\x78 \xb0\x78");
+	_charset->setCurID(cid);
+	int yCntr = _screenHeight / 2;
+	int calculatedHeight = (110 + lh) / 2;
 
-	// V6 ausiliary constant
+	// V6 auxiliary constant
 	yConstantV6 = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
 
 	for (int i = 0; i < ARRAYSIZE(_internalGUIControls); i++) {
@@ -2224,9 +2230,9 @@ void ScummEngine_v6::setUpMainMenuControls() {
 		getBannerColor(6),
 		getBannerColor(4),
 		(_game.version == 7 ? 16 : 20),
-		(_game.version == 7 ? yConstantV7 : yConstantV6 - 60),
+		(_game.version == 7 ? yCntr - calculatedHeight : yConstantV6 - 60),
 		(_game.version == 7 ? 303 : 300),
-		(_game.version == 7 ? yConstant2V7 : yConstantV6 + 60),
+		(_game.version == 7 ? yCntr + calculatedHeight : yConstantV6 + 60),
 		_emptyMsg, 1, 1);
 
 	// Inner box
@@ -2240,7 +2246,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 		getBannerColor(6),
 		getBannerColor(7),
 		(_game.version == 7 ? 22 : 26),
-		(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 21 : 13) : yConstantV6 - 47),
+		(_game.version == 7 ? yCntr - calculatedHeight + lh + 4 : yConstantV6 - 47),
 		(_game.version == 7 ? -183 : -176),
 		-102,
 		_emptyMsg, 1, 1);
@@ -2322,7 +2328,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				getBannerColor(10),
 				getBannerColor(12),
 				(_game.version == 7 ? 108 : 102),
-				(_game.version == 7 ? yConstantV7 + 25 : yConstantV6 - 39),
+				(_game.version == 7 ? yCntr - calculatedHeight + 25 : yConstantV6 - 39),
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -2338,7 +2344,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				getBannerColor(10),
 				getBannerColor(12),
 				(_game.version == 7 ? 108 : 102),
-				(_game.version == 7 ? yConstantV7 + 43 : yConstantV6 - 25),
+				(_game.version == 7 ? yCntr - calculatedHeight + 43 : yConstantV6 - 25),
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -2354,7 +2360,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				getBannerColor(10),
 				getBannerColor(12),
 				(_game.version == 7 ? 108 : 102),
-				(_game.version == 7 ? yConstantV7 + 61 : yConstantV6 - 11),
+				(_game.version == 7 ? yCntr - calculatedHeight + 61 : yConstantV6 - 11),
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -2371,7 +2377,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(11),
 			getBannerColor(12),
 			(_game.version == 7 ? 108 : 102),
-			(_game.version == 7 ? yConstantV7 + 85 : yConstantV6 + 17),
+			(_game.version == 7 ? yCntr - calculatedHeight + 85 : yConstantV6 + 17),
 			-12,
 			-12,
 			_uncheckedBox, 1, 1);
@@ -2387,9 +2393,9 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(10),
 			getBannerColor(12),
 			(_game.version == 7 ? 108 : 102),
-			(_game.version == 7 ? yConstantV7 + 99 : yConstantV6 + 31),
+			(_game.version == 7 ? yCntr - calculatedHeight + 99 : yConstantV6 + 31),
 			-90,
-			-12,
+			-(lh + 4),
 			_uncheckedBox, 1, 1);
 
 		// Save button
@@ -2403,15 +2409,12 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(6),
 			getBannerColor(7),
 			(_game.version == 7 ? 235 : 232),
-			(_game.version == 7 ? yConstantV7 + 37 : yConstantV6 - 23),
+			(_game.version == 7 ? yCntr - calculatedHeight + 30 : yConstantV6 - 23),
 			-60,
-			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			-(lh + 4),
 			getGUIString(gsSave), 1, 1);
 
 		// Load button
-		int loadButtonAnchorY = yConstantV7 +
-			((_game.id == GID_DIG && _useCJKMode) ? 18 : 12)
-			+ 40;
 		setUpInternalGUIControl(GUI_CTRL_LOAD_BUTTON,
 			getBannerColor(4),
 			getBannerColor(5),
@@ -2422,15 +2425,12 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(6),
 			getBannerColor(7),
 			(_game.version == 7 ? 235 : 232),
-			(_game.version == 7 ? loadButtonAnchorY : yConstantV6 - 8),
+			(_game.version == 7 ? yCntr - calculatedHeight + lh + 37 : yConstantV6 - 8),
 			-60,
-			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			-(lh + 4),
 			getGUIString(gsLoad), 1, 1);
 
 		// Play button
-		int playButtonAnchorY = yConstantV7 +
-			2 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12)
-			+ 43;
 		setUpInternalGUIControl(GUI_CTRL_PLAY_BUTTON,
 			getBannerColor(4),
 			getBannerColor(5),
@@ -2441,15 +2441,12 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(6),
 			getBannerColor(7),
 			(_game.version == 7 ? 235 : 232),
-			(_game.version == 7 ? playButtonAnchorY : yConstantV6 + 7),
+			(_game.version == 7 ? yCntr - calculatedHeight + lh * 2 + 44 : yConstantV6 + 7),
 			-60,
-			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			-(lh + 4),
 			getGUIString(gsPlay), 1, 1);
 
 		// Quit button
-		int quitButtonAnchorY = yConstantV7 +
-			3 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12)
-			+ 46;
 		setUpInternalGUIControl(GUI_CTRL_QUIT_BUTTON,
 			getBannerColor(4),
 			getBannerColor(5),
@@ -2460,9 +2457,9 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(6),
 			getBannerColor(7),
 			(_game.version == 7 ? 235 : 232),
-			(_game.version == 7 ? quitButtonAnchorY : yConstantV6 + 22),
+			(_game.version == 7 ? yCntr - calculatedHeight + lh * 3 + 51 : yConstantV6 + 22),
 			-60,
-			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			-(lh + 4),
 			getGUIString(gsQuit), 1, 1);
 	}
 
@@ -2478,7 +2475,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(11),
 			getBannerColor(12),
 			(_game.version == 7 ? 209 : 206),
-			(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 25 : 17) : yConstantV6 - 43),
+			(_game.version == 7 ? yCntr - calculatedHeight + lh + 8: yConstantV6 - 43),
 			-16,
 			-47,
 			_arrowUp, 1, 1);
@@ -2494,7 +2491,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(11),
 			getBannerColor(12),
 			(_game.version == 7 ? 209 : 206),
-			(_game.version == 7 ? yConstantV7 + ((_game.id == GID_DIG && _useCJKMode) ? 75 : 67) : yConstantV6 + 7),
+			(_game.version == 7 ? yCntr - calculatedHeight + lh + 58 : yConstantV6 + 7),
 			-16,
 			-45,
 			_arrowDown, 1, 1);
@@ -2503,7 +2500,6 @@ void ScummEngine_v6::setUpMainMenuControls() {
 	if (_menuPage == GUI_PAGE_SAVE || _menuPage == GUI_PAGE_LOAD) {
 		if (_menuPage == GUI_PAGE_SAVE) {
 			// OK button
-			int okButtonAnchorY = ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) + yConstantV7 + 40;
 			setUpInternalGUIControl(GUI_CTRL_OK_BUTTON,
 				getBannerColor(4),
 				getBannerColor(5),
@@ -2514,9 +2510,9 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				getBannerColor(6),
 				getBannerColor(7),
 				(_game.version == 7 ? 235 : 232),
-				(_game.version == 7 ? okButtonAnchorY : yConstantV6 - 8),
+				(_game.version == 7 ? yCntr - calculatedHeight + lh + 37: yConstantV6 - 8),
 				-60,
-				((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+				-(lh + 4),
 				getGUIString(gsOK), 1, 1);
 		}
 
@@ -2524,16 +2520,13 @@ void ScummEngine_v6::setUpMainMenuControls() {
 		int cancelButtonAnchorY;
 		if (_menuPage == GUI_PAGE_LOAD) {
 			if (_game.version == 7) {
-				cancelButtonAnchorY = _screenHeight / 2 +
-					(((_game.id == GID_DIG && _useCJKMode) ? 10 : 7) - yComponentV7 / 2) +
-					((_game.id == GID_DIG && _useCJKMode) ? 18 : 12) +
-					40;
+				cancelButtonAnchorY = yCntr - calculatedHeight + (lh + 7) / 2 + lh + 37;
 			} else {
 				cancelButtonAnchorY = yConstantV6 - 1;
 			}
 		} else {
 			if (_game.version == 7) {
-				cancelButtonAnchorY = yConstantV7 + 43 + 2 * ((_game.id == GID_DIG && _useCJKMode) ? 18 : 12);
+				cancelButtonAnchorY = yCntr - calculatedHeight + lh * 2 + 44;
 			} else {
 				cancelButtonAnchorY = yConstantV6 + 7;
 			}
@@ -2550,12 +2543,11 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			(_game.version == 7 ? 235 : 232),
 			cancelButtonAnchorY,
 			-60,
-			((_game.id == GID_DIG && _useCJKMode) ? -18 : -12),
+			-(lh + 4),
 			getGUIString(gsCancel), 1, 1);
 
 		// Savegame names
 		for (int i = GUI_CTRL_FIRST_SG, j = 11; i <= GUI_CTRL_LAST_SG; i++, j += 11) {
-			int curSaveLabelAnchorY = yConstantV7 + j + ((_game.id == GID_DIG && _useCJKMode) ? 12 : 4);
 			setUpInternalGUIControl(i,
 				getBannerColor(9),
 				getBannerColor(10),
@@ -2566,10 +2558,10 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				getBannerColor(11),
 				getBannerColor(12),
 				(_game.version == 7 ? 24 : 28),
-				(_game.version == 7 ? curSaveLabelAnchorY : yConstantV6 + j - 56),
+				(_game.version == 7 ? yCntr - calculatedHeight + j + lh - 5 : yConstantV6 + j - 56),
 				(_game.version == 7 ? -179 : -172),
 				-9,
-				_savegameNames[i - 1].label, 0, 0);
+				_savegameNames[i - 1].c_str(), 0, 0);
 		}
 	}
 }
@@ -2622,7 +2614,6 @@ void ScummEngine::drawMainMenuControls() {
 				drawInternalGUIControl(i, 0);
 		}
 
-
 		if (_game.version > 4 || (_game.version == 4 && _game.id == GID_LOOM)) {
 			drawInternalGUIControl(GUI_CTRL_ARROW_UP_BUTTON, 0);   // Arrow up button
 			drawInternalGUIControl(GUI_CTRL_ARROW_DOWN_BUTTON, 0); // Arrow down button
@@ -2648,16 +2639,20 @@ void ScummEngine::updateMainMenuControls() {
 	if ((_game.variant && !strcmp(_game.variant, "Floppy")) || _game.version < 6)
 		return;
 
+	int cid = _charset->getCurID();
+	_charset->setCurID(1);
+	int lh = getGUIStringHeight("ABC \x80\x78 \xb0\x78");
+	_charset->setCurID(cid);
+
 	char msg[256];
-	int yComponentV7, yConstantV7, yConstantV6;
-	int textColor = getBannerColor(2);
 
-	// V7 ausiliary constants
-	yComponentV7 = (_game.id == GID_DIG && _useCJKMode) ? 130 : 121;
-	yConstantV7 = _screenHeight / 2 - ((yComponentV7 - 1) / 2);
+	// V7 auxiliary constants
+	int yCntr = _screenHeight / 2;
+	int calculatedHeight = (110 + lh) / 2;
+	int textColor = getBannerColor(2);
 
-	// V6 ausiliary constant
-	yConstantV6 = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
+	// V6 auxiliary constant
+	int yConstantV6 = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
 
 	strncpy(_mainMenuMusicSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuMusicSlider));
 	strncpy(_mainMenuSpeechSlider, "\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v\v", sizeof(_mainMenuSpeechSlider));
@@ -2710,54 +2705,54 @@ 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, 29, yConstantV7 + 19, _screenWidth - 1, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 19, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 29, yConstantV7 + 33, _screenWidth - 1, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 33, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 29, yConstantV7 + 47, _screenWidth - 1, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 47, textColor, false);
 		} else {
 			convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 29, yConstantV7 + 25, _screenWidth - 1, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 25, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 29, yConstantV7 + 43, _screenWidth - 1, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 43, textColor, false);
 		}
 
 		convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstantV7 + 61, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 61, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstantV7 + 88, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 88, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 29, yConstantV7 + 102, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 102, textColor, false);
 
-		drawLine(23, yConstantV7 + 77, 204, yConstantV7 + 77, getBannerColor(17));
-		drawLine(23, yConstantV7 + 78, 204, yConstantV7 + 78, getBannerColor(4));
-		drawLine(23, yConstantV7 + 79, 204, yConstantV7 + 79, getBannerColor(4));
-		drawLine(23, yConstantV7 + 80, 204, yConstantV7 + 80, getBannerColor(18));
+		drawLine(23, yCntr - calculatedHeight + 77, 204, yCntr - calculatedHeight + 77, getBannerColor(17));
+		drawLine(23, yCntr - calculatedHeight + 78, 204, yCntr - calculatedHeight + 78, getBannerColor(4));
+		drawLine(23, yCntr - calculatedHeight + 79, 204, yCntr - calculatedHeight + 79, getBannerColor(4));
+		drawLine(23, yCntr - calculatedHeight + 80, 204, yCntr - calculatedHeight + 80, getBannerColor(18));
 
 		// The following line is from the Aaron Giles' interpreter of FT, based on the first DOS version;
 		// for some reason it doesn't get displayed in the DOS version, and it also overflows
 		// onto the internal panel lines, so let's just not draw it...
-		// drawLine(24, yConstantV7 + 81, 204, yConstantV7 + 81, getBannerColor(4));
+		// drawLine(24, yCntr - calculatedHeight + 81, 204, yCntr - calculatedHeight + 81, getBannerColor(4));
 	} else {
 		convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 33, yConstantV6 - 36, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 0, 33, yConstantV6 - 36, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 33, yConstantV6 - 22, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 0, 33, yConstantV6 - 22, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 33, yConstantV6 - 8, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 0, 33, yConstantV6 - 8, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 33, yConstantV6 + 19, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 0, 33, yConstantV6 + 19, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 33, yConstantV6 + 34, _screenWidth - 1, textColor, false);
+		drawGUIText(msg, 0, 33, yConstantV6 + 34, textColor, false);
 
 		drawLine(27, yConstantV6 + 8,  201, yConstantV6 + 8,  getBannerColor(17));
 		drawLine(27, yConstantV6 + 9,  201, yConstantV6 + 9,  getBannerColor(4));
@@ -2787,34 +2782,38 @@ void ScummEngine::drawMainMenuTitle(const char *title) {
 	}
 
 	if (_game.id == GID_DIG) {
-		int yComponent = _useCJKMode ? 130 : 121;
+		int cid = _charset->getCurID();
+		_charset->setCurID(1);
+		int lh = getGUIStringHeight("ABC \x80\x78 \xb0\x78");
+		_charset->setCurID(cid);
+		int yCntr = _screenHeight / 2;
+		int calculatedHeight = (110 + lh) / 2;
 
 		drawBox(18,
-			_screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop + 4,
+			yCntr - calculatedHeight + _screenTop + 4,
 			301,
-			_screenHeight / 2 - ((yComponent - 1) / 2) + _screenTop + 12,
+			yCntr - calculatedHeight + _screenTop + 3 + lh,
 			boxColor);
 
-		drawGUIText(title,
+		drawGUIText(title, 0,
 			159,
-			_screenHeight / 2 - ((yComponent - 1) / 2) + 4,
-			_screenWidth - 1,
+			yCntr - calculatedHeight + 4,
 			stringColor,
 			true);
 	} else if (_game.version == 7) {
 		drawBox(18, _screenTop + 44, 301, _screenTop + 52, boxColor);
-		drawGUIText(title, 159, 44, _screenWidth - 1, stringColor, true);
+		drawGUIText(title, 0, 159, 44, stringColor, true);
 	} else if (_game.version == 4) {
 		if (_game.id == GID_LOOM) {
 			drawBox(22, yConstantV6 - 57, 298, yConstantV6 - 49, boxColor);
-			drawGUIText(title, 160, yConstantV6 - 57, _screenWidth - 1, stringColor, true);
+			drawGUIText(title, 0, 160, yConstantV6 - 57, stringColor, true);
 		} else {
 			drawBox(21, yConstantV6 - 55, 299, yConstantV6 - 47, boxColor);
-			drawGUIText(title, 160, yConstantV6 - 55, _screenWidth - 1, stringColor, true);
+			drawGUIText(title, 0, 160, yConstantV6 - 55, stringColor, true);
 		}
 	} else {
 		drawBox(22, yConstantV6 - 56, 298, yConstantV6 - 48, boxColor);
-		drawGUIText(title, 160, yConstantV6 - 56, _screenWidth - 1, stringColor, true);
+		drawGUIText(title, 0, 160, yConstantV6 - 56, stringColor, true);
 	}
 
 	ScummEngine::drawDirtyScreenParts();
@@ -2829,12 +2828,12 @@ int ScummEngine::getGUIStringWidth(const char *str) {
 	return _charset->getStringWidth(0, (const byte *)str);
 }
 
-void ScummEngine::drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag) {
+void ScummEngine::drawGUIText(const char *buttonString, Common::Rect *clipRect, int textXPos, int textYPos, int textColor, bool centerFlag) {
 	int tmpRight = _string[5].right;
 
 	_string[5].xpos = textXPos;
 	_string[5].ypos = textYPos;
-	_string[5].right = rightRectClip;
+	_string[5].right = clipRect ? clipRect->right : _screenWidth - 1;
 	_string[5].center = centerFlag;
 	_string[5].color = textColor;
 	_string[5].charset = 1;
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index c757dd33b13..22aaf320ba5 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -164,8 +164,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
 
 	setTimerAndShakeFrequency();
 
-	memset(_savegameNames, 0, sizeof(_savegameNames));
-
 	camera.reset();
 	memset(_colorCycle, 0, sizeof(_colorCycle));
 	memset(_colorUsedByCycle, 0, sizeof(_colorUsedByCycle));
@@ -810,7 +808,9 @@ ScummEngine_v7::ScummEngine_v7(OSystem *syst, const DetectorResult &dr)
 	_textV7 = NULL;
 	_newTextRenderStyle = (_game.version == 8 || _language == Common::JA_JPN || _language == Common::KO_KOR || _language == Common::ZH_TWN);
 	_defaultTextClipRect = Common::Rect(_screenWidth, _screenHeight);
-	_wrappedTextClipRect = _newTextRenderStyle ? Common::Rect(10, 10, _screenWidth - 10, _screenHeight - 10)  : Common::Rect(_screenWidth, _screenHeight);
+	_wrappedTextClipRect = _newTextRenderStyle ? Common::Rect(10, 10, _screenWidth - 10, _screenHeight - 10) : Common::Rect(_screenWidth, _screenHeight);
+
+	_guiStringTransBuff = new byte[512];
 
 	_game.features |= GF_NEW_COSTUMES;
 }
@@ -823,6 +823,7 @@ ScummEngine_v7::~ScummEngine_v7() {
 
 	delete _insane;
 	delete _textV7;
+	delete[] _guiStringTransBuff;
 
 	free(_languageBuffer);
 	free(_languageIndex);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 41e40bf8c33..3570b394800 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -446,14 +446,10 @@ struct InternalGUIControl {
 	int highlightedTextColor;
 	int highlightedFillColor;
 	bool centerText;
-	const char *label;
+	Common::String label;
 	bool doubleLinesFlag;
 };
 
-struct GUISaveGameLabel {
-	char label[40];
-};
-
 /**
  * Base class for all SCUMM engines.
  */
@@ -622,7 +618,7 @@ protected:
 	const char _arrowUp[2] = {'\x18', '\0'};
 	const char _arrowDown[2] = {'\x19', '\0'};
 
-	GUISaveGameLabel _savegameNames[9];
+	Common::StringArray _savegameNames;
 	int _menuPage = 0;
 	int _mainMenuSavegameLabel = 1;
 	int _curDisplayedSaveSlotPage = 0;
@@ -673,7 +669,7 @@ protected:
 	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked);
 	virtual int getGUIStringHeight(const char *str);
 	virtual int getGUIStringWidth(const char *str);
-	virtual void drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag);
+	virtual void drawGUIText(const char *buttonString, Common::Rect *clipRect, int textXPos, int textYPos, int textColor, bool centerFlag);
 	void getSliderString(int stringId, int value, char *sliderString, int size);
 	virtual int getMusicVolume();
 	virtual int getSpeechVolume();
diff --git a/engines/scumm/scumm_v7.h b/engines/scumm/scumm_v7.h
index 3f2bf605be6..39c0a012491 100644
--- a/engines/scumm/scumm_v7.h
+++ b/engines/scumm/scumm_v7.h
@@ -133,7 +133,7 @@ protected:
 
 	void createTextRenderer(GlyphRenderer_v7 *gr) override;
 	void enqueueText(const byte *text, int x, int y, byte color, byte charset, TextStyleFlags flags);
-	void drawTextImmediately(const byte *text, int x, int y, byte color, byte charset, TextStyleFlags flags);
+	void drawTextImmediately(const byte *text, Common::Rect *clipRect, int x, int y, byte color, byte charset, TextStyleFlags flags);
 	void drawBlastTexts() override;
 	void showMessageDialog(const byte *msg) override;
 
@@ -147,7 +147,7 @@ protected:
 	const char *getGUIString(int stringId) override;
 	int getGUIStringHeight(const char *str) override;
 	int getGUIStringWidth(const char *str) override;
-	void drawGUIText(const char *buttonString, int textXPos, int textYPos, int rightRectClip, int textColor, bool centerFlag) override;
+	void drawGUIText(const char *buttonString, Common::Rect *clipRect, int textXPos, int textYPos, int textColor, bool centerFlag) override;
 	int getMusicVolume() override;
 	int getSpeechVolume() override;
 	int getSFXVolume() override;
@@ -179,6 +179,8 @@ protected:
 
 	int _blastTextQueuePos;
 	BlastText _blastTextQueue[50];
+
+	byte *_guiStringTransBuff = nullptr;
 };
 
 
diff --git a/engines/scumm/string_v7.cpp b/engines/scumm/string_v7.cpp
index a2504ffc6d3..46989e9db23 100644
--- a/engines/scumm/string_v7.cpp
+++ b/engines/scumm/string_v7.cpp
@@ -436,11 +436,11 @@ void ScummEngine_v7::enqueueText(const byte *text, int x, int y, byte color, byt
 	bt.flags = flags;
 }
 
-void ScummEngine_v7::drawTextImmediately(const byte *text, int x, int y, byte color, byte charset, TextStyleFlags flags) {
+void ScummEngine_v7::drawTextImmediately(const byte *text, Common::Rect *clipRect, int x, int y, byte color, byte charset, TextStyleFlags flags) {
 	// This function allows for a string to be immediately
 	// drawn on the screen without having to enqueueing it.
 	byte msg[256];
-	Common::Rect rect = _defaultTextClipRect;
+	Common::Rect rect = clipRect ? *clipRect : _defaultTextClipRect;
 	int effX = x;
 	TextStyleFlags effFlags = flags;
 	VirtScreen *vs = &_virtscr[kMainVirtScreen];


Commit: 13663bcb6f22601ba4431c359e00268aab211c3e
    https://github.com/scummvm/scummvm/commit/13663bcb6f22601ba4431c359e00268aab211c3e
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix v7 menu components positioning for non-CJK versions

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 8afbf0d9cc9..3be795a828e 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -537,7 +537,7 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 				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
@@ -2211,6 +2211,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 	_charset->setCurID(cid);
 	int yCntr = _screenHeight / 2;
 	int calculatedHeight = (110 + lh) / 2;
+	int yOffset = _useCJKMode ? 0 : 1;
 
 	// V6 auxiliary constant
 	yConstantV6 = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
@@ -2230,9 +2231,9 @@ void ScummEngine_v6::setUpMainMenuControls() {
 		getBannerColor(6),
 		getBannerColor(4),
 		(_game.version == 7 ? 16 : 20),
-		(_game.version == 7 ? yCntr - calculatedHeight : yConstantV6 - 60),
+		(_game.version == 7 ? yCntr - calculatedHeight - yOffset : yConstantV6 - 60),
 		(_game.version == 7 ? 303 : 300),
-		(_game.version == 7 ? yCntr + calculatedHeight : yConstantV6 + 60),
+		(_game.version == 7 ? yCntr + calculatedHeight + yOffset : yConstantV6 + 60),
 		_emptyMsg, 1, 1);
 
 	// Inner box
@@ -2328,7 +2329,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				getBannerColor(10),
 				getBannerColor(12),
 				(_game.version == 7 ? 108 : 102),
-				(_game.version == 7 ? yCntr - calculatedHeight + 25 : yConstantV6 - 39),
+				(_game.version == 7 ? yCntr - calculatedHeight - yOffset + 25 : yConstantV6 - 39),
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -2344,7 +2345,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				getBannerColor(10),
 				getBannerColor(12),
 				(_game.version == 7 ? 108 : 102),
-				(_game.version == 7 ? yCntr - calculatedHeight + 43 : yConstantV6 - 25),
+				(_game.version == 7 ? yCntr - calculatedHeight - yOffset + 43 : yConstantV6 - 25),
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -2360,7 +2361,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				getBannerColor(10),
 				getBannerColor(12),
 				(_game.version == 7 ? 108 : 102),
-				(_game.version == 7 ? yCntr - calculatedHeight + 61 : yConstantV6 - 11),
+				(_game.version == 7 ? yCntr - calculatedHeight - yOffset + 61 : yConstantV6 - 11),
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
@@ -2377,7 +2378,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(11),
 			getBannerColor(12),
 			(_game.version == 7 ? 108 : 102),
-			(_game.version == 7 ? yCntr - calculatedHeight + 85 : yConstantV6 + 17),
+			(_game.version == 7 ? yCntr - calculatedHeight - yOffset + 85 : yConstantV6 + 17),
 			-12,
 			-12,
 			_uncheckedBox, 1, 1);
@@ -2393,7 +2394,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(10),
 			getBannerColor(12),
 			(_game.version == 7 ? 108 : 102),
-			(_game.version == 7 ? yCntr - calculatedHeight + 99 : yConstantV6 + 31),
+			(_game.version == 7 ? yCntr - calculatedHeight - yOffset + 99 : yConstantV6 + 31),
 			-90,
 			-(lh + 4),
 			_uncheckedBox, 1, 1);
@@ -2409,7 +2410,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(6),
 			getBannerColor(7),
 			(_game.version == 7 ? 235 : 232),
-			(_game.version == 7 ? yCntr - calculatedHeight + 30 : yConstantV6 - 23),
+			(_game.version == 7 ? yCntr - calculatedHeight + yOffset * 6 + 30 : yConstantV6 - 23),
 			-60,
 			-(lh + 4),
 			getGUIString(gsSave), 1, 1);
@@ -2425,7 +2426,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(6),
 			getBannerColor(7),
 			(_game.version == 7 ? 235 : 232),
-			(_game.version == 7 ? yCntr - calculatedHeight + lh + 37 : yConstantV6 - 8),
+			(_game.version == 7 ? yCntr - calculatedHeight + lh  + yOffset * 6 + 37 : yConstantV6 - 8),
 			-60,
 			-(lh + 4),
 			getGUIString(gsLoad), 1, 1);
@@ -2441,7 +2442,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(6),
 			getBannerColor(7),
 			(_game.version == 7 ? 235 : 232),
-			(_game.version == 7 ? yCntr - calculatedHeight + lh * 2 + 44 : yConstantV6 + 7),
+			(_game.version == 7 ? yCntr - calculatedHeight + lh * 2  + yOffset * 6 + 44 : yConstantV6 + 7),
 			-60,
 			-(lh + 4),
 			getGUIString(gsPlay), 1, 1);
@@ -2457,7 +2458,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 			getBannerColor(6),
 			getBannerColor(7),
 			(_game.version == 7 ? 235 : 232),
-			(_game.version == 7 ? yCntr - calculatedHeight + lh * 3 + 51 : yConstantV6 + 22),
+			(_game.version == 7 ? yCntr - calculatedHeight + lh * 3  + yOffset * 6 + 51 : yConstantV6 + 22),
 			-60,
 			-(lh + 4),
 			getGUIString(gsQuit), 1, 1);
@@ -2510,7 +2511,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				getBannerColor(6),
 				getBannerColor(7),
 				(_game.version == 7 ? 235 : 232),
-				(_game.version == 7 ? yCntr - calculatedHeight + lh + 37: yConstantV6 - 8),
+				(_game.version == 7 ? yCntr - calculatedHeight + lh + yOffset * 6 + 37: yConstantV6 - 8),
 				-60,
 				-(lh + 4),
 				getGUIString(gsOK), 1, 1);
@@ -2520,13 +2521,13 @@ void ScummEngine_v6::setUpMainMenuControls() {
 		int cancelButtonAnchorY;
 		if (_menuPage == GUI_PAGE_LOAD) {
 			if (_game.version == 7) {
-				cancelButtonAnchorY = yCntr - calculatedHeight + (lh + 7) / 2 + lh + 37;
+				cancelButtonAnchorY = yCntr - calculatedHeight + (lh + 7) / 2 + lh + yOffset * 6 + 37;
 			} else {
 				cancelButtonAnchorY = yConstantV6 - 1;
 			}
 		} else {
 			if (_game.version == 7) {
-				cancelButtonAnchorY = yCntr - calculatedHeight + lh * 2 + 44;
+				cancelButtonAnchorY = yCntr - calculatedHeight + lh * 2 + yOffset * 6 + 44;
 			} else {
 				cancelButtonAnchorY = yConstantV6 + 7;
 			}
@@ -2650,6 +2651,7 @@ void ScummEngine::updateMainMenuControls() {
 	int yCntr = _screenHeight / 2;
 	int calculatedHeight = (110 + lh) / 2;
 	int textColor = getBannerColor(2);
+	int yOffset = _useCJKMode ? 0 : 1;
 
 	// V6 auxiliary constant
 	int yConstantV6 = _virtscr[kMainVirtScreen].topline + (_virtscr[kMainVirtScreen].h / 2);
@@ -2705,34 +2707,34 @@ 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 + 19, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 19, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 33, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 33, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 47, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 47, textColor, false);
 		} else {
 			convertMessageToString((const byte *)getGUIString(gsMusic), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 25, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 25, textColor, false);
 
 			convertMessageToString((const byte *)getGUIString(gsVoice), (byte *)msg, sizeof(msg));
-			drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 43, textColor, false);
+			drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 43, textColor, false);
 		}
 
 		convertMessageToString((const byte *)getGUIString(gsSfx), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 61, textColor, false);
+		drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 61, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsDisplayText), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 88, textColor, false);
+		drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 88, textColor, false);
 
 		convertMessageToString((const byte *)getGUIString(gsTextSpeed), (byte *)msg, sizeof(msg));
-		drawGUIText(msg, 0, 29, yCntr - calculatedHeight + 102, textColor, false);
+		drawGUIText(msg, 0, 29, yCntr - calculatedHeight - yOffset + 102, textColor, false);
 
-		drawLine(23, yCntr - calculatedHeight + 77, 204, yCntr - calculatedHeight + 77, getBannerColor(17));
-		drawLine(23, yCntr - calculatedHeight + 78, 204, yCntr - calculatedHeight + 78, getBannerColor(4));
-		drawLine(23, yCntr - calculatedHeight + 79, 204, yCntr - calculatedHeight + 79, getBannerColor(4));
-		drawLine(23, yCntr - calculatedHeight + 80, 204, yCntr - calculatedHeight + 80, getBannerColor(18));
+		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));
+		drawLine(23, yCntr - calculatedHeight - yOffset + 79, 204, yCntr - calculatedHeight - yOffset + 79, getBannerColor(4));
+		drawLine(23, yCntr - calculatedHeight - yOffset + 80, 204, yCntr - calculatedHeight - yOffset + 80, getBannerColor(18));
 
 		// The following line is from the Aaron Giles' interpreter of FT, based on the first DOS version;
 		// for some reason it doesn't get displayed in the DOS version, and it also overflows
@@ -2788,16 +2790,17 @@ void ScummEngine::drawMainMenuTitle(const char *title) {
 		_charset->setCurID(cid);
 		int yCntr = _screenHeight / 2;
 		int calculatedHeight = (110 + lh) / 2;
+		int yOffset = _useCJKMode ? 0 : 1;
 
 		drawBox(18,
-			yCntr - calculatedHeight + _screenTop + 4,
+			yCntr - calculatedHeight + _screenTop - yOffset + 4,
 			301,
-			yCntr - calculatedHeight + _screenTop + 3 + lh,
+			yCntr - calculatedHeight + _screenTop - yOffset + 3 + lh,
 			boxColor);
 
 		drawGUIText(title, 0,
 			159,
-			yCntr - calculatedHeight + 4,
+			yCntr - calculatedHeight - yOffset + 4,
 			stringColor,
 			true);
 	} else if (_game.version == 7) {


Commit: 62af2cff9b6a30ec76c0dcd23545583d117f6e1f
    https://github.com/scummvm/scummvm/commit/62af2cff9b6a30ec76c0dcd23545583d117f6e1f
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix _curGrabbedCursor memory leak

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 3be795a828e..c0a007055a3 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1603,6 +1603,8 @@ void ScummEngine::showMainMenu() {
 		_tempTextSurface = nullptr;
 		free(_tempMainSurface);
 		_tempMainSurface = nullptr;
+		free(_curGrabbedCursor);
+		_curGrabbedCursor = nullptr;
 	}
 
 	_savegameThumbnail.free();


Commit: 68ff04184fdfbe1100dccc7db1bec69a2704fde8
    https://github.com/scummvm/scummvm/commit/68ff04184fdfbe1100dccc7db1bec69a2704fde8
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: remove leftover/garbage code

(from my DIG CJK menu experiments)

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index c0a007055a3..ab84e20b6f3 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -846,7 +846,6 @@ const char *ScummEngine_v8::getGUIString(int stringId) {
 const char *ScummEngine_v7::getGUIString(int stringId) {
 	InfoDialog d(this, 0);
 	int resStringId = -1;
-	resStringId = VAR(stringId);
 
 	switch (stringId) {
 	case gsPause:


Commit: f05d770c69f25f7047d42d9e6b44312dc5422650
    https://github.com/scummvm/scummvm/commit/f05d770c69f25f7047d42d9e6b44312dc5422650
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (DIG/CJK) - implement special arrow buttons

Instead of printing the "normal" arrow glyphs, the DIG CJK interpreter draws slightly larger arrows.

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index ab84e20b6f3..e00534f5e8a 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -556,15 +556,29 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 			Common::strlcat(buttonString, "_", sizeof(buttonString));
 		}
 
-		int tmpRight = _string[5].right;
-		_string[5].right = _screenWidth - 1;
-
-		// The original CJK DIG interpreter limits the clipping to the save slots. Other elements
-		// seem to (theoretically) be allowed to draw text wherever they want...
-		bool isSaveSlot = (id >= 1 && id <= 9);
-		Common::Rect clipRect(relCentX, relCentY, x, y);
-		drawGUIText(buttonString, isSaveSlot ? &clipRect : 0, textXPos, textYPos, textColor, centerFlag);
-		_string[5].right = tmpRight;
+		if ((id == GUI_CTRL_ARROW_UP_BUTTON || id == GUI_CTRL_ARROW_DOWN_BUTTON) && _useCJKMode && _game.id == GID_DIG) {
+			// Instead of printing the "normal" arrow glyphs, the DIG CJK interpreter draws slightly larger arrows
+			// using the drawLine function. Instead of making a row of 14 drawLine calls here (like the original),
+			// I have implemented it like this...
+			static const int8 drwOffsets[2][29] = {
+				{ 0, 13, -5, 18, -5, 18, -3, 18, -3, 18, -3, 33, 0, 13, 5, 18, 5, 18, 3, 18, 3, 18, 3, 33, -3, 33, 3, 33, -1 },
+				{ 0, 33, -5, 28, -5, 28, -3, 28, -3, 28, -3, 13, 0, 33, 5, 28, 5, 28, 3, 28, 3, 28, 3, 13, -3, 13, 3, 13, -1 }
+			};
+
+			for (const int8 *s = drwOffsets[id - GUI_CTRL_ARROW_UP_BUTTON]; *s != -1; s += 4)
+				drawLine(textXPos + s[0], relCentY + s[1], textXPos + s[2], relCentY + s[3], textColor);
+
+		} else {
+			int tmpRight = _string[5].right;
+			_string[5].right = _screenWidth - 1;
+
+			// The original CJK DIG interpreter limits the clipping to the save slots. Other elements
+			// 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);
+			_string[5].right = tmpRight;
+		}
 
 		// Restore the previous charset
 		if (oldId)


Commit: 9e53af16c7d8a9a610587c06f76c44690c00e7da
    https://github.com/scummvm/scummvm/commit/9e53af16c7d8a9a610587c06f76c44690c00e7da
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix savegame replace prompt regression

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index e00534f5e8a..2ada7c33a15 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1325,7 +1325,7 @@ bool ScummEngine::canWriteGame(int slotId) {
 		return true;
 
 	listSavegames(saveList, ARRAYSIZE(saveList));
-	if (saveList[slotId]) {
+	if (saveList[slotId - 1]) {
 		convertMessageToString((const byte *)getGUIString(gsReplacePrompt), (byte *)msgLabelPtr, sizeof(msgLabelPtr));
 
 		// Fallback to a hardcoded string


Commit: c8ba69ed9a15e11b547df0afcf0411f65cfecdaa
    https://github.com/scummvm/scummvm/commit/c8ba69ed9a15e11b547df0afcf0411f65cfecdaa
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Make quit prompt behavior more consistent

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


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 2ada7c33a15..9dbea0abc32 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -85,6 +85,8 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	int rightLineColor, leftLineColor, bottomLineColor, topLineColor;
 	int normalTextColor, normalFillColor;
 
+	_messageBannerActive = true;
+
 	// Fetch the translated string for the message...
 	convertMessageToString((const byte *)msg, (byte *)localizedMsg, sizeof(localizedMsg));
 	ptrToBreak = strstr(localizedMsg, "\\n");
@@ -251,6 +253,8 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 	// getInternalGUIControlFromCoordinates() (which can cause serious errors)
 	_internalGUIControls[0].relativeCenterX = -1;
 
+	_messageBannerActive = false;
+
 	return ks;
 }
 
@@ -265,6 +269,8 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	int startingPointY;
 	int bannerSaveYStart;
 
+	_messageBannerActive = true;
+
 	// Fetch the translated string for the message...
 	convertMessageToString((const byte *)msg, (byte *)bannerMsg, sizeof(bannerMsg));
 
@@ -340,6 +346,8 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 	// getInternalGUIControlFromCoordinates() (which can cause serious errors)
 	_internalGUIControls[0].relativeCenterX = -1;
 
+	_messageBannerActive = false;
+
 	return ks;
 }
 
@@ -552,7 +560,8 @@ void ScummEngine::drawInternalGUIControl(int id, bool highlightColor) {
 
 		Common::strlcpy(buttonString, ctrl->label.c_str(), sizeof(buttonString));
 
-		if (_mainMenuSavegameLabel == id && _menuPage == GUI_PAGE_SAVE) {
+		if ((id >= GUI_CTRL_FIRST_SG && id <= GUI_CTRL_LAST_SG) &&
+			_mainMenuSavegameLabel == id && _menuPage == GUI_PAGE_SAVE) {
 			Common::strlcat(buttonString, "_", sizeof(buttonString));
 		}
 
@@ -614,6 +623,9 @@ void ScummEngine_v7::queryQuit() {
 			byte *curGrabbedCursor;
 			int curCursorWidth, curCursorHeight, curCursorHotspotX, curCursorHotspotY, curCursorState;
 
+			_messageBannerActive = true;
+			_comiQuitMenuIsOpen = true;
+
 			// Force the cursor to be ON...
 			int8 oldCursorState = _cursor.state;
 			_cursor.state = 1;
@@ -751,8 +763,10 @@ void ScummEngine_v7::queryQuit() {
 					 (ks.keycode == Common::KEYCODE_c && ks.hasFlags(Common::KBD_CTRL)));
 
 			ctrlId = getInternalGUIControlFromCoordinates(_mouse.x, _mouse.y);
-			if ((leftBtnPressed && ctrlId == 0) || (toupper(ks.ascii) == yesLabelPtr[0]))
+			if ((leftBtnPressed && ctrlId == 0) || (toupper(ks.ascii) == yesLabelPtr[0])) {
+				_quitByGUIPrompt = true;
 				quitGame();
+			}
 
 			// Restore the previous cursor...
 			_cursor.state = curCursorState;
@@ -789,6 +803,9 @@ void ScummEngine_v7::queryQuit() {
 			// Restore the old cursor state...
 			_cursor.state = oldCursorState;
 			CursorMan.showMouse(_cursor.state > 0);
+
+			_comiQuitMenuIsOpen = false;
+			_messageBannerActive = false;
 		} else {
 			ScummEngine::queryQuit();
 		}
@@ -1238,7 +1255,7 @@ void ScummEngine::queryQuit() {
 		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii ||
 			(ks.keycode == Common::KEYCODE_c && ks.hasFlags(Common::KBD_CTRL)) ||
 			(ks.keycode == Common::KEYCODE_x && ks.hasFlags(Common::KBD_ALT))) {
-			_quitByButton = true;
+			_quitByGUIPrompt = true;
 			quitGame();
 		}
 	}
@@ -1569,13 +1586,14 @@ void ScummEngine::showMainMenu() {
 				}
 			}
 		}
-	}
 
-	if (shouldQuit() && !_quitByButton) {
-		getEventManager()->resetQuit();
-		getEventManager()->resetReturnToLauncher();
-		clearClickedStatus();
-		queryQuit();
+		if (shouldQuit() && !_quitByGUIPrompt) {
+			clearClickedStatus();
+			getEventManager()->resetQuit();
+			getEventManager()->resetReturnToLauncher();
+			if (executeMainMenuOperation(GUI_CTRL_QUIT_BUTTON, 0, 0, hasLoadedState) || _quitByGUIPrompt)
+				break;
+		}
 	}
 
 	_mainMenuIsActive = false;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index e1d96c73290..e0eb2641d85 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -243,6 +243,26 @@ void ScummEngine::parseEvent(Common::Event event) {
 		if (isUsingOriginalGUI() && _mainMenuIsActive)
 			openMainMenuDialog();
 		break;
+	case Common::EVENT_RETURN_TO_LAUNCHER:
+	case Common::EVENT_QUIT:
+		if (isUsingOriginalGUI()) {
+			if (!_quitByGUIPrompt && !_mainMenuIsActive) {
+				// If another message banner is currently on the screen, close it
+				// and then execute the quit prompt. Otherwise, prompt the user.
+				getEventManager()->resetQuit();
+				getEventManager()->resetReturnToLauncher();
+				if (!_messageBannerActive) {
+					queryQuit();
+					_closeBannerAndQueryQuitFlag = false;
+				} else {
+					_closeBannerAndQueryQuitFlag = true;
+				}
+			} else if (_quitByGUIPrompt) {
+				if (!getEventManager()->shouldReturnToLauncher())
+					quitGame();
+			}
+		}
+		break;
 	default:
 		break;
 	}
@@ -514,6 +534,14 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 
 			if (shouldQuit())
 				return;
+
+			if (_closeBannerAndQueryQuitFlag) {
+				_closeBannerAndQueryQuitFlag = false;
+				Common::Event event;
+				event.type = Common::EVENT_QUIT;
+				getEventManager()->pushEvent(event);
+				return;
+			}
 		}
 	} else {
 		while (!validKey && !leftBtnClicked && !rightBtnClicked) {
@@ -531,6 +559,14 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 			if (shouldQuit())
 				return;
 
+			if (_closeBannerAndQueryQuitFlag && !_comiQuitMenuIsOpen) {
+				_closeBannerAndQueryQuitFlag = false;
+				Common::Event event;
+				event.type = Common::EVENT_QUIT;
+				getEventManager()->pushEvent(event);
+				return;
+			}
+
  			validKey = ks.keycode != Common::KEYCODE_INVALID &&
 					   ks.keycode != Common::KEYCODE_LALT    &&
 					   ks.keycode != Common::KEYCODE_RALT    &&
@@ -922,7 +958,9 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 
 		if ((lastKeyHit.keycode == Common::KEYCODE_c && lastKeyHit.hasFlags(Common::KBD_CTRL)) ||
 			(lastKeyHit.keycode == Common::KEYCODE_x && lastKeyHit.hasFlags(Common::KBD_ALT))) {
-			queryQuit();
+			Common::Event event;
+			event.type = Common::EVENT_QUIT;
+			getEventManager()->pushEvent(event);
 			return;
 		}
 
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 3570b394800..7c7b1fb8962 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -604,6 +604,9 @@ protected:
 	int32 _bannerColors[50]; // Colors for the original GUI
 	byte *_bannerMem = nullptr;
 	uint32 _bannerMemSize = 0;
+	bool _messageBannerActive = false;
+	bool _comiQuitMenuIsOpen = false;
+	bool _closeBannerAndQueryQuitFlag = false;
 
 	// The followings are needed for MI1 FM-Towns
 	byte *_textSurfBannerMem = nullptr;
@@ -624,7 +627,7 @@ protected:
 	int _curDisplayedSaveSlotPage = 0;
 	int _firstSaveStateOfList = 0; // For LOOM VGA
 	bool _mainMenuIsActive = false;
-	bool _quitByButton = false;
+	bool _quitByGUIPrompt = false;
 	char _mainMenuMusicSlider[17];
 	char _mainMenuSpeechSlider[17];
 	char _mainMenuSfxSlider[17];


Commit: daebac23fb56a6c4e4fa8e1573b239fdd22db3b6
    https://github.com/scummvm/scummvm/commit/daebac23fb56a6c4e4fa8e1573b239fdd22db3b6
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Notify the backend to bring up virtual keyboard on user prompts

These changes should make life easier for Android (and more...) users.

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 9dbea0abc32..c53e7603002 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1245,6 +1245,8 @@ void ScummEngine::queryQuit() {
 		localizedYesKey = msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1];
 		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
 
+		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+
 		// "Are you sure you want to quit?  (Y/N)"
 		Common::KeyState ks;
 		if (_game.version > 4)
@@ -1252,6 +1254,8 @@ void ScummEngine::queryQuit() {
 		else
 			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
 
+		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+
 		if (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii ||
 			(ks.keycode == Common::KEYCODE_c && ks.hasFlags(Common::KBD_CTRL)) ||
 			(ks.keycode == Common::KEYCODE_x && ks.hasFlags(Common::KBD_ALT))) {
@@ -1270,6 +1274,8 @@ void ScummEngine::queryRestart() {
 		localizedYesKey = msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1];
 		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
 
+		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+
 		// "Are you sure you want to restart?  (Y/N)"
 		Common::KeyState ks;
 		if (_game.version > 4)
@@ -1277,6 +1283,8 @@ void ScummEngine::queryRestart() {
 		else
 			ks = showOldStyleBannerAndPause(msgLabelPtr, 12, -1);
 
+		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+
 		if ((tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii) ||
 			(_game.version == 8 && ks.keycode == Common::KEYCODE_y)) {
 
@@ -1353,9 +1361,13 @@ bool ScummEngine::canWriteGame(int slotId) {
 		localizedYesKey = msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1];
 		msgLabelPtr[strnlen(msgLabelPtr, sizeof(msgLabelPtr)) - 1] = '\0';
 
+		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+
 		// "Do you want to replace this saved game?  (Y/N)"
 		Common::KeyState ks = showBannerAndPause(0, -1, msgLabelPtr);
 
+		_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+
 		return (tolower(localizedYesKey) == ks.ascii || toupper(localizedYesKey) == ks.ascii);
 	}
 
@@ -1365,6 +1377,9 @@ bool ScummEngine::canWriteGame(int slotId) {
 bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked) {
 	bool hasLoadedState = false;
 	int firstChar = (_game.version == 4 && _game.id != GID_LOOM) ? 0 : 4;
+
+	_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+
 	while (!shouldQuit()) {
 		waitForTimer(1);
 
@@ -1373,6 +1388,8 @@ bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicke
 		if (ks.keycode == Common::KEYCODE_RETURN) {
 			clearClickedStatus();
 			executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1, -1, hasLoadedState);
+
+			_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
 			return true;
 		} else if (leftMsClicked) {
 			clearClickedStatus();
@@ -1403,6 +1420,7 @@ bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicke
 		clearClickedStatus();
 	}
 
+	_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
 	return false;
 }
 


Commit: 537e6043f28e127fe265259271ebe77920276e53
    https://github.com/scummvm/scummvm/commit/537e6043f28e127fe265259271ebe77920276e53
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (GUI) - add mouse wheel support to save/load dialog

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


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index c53e7603002..3354d47bb2b 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1550,13 +1550,27 @@ void ScummEngine::showMainMenu() {
 				break;
 		} else {
 			// Wait for any mouse button presses...
-			waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked);
+			waitForBannerInput(-1, ks, leftMsClicked, rightMsClicked, _menuPage != GUI_PAGE_MAIN);
 		}
 
-		if (leftMsClicked || rightMsClicked) {
+		if (leftMsClicked || rightMsClicked || _mouseWheelFlag) {
 			curMouseX = _mouse.x;
 			curMouseY = _mouse.y;
 			clickedControl = getInternalGUIControlFromCoordinates(curMouseX, curMouseY);
+
+			// Mouse wheel movement with cursor over the list box. If there are actual button
+			// clicks, we ignore the wheel.
+			if (!(leftMsClicked || rightMsClicked)) {
+				if (clickedControl >= GUI_CTRL_FIRST_SG && clickedControl <= GUI_CTRL_LAST_SG) {
+					if (_mouseWheelFlag == Common::EVENT_WHEELUP)
+						clickedControl = (_internalGUIControls[GUI_CTRL_ARROW_UP_BUTTON].relativeCenterX != -1) ? GUI_CTRL_ARROW_UP_BUTTON : -1;
+					else if (_mouseWheelFlag == Common::EVENT_WHEELDOWN)
+						clickedControl = (_internalGUIControls[GUI_CTRL_ARROW_DOWN_BUTTON].relativeCenterX != -1) ? GUI_CTRL_ARROW_DOWN_BUTTON : -1;
+				} else {
+					clickedControl = -1;
+				}
+			}
+
 			clearClickedStatus();
 			leftMsClicked = false;
 			rightMsClicked = false;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index e0eb2641d85..faf62621fe3 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -231,11 +231,15 @@ void ScummEngine::parseEvent(Common::Event event) {
 	case Common::EVENT_WHEELDOWN:
 		if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD)
 			_keyPressed = Common::KeyState(Common::KEYCODE_7, 55);	// '7'
+		if (_mainMenuIsActive)
+			_mouseWheelFlag = Common::EVENT_WHEELDOWN;
 		break;
 
 	case Common::EVENT_WHEELUP:
 		if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD)
 			_keyPressed = Common::KeyState(Common::KEYCODE_6, 54);	// '6'
+		if (_mainMenuIsActive)
+			_mouseWheelFlag = Common::EVENT_WHEELUP;
 		break;
 
 	case Common::EVENT_MAINMENU:
@@ -298,6 +302,7 @@ void ScummEngine::clearClickedStatus() {
 	_mouseAndKeyboardStat = 0;
 	_leftBtnPressed &= ~msClicked;
 	_rightBtnPressed &= ~msClicked;
+	_mouseWheelFlag = 0;
 }
 
 void ScummEngine_v0::processInput() {
@@ -507,7 +512,7 @@ void ScummEngine_v7::processKeyboard(Common::KeyState lastKeyHit) {
 #endif
 
 
-void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked) {
+void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked, bool handeleMouseWheel) {
 	bool validKey = false;
 
 	if (waitTime && waitTime != -1) {
@@ -529,7 +534,7 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 					   ks.keycode != Common::KEYCODE_RALT    &&
 					   !(ks.keycode == Common::KEYCODE_s && ks.hasFlags(Common::KBD_ALT));
 
-			if (validKey || leftBtnClicked || rightBtnClicked)
+			if (validKey || leftBtnClicked || rightBtnClicked || (handeleMouseWheel && _mouseWheelFlag))
 				return;
 
 			if (shouldQuit())
@@ -544,7 +549,7 @@ void ScummEngine::waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool
 			}
 		}
 	} else {
-		while (!validKey && !leftBtnClicked && !rightBtnClicked) {
+		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)) {
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 7c7b1fb8962..2042866979f 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -669,7 +669,7 @@ protected:
 	virtual void queryQuit();
 	virtual void queryRestart();
 	virtual const char *getGUIString(int stringId);
-	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked);
+	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked, bool handeleMouseWheel = false);
 	virtual int getGUIStringHeight(const char *str);
 	virtual int getGUIStringWidth(const char *str);
 	virtual void drawGUIText(const char *buttonString, Common::Rect *clipRect, int textXPos, int textYPos, int textColor, bool centerFlag);
@@ -791,6 +791,8 @@ protected:
 	uint16 _mouseAndKeyboardStat = 0;
 	byte _leftBtnPressed = 0, _rightBtnPressed = 0;
 
+	int _mouseWheelFlag = 0; // For original save/load dialog only
+
 	/**
 	 * Last time runInputScript was run (measured in terms of OSystem::getMillis()).
 	 * This is currently only used for Indy3 mac to detect "double clicks".


Commit: 7cf77ce86589c1569d6f9cba51b6de3b138e426a
    https://github.com/scummvm/scummvm/commit/7cf77ce86589c1569d6f9cba51b6de3b138e426a
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: fix rtl feature

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


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 3354d47bb2b..ec81869185f 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -612,7 +612,7 @@ int ScummEngine::getInternalGUIControlFromCoordinates(int x, int y) {
 
 
 #ifdef ENABLE_SCUMM_7_8
-void ScummEngine_v7::queryQuit() {
+void ScummEngine_v7::queryQuit(bool returnToLauncher) {
 	if (isUsingOriginalGUI()) {
 		if (_game.version == 8 && !(_game.features & GF_DEMO)) {
 			int boxWidth, strWidth;
@@ -765,7 +765,13 @@ void ScummEngine_v7::queryQuit() {
 			ctrlId = getInternalGUIControlFromCoordinates(_mouse.x, _mouse.y);
 			if ((leftBtnPressed && ctrlId == 0) || (toupper(ks.ascii) == yesLabelPtr[0])) {
 				_quitByGUIPrompt = true;
-				quitGame();
+				if (returnToLauncher) {
+					Common::Event event;
+					event.type = Common::EVENT_RETURN_TO_LAUNCHER;
+					getEventManager()->pushEvent(event);
+				} else {
+					quitGame();
+				};
 			}
 
 			// Restore the previous cursor...
@@ -807,7 +813,7 @@ void ScummEngine_v7::queryQuit() {
 			_comiQuitMenuIsOpen = false;
 			_messageBannerActive = false;
 		} else {
-			ScummEngine::queryQuit();
+			ScummEngine::queryQuit(returnToLauncher);
 		}
 	} else {
 		ScummEngine::confirmExitDialog();
@@ -1236,7 +1242,7 @@ int ScummEngine::getSFXVolume() {
 	return CLIP<int>(_mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType) / 2, 0, 127);
 }
 
-void ScummEngine::queryQuit() {
+void ScummEngine::queryQuit(bool returnToLauncher) {
 	char msgLabelPtr[512];
 	char localizedYesKey;
 
@@ -1260,7 +1266,13 @@ void ScummEngine::queryQuit() {
 			(ks.keycode == Common::KEYCODE_c && ks.hasFlags(Common::KBD_CTRL)) ||
 			(ks.keycode == Common::KEYCODE_x && ks.hasFlags(Common::KBD_ALT))) {
 			_quitByGUIPrompt = true;
-			quitGame();
+			if (returnToLauncher) {
+				Common::Event event;
+				event.type = Common::EVENT_RETURN_TO_LAUNCHER;
+				getEventManager()->pushEvent(event);
+			} else {
+				quitGame();
+			}
 		}
 	}
 }
@@ -1621,8 +1633,6 @@ void ScummEngine::showMainMenu() {
 
 		if (shouldQuit() && !_quitByGUIPrompt) {
 			clearClickedStatus();
-			getEventManager()->resetQuit();
-			getEventManager()->resetReturnToLauncher();
 			if (executeMainMenuOperation(GUI_CTRL_QUIT_BUTTON, 0, 0, hasLoadedState) || _quitByGUIPrompt)
 				break;
 		}
@@ -1683,6 +1693,7 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool
 	int curSlot;
 	bool isLoomVga = (_game.id == GID_LOOM && _game.version == 4);
 	size_t labelSkip = (_game.version == 4 && _game.id != GID_LOOM) ? 0 : 4;
+	bool rtlRequest = getEventManager()->shouldReturnToLauncher();
 
 	switch (op) {
 	case GUI_CTRL_SAVE_BUTTON:
@@ -1704,7 +1715,9 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool
 	case GUI_CTRL_PLAY_BUTTON:
 		return true;
 	case GUI_CTRL_QUIT_BUTTON:
-		queryQuit();
+		getEventManager()->resetQuit();
+		getEventManager()->resetReturnToLauncher();
+		queryQuit(rtlRequest);
 		if (_game.version == 7)
 			return true;
 		break;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index faf62621fe3..b6435a2368b 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -251,12 +251,13 @@ void ScummEngine::parseEvent(Common::Event event) {
 	case Common::EVENT_QUIT:
 		if (isUsingOriginalGUI()) {
 			if (!_quitByGUIPrompt && !_mainMenuIsActive) {
+				bool exitType = (event.type == Common::EVENT_RETURN_TO_LAUNCHER);
 				// If another message banner is currently on the screen, close it
 				// and then execute the quit prompt. Otherwise, prompt the user.
 				getEventManager()->resetQuit();
 				getEventManager()->resetReturnToLauncher();
 				if (!_messageBannerActive) {
-					queryQuit();
+					queryQuit(exitType);
 					_closeBannerAndQueryQuitFlag = false;
 				} else {
 					_closeBannerAndQueryQuitFlag = true;
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 2042866979f..3dd94916e5b 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -666,7 +666,7 @@ protected:
 	int getInternalGUIControlFromCoordinates(int x, int y);
 	virtual bool isSmushActive() { return false; }
 
-	virtual void queryQuit();
+	virtual void queryQuit(bool returnToLauncher);
 	virtual void queryRestart();
 	virtual const char *getGUIString(int stringId);
 	void waitForBannerInput(int32 waitTime, Common::KeyState &ks, bool &leftBtnClicked, bool &rightBtnClicked, bool handeleMouseWheel = false);
diff --git a/engines/scumm/scumm_v7.h b/engines/scumm/scumm_v7.h
index 39c0a012491..b90752cf80a 100644
--- a/engines/scumm/scumm_v7.h
+++ b/engines/scumm/scumm_v7.h
@@ -142,7 +142,7 @@ protected:
 	void loadLanguageBundle() override;
 	void playSpeech(const byte *ptr);
 
-	void queryQuit() override;
+	void queryQuit(bool returnToLauncher) override;
 	int getBannerColor(int bannerId) override;
 	const char *getGUIString(int stringId) override;
 	int getGUIStringHeight(const char *str) override;


Commit: c09ae8edcefefa79bb0f456af6287a452b6d1c03
    https://github.com/scummvm/scummvm/commit/c09ae8edcefefa79bb0f456af6287a452b6d1c03
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Implement draggable sliders for v6-v7 menus

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index ec81869185f..edd4131858f 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1494,6 +1494,7 @@ void ScummEngine::showMainMenu() {
 	int args[NUM_SCRIPT_LOCAL];
 	bool leftMsClicked = false, rightMsClicked = false;
 	int clickedControl = -1;
+	int heldControl = -1;
 	int curMouseX, curMouseY;
 	bool hasLoadedState = false;
 
@@ -1583,6 +1584,36 @@ void ScummEngine::showMainMenu() {
 				}
 			}
 
+			// Allow the user to drag the volume and text speed sliders horizontally;
+			// this feature isn't available in the original interpreters (v6-v7),
+			// but it makes the sliders a lot more comfortable to use, so there shouldn't be
+			// any harm in this.
+			while ((_game.version >= 6) && (_menuPage == GUI_PAGE_MAIN) && (_leftBtnPressed & 1)) {
+				// Allow the engine to fetch new mouse states...
+				waitForTimer(1);
+
+				// Register one and only one control for the duration of this loop...
+				if (heldControl == -1)
+					heldControl = getInternalGUIControlFromCoordinates(curMouseX, curMouseY);
+
+				// Choose among the available sliders, register the new mouse coordinates,
+				// and execute the control operation...
+				switch (heldControl) {
+				case GUI_CTRL_MUSIC_SLIDER:
+				case GUI_CTRL_SPEECH_SLIDER:
+				case GUI_CTRL_SFX_SLIDER:
+				case GUI_CTRL_TEXT_SPEED_SLIDER:
+					curMouseX = _mouse.x;
+					curMouseY = _mouse.y;
+					executeMainMenuOperation(heldControl, curMouseX, curMouseY, hasLoadedState);
+					break;
+				default:
+					break;
+				}
+			}
+
+			heldControl = -1;
+
 			clearClickedStatus();
 			leftMsClicked = false;
 			rightMsClicked = false;


Commit: ae88c0be13cab0cd2a3c10d16a2840e966f5dfbb
    https://github.com/scummvm/scummvm/commit/ae88c0be13cab0cd2a3c10d16a2840e966f5dfbb
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix v6 controls unavailable in floppy versions appearing when they shouldn't

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index edd4131858f..fac918c8aca 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -2426,7 +2426,7 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				-90,
 				-12,
 				_uncheckedBox, 1, 1);
-		} else {
+		} else if (_game.variant && strcmp(_game.variant, "Floppy")) {
 			// Music volume slider
 			setUpInternalGUIControl(GUI_CTRL_MUSIC_SLIDER,
 				getBannerColor(9),
@@ -2476,37 +2476,39 @@ void ScummEngine_v6::setUpMainMenuControls() {
 				_uncheckedBox, 1, 1);
 		}
 
-		// Display text checkbox
-		setUpInternalGUIControl(GUI_CTRL_DISPLAY_TEXT_CHECKBOX,
-			getBannerColor(9),
-			getBannerColor(10),
-			getBannerColor(18),
-			getBannerColor(17),
-			getBannerColor(20),
-			getBannerColor(19),
-			getBannerColor(11),
-			getBannerColor(12),
-			(_game.version == 7 ? 108 : 102),
-			(_game.version == 7 ? yCntr - calculatedHeight - yOffset + 85 : yConstantV6 + 17),
-			-12,
-			-12,
-			_uncheckedBox, 1, 1);
+		if (_game.variant && strcmp(_game.variant, "Floppy")) {
+			// Display text checkbox
+			setUpInternalGUIControl(GUI_CTRL_DISPLAY_TEXT_CHECKBOX,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(18),
+				getBannerColor(17),
+				getBannerColor(20),
+				getBannerColor(19),
+				getBannerColor(11),
+				getBannerColor(12),
+				(_game.version == 7 ? 108 : 102),
+				(_game.version == 7 ? yCntr - calculatedHeight - yOffset + 85 : yConstantV6 + 17),
+				-12,
+				-12,
+				_uncheckedBox, 1, 1);
 
-		// Text speed slider
-		setUpInternalGUIControl(GUI_CTRL_TEXT_SPEED_SLIDER,
-			getBannerColor(9),
-			getBannerColor(10),
-			getBannerColor(18),
-			getBannerColor(17),
-			getBannerColor(20),
-			getBannerColor(19),
-			getBannerColor(10),
-			getBannerColor(12),
-			(_game.version == 7 ? 108 : 102),
-			(_game.version == 7 ? yCntr - calculatedHeight - yOffset + 99 : yConstantV6 + 31),
-			-90,
-			-(lh + 4),
-			_uncheckedBox, 1, 1);
+			// Text speed slider
+			setUpInternalGUIControl(GUI_CTRL_TEXT_SPEED_SLIDER,
+				getBannerColor(9),
+				getBannerColor(10),
+				getBannerColor(18),
+				getBannerColor(17),
+				getBannerColor(20),
+				getBannerColor(19),
+				getBannerColor(10),
+				getBannerColor(12),
+				(_game.version == 7 ? 108 : 102),
+				(_game.version == 7 ? yCntr - calculatedHeight - yOffset + 99 : yConstantV6 + 31),
+				-90,
+				-(lh + 4),
+				_uncheckedBox, 1, 1);
+		}
 
 		// Save button
 		setUpInternalGUIControl(GUI_CTRL_SAVE_BUTTON,


Commit: 913eada820035ab534d1fc2b03d4490df4aeaaa6
    https://github.com/scummvm/scummvm/commit/913eada820035ab534d1fc2b03d4490df4aeaaa6
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (GUI) - minor improvement to mouse wheel handling

Make sure the wheel catches, even if the cursor is exactly between two save slots (and not actually over one of them).

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index fac918c8aca..db012e23748 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1574,6 +1574,20 @@ void ScummEngine::showMainMenu() {
 			// Mouse wheel movement with cursor over the list box. If there are actual button
 			// clicks, we ignore the wheel.
 			if (!(leftMsClicked || rightMsClicked)) {
+				// Unfortunately, there can be space (vertically) between the save slot controls,
+				// so the mouse wheel will not catch if the cursor happens to be right at that pixel.
+				// Thus, we also have to check for the GUI_CTRL_OUTER_BOX and the see if the cursor
+				// is within the save list bounds. 
+				if (clickedControl == GUI_CTRL_OUTER_BOX && _internalGUIControls[GUI_CTRL_FIRST_SG].relativeCenterX != -1 &&
+					_internalGUIControls[GUI_CTRL_LAST_SG].relativeCenterX != -1) {
+						Common::Rect saveList(_internalGUIControls[GUI_CTRL_FIRST_SG].relativeCenterX,
+							_internalGUIControls[GUI_CTRL_FIRST_SG].relativeCenterY,
+							_internalGUIControls[GUI_CTRL_LAST_SG].xPos + 1,
+							_internalGUIControls[GUI_CTRL_LAST_SG].yPos + 1);
+						// Doesn't matter which slot we assign, we just want to trigger the next if-clause.
+						clickedControl = saveList.contains(curMouseX, curMouseY) ? GUI_CTRL_FIRST_SG : -1;
+				}
+
 				if (clickedControl >= GUI_CTRL_FIRST_SG && clickedControl <= GUI_CTRL_LAST_SG) {
 					if (_mouseWheelFlag == Common::EVENT_WHEELUP)
 						clickedControl = (_internalGUIControls[GUI_CTRL_ARROW_UP_BUTTON].relativeCenterX != -1) ? GUI_CTRL_ARROW_UP_BUTTON : -1;


Commit: 5c47ccd4785083e683a0aa5df278312ffb9c8067
    https://github.com/scummvm/scummvm/commit/5c47ccd4785083e683a0aa5df278312ffb9c8067
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: Allow setting voice mode for SE Talkie games

Changed paths:
    engines/scumm/input.cpp


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index b6435a2368b..d7b5a0587d7 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -868,8 +868,8 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 
 		// Generally allow voice mode settings only for v6, 7 and 8.
 		// Also allow it for Indy4 Talkie, which does its own thing.
-		if (((VAR_VOICE_MODE != 0xFF) || (_game.id == GID_INDY4 &&
-				strcmp(_game.variant, "Floppy") && strcmp(_game.variant, "Amiga"))) &&
+		if (((VAR_VOICE_MODE != 0xFF) || !strcmp(_game.variant, "SE Talkie") ||
+			(_game.id == GID_INDY4 && strcmp(_game.variant, "Floppy") && strcmp(_game.variant, "Amiga"))) &&
 			(lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL))) {
 			int voiceMode = (_game.version == 5) ? _v5VoiceMode : VAR(VAR_VOICE_MODE);
 


Commit: c71d6d19cd4a725f9d3b4b27ecf730b1670c2ad5
    https://github.com/scummvm/scummvm/commit/c71d6d19cd4a725f9d3b4b27ecf730b1670c2ad5
Author: athrxx (athrxx at scummvm.org)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: (MI1/FM-TOWNS) - adjust bogus values to avoid assert

Regression from recent text clipping update. Now, the bogus values must at least make a valid rect, even if they're not used.

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index db012e23748..b5dc6ed9f50 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -167,8 +167,8 @@ Common::KeyState ScummEngine::showBannerAndPause(int bannerId, int32 waitTime, c
 		bannerMsgWidth = getGUIStringWidth(bannerMsg) / 2;
 		startingPointX = ((160 - bannerMsgWidth) - 8) & 0xFFF8;
 		startingPointY = (bannerMsgWidth + 168) | 0x7;
-		xPos = 1; // Bogus value, since it is unused
-		yPos = 1; // Bogus value, since it is unused
+		xPos = startingPointX + 1; // Bogus value, since it is unused
+		yPos = startingPointY + 1; // Bogus value, since it is unused
 		bannerSaveYStart = 78;
 	} else {
 		startingPointX = 156 - roundedWidth;


Commit: bb343ad6bd34f50c6482a35e7e4248bcfc2cacc6
    https://github.com/scummvm/scummvm/commit/bb343ad6bd34f50c6482a35e7e4248bcfc2cacc6
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: Fix nullptr access

Changed paths:
    engines/scumm/input.cpp


diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index d7b5a0587d7..a5b13fc9213 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -868,8 +868,8 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 
 		// Generally allow voice mode settings only for v6, 7 and 8.
 		// Also allow it for Indy4 Talkie, which does its own thing.
-		if (((VAR_VOICE_MODE != 0xFF) || !strcmp(_game.variant, "SE Talkie") ||
-			(_game.id == GID_INDY4 && strcmp(_game.variant, "Floppy") && strcmp(_game.variant, "Amiga"))) &&
+		if (((VAR_VOICE_MODE != 0xFF) || (_game.variant && (!strcmp(_game.variant, "SE Talkie") ||
+			(_game.id == GID_INDY4 && strcmp(_game.variant, "Floppy") && strcmp(_game.variant, "Amiga"))))) &&
 			(lastKeyHit.keycode == Common::KEYCODE_t && lastKeyHit.hasFlags(Common::KBD_CTRL))) {
 			int voiceMode = (_game.version == 5) ? _v5VoiceMode : VAR(VAR_VOICE_MODE);
 


Commit: 1c51cf639698ad724be4243476d877707384de09
    https://github.com/scummvm/scummvm/commit/1c51cf639698ad724be4243476d877707384de09
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Save and restore the verb surface before and after showing GUI elements

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 b5dc6ed9f50..3a16de1cb7b 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1115,7 +1115,7 @@ int ScummEngine::getBannerColor(int bannerId) {
 }
 
 void ScummEngine::saveSurfacesPreGUI() {
-	// Why are we saving not one but TWO surfaces? Bear with me:
+	// Why are we saving three surfaces? Bear with me:
 	// texts in v6 and below are drawn sometimes onto the main surface, while
 	// other times they are drawn onto the text surface.
 	//
@@ -1125,6 +1125,11 @@ void ScummEngine::saveSurfacesPreGUI() {
 	//
 	// We can do better than that! Let's save both the main and the text surfaces
 	// so that we can restore them later when we're done with the menu.
+	//
+	// Some edge cases can happen though: i.e. during the SAMNMAX credits there's
+	// not enough space for the menu to be drawn completely on the main surface,
+	// so the last line is being drawn on the verb surface; to address this, we
+	// save and restore that too.
 
 	uint32 curPix;
 
@@ -1133,6 +1138,7 @@ void ScummEngine::saveSurfacesPreGUI() {
 
 	_tempTextSurface = (byte *)malloc(_screenWidth * _screenHeight * sizeof(byte));
 	_tempMainSurface = (byte *)malloc(_virtscr[kMainVirtScreen].w * _virtscr[kMainVirtScreen].h * sizeof(byte));
+	_tempVerbSurface = (byte *)malloc(_virtscr[kVerbVirtScreen].w * _virtscr[kVerbVirtScreen].h * sizeof(byte));
 
 	if (_tempMainSurface) {
 		for (int y = 0; y < _virtscr[kMainVirtScreen].h; y++) {
@@ -1143,6 +1149,15 @@ void ScummEngine::saveSurfacesPreGUI() {
 		}
 	}
 
+	if (_tempVerbSurface) {
+		for (int y = 0; y < _virtscr[kVerbVirtScreen].h; y++) {
+			for (int x = 0; x < _virtscr[kVerbVirtScreen].w; x++) {
+				curPix = _virtscr[kVerbVirtScreen].getPixel(x, y);
+				_tempVerbSurface[x + y * _virtscr[kVerbVirtScreen].w] = curPix;
+			}
+		}
+	}
+
 	if (_tempTextSurface) {
 		for (int y = 0; y < _screenHeight; y++) {
 			for (int x = 0; x < _screenWidth; x++) {
@@ -1193,6 +1208,20 @@ void ScummEngine::restoreSurfacesPostGUI() {
 
 		_virtscr[kMainVirtScreen].setDirtyRange(0, _virtscr[kMainVirtScreen].h);
 	}
+
+	if (_tempVerbSurface) {
+		for (int y = 0; y < _virtscr[kVerbVirtScreen].h; y++) {
+			for (int x = 0; x < _virtscr[kVerbVirtScreen].w; x++) {
+				curPix = _tempVerbSurface[x + y * _virtscr[kVerbVirtScreen].w];
+				_virtscr[kVerbVirtScreen].setPixel(x, y, curPix);
+			}
+		}
+
+		free(_tempVerbSurface);
+		_tempVerbSurface = nullptr;
+
+		_virtscr[kVerbVirtScreen].setDirtyRange(0, _virtscr[kVerbVirtScreen].h);
+	}
 }
 
 void ScummEngine::toggleVoiceMode() {
@@ -1577,7 +1606,7 @@ void ScummEngine::showMainMenu() {
 				// Unfortunately, there can be space (vertically) between the save slot controls,
 				// so the mouse wheel will not catch if the cursor happens to be right at that pixel.
 				// Thus, we also have to check for the GUI_CTRL_OUTER_BOX and the see if the cursor
-				// is within the save list bounds. 
+				// is within the save list bounds.
 				if (clickedControl == GUI_CTRL_OUTER_BOX && _internalGUIControls[GUI_CTRL_FIRST_SG].relativeCenterX != -1 &&
 					_internalGUIControls[GUI_CTRL_LAST_SG].relativeCenterX != -1) {
 						Common::Rect saveList(_internalGUIControls[GUI_CTRL_FIRST_SG].relativeCenterX,
@@ -1721,6 +1750,8 @@ void ScummEngine::showMainMenu() {
 		_tempTextSurface = nullptr;
 		free(_tempMainSurface);
 		_tempMainSurface = nullptr;
+		free(_tempVerbSurface);
+		_tempVerbSurface = nullptr;
 		free(_curGrabbedCursor);
 		_curGrabbedCursor = nullptr;
 	}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 3dd94916e5b..06355359249 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -641,6 +641,7 @@ protected:
 	Graphics::Surface _savegameThumbnail;
 	byte *_tempTextSurface = nullptr;
 	byte *_tempMainSurface = nullptr;
+	byte *_tempVerbSurface = nullptr;
 	bool _postGUICharMask = false;
 
 	// Saved cursor pre and post GUI


Commit: 80a8b3cb17d3093e8aff240ea1bacf9c640292f8
    https://github.com/scummvm/scummvm/commit/80a8b3cb17d3093e8aff240ea1bacf9c640292f8
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Simplify the saving/restoring routines for the screen surfaces

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 3a16de1cb7b..48902d36691 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1131,40 +1131,41 @@ void ScummEngine::saveSurfacesPreGUI() {
 	// so the last line is being drawn on the verb surface; to address this, we
 	// save and restore that too.
 
-	uint32 curPix;
-
 	if (_game.version < 4 || _game.version > 6)
 		return;
 
-	_tempTextSurface = (byte *)malloc(_screenWidth * _screenHeight * 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));
 
 	if (_tempMainSurface) {
 		for (int y = 0; y < _virtscr[kMainVirtScreen].h; y++) {
-			for (int x = 0; x < _virtscr[kMainVirtScreen].w; x++) {
-				curPix = _virtscr[kMainVirtScreen].getPixel(x, y);
-				_tempMainSurface[x + y * _virtscr[kMainVirtScreen].w] = curPix;
-			}
+			memcpy(&_tempMainSurface[y * _virtscr[kMainVirtScreen].w],
+				_virtscr[kMainVirtScreen].getBasePtr(_virtscr[kMainVirtScreen].xstart, y),
+				_virtscr[kMainVirtScreen].w);
 		}
 	}
 
 	if (_tempVerbSurface) {
-		for (int y = 0; y < _virtscr[kVerbVirtScreen].h; y++) {
-			for (int x = 0; x < _virtscr[kVerbVirtScreen].w; x++) {
-				curPix = _virtscr[kVerbVirtScreen].getPixel(x, y);
-				_tempVerbSurface[x + y * _virtscr[kVerbVirtScreen].w] = curPix;
-			}
-		}
+		memcpy(_tempVerbSurface,
+			_virtscr[kVerbVirtScreen].getBasePtr(0, 0),
+			_virtscr[kVerbVirtScreen].pitch * _virtscr[kVerbVirtScreen].h);
 	}
 
 	if (_tempTextSurface) {
-		for (int y = 0; y < _screenHeight; y++) {
-			for (int x = 0; x < _screenWidth; x++) {
-				curPix = _textSurface.getPixel(x, y);
-				_tempTextSurface[x + y * _screenWidth] = curPix;
-				if (curPix != 0xFD && !(_game.version == 4 && _game.id == GID_LOOM)) {
-					_virtscr[kMainVirtScreen].setPixel(_virtscr[kMainVirtScreen].xstart + x, y, curPix);
+		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
+		// 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)) {
+			for (int y = 0; y < _screenHeight; y++) {
+				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]);
+					}
 				}
 			}
 		}
@@ -1172,18 +1173,12 @@ void ScummEngine::saveSurfacesPreGUI() {
 }
 
 void ScummEngine::restoreSurfacesPostGUI() {
-	uint32 curPix;
 
 	if (_game.version < 4 || _game.version > 6)
 		return;
 
 	if (_tempTextSurface) {
-		for (int y = 0; y < _screenHeight; y++) {
-			for (int x = 0; x < _screenWidth; x++) {
-				curPix = _tempTextSurface[x + y * _screenWidth];
-				_textSurface.setPixel(x, y, curPix);
-			}
-		}
+		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
@@ -1197,10 +1192,9 @@ void ScummEngine::restoreSurfacesPostGUI() {
 
 	if (_tempMainSurface) {
 		for (int y = 0; y < _virtscr[kMainVirtScreen].h; y++) {
-			for (int x = 0; x < _virtscr[kMainVirtScreen].w; x++) {
-				curPix = _tempMainSurface[x + y * _virtscr[kMainVirtScreen].w];
-				_virtscr[kMainVirtScreen].setPixel(x, y, curPix);
-			}
+			memcpy(_virtscr[kMainVirtScreen].getBasePtr(_virtscr[kMainVirtScreen].xstart, y),
+				&_tempMainSurface[y * _virtscr[kMainVirtScreen].w],
+				_virtscr[kMainVirtScreen].w);
 		}
 
 		free(_tempMainSurface);
@@ -1210,12 +1204,9 @@ void ScummEngine::restoreSurfacesPostGUI() {
 	}
 
 	if (_tempVerbSurface) {
-		for (int y = 0; y < _virtscr[kVerbVirtScreen].h; y++) {
-			for (int x = 0; x < _virtscr[kVerbVirtScreen].w; x++) {
-				curPix = _tempVerbSurface[x + y * _virtscr[kVerbVirtScreen].w];
-				_virtscr[kVerbVirtScreen].setPixel(x, y, curPix);
-			}
-		}
+		memcpy(_virtscr[kVerbVirtScreen].getBasePtr(0, 0),
+			_tempVerbSurface,
+			_virtscr[kVerbVirtScreen].pitch * _virtscr[kVerbVirtScreen].h);
 
 		free(_tempVerbSurface);
 		_tempVerbSurface = nullptr;


Commit: a71e03444e0deccc2cee520a5a9bac8dbfa93d1a
    https://github.com/scummvm/scummvm/commit/a71e03444e0deccc2cee520a5a9bac8dbfa93d1a
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Fix menu closing after failed replace savestate prompt

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 48902d36691..13dc80212e5 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1409,7 +1409,7 @@ bool ScummEngine::canWriteGame(int slotId) {
 bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicked, bool &rightMsClicked) {
 	bool hasLoadedState = false;
 	int firstChar = (_game.version == 4 && _game.id != GID_LOOM) ? 0 : 4;
-
+	bool opResult = true;
 	_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
 
 	while (!shouldQuit()) {
@@ -1419,10 +1419,10 @@ bool ScummEngine::userWriteLabelRoutine(Common::KeyState &ks, bool &leftMsClicke
 		rightMsClicked = false;
 		if (ks.keycode == Common::KEYCODE_RETURN) {
 			clearClickedStatus();
-			executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1, -1, hasLoadedState);
+			opResult = executeMainMenuOperation(GUI_CTRL_OK_BUTTON, -1, -1, hasLoadedState);
 
 			_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
-			return true;
+			return opResult;
 		} else if (leftMsClicked) {
 			clearClickedStatus();
 			break;


Commit: 3475e94b6ca90b6c60dcd50a9a8d52fd8bdd5565
    https://github.com/scummvm/scummvm/commit/3475e94b6ca90b6c60dcd50a9a8d52fd8bdd5565
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Remove unnecessary call to the cursor restoring routine

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 13dc80212e5..b9f06dde157 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1813,7 +1813,6 @@ bool ScummEngine::executeMainMenuOperation(int op, int mouseX, int mouseY, bool
 						return true;
 					}
 				} else {
-					restoreCursorPostMenu();
 					convertMessageToString((const byte *)getGUIString(gsGameNotSaved), (byte *)saveScreenTitle, sizeof(saveScreenTitle));
 					if (_game.id == GID_DIG) {
 						showBannerAndPause(1, -1, saveScreenTitle);


Commit: e0a2dccd77955ac250115884dc330a2b3323ac55
    https://github.com/scummvm/scummvm/commit/e0a2dccd77955ac250115884dc330a2b3323ac55
Author: AndywinXp (andywinxp at gmail.com)
Date: 2022-09-08T19:10:42+02:00

Commit Message:
SCUMM: GUI: Save shake effect in showOldStyleBannerAndPause()

Changed paths:
    engines/scumm/gfx_gui.cpp


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index b9f06dde157..a3d9598d931 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -281,6 +281,10 @@ Common::KeyState ScummEngine::showOldStyleBannerAndPause(const char *msg, int co
 			restoreCharsetBg();
 	}
 
+	// Pause shake effect
+	_shakeTempSavedState = _shakeEnabled;
+	setShake(0);
+
 	// Pause the engine
 	PauseToken pt = pauseEngine();
 




More information about the Scummvm-git-logs mailing list