[Scummvm-git-logs] scummvm master -> 1f0334ee6b0290465590dd30135e4679615e816e

sluicebox 22204938+sluicebox at users.noreply.github.com
Mon Apr 20 07:30:15 UTC 2020


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

Summary:
916ce02661 SCI: Factor save game code into functions
12d37a352b SCI32: Implement KQ7/SHIVERS custom Mac saving
1f0334ee6b SCI32: Don't delete planes on restore in all Mac games


Commit: 916ce02661b9f3bef2d98dae667137160fed00ce
    https://github.com/scummvm/scummvm/commit/916ce02661b9f3bef2d98dae667137160fed00ce
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2020-04-19T23:33:54-07:00

Commit Message:
SCI: Factor save game code into functions

Factors some common save game code into functions and creates an
overload of GuestAdditions::runSaveRestore that doesn't rely on
SCI memory for returning the description string, all of which will
be used by the custom save/restore kMacPlatform32 subops.

Changed paths:
    engines/sci/detection.cpp
    engines/sci/engine/file.cpp
    engines/sci/engine/file.h
    engines/sci/engine/guest_additions.cpp
    engines/sci/engine/guest_additions.h
    engines/sci/engine/kfile.cpp
    engines/sci/engine/savegame.cpp
    engines/sci/engine/savegame.h


diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 53c1e2e0a5..9c5719ed42 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -938,28 +938,11 @@ Common::Error SciEngine::loadGameState(int slot) {
 }
 
 Common::Error SciEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
-	Common::String fileName = Common::String::format("%s.%03d", _targetName.c_str(), slot);
-	Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
-	Common::OutSaveFile *out = saveFileMan->openForSaving(fileName);
 	const char *version = "";
-	if (!out) {
-		warning("Opening savegame \"%s\" for writing failed", fileName.c_str());
-		return Common::kWritingFailed;
+	if (gamestate_save(_gamestate, slot, desc, version)) {
+		return Common::kNoError;
 	}
-
-	if (!gamestate_save(_gamestate, out, desc, version)) {
-		warning("Saving the game state to '%s' failed", fileName.c_str());
-		return Common::kWritingFailed;
-	} else {
-		out->finalize();
-		if (out->err()) {
-			warning("Writing the savegame failed");
-			return Common::kWritingFailed;
-		}
-		delete out;
-	}
-
-	return Common::kNoError;
+	return Common::kWritingFailed;
 }
 
 bool SciEngine::canLoadGameStateCurrently() {
diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp
index 8d93269604..e1b727c521 100644
--- a/engines/sci/engine/file.cpp
+++ b/engines/sci/engine/file.cpp
@@ -445,6 +445,24 @@ Common::MemoryReadStream *makeCatalogue(const uint maxNumSaves, const uint gameN
 
 	return new Common::MemoryReadStream(data, dataSize, DisposeAfterUse::YES);
 }
+
+int shiftSciToScummVMSaveId(int saveId) {
+	if (saveId == kMaxShiftedSaveId) {
+		return 0;
+	} else if (saveId >= 0) {
+		return saveId + kSaveIdShift;
+	}
+	return saveId;
+}
+
+int shiftScummVMToSciSaveId(int saveId) {
+	if (saveId == 0) {
+		return kMaxShiftedSaveId;
+	} else if (saveId > 0) {
+		return saveId - kSaveIdShift;
+	}
+	return saveId;
+}
 #endif
 
 FileHandle::FileHandle() : _in(0), _out(0) {
diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h
index be6acca88f..1583a25176 100644
--- a/engines/sci/engine/file.h
+++ b/engines/sci/engine/file.h
@@ -177,6 +177,9 @@ bool fillSavegameDesc(const Common::String &filename, SavegameDesc &desc);
  * compatible with game scripts' game catalogue readers.
  */
 Common::MemoryReadStream *makeCatalogue(const uint maxNumSaves, const uint gameNameSize, const Common::String &fileNamePattern, const bool ramaFormat);
+
+int shiftSciToScummVMSaveId(int saveId);
+int shiftScummVMToSciSaveId(int saveId);
 #endif
 
 } // End of namespace Sci
diff --git a/engines/sci/engine/guest_additions.cpp b/engines/sci/engine/guest_additions.cpp
index a9754afe91..017b41abee 100644
--- a/engines/sci/engine/guest_additions.cpp
+++ b/engines/sci/engine/guest_additions.cpp
@@ -669,12 +669,28 @@ reg_t GuestAdditions::promptSaveRestoreRama(EngineState *s, int argc, reg_t *arg
 	return make_reg(0, saveIndex);
 }
 
-int GuestAdditions::runSaveRestore(const bool isSave, reg_t outDescription, const int forcedSaveNo) const {
-	int saveNo;
+int GuestAdditions::runSaveRestore(const bool isSave, reg_t outDescription, const int forcedSaveId) const {
+	assert(!(isSave && outDescription.isNull()));
+
 	Common::String descriptionString;
+	int saveId = runSaveRestore(isSave, descriptionString, forcedSaveId);
+
+	if (!outDescription.isNull()) {
+		if (_segMan->isObject(outDescription)) {
+			outDescription = readSelector(_segMan, outDescription, SELECTOR(data));
+		}
+		SciArray &description = *_segMan->lookupArray(outDescription);
+		description.fromString(descriptionString);
+	}
+
+	return saveId;
+}
 
-	if (!isSave && forcedSaveNo != -1) {
-		saveNo = forcedSaveNo;
+int GuestAdditions::runSaveRestore(const bool isSave, Common::String &outDescription, const int forcedSaveId) const {
+	int saveId;
+
+	if (!isSave && forcedSaveId != -1) {
+		saveId = forcedSaveId;
 	} else {
 		const char *title;
 		const char *action;
@@ -687,36 +703,23 @@ int GuestAdditions::runSaveRestore(const bool isSave, reg_t outDescription, cons
 		}
 
 		GUI::SaveLoadChooser dialog(title, action, isSave);
-		saveNo = dialog.runModalWithCurrentTarget();
-		if (saveNo != -1) {
-			descriptionString = dialog.getResultString();
-			if (descriptionString.empty()) {
-				descriptionString = dialog.createDefaultSaveDescription(saveNo - 1);
+		saveId = dialog.runModalWithCurrentTarget();
+		if (saveId != -1) {
+			outDescription = dialog.getResultString();
+			if (outDescription.empty()) {
+				outDescription = dialog.createDefaultSaveDescription(saveId - 1);
 			}
 		}
 	}
 
-	assert(!isSave || !outDescription.isNull());
-	if (!outDescription.isNull()) {
-		if (_segMan->isObject(outDescription)) {
-			outDescription = readSelector(_segMan, outDescription, SELECTOR(data));
-		}
-		SciArray &description = *_segMan->lookupArray(outDescription);
-		description.fromString(descriptionString);
-	}
-
 	// The autosave slot in ScummVM takes up slot 0, but in SCI the first
 	// non-autosave save game number needs to be 0, so reduce the save
 	// number here to match what would come from the normal SCI save/restore
 	// dialog. Wrap slot 0 around to kMaxShiftedSaveId so that it remains
 	// a legal SCI value.
-	if (saveNo > 0) {
-		saveNo -= kSaveIdShift;
-	} else if (saveNo == 0) {
-		saveNo = kMaxShiftedSaveId;
-	}
+	saveId = shiftScummVMToSciSaveId(saveId);
 
-	return saveNo;
+	return saveId;
 }
 
 reg_t GuestAdditions::promptSaveRestoreHoyle5(EngineState *s, int argc, reg_t *argv) const {
diff --git a/engines/sci/engine/guest_additions.h b/engines/sci/engine/guest_additions.h
index cabcc4d620..713695261d 100644
--- a/engines/sci/engine/guest_additions.h
+++ b/engines/sci/engine/guest_additions.h
@@ -269,10 +269,11 @@ public:
 	 * @param isSave If true, the prompt is for saving.
 	 * @param outDescription Will be filled with the save game description.
 	 * Optional for loads, required for saves.
-	 * @param forcedSaveNo During delayed restore, force the returned save game
-	 * number to this value.
+	 * @param forcedSaveId During delayed restore, force the returned save game
+	 * id to this value.
 	 */
-	int runSaveRestore(const bool isSave, const reg_t outDescription, const int forcedSaveNo = -1) const;
+	int runSaveRestore(const bool isSave, const reg_t outDescription, const int forcedSaveId = -1) const;
+	int runSaveRestore(const bool isSave, Common::String &outDescription, const int forcedSaveId = -1) const;
 #endif
 
 #pragma mark -
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index b7e2a94a5d..633793100d 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -1151,31 +1151,10 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
 		s->_lastSaveNewId = savegameId;
 	}
 
-	s->r_acc = NULL_REG;
-
-	Common::String filename = g_sci->getSavegameName(savegameId);
-	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
-	Common::OutSaveFile *out;
-
-	out = saveFileMan->openForSaving(filename);
-	if (!out) {
-		warning("Error opening savegame \"%s\" for writing", filename.c_str());
-	} else {
-		if (!gamestate_save(s, out, game_description, version)) {
-			warning("Saving the game failed");
-		} else {
-			s->r_acc = TRUE_REG; // save successful
-		}
-
-		out->finalize();
-		if (out->err()) {
-			warning("Writing the savegame failed");
-			s->r_acc = NULL_REG; // write failure
-		}
-		delete out;
+	if (gamestate_save(s, savegameId, game_description, version)) {
+		return TRUE_REG;
 	}
-
-	return s->r_acc;
+	return NULL_REG;
 }
 
 reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) {
@@ -1221,23 +1200,8 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) {
 	if (findSavegame(saves, savegameId) == -1) {
 		s->r_acc = TRUE_REG;
 		warning("Savegame ID %d not found", savegameId);
-	} else {
-		Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
-		Common::String filename = g_sci->getSavegameName(savegameId);
-		Common::SeekableReadStream *in;
-
-		in = saveFileMan->openForLoading(filename);
-		if (in) {
-			// found a savegame file
-			gamestate_restore(s, in);
-			delete in;
-
-			gamestate_afterRestoreFixUp(s, savegameId);
-
-		} else {
-			s->r_acc = TRUE_REG;
-			warning("Savegame #%d not found", savegameId);
-		}
+	} else if (!gamestate_restore(s, savegameId)) {
+		s->r_acc = TRUE_REG; // signals failure
 	}
 
 	if (!s->r_acc.isNull()) {
@@ -1370,10 +1334,8 @@ reg_t kSaveGame32(EngineState *s, int argc, reg_t *argv) {
 			// Autosave slot 1 is a "new game" save
 			saveNo = kNewGameId;
 		}
-	} else if (saveNo == kMaxShiftedSaveId) {
-		saveNo = 0;
 	} else {
-		saveNo += kSaveIdShift;
+		saveNo = shiftSciToScummVMSaveId(saveNo);
 	}
 
 	if (g_sci->getGameId() == GID_PHANTASMAGORIA2 && s->callInStack(g_sci->getGameObject(), SELECTOR(bookMark))) {
@@ -1394,31 +1356,10 @@ reg_t kSaveGame32(EngineState *s, int argc, reg_t *argv) {
 		s->_segMan->freeArray(autoSaveNameId);
 	}
 
-	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
-	const Common::String filename = g_sci->getSavegameName(saveNo);
-	Common::OutSaveFile *saveStream = saveFileMan->openForSaving(filename);
-
-	if (saveStream == nullptr) {
-		warning("Error opening savegame \"%s\" for writing", filename.c_str());
-		return NULL_REG;
-	}
-
-	if (!gamestate_save(s, saveStream, saveDescription, gameVersion)) {
-		warning("Saving the game failed");
-		saveStream->finalize();
-		delete saveStream;
-		return NULL_REG;
-	}
-
-	saveStream->finalize();
-	if (saveStream->err()) {
-		warning("Writing the savegame failed");
-		delete saveStream;
-		return NULL_REG;
+	if (gamestate_save(s, saveNo, saveDescription, gameVersion)) {
+		return TRUE_REG;
 	}
-
-	delete saveStream;
-	return TRUE_REG;
+	return NULL_REG;
 }
 
 reg_t kRestoreGame32(EngineState *s, int argc, reg_t *argv) {
@@ -1444,26 +1385,14 @@ reg_t kRestoreGame32(EngineState *s, int argc, reg_t *argv) {
 			// Autosave slot 1 is a "new game" save
 			saveNo = kNewGameId;
 		}
-	} else if (saveNo == kMaxShiftedSaveId) {
-		saveNo = 0;
 	} else {
-		saveNo += kSaveIdShift;
+		saveNo = shiftSciToScummVMSaveId(saveNo);
 	}
 
-	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
-	const Common::String filename = g_sci->getSavegameName(saveNo);
-	Common::SeekableReadStream *saveStream = saveFileMan->openForLoading(filename);
-
-	if (saveStream == nullptr) {
-		warning("Savegame #%d not found", saveNo);
-		return NULL_REG;
+	if (gamestate_restore(s, saveNo)) {
+		return TRUE_REG;
 	}
-
-	gamestate_restore(s, saveStream);
-	delete saveStream;
-
-	gamestate_afterRestoreFixUp(s, saveNo);
-	return TRUE_REG;
+	return NULL_REG;
 }
 
 reg_t kCheckSaveGame32(EngineState *s, int argc, reg_t *argv) {
@@ -1475,10 +1404,8 @@ reg_t kCheckSaveGame32(EngineState *s, int argc, reg_t *argv) {
 		if (saveNo == 1) {
 			saveNo = kNewGameId;
 		}
-	} else if (saveNo == kMaxShiftedSaveId) {
-		saveNo = 0;
 	} else {
-		saveNo += kSaveIdShift;
+		saveNo = shiftSciToScummVMSaveId(saveNo);
 	}
 
 	SavegameDesc save;
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index b9cd58581a..3308f59027 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -1196,6 +1196,33 @@ void SegManager::reconstructClones() {
 
 #pragma mark -
 
+bool gamestate_save(EngineState *s, int saveId, const Common::String &savename, const Common::String &version) {
+	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+	const Common::String filename = g_sci->getSavegameName(saveId);
+
+	Common::OutSaveFile *saveStream = saveFileMan->openForSaving(filename);
+	if (saveStream == nullptr) {
+		warning("Error opening savegame \"%s\" for writing", filename.c_str());
+		return false;
+	}
+
+	if (!gamestate_save(s, saveStream, savename, version)) {
+		warning("Saving the game failed");
+		saveStream->finalize();
+		delete saveStream;
+		return false;
+	}
+
+	saveStream->finalize();
+	if (saveStream->err()) {
+		warning("Writing the savegame failed");
+		delete saveStream;
+		return false;
+	}
+
+	delete saveStream;
+	return true;
+}
 
 bool gamestate_save(EngineState *s, Common::WriteStream *fh, const Common::String &savename, const Common::String &version) {
 	Common::Serializer ser(nullptr, fh);
@@ -1345,6 +1372,23 @@ void gamestate_afterRestoreFixUp(EngineState *s, int savegameId) {
 	}
 }
 
+bool gamestate_restore(EngineState *s, int saveId) {
+	Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+	const Common::String filename = g_sci->getSavegameName(saveId);
+	Common::SeekableReadStream *saveStream = saveFileMan->openForLoading(filename);
+
+	if (saveStream == nullptr) {
+		warning("Savegame #%d not found", saveId);
+		return false;
+	}
+
+	gamestate_restore(s, saveStream);
+	delete saveStream;
+
+	gamestate_afterRestoreFixUp(s, saveId);
+	return true;
+}
+
 void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
 	SavegameMetadata meta;
 
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index 76f7cec58a..e8104d4764 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -97,22 +97,41 @@ struct SavegameMetadata {
 	uint8 avatarId;
 };
 
+/**
+* Saves a game state to the hard disk in a portable way.
+* @param s			The state to save
+* @param saveId		The id of the savegame
+* @param savename	The description of the savegame
+* @param version	The version string of the game
+* @return true on success, false otherwise
+*/
+bool gamestate_save(EngineState *s, int saveId, const Common::String &savename, const Common::String &version);
+
 /**
  * Saves a game state to the hard disk in a portable way.
  * @param s			The state to save
  * @param save		The stream to save to
  * @param savename	The description of the savegame
- * @return 0 on success, 1 otherwise
+ * @param version	The version string of the game
+ * @return true on success, false otherwise
  */
 bool gamestate_save(EngineState *s, Common::WriteStream *save, const Common::String &savename, const Common::String &version);
 
 // does a few fixups right after restoring a saved game
 void gamestate_afterRestoreFixUp(EngineState *s, int savegameId);
 
+/**
+* Restores a game state from a directory.
+* @param s			An older state from the same game
+* @param saveId		The id of the savegame to restore from
+* @return true on success, false otherwise
+*/
+bool gamestate_restore(EngineState *s, int saveId);
+
 /**
  * Restores a game state from a directory.
  * @param s			An older state from the same game
- * @param dirname	The subdirectory to restore from
+ * @param save		The stream to restore from
  */
 void gamestate_restore(EngineState *s, Common::SeekableReadStream *save);
 


Commit: 12d37a352b74ee9652e83fdb0c71888a4b7aa5cd
    https://github.com/scummvm/scummvm/commit/12d37a352b74ee9652e83fdb0c71888a4b7aa5cd
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2020-04-19T23:46:13-07:00

Commit Message:
SCI32: Implement KQ7/SHIVERS custom Mac saving

Implements the custom Mac save and restore kPlatform subops
for KQ7 and Shivers. Still TODO: Mothergoose and Lighthouse.

Changed paths:
    engines/sci/engine/guest_additions.cpp
    engines/sci/engine/kmisc.cpp
    engines/sci/engine/state.cpp
    engines/sci/engine/state.h
    engines/sci/engine/vm.h
    engines/sci/engine/workarounds.cpp


diff --git a/engines/sci/engine/guest_additions.cpp b/engines/sci/engine/guest_additions.cpp
index 017b41abee..2219c4ee81 100644
--- a/engines/sci/engine/guest_additions.cpp
+++ b/engines/sci/engine/guest_additions.cpp
@@ -25,6 +25,7 @@
 #include "common/gui_options.h"
 #include "common/savefile.h"
 #include "sci/engine/features.h"
+#include "sci/engine/file.h"
 #include "sci/engine/guest_additions.h"
 #include "sci/engine/kernel.h"
 #include "sci/engine/savegame.h"
@@ -789,11 +790,25 @@ bool GuestAdditions::restoreFromLauncher() const {
 			reg_t args[] = { make_reg(0, _state->_delayedRestoreGameId - kSaveIdShift) };
 			invokeSelector(g_sci->getGameObject(), SELECTOR(restore), 1, args);
 		} else {
+			int saveId = _state->_delayedRestoreGameId;
+
 			// When `Game::restore` is invoked, it will call to `Restore::doit`
 			// which will automatically return the `_delayedRestoreGameId` instead
 			// of prompting the user for a save game
 			invokeSelector(g_sci->getGameObject(), SELECTOR(restore));
 
+			// initialize KQ7 Mac's global save state by recording the save id
+			//  and description. this is necessary for subsequent saves to work
+			//  after restoring from launcher.
+			if (g_sci->getGameId() == GID_KQ7 || g_sci->getPlatform() == Common::kPlatformMacintosh) {
+				_state->_kq7MacSaveGameId = saveId;
+
+				SavegameDesc savegameDesc;
+				if (fillSavegameDesc(g_sci->getSavegameName(saveId), savegameDesc)) {
+					_state->_kq7MacSaveGameDescription = savegameDesc.name;
+				}
+			}
+
 			// The normal save game system resets _delayedRestoreGameId with a
 			// call to `EngineState::reset`, but RAMA uses a custom save game
 			// system which does not reset the engine, so we need to clear the
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index ddd82c124e..fa6f6d5087 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "common/config-manager.h"
+#include "common/savefile.h"
 #include "common/system.h"
 
 #include "sci/sci.h"
@@ -29,10 +30,15 @@
 #include "sci/engine/state.h"
 #include "sci/engine/kernel.h"
 #include "sci/engine/gc.h"
+#ifdef ENABLE_SCI32
+#include "sci/engine/guest_additions.h"
+#endif
+#include "sci/engine/savegame.h"
 #include "sci/graphics/cursor.h"
 #include "sci/graphics/palette.h"
 #ifdef ENABLE_SCI32
 #include "sci/graphics/cursor32.h"
+#include "sci/graphics/frameout.h"
 #endif
 #include "sci/graphics/maciconbar.h"
 #include "sci/console.h"
@@ -570,32 +576,118 @@ reg_t kMacPlatform(EngineState *s, int argc, reg_t *argv) {
 }
 
 #ifdef ENABLE_SCI32
+// kMacKq7InitializeSave is a subop of kMacPlatform32.
+//  KQ7 Mac would display a native Save dialog with the prompt "Who's game?"
+//  and store the result in a global variable inside the interpreter
+//  for subsequent calls to kMacKq7SaveGame.
+reg_t kMacKq7InitializeSave(EngineState *s) {
+	s->_kq7MacSaveGameId = g_sci->_guestAdditions->runSaveRestore(true, s->_kq7MacSaveGameDescription);
+	s->_kq7MacSaveGameId = shiftSciToScummVMSaveId(s->_kq7MacSaveGameId);
+	return (s->_kq7MacSaveGameId != -1) ? TRUE_REG : NULL_REG;
+}
+
+// kMacKq7SaveGame is a subop of kMacPlatform32.
+//  Saves the game using the current save id and description that's set
+//  when initializing or restoring a saved game.
+reg_t kMacKq7SaveGame(EngineState *s) {
+	if (s->_kq7MacSaveGameId == -1) {
+		error("kMacKq7SaveGame: save game hasn't been initialized");
+	}
+
+	const reg_t version = s->variables[VAR_GLOBAL][kGlobalVarVersion];
+	const Common::String versionString = s->_segMan->getString(version);
+	if (gamestate_save(s, s->_kq7MacSaveGameId, s->_kq7MacSaveGameDescription, versionString)) {
+		return TRUE_REG;
+	}
+	return NULL_REG;
+}
+
+// kMacKq7RestoreGame is a subop of kMacPlatform32.
+//  KQ7 Mac would display a native Open dialog with the prompt "Who's game?"
+//  and store the result in a global variable inside the interpreter to
+//  use in subsequent calls to kMacKq7SaveGame before restoring.
+reg_t kMacKq7RestoreGame(EngineState *s) {
+	s->_kq7MacSaveGameId = g_sci->_guestAdditions->runSaveRestore(false, s->_kq7MacSaveGameDescription);
+	s->_kq7MacSaveGameId = shiftSciToScummVMSaveId(s->_kq7MacSaveGameId);
+	if (s->_kq7MacSaveGameId == -1) {
+		return NULL_REG;
+	}
+
+	// gamestate_restore() resets s->_kq7MacSaveGameId and 
+	//  s->_kq7MacSaveGameDescription so save and restore them.
+	int kq7MacSaveGameId = s->_kq7MacSaveGameId;
+	Common::String kq7MacSaveGameDescription = s->_kq7MacSaveGameDescription;
+	bool success = gamestate_restore(s, s->_kq7MacSaveGameId);
+	s->_kq7MacSaveGameId = kq7MacSaveGameId;
+	s->_kq7MacSaveGameDescription = kq7MacSaveGameDescription;
+
+	return success ? TRUE_REG : NULL_REG;
+}
+
+// kMacShiversInitializeSave is a subop of kMacPlatform32.
+reg_t kMacShiversInitializeSave(EngineState *s, int argc, reg_t *argv) {
+	return TRUE_REG; // NULL_REG if i/o errors
+}
+
+// kMacShiversSaveGame is a subop of kMacPlatform32.
+reg_t kMacShiversSaveGame(EngineState *s, int argc, reg_t *argv) {
+	g_sci->_gfxFrameout->kernelFrameOut(true); // see kSaveGame32
+
+	const int saveId = shiftSciToScummVMSaveId(argv[1].toUint16());
+	const Common::String description = s->_segMan->getString(argv[2]);
+	const reg_t version = s->variables[VAR_GLOBAL][kGlobalVarVersion];
+	const Common::String versionString = s->_segMan->getString(version);
+	if (gamestate_save(s, saveId, description, versionString)) {
+		return TRUE_REG;
+	}
+	return NULL_REG;
+}
+
+// kMacShiversRestoreGame is a subop of kMacPlatform32.
+reg_t kMacShiversRestoreGame(EngineState *s, int argc, reg_t *argv) {
+	const int saveId = shiftSciToScummVMSaveId(argv[1].toUint16());
+	if (gamestate_restore(s, saveId)) {
+		return TRUE_REG;
+	}
+	return NULL_REG;
+}
+
 reg_t kMacPlatform32(EngineState *s, int argc, reg_t *argv) {
 	switch (argv[0].toUint16()) {
 	case 0: // build cursor view map
 		g_sci->_gfxCursor32->setMacCursorRemapList(argc - 1, argv + 1);
-		break;
+		return s->r_acc;
 
 	case 1: // compact/purge mac memory
 	case 2: // hands-off/hands-on for mac menus
-		break;
+		return s->r_acc;
 
-	// TODO: Save game handling in KQ7, Shivers, and Lighthouse.
-	// - KQ7 uses all three with no parameters; the interpreter would
-	//   remember the current save file.
-	// - Shivers uses all three but passes parameters in a similar
-	//   manner as the normal kSave\kRestore calls.
-	// - Lighthouse goes insane and only uses subop 3 but adds sub-subops
-	//   which appear to do the three operations.
-	// Temporarily stubbing these out with success values so that KQ7 can start.
-	case 3: // initialize save game file
-		warning("Unimplemented kMacPlatform32(%d): Initialize save game file", argv[0].toUint16());
-		return TRUE_REG;
-	case 4: // save game
-		warning("Unimplemented kMacPlatform32(%d): Save game", argv[0].toUint16());
-		return TRUE_REG;
-	case 5: // restore game
-		warning("Unimplemented kMacPlatform32(%d): Restore game", argv[0].toUint16());
+	// Subops 3-5 are used for custom saving and restoring but they
+	//  changed completely between each game that uses them.
+	//
+	//  KQ7:        3-5 with no parameters
+	//  Shivers:    3-5 with parameters
+	//  Lighthouse: 3 with sub-subops: -1, 0, and 1 (TODO)
+	case 3:
+		if (argc == 1) {
+			return kMacKq7InitializeSave(s);
+		} else if (argc == 3) {
+			return kMacShiversInitializeSave(s, argc - 1, argv + 1);
+		} 
+		break;
+	case 4:
+		if (argc == 1) {
+			return kMacKq7SaveGame(s);
+		} else if (argc == 4) {
+			return kMacShiversSaveGame(s, argc - 1, argv + 1);
+		}
+		break;
+	case 5:
+		if (argc == 1) {
+			return kMacKq7RestoreGame(s);
+		} else if (argc == 3) {
+			return kMacShiversRestoreGame(s, argc - 1, argv + 1);
+		}
 		break;
 
 	// TODO: Mother Goose save game handling
@@ -605,18 +697,18 @@ reg_t kMacPlatform32(EngineState *s, int argc, reg_t *argv) {
 	case 9:
 	case 10:
 	case 11:
-		error("Unimplemented kMacPlatform32(%d) save game operation", argv[0].toUint16());
 		break;
 
 	// TODO: Phantasmagoria music volume adjustment [ 0-15 ]
 	case 12:
 		warning("Unimplemented kMacPlatform32(%d): Set volume: %d", argv[0].toUint16(), argv[1].toUint16());
-		break;
+		return s->r_acc;
 
 	default:
-		error("Unknown kMacPlatform32(%d)", argv[0].toUint16());
+		break;
 	}
 
+	error("Unknown kMacPlatform32(%d)", argv[0].toUint16());
 	return s->r_acc;
 }
 #endif
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index 5bb1343839..6648458bd7 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -88,6 +88,9 @@ void EngineState::reset(bool isRestoring) {
 
 	_delayedRestoreGameId = -1;
 
+	_kq7MacSaveGameId = -1;
+	_kq7MacSaveGameDescription.clear();
+
 	executionStackBase = 0;
 	_executionStackPosChanged = false;
 	stack_base = 0;
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index a783f09d82..46161a3187 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -136,6 +136,10 @@ public:
 	// see detection.cpp / SciEngine::loadGameState()
 	int _delayedRestoreGameId; // the saved game id, that it supposed to get restored (triggered by ScummVM menu)
 
+	// see kmisc.cpp / kMacPlatform32
+	int _kq7MacSaveGameId; // the saved game id to use when saving (might not exist yet)
+	Common::String _kq7MacSaveGameDescription; // description to use when saving game
+
 	uint _chosenQfGImportItem; // Remembers the item selected in QfG import rooms
 
 	bool _cursorWorkaroundActive; // Refer to GfxCursor::setPosition()
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index c80070409b..f1af11a249 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -149,6 +149,7 @@ enum GlobalVar {
 	kGlobalVarPreviousRoomNo = 12,
 	kGlobalVarNewRoomNo      = 13,
 	kGlobalVarScore          = 15,
+	kGlobalVarVersion        = 27,
 	kGlobalVarGK2MusicVolume = 76, // 0 to 127
 	kGlobalVarPhant2SecondaryVolume = 76, // 0 to 127
 	kGlobalVarFastCast             = 84, // SCI16
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index a921833708..7050edbf9c 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -446,6 +446,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
 	{ GID_KQ7,          2450,  2450,  0,       "maliciaComes", "handleEvent",                     NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // when malicia appears at the southeast exit of the main chamber near the end of chapter 2
 	{ GID_KQ7,          5300,  5302,  0,          "putOnMask", "handleEvent",                     NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // in chapter 3, after using the mask on Valanice, click the jackalope hair in inventory - bug Trac#9759
 	{ GID_KQ7,          6060, 64964,  0,              "DPath", "init",                            NULL,     1,     1, { WORKAROUND_FAKE,   0 } }, // after entering the harp crystal in chapter 5
+	{ GID_KQ7,            -1, 64994, -1,               "Game", "restore",                         NULL,     0,     0, { WORKAROUND_FAKE,   0 } }, // when restoring from ScummVM launcher in Mac version
 	{ GID_LAURABOW,       37,     0,  0,                "CB1", "doit",                            NULL,     1,     1, { WORKAROUND_FAKE,   0 } }, // when going up the stairs - bug #5084
 	{ GID_LAURABOW,       -1,   967,  0,             "myIcon", "cycle",                           NULL,     1,     1, { WORKAROUND_FAKE,   0 } }, // having any portrait conversation coming up - initial bug #4971
 	{ GID_LAURABOW2,      -1,    24,  0,              "gcWin", "open",                            NULL,     5,     5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu


Commit: 1f0334ee6b0290465590dd30135e4679615e816e
    https://github.com/scummvm/scummvm/commit/1f0334ee6b0290465590dd30135e4679615e816e
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2020-04-20T00:19:38-07:00

Commit Message:
SCI32: Don't delete planes on restore in all Mac games

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


diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 0c7f0dee8e..9dc76a9b60 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -348,7 +348,17 @@ void GfxFrameout::deletePlane(Plane &planeToFind) {
 void GfxFrameout::deletePlanesForMacRestore() {
 	// SCI32 PC games delete planes and screen items from
 	//  their Game:restore script before calling kRestore.
-	//  In Mac this work was moved into the interpreter.
+	//  In Mac this work was moved into the interpreter
+	//  for some games, while others added it back to
+    //  Game:restore or used their own scripts that took
+	//  care of this in both PC and Mac versions.
+	if (!(g_sci->getGameId() == GID_GK1 ||
+		  g_sci->getGameId() == GID_PQ4 ||
+		  g_sci->getGameId() == GID_LSL6 ||
+		  g_sci->getGameId() == GID_KQ7)) {
+		return;
+	}
+
 	for (PlaneList::size_type i = 0; i < _planes.size(); ) {
 		Plane *plane = _planes[i];
 




More information about the Scummvm-git-logs mailing list