[Scummvm-git-logs] scummvm branch-2-7 -> 1a0b05dcff76e258774310475e89eed479bf583c

AndywinXp noreply at scummvm.org
Wed Jul 5 18:40:40 UTC 2023


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

Summary:
193dda7d40 SCUMM: SAMNMAX: Fix cursor being invisible after load
765f6033f6 SCUMM: SAMNMAX: Fix bug #14468
ad4e3abfc6 SCUMM: SAMNMAX: Don't run post-load script for non-available quicksaves
12ce9790b5 SCUMM: SAMNMAX: Post-load fix for savegames presenting bug #14467
cccac84717 SCUMM: SAMNMAX: Fix bug #14467
fd8cf5dee5 SCUMM: ZAK (FM-Towns): Fix bug #14387
1a0b05dcff SCUMM: v0-1-2-3: Implement post-load fixes (from orig. menu to GMM)


Commit: 193dda7d40910b7862d906273d9b2e8f13ae37ba
    https://github.com/scummvm/scummvm/commit/193dda7d40910b7862d906273d9b2e8f13ae37ba
Author: AndywinXp (andywinxp at gmail.com)
Date: 2023-07-05T20:36:22+02:00

Commit Message:
SCUMM: SAMNMAX: Fix cursor being invisible after load

This happened when creating savestates within the original menu
and then loading them from the GMM

Changed paths:
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index bef3d67a035..6c15b79719c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2730,6 +2730,12 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 
 			if (success && (_saveTemporaryState || _game.version == 8) && VAR_GAME_LOADED != 0xFF)
 				VAR(VAR_GAME_LOADED) = (_game.version == 8) ? 1 : GAME_PROPER_LOAD;
+
+			// If we are here, it means that we are loading a game from the ScummVM menu;
+			// let's call the exit save/load script (only used in v6) to restore the cursor
+			// properly.
+			if (VAR_SAVELOAD_SCRIPT2 != 0xFF && _currentRoom != 0)
+				runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, nullptr);
 		}
 
 		if (!success) {
@@ -2941,6 +2947,15 @@ void ScummEngine_v5::scummLoop_handleSaveLoad() {
 }
 
 void ScummEngine_v6::scummLoop_handleSaveLoad() {
+	// When launching a savegame from the launcher it may happen (if the game was
+	// saved within the original GUI) that the cursor can remain invisible until
+	// an event changes it. The original save dialog calls the exit save/load script
+	// to reinstate the cursor correctly, so we do that manually for this edge case.
+	if (_loadFromLauncher && VAR_SAVELOAD_SCRIPT2 != 0xFF && _currentRoom != 0) {
+		_loadFromLauncher = false;
+		runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, nullptr);
+	}
+
 	ScummEngine::scummLoop_handleSaveLoad();
 
 	if (_videoModeChanged) {


Commit: 765f6033f6723ccd706878340dacd50b34edcf6d
    https://github.com/scummvm/scummvm/commit/765f6033f6723ccd706878340dacd50b34edcf6d
Author: AndywinXp (andywinxp at gmail.com)
Date: 2023-07-05T20:36:22+02:00

Commit Message:
SCUMM: SAMNMAX: Fix bug #14468

I really have no idea why I wrote the code in such a way that
it attempted to load stuff that was never saved in the first place,
and I guess we'll never know. Findings by athrxx!

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


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index e1c2c600ce7..3c0122f8dac 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1750,10 +1750,6 @@ void ScummEngine::restoreCursorPostMenu() {
 		setCursorFromBuffer(_curGrabbedCursor, _curCursorWidth, _curCursorHeight, _curCursorWidth, true);
 		free(_curGrabbedCursor);
 		_curGrabbedCursor = nullptr;
-	} else if (_game.version == 6 && _game.id != GID_TENTACLE) {
-		setCursorHotspot(_curCursorHotspotX, _curCursorHotspotY);
-		_cursor.width = _curCursorWidth;
-		_cursor.height = _curCursorHeight;
 	}
 
 	// Restore the old cursor state...
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index d1faf051879..06734cb1f87 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -1438,6 +1438,17 @@ void ScummEngine::saveLoadWithSerializer(Common::Serializer &s) {
 	s.syncAsSint16LE(_cursor.height, VER(20));
 	s.syncAsSint16LE(_cursor.hotspotX, VER(20));
 	s.syncAsSint16LE(_cursor.hotspotY, VER(20));
+
+	// Post-load fix for broken SAMNMAX savegames which contain invalid
+	// cursor values; the value we're setting here should not count since
+	// it's being replaced by the post-load script, as long as it's not zero.
+	if (_game.version == 6 && (_cursor.width == 0 || _cursor.height == 0)) {
+		_cursor.width = 15;
+		_cursor.height = 15;
+		_cursor.hotspotX = 7;
+		_cursor.hotspotY = 7;
+	}
+
 	s.syncAsByte(_cursor.animate, VER(20));
 	s.syncAsByte(_cursor.animateIndex, VER(20));
 


Commit: ad4e3abfc68d14bcf5413fd739a1dd7a4fcec376
    https://github.com/scummvm/scummvm/commit/ad4e3abfc68d14bcf5413fd739a1dd7a4fcec376
Author: AndywinXp (andywinxp at gmail.com)
Date: 2023-07-05T20:36:23+02:00

Commit Message:
SCUMM: SAMNMAX: Don't run post-load script for non-available quicksaves

Fixes part of #14467

Changed paths:
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 6c15b79719c..6b35077bd51 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2734,7 +2734,7 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 			// If we are here, it means that we are loading a game from the ScummVM menu;
 			// let's call the exit save/load script (only used in v6) to restore the cursor
 			// properly.
-			if (VAR_SAVELOAD_SCRIPT2 != 0xFF && _currentRoom != 0)
+			if (success && VAR_SAVELOAD_SCRIPT2 != 0xFF && _currentRoom != 0)
 				runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, nullptr);
 		}
 


Commit: 12ce9790b502b9e69e1436dd685ccf00b323c559
    https://github.com/scummvm/scummvm/commit/12ce9790b502b9e69e1436dd685ccf00b323c559
Author: AndywinXp (andywinxp at gmail.com)
Date: 2023-07-05T20:36:23+02:00

Commit Message:
SCUMM: SAMNMAX: Post-load fix for savegames presenting bug #14467

The root cause of the issue is not solved yet, but this would allow for the
affected savegames to still work.

Changed paths:
    engines/scumm/script_v6.cpp


diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp
index 4e6ddd2694b..3b8b500eccc 100644
--- a/engines/scumm/script_v6.cpp
+++ b/engines/scumm/script_v6.cpp
@@ -916,6 +916,11 @@ void ScummEngine_v6::o6_cursorCommand() {
 			} else {
 				obj = popRoomAndObj(&room);
 			}
+
+			// Post-load fix for broken SAMNMAX savegames (see bug no. 14467)
+			if (_game.id == GID_SAMNMAX && obj == 0 && room == 93)
+				break;
+
 			setCursorFromImg(obj, room, 1);
 			break;
 		}


Commit: cccac8471779d9504d9c667bf39405073070c7e5
    https://github.com/scummvm/scummvm/commit/cccac8471779d9504d9c667bf39405073070c7e5
Author: AndywinXp (andywinxp at gmail.com)
Date: 2023-07-05T20:36:24+02:00

Commit Message:
SCUMM: SAMNMAX: Fix bug #14467

This was caused by the fact that the pre and post save screen scripts
were not being called, and this messed up the cursor state with savegames
created as quicksaves.

Also, renamed the variables containing said scripts numbers, so that
they are a little bit more meaningful now.

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


diff --git a/engines/scumm/gfx_gui.cpp b/engines/scumm/gfx_gui.cpp
index 3c0122f8dac..363abb42707 100644
--- a/engines/scumm/gfx_gui.cpp
+++ b/engines/scumm/gfx_gui.cpp
@@ -1716,6 +1716,7 @@ void ScummEngine::saveCursorPreMenu() {
 	if (_game.version > 6) {
 		// Backup the current cursor graphics and parameters
 		// and set up the main menu cursor...
+		// V6 handles this within scripts, so this is not needed.
 		_curGrabbedCursor = (byte *)malloc(sizeof(_grabbedCursor));
 		if (_curGrabbedCursor) {
 			memcpy(_curGrabbedCursor, _grabbedCursor, sizeof(_grabbedCursor));
@@ -1726,12 +1727,6 @@ 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);
@@ -1784,9 +1779,12 @@ void ScummEngine::showMainMenu() {
 	// 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);
+	// Run the entrance savescreen script, if available.
+	// This is only available in v6 and automatically brings up the
+	// default cross cursor. The post-save/load script will restore
+	// the previous cursor.
+	if (VAR_PRE_SAVELOAD_SCRIPT != 0xFF)
+		runScript(VAR(VAR_PRE_SAVELOAD_SCRIPT), 0, 0, nullptr);
 
 	_saveSound = 1;
 	_shakeTempSavedState = _shakeEnabled;
@@ -1978,8 +1976,8 @@ void ScummEngine::showMainMenu() {
 	// Run the exit savescreen script, if available
 	if (_saveScriptParam != 0 || _game.version == 6) {
 		args[0] = _saveScriptParam;
-		if (VAR_SAVELOAD_SCRIPT2 != 0xFF) {
-			runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, args);
+		if (VAR_POST_SAVELOAD_SCRIPT != 0xFF) {
+			runScript(VAR(VAR_POST_SAVELOAD_SCRIPT), 0, 0, args);
 			_saveScriptParam = 0;
 		}
 	}
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 8fe89291cd7..49ce5ab9ca8 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -1242,16 +1242,16 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
 		mainmenuKeyEnabled = true;
 
 	if (mainmenuKeyEnabled && !isUsingOriginalGUI() && (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.hasFlags(0))) {
-		if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
-			runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, nullptr);
+		if (VAR_PRE_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
+			runScript(VAR(VAR_PRE_SAVELOAD_SCRIPT), 0, 0, nullptr);
 
 		openMainMenuDialog();		// Display global main menu
 
 		// reload options
 		_enableAudioOverride = ConfMan.getBool("audio_override");
 
-		if (VAR_SAVELOAD_SCRIPT2 != 0xFF && _currentRoom != 0)
-			runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, nullptr);
+		if (VAR_POST_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
+			runScript(VAR(VAR_POST_SAVELOAD_SCRIPT), 0, 0, nullptr);
 
 	} else if (restartKeyEnabled && !isUsingOriginalGUI() && (lastKeyHit.keycode == Common::KEYCODE_F8 && lastKeyHit.hasFlags(0))) {
 		confirmRestartDialog();
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 6b35077bd51..80b12f51316 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2706,7 +2706,12 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 		if (_game.version == 8 && VAR_GAME_LOADED != 0xFF)
 			VAR(VAR_GAME_LOADED) = 0;
 
+		// Launch the pre-save/load script for SAMNMAX, to properly save the cursor...
+		if (_game.version == 6 && VAR_PRE_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
+			runScript(VAR(VAR_PRE_SAVELOAD_SCRIPT), 0, 0, nullptr);
+
 		Common::String filename;
+
 		if (_saveLoadFlag == 1) {
 			success = saveState(_saveLoadSlot, _saveTemporaryState, filename);
 			if (!success) {
@@ -2730,14 +2735,12 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 
 			if (success && (_saveTemporaryState || _game.version == 8) && VAR_GAME_LOADED != 0xFF)
 				VAR(VAR_GAME_LOADED) = (_game.version == 8) ? 1 : GAME_PROPER_LOAD;
-
-			// If we are here, it means that we are loading a game from the ScummVM menu;
-			// let's call the exit save/load script (only used in v6) to restore the cursor
-			// properly.
-			if (success && VAR_SAVELOAD_SCRIPT2 != 0xFF && _currentRoom != 0)
-				runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, nullptr);
 		}
 
+		// ... and finally launch the post-save/load script for SAMNMAX, to restore the cursor.
+		if (_game.version == 6 && VAR_POST_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
+			runScript(VAR(VAR_POST_SAVELOAD_SCRIPT), 0, 0, nullptr);
+
 		if (!success) {
 			Common::U32String buf = Common::U32String::format(errMsg, filename.c_str());
 
@@ -2951,9 +2954,9 @@ void ScummEngine_v6::scummLoop_handleSaveLoad() {
 	// saved within the original GUI) that the cursor can remain invisible until
 	// an event changes it. The original save dialog calls the exit save/load script
 	// to reinstate the cursor correctly, so we do that manually for this edge case.
-	if (_loadFromLauncher && VAR_SAVELOAD_SCRIPT2 != 0xFF && _currentRoom != 0) {
+	if (_loadFromLauncher && VAR_POST_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0) {
 		_loadFromLauncher = false;
-		runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, nullptr);
+		runScript(VAR(VAR_POST_SAVELOAD_SCRIPT), 0, 0, nullptr);
 	}
 
 	ScummEngine::scummLoop_handleSaveLoad();
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 7abafbe822c..e4e9297b3c0 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -1729,8 +1729,8 @@ public:
 	byte VAR_RIGHTBTN_DOWN = 0xFF;	// V7/V8
 	byte VAR_LEFTBTN_HOLD = 0xFF;	// V6/V72HE/V7/V8
 	byte VAR_RIGHTBTN_HOLD = 0xFF;	// V6/V72HE/V7/V8
-	byte VAR_SAVELOAD_SCRIPT = 0xFF;	// V6/V7 (not HE)
-	byte VAR_SAVELOAD_SCRIPT2 = 0xFF;	// V6/V7 (not HE)
+	byte VAR_PRE_SAVELOAD_SCRIPT = 0xFF;	// V6/V7 (not HE)
+	byte VAR_POST_SAVELOAD_SCRIPT = 0xFF;	// V6/V7 (not HE)
 	byte VAR_SAVELOAD_PAGE = 0xFF;		// V8
 	byte VAR_OBJECT_LABEL_FLAG = 0xFF;	// V8
 
diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp
index 66fca7a50ae..3a1f3a56a7d 100644
--- a/engines/scumm/vars.cpp
+++ b/engines/scumm/vars.cpp
@@ -185,8 +185,8 @@ void ScummEngine_v6::setupScummVars() {
 		VAR_NOSUBTITLES = 60;
 	} else {
 		VAR_VOICE_MODE = 60; // 0 is voice, 1 is voice+text, 2 is text only
-		VAR_SAVELOAD_SCRIPT = 61;
-		VAR_SAVELOAD_SCRIPT2 = 62;
+		VAR_PRE_SAVELOAD_SCRIPT = 61;
+		VAR_POST_SAVELOAD_SCRIPT = 62;
 	}
 
 	VAR_LEFTBTN_HOLD = 74;
@@ -413,8 +413,8 @@ void ScummEngine_v7::setupScummVars() {
 	VAR_INVENTORY_SCRIPT = 57;
 	VAR_CUTSCENE_START_SCRIPT = 58;
 	VAR_CUTSCENE_END_SCRIPT = 59;
-	VAR_SAVELOAD_SCRIPT = 60;
-	VAR_SAVELOAD_SCRIPT2 = 61;
+	VAR_PRE_SAVELOAD_SCRIPT = 60;
+	VAR_POST_SAVELOAD_SCRIPT = 61;
 
 	VAR_CUTSCENEEXIT_KEY = 62;
 	VAR_RESTART_KEY = 63;


Commit: fd8cf5dee5994bcbbc226144dc556a8623a07180
    https://github.com/scummvm/scummvm/commit/fd8cf5dee5994bcbbc226144dc556a8623a07180
Author: AndywinXp (andywinxp at gmail.com)
Date: 2023-07-05T20:36:24+02:00

Commit Message:
SCUMM: ZAK (FM-Towns): Fix bug #14387

This fixes a crash when loading from the GMM save states which had
been created from the original menu. This also fixes the auto-close of the
menu when a game is loaded from the original menu.

Changed paths:
    engines/scumm/saveload.cpp


diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 06734cb1f87..f8c71d71165 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -1858,8 +1858,11 @@ void ScummEngine::saveLoadWithSerializer(Common::Serializer &s) {
 			for (int v = 102 + 6; v <= 111; v++)
 				VAR(v) = 0;
 
-		// make sure the appropriate verbs and arrows are displayed
-		runInventoryScript(0);
+		// Make sure the appropriate verbs and arrows are displayed.
+		// We avoid doing that in room 50 (save room) since it can crash
+		// the game and trigger several unwanted side effects (bug #14387).
+		if (_currentRoom != 50)
+			runInventoryScript(0);
 	}
 
 	//


Commit: 1a0b05dcff76e258774310475e89eed479bf583c
    https://github.com/scummvm/scummvm/commit/1a0b05dcff76e258774310475e89eed479bf583c
Author: AndywinXp (andywinxp at gmail.com)
Date: 2023-07-05T20:36:25+02:00

Commit Message:
SCUMM: v0-1-2-3: Implement post-load fixes (from orig. menu to GMM)

This commit implements proper loading of savestates saved from
the original menu in v0-3 games and loaded either from launcher
or GMM. Why is all of this necessary? It is because these saves
are built under the assumption that they will be reloaded from the
main menu room, and that therefore there will be a graceful
termination of the global script handling the main menu.

Terminating said script gracefully implies cleaning up variables,
stopping menu related scripts, and reboot other scripts which had
previously been stopped.

This certainly doesn't happen when reloading said savestates from
the GMM/launcher, and what instead happens is, in order:
- The game loads from the menu room;
- The menu scripts continues from an inconsistent location,
effectively re-saving the game;
- This invalidates the thumbnail of the savestate, which will now
show a picture of the menu;
- Closing the menu gets the user back to the saved state,
with probably an inconsistent state of some variables and scripts.

This fixes all of this, by detecting if we are loading a savestate
saved from the original menu, and by manually running the correct
script operations for each game in order to correctly close the
menu and resume the game.

Please note that this commit works under different assumptions
from the ones pertaining the already available post-load fixes
(which assume that you are saving the game from GMM).

Changed paths:
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v0.h
    engines/scumm/scumm_v2.h
    engines/scumm/scumm_v3.h


diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 80b12f51316..b701bfa89f1 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2761,6 +2761,271 @@ void ScummEngine::scummLoop_handleSaveLoad() {
 	}
 }
 
+void ScummEngine_v0::terminateSaveMenuScript() {
+	// Stop the script which handles the save menu strings
+	stopScript(128);
+
+	// Terminate the cutscene state
+	o_endCutscene();
+
+	// Stop code for all the objects in the save screen
+	stopObjectCode();
+}
+
+void ScummEngine_v2::terminateSaveMenuScript() {
+	if (_game.id == GID_MANIAC) {
+		if (_game.version == 1 && _game.platform != Common::kPlatformNES) {
+			// Clear state 08 for objects 182 and 193
+			int obj[] = {182, 193};
+
+			for (int i = 0; i < ARRAYSIZE(obj); i++) {
+				putState(obj[i], getState(obj[i]) & ~kObjectState_08);
+				markObjectRectAsDirty(obj[i]);
+				clearDrawObjectQueue();
+			}
+		}
+
+		// Stop the script which handles the save menu strings
+		stopScript(133);
+
+		if (_game.version == 2 || _game.platform == Common::kPlatformNES) {
+			// Restart if needed
+			if (readVar(164) == 0) {
+				restart();
+			}
+		}
+
+		// Terminate the cutscene state
+		endCutscene();
+
+		// Stop code for all the objects in the save screen
+		stopObjectCode();
+	} else if (_game.id == GID_ZAK) {
+		// Stop the script which handles the save menu strings
+		stopScript(8);
+
+		// Terminate the cutscene state
+		endCutscene();
+
+		// Save actor 1 costume in VAR(1), and if it's costume 30, run script 108
+		Actor *a = derefActor(1, "terminateSaveMenuScript");
+		if (a) {
+			VAR(1) = a->_costume;
+			if (VAR(1) == 30)
+				runScript(108, false, false, nullptr);
+		}
+
+		// Stop code for all the objects in the save screen
+		stopObjectCode();
+	}
+}
+
+void ScummEngine_v3::terminateSaveMenuScript() {
+	if (_game.id == GID_ZAK) {
+		// Restore variables
+		runScript(204, false, false, nullptr);
+
+		// Stop the script which handles the save screen strings
+		stopScript(203);
+
+		// Restore the verbs (adapted from o5_saveRestoreVerbs(), SO_RESTORE_VERBS)
+		int a = 1;
+		int b = 125;
+		int c = 4;
+		int slot, slot2;
+		while (a <= b) {
+			slot = getVerbSlot(a, c);
+			if (slot) {
+				slot2 = getVerbSlot(a, 0);
+				if (slot2)
+					killVerb(slot2);
+				slot = getVerbSlot(a, c);
+				_verbs[slot].saveid = 0;
+				drawVerb(slot, 0);
+				verbMouseOver(0);
+			}
+			a++;
+		}
+
+		// Restore VAR_VERB_SCRIPT with whatever value was in local variable 3
+		VAR(VAR_VERB_SCRIPT) = readVar(0x4003);
+
+		// Reallocate some strings (in the same order as the script does)
+		for (int i = 10; i < 24; i++) {
+			loadPtrToResource(rtString, i, nullptr);
+		}
+
+		loadPtrToResource(rtString, 9, nullptr);
+		loadPtrToResource(rtString, 8, nullptr);
+		loadPtrToResource(rtString, 33, nullptr);
+
+		// Terminate the cutscene state
+		endCutscene();
+
+		// Restore the previous sound
+		if (readVar(305)) {
+			_sound->addSoundToQueue(readVar(305));
+		}
+
+		// Show the cursor
+		_cursor.state++;
+		verbMouseOver(0);
+
+		// Enable user interaction
+		_userPut++;
+
+		// Stop code for all the objects in the save screen
+		stopObjectCode();
+	} else if (_game.id == GID_INDY3) {
+		// Restore variables
+		runScript(204, false, false, nullptr);
+		runScript(206, false, false, nullptr);
+
+		// Stop the script which handles the save screen strings
+		stopScript(203);
+
+		// Restore VAR_VERB_SCRIPT with whatever value was in local variable 4
+		VAR(VAR_VERB_SCRIPT) = readVar(0x4004);
+
+		// Reallocate some strings (in the same order as the script does)
+		for (int i = 10; i < 24; i++) {
+			loadPtrToResource(rtString, i, nullptr);
+		}
+
+		loadPtrToResource(rtString, 9, nullptr);
+		loadPtrToResource(rtString, 8, nullptr);
+		loadPtrToResource(rtString, 33, nullptr);
+
+		// Indy3 VGA only: draw a black box
+		if ((_game.features & GF_OLD256) && _game.platform != Common::kPlatformFMTowns)
+			drawBox(0, 160, 319, 190, 0);
+
+		// Restore the verbs (adapted from o5_saveRestoreVerbs(), SO_RESTORE_VERBS)
+		int a = 1;
+		int b = 125;
+		int c = 4;
+		int slot, slot2;
+		while (a <= b) {
+			slot = getVerbSlot(a, c);
+			if (slot) {
+				slot2 = getVerbSlot(a, 0);
+				if (slot2)
+					killVerb(slot2);
+				slot = getVerbSlot(a, c);
+				_verbs[slot].saveid = 0;
+				drawVerb(slot, 0);
+				verbMouseOver(0);
+			}
+			a++;
+		}
+
+		// Re-stop script 203 (probably an oversight in the script)
+		stopScript(203);
+
+		// Restore the previous sound
+		if (readVar(0x4007)) {
+			_sound->addSoundToQueue(readVar(0x4007));
+		}
+
+		// Terminate the cutscene state
+		endCutscene();
+
+		// If local variable 0 and the override flag are set, chain script 119
+		if (readVar(0x4000)) {
+			if (VAR(VAR_OVERRIDE)) {
+				int cur = _currentScript;
+
+				vm.slot[cur].number = 0;
+				vm.slot[cur].status = ssDead;
+				_currentScript = 0xFF;
+
+				runScript(119, vm.slot[cur].freezeResistant, vm.slot[cur].recursive, nullptr);
+			}
+		}
+
+		// Show the cursor
+		_cursor.state++;
+		verbMouseOver(0);
+
+		// Enable user interaction
+		_userPut++;
+
+		// Stop code for all the objects in the save screen
+		stopObjectCode();
+	} else if (_game.id == GID_LOOM) {
+		if (_game.platform == Common::kPlatformFMTowns)
+			// Stop the script which handles the save screen strings
+			stopScript(202);
+
+		// Set VAR(VAR_VERB_SCRIPT) to local variable 2
+		VAR(VAR_VERB_SCRIPT) = readVar(0x4002);
+
+		// Reallocate some strings (in the same order as the script does)
+		for (int i = 9; i < 21; i++) {
+			loadPtrToResource(rtString, i, nullptr);
+		}
+
+		// Stop the script which handles the save screen strings
+		// (in FM-Towns case this will be a duplicate call)
+		stopScript(202);
+
+		if (_game.platform == Common::kPlatformFMTowns) {
+			// Set bit 14 of VAR(214) to 0
+			writeVar(0x8d6e, 0);
+		} else {
+			// Set bit 13 of VAR(214) to 0
+			writeVar(0x8d6d, 0);
+		}
+
+		// Set variable 100 to 0
+		VAR(100) = 0;
+
+		if (_game.platform == Common::kPlatformFMTowns) {
+			// Set the states of objects 909, 908, 903 and 904 to 0
+			int obj[] = {909, 908, 903, 904};
+			for (int i = 0; i < ARRAYSIZE(obj); i++) {
+				putState(obj[i], 0);
+				markObjectRectAsDirty(obj[i]);
+				if (_bgNeedsRedraw)
+					clearDrawObjectQueue();
+			}
+		}
+
+		// Terminate the cutscene state
+		endCutscene();
+
+		// Launch sound restore script
+		if (_game.platform == Common::kPlatformFMTowns && VAR(163)) {
+			int soundArgs[NUM_SCRIPT_LOCAL];
+			memset(soundArgs, 0, sizeof(soundArgs));
+			soundArgs[0] = VAR(163);
+			runScript(38, false, false, soundArgs);
+		}
+
+		// Show the cursor
+		_cursor.state++;
+		verbMouseOver(0);
+
+		// Enable user interaction
+		_userPut++;
+
+		// Chain script 5 (or 6 for FM-Towns)
+		int chainedArgs[NUM_SCRIPT_LOCAL];
+		int cur = _currentScript;
+		int scriptToChain = _game.platform == Common::kPlatformFMTowns ? 6 : 5;
+
+		chainedArgs[0] = 0;
+		vm.slot[cur].number = 0;
+		vm.slot[cur].status = ssDead;
+		_currentScript = 0xFF;
+
+		runScript(scriptToChain, vm.slot[cur].freezeResistant, vm.slot[cur].recursive, chainedArgs);
+
+		// Stop code for all the objects in the save screen
+		stopObjectCode();
+	}
+}
+
 void ScummEngine_v3::scummLoop_handleSaveLoad() {
 	if (isUsingOriginalGUI() && _saveLoadFlag == 0 && !_loadFromLauncher)
 		return;
@@ -2776,66 +3041,92 @@ void ScummEngine_v3::scummLoop_handleSaveLoad() {
 		bool restoreFMTownsSounds = (_townsPlayer != nullptr);
 
 		if (_game.id == GID_LOOM) {
-			// HACK as in game save stuff isn't supported exactly as in the original interpreter when using the
-			// ScummVM save/load dialog. The original save/load screen uses a special script (which we cannot
-			// call without displaying that screen) which will also makes some necessary follow-up operations. We
-			// simply try to achieve that manually. It fixes bugs #6011 and #13369.
-			// We just have to kind of pretend that we've gone through the save/load "room" (with all the right
-			// variables in place), so that all the operations get triggered properly.
-			// The Mac, DOS Talkie and PC-Engine don't have the bugs. We can rely on our old hack there, since
-			// it wouldn't work otherwise, anyway.
-			int args[NUM_SCRIPT_LOCAL];
-			memset(args, 0, sizeof(args));
-
-			uint saveLoadVar = 100;
-			if (_game.platform == Common::kPlatformMacintosh)
-				saveLoadVar = 105;
-			else if (_game.platform == Common::kPlatformPCEngine || _game.version == 4)
-				saveLoadVar = 150;
-
-			// Run this hack only under conditions where the original save script could actually be executed.
-			// Otherwise this would cause all sorts of glitches. Also exclude Mac, PC-Engine and DOS Talkie...
-			if (saveLoadVar == 100 && _userPut > 0 && !isScriptRunning(VAR(VAR_VERB_SCRIPT))) {
-				uint16 prevFlag = VAR(214) & 0x6000;
-				beginCutscene(args);
-				uint16 blockVerbsFlag = VAR(214) & (0x6000 ^ prevFlag);
-				if (Actor *a = derefActor(VAR(VAR_EGO))) {
-					// This is used to restore the correct camera position.
-					VAR(171) = a->_walkbox;
-					VAR(172) = a->getRealPos().x;
-					VAR(173) = a->getRealPos().y;
-				}
-				startScene(70, nullptr, 0);
-				VAR(saveLoadVar) = 0;
-				VAR(214) &= ~blockVerbsFlag;
-				endCutscene();
-
-				if (_game.platform == Common::kPlatformFMTowns && VAR(163)) {
-					// Sound restore script. Unlike other versions which handle this
-					// inside the usual entry scripts, FM-Towns calls this from the save script.
-					memset(args, 0, sizeof(args));
-					args[0] = VAR(163);
-					runScript(38, false, false, args);
-				}
+			if (_currentRoom == 70) {
+				// If we are in the menu room (70), it means that we've saved
+				// the game from the original save menu and we are attempting
+				// to load it either from ScummVM launcher or from the GMM.
+				// This means that we have to terminate the menu script gracefully.
+				//
+				// Note that these post-load operations and the post-load fixes in the
+				// "else" block below work on totally different assumptions:
+				//
+				// - The formers assume that we saved the game from the original menu,
+				//   that we are loading it from GMM/launcher, and that we have to progress
+				//   the script in order to bring it to its post-load termination state.
+				//
+				// - The latters assume that we are loading a game which was saved within
+				//   GMM/launcher to begin with, so the post-load fixes are aimed at executing
+				//   only some of these operations (since we're not in the save room anyway).
+				updateScriptPtr();
+				getScriptBaseAddress();
+				resetScriptPointer();
+
+				terminateSaveMenuScript();
+			} else {
+				// HACK as in game save stuff isn't supported exactly as in the original interpreter when using the
+				// ScummVM save/load dialog. The original save/load screen uses a special script (which we cannot
+				// call without displaying that screen) which will also makes some necessary follow-up operations. We
+				// simply try to achieve that manually. It fixes bugs #6011 and #13369.
+				// We just have to kind of pretend that we've gone through the save/load "room" (with all the right
+				// variables in place), so that all the operations get triggered properly.
+				// The Mac, DOS Talkie and PC-Engine don't have the bugs. We can rely on our old hack there, since
+				// it wouldn't work otherwise, anyway.
+				int args[NUM_SCRIPT_LOCAL];
+				memset(args, 0, sizeof(args));
+
+				uint saveLoadVar = 100;
+				if (_game.platform == Common::kPlatformMacintosh)
+					saveLoadVar = 105;
+				else if (_game.platform == Common::kPlatformPCEngine || _game.version == 4)
+					saveLoadVar = 150;
+
+				// Run this hack only under conditions where the original save script could actually be executed.
+				// Otherwise this would cause all sorts of glitches. Also exclude Mac, PC-Engine and DOS Talkie...
+				if (saveLoadVar == 100 && _userPut > 0 && !isScriptRunning(VAR(VAR_VERB_SCRIPT))) {
+					uint16 prevFlag = VAR(214) & 0x6000;
+					beginCutscene(args);
+					uint16 blockVerbsFlag = VAR(214) & (0x6000 ^ prevFlag);
+					if (Actor *a = derefActor(VAR(VAR_EGO))) {
+						// This is used to restore the correct camera position.
+						VAR(171) = a->_walkbox;
+						VAR(172) = a->getRealPos().x;
+						VAR(173) = a->getRealPos().y;
+					}
+					startScene(70, nullptr, 0);
+					VAR(saveLoadVar) = 0;
+					VAR(214) &= ~blockVerbsFlag;
+					endCutscene();
 
-				restoreFMTownsSounds = false;
-
-			} else if (VAR(saveLoadVar) == 2) {
-				// This is our old hack. If verbs should be shown restore them.
-				byte restoreScript = (_game.platform == Common::kPlatformFMTowns) ? 17 : 18;
-				args[0] = 2;
-				runScript(restoreScript, 0, 0, args);
-				// Reset two variables, similiar to what the save script would do, to avoid minor glitches
-				// of the verb image on the right of the distaff (image remainung blank when moving the
-				// mouse cursor over an object, bug #13369).
-				VAR(saveLoadVar + 2) = VAR(saveLoadVar + 3) = 0;
-			}
+					if (_game.platform == Common::kPlatformFMTowns && VAR(163)) {
+						// Sound restore script. Unlike other versions which handle this
+						// inside the usual entry scripts, FM-Towns calls this from the save script.
+						memset(args, 0, sizeof(args));
+						args[0] = VAR(163);
+						runScript(38, false, false, args);
+					}
+
+					restoreFMTownsSounds = false;
 
+				} else if (VAR(saveLoadVar) == 2) {
+					// This is our old hack. If verbs should be shown restore them.
+					byte restoreScript = (_game.platform == Common::kPlatformFMTowns) ? 17 : 18;
+					args[0] = 2;
+					runScript(restoreScript, 0, 0, args);
+					// Reset two variables, similiar to what the save script would do, to avoid minor glitches
+					// of the verb image on the right of the distaff (image remainung blank when moving the
+					// mouse cursor over an object, bug #13369).
+					VAR(saveLoadVar + 2) = VAR(saveLoadVar + 3) = 0;
+				}
+			}
 		} else {
-			if (_game.platform == Common::kPlatformNES) {
+			if (_game.platform == Common::kPlatformNES && _currentRoom != 50) {
 				// WORKAROUND: Original save/load script ran this script
 				// after game load, and o2_loadRoomWithEgo() does as well
-				// this script starts character-dependent music
+				// this script starts character-dependent music.
+				//
+				// (This will not be run if the current room is the save room,
+				// as terminateSaveMenuScript() will be gracefully handling that)
+				//
 				// Fixes bug #3362: MANIACNES: Music Doesn't Start On Load Game
 				if (_game.platform == Common::kPlatformNES) {
 					runScript(5, 0, 0, nullptr);
@@ -2843,7 +3134,7 @@ void ScummEngine_v3::scummLoop_handleSaveLoad() {
 						_sound->addSoundToQueue(VAR(224));
 				}
 
-			} else if (_game.platform != Common::kPlatformC64 && _game.platform != Common::kPlatformMacintosh) {
+			} else if (_game.platform != Common::kPlatformMacintosh) {
 				// MM and ZAK (v1/2)
 				int saveLoadRoom = 50;
 				int saveLoadVar = 21;
@@ -2857,8 +3148,24 @@ void ScummEngine_v3::scummLoop_handleSaveLoad() {
 					saveLoadVar = 115;
 				}
 
-				// Only execute this if the original would even allow saving in that situation
-				if (VAR(saveLoadVar) == saveLoadEnable && _userPut > 0 && !(VAR_VERB_SCRIPT != 0xFF && isScriptRunning(VAR(VAR_VERB_SCRIPT)))) {
+				if (_currentRoom == saveLoadRoom) {
+					// If we are in the menu room, it means that we've saved
+					// the game from the original save menu and we are attempting
+					// to load it either from ScummVM launcher or from the GMM.
+					// This means that we have to terminate the menu script gracefully.
+
+					// Just as noted above, when handling post-load fixes for LOOM:
+					// these post-load operations work on different assumptions from
+					// the ones necessary for the post-load fixes on the "else if" block.
+					updateScriptPtr();
+					getScriptBaseAddress();
+					resetScriptPointer();
+
+					terminateSaveMenuScript();
+				} else if (_game.platform != Common::kPlatformC64 &&
+					VAR(saveLoadVar) == saveLoadEnable && _userPut > 0 &&
+					!(VAR_VERB_SCRIPT != 0xFF && isScriptRunning(VAR(VAR_VERB_SCRIPT)))) {
+					// Only execute this if the original would even allow saving in that situation
 					int args[NUM_SCRIPT_LOCAL];
 					memset(args, 0, sizeof(args));
 					beginCutscene(args);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index e4e9297b3c0..be0e2716c73 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -589,6 +589,8 @@ protected:
 
 	virtual void runBootscript();
 
+	virtual void terminateSaveMenuScript() {};
+
 	// Event handling
 public:
 	void parseEvents();	// Used by IMuseDigital::startSound
diff --git a/engines/scumm/scumm_v0.h b/engines/scumm/scumm_v0.h
index 3ebcdea9c2c..dc60cb2dc90 100644
--- a/engines/scumm/scumm_v0.h
+++ b/engines/scumm/scumm_v0.h
@@ -86,6 +86,7 @@ protected:
 	void processInput() override;
 
 	void saveLoadWithSerializer(Common::Serializer &s) override;
+	void terminateSaveMenuScript() override;
 
 	bool objIsActor(int obj) override;
 	int objToActor(int obj) override;
diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h
index 264b2bc25e9..d65b48b198f 100644
--- a/engines/scumm/scumm_v2.h
+++ b/engines/scumm/scumm_v2.h
@@ -64,6 +64,7 @@ protected:
 	void decodeParseString() override;
 
 	void saveLoadWithSerializer(Common::Serializer &s) override;
+	void terminateSaveMenuScript() override;
 
 	void processKeyboard(Common::KeyState lastKeyHit) override;
 
diff --git a/engines/scumm/scumm_v3.h b/engines/scumm/scumm_v3.h
index d6a32450ca9..8b3e5c49065 100644
--- a/engines/scumm/scumm_v3.h
+++ b/engines/scumm/scumm_v3.h
@@ -39,6 +39,7 @@ protected:
 	void setupOpcodes() override;
 
 	void scummLoop_handleSaveLoad() override;
+	void terminateSaveMenuScript() override;
 
 	void readRoomsOffsets() override;
 	void loadCharset(int no) override;




More information about the Scummvm-git-logs mailing list