[Scummvm-git-logs] scummvm master -> 6aeda1224741b4b07935f6932355c5decc7ce0b9

sev- sev at scummvm.org
Mon Aug 23 11:34:40 UTC 2021


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

Summary:
7adad5aaf5 ENGINES: Streamline auto-save write/delete protection
fb8f233ed7 BACKENDS: Replace virtual with override in SaveFileManager subclasses
a0c818bde6 COMMON: Introduce SaveFileManager::exists
6aeda12247 ENGINES: Warn when overwriting a non-autosave on autosave


Commit: 7adad5aaf5831dc5adcee140f38aacc4a5db2518
    https://github.com/scummvm/scummvm/commit/7adad5aaf5831dc5adcee140f38aacc4a5db2518
Author: Orgad Shaneh (orgads at gmail.com)
Date: 2021-08-23T13:34:35+02:00

Commit Message:
ENGINES: Streamline auto-save write/delete protection

Some engines call setAutosave and some don't. isAutosave is used to
determine if a saved game is an autosave, but in fact, on most cases it
just falls back to comparing the name to "Autosave".

This is wrong for several reasons:
* Older versions of ScummVM used Autosave 0.
* The name "Autosave" is translated, so if you change the language, it
  won't be detected.

Instead of relying on the name, use the well-known getAutosaveSlot() from
Engine/MetaEngine.

Fixes #12735.

Changed paths:
    engines/agi/metaengine.cpp
    engines/ags/metaengine.cpp
    engines/bbvs/metaengine.cpp
    engines/cge/metaengine.cpp
    engines/cge2/metaengine.cpp
    engines/cine/metaengine.cpp
    engines/dragons/metaengine.cpp
    engines/drascula/metaengine.cpp
    engines/drascula/saveload.cpp
    engines/hugo/metaengine.cpp
    engines/illusions/metaengine.cpp
    engines/kyra/metaengine.cpp
    engines/lab/metaengine.cpp
    engines/lilliput/metaengine.cpp
    engines/macventure/metaengine.cpp
    engines/macventure/saveload.cpp
    engines/metaengine.cpp
    engines/mohawk/myst_state.cpp
    engines/mortevielle/saveload.cpp
    engines/neverhood/metaengine.cpp
    engines/savestate.cpp
    engines/savestate.h
    engines/sci/metaengine.cpp
    engines/scumm/metaengine.cpp
    engines/startrek/metaengine.cpp
    engines/trecision/metaengine.cpp
    engines/zvision/metaengine.cpp


diff --git a/engines/agi/metaengine.cpp b/engines/agi/metaengine.cpp
index a1d9b5c162..b67652ed6a 100644
--- a/engines/agi/metaengine.cpp
+++ b/engines/agi/metaengine.cpp
@@ -263,16 +263,6 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl
 
 		SaveStateDescriptor descriptor(slotNr, description);
 
-		// Do not allow save slot 0 (used for auto-saving) to be deleted or
-		// overwritten.
-		if (slotNr == 0) {
-			descriptor.setWriteProtectedFlag(true);
-			descriptor.setDeletableFlag(false);
-		} else {
-			descriptor.setWriteProtectedFlag(false);
-			descriptor.setDeletableFlag(true);
-		}
-
 		char saveVersion = in->readByte();
 		if (saveVersion >= 4) {
 			Graphics::Surface *thumbnail;
@@ -313,6 +303,7 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl
 		SaveStateDescriptor emptySave;
 		// Do not allow save slot 0 (used for auto-saving) to be overwritten.
 		if (slotNr == 0) {
+			emptySave.setAutosave(true);
 			emptySave.setWriteProtectedFlag(true);
 		} else {
 			emptySave.setWriteProtectedFlag(false);
diff --git a/engines/ags/metaengine.cpp b/engines/ags/metaengine.cpp
index a5696a2229..2663e24146 100644
--- a/engines/ags/metaengine.cpp
+++ b/engines/ags/metaengine.cpp
@@ -69,13 +69,7 @@ SaveStateList AGSMetaEngine::listSaves(const char *target) const {
 				if (slotNum > maxSlot)
 					continue;
 
-				SaveStateDescriptor desc;
-				desc.setSaveSlot(slotNum);
-				desc.setDescription(rich_media_header.getSaveName());
-
-				if (slotNum == getAutosaveSlot())
-					desc.setWriteProtectedFlag(true);
-
+				SaveStateDescriptor desc(slotNum, rich_media_header.getSaveName());
 				saveList.push_back(desc);
 			}
 		}
@@ -117,12 +111,7 @@ SaveStateDescriptor AGSMetaEngine::querySaveMetaInfos(const char *target, int sl
 		rich_media_header.ReadFromFile(&saveFile);
 
 		if (rich_media_header.dwMagicNumber == RM_MAGICNUMBER) {
-			SaveStateDescriptor desc;
-			desc.setSaveSlot(slot);
-			if (slot == getAutosaveSlot()) {
-				desc.setAutosave(true);
-				desc.setWriteProtectedFlag(true);
-			}
+			SaveStateDescriptor desc(slot, Common::U32String());
 
 			// Thumbnail handling
 			if (rich_media_header.dwThumbnailOffsetLowerDword != 0 &&
diff --git a/engines/bbvs/metaengine.cpp b/engines/bbvs/metaengine.cpp
index ead8186c7a..d161ef09eb 100644
--- a/engines/bbvs/metaengine.cpp
+++ b/engines/bbvs/metaengine.cpp
@@ -108,9 +108,6 @@ SaveStateDescriptor BbvsMetaEngine::querySaveMetaInfos(const char *target, int s
 		delete in;
 		if (error == Bbvs::BbvsEngine::kRSHENoError) {
 			SaveStateDescriptor desc(slot, header.description);
-			// Slot 0 is used for the "Continue" save
-			desc.setDeletableFlag(slot != 0);
-			desc.setWriteProtectedFlag(slot == 0);
 			desc.setThumbnail(header.thumbnail);
 			desc.setSaveDate(header.saveDate & 0xFFFF, (header.saveDate >> 16) & 0xFF, (header.saveDate >> 24) & 0xFF);
 			desc.setSaveTime((header.saveTime >> 16) & 0xFF, (header.saveTime >> 8) & 0xFF);
diff --git a/engines/cge/metaengine.cpp b/engines/cge/metaengine.cpp
index ede99e9129..ff1c023664 100644
--- a/engines/cge/metaengine.cpp
+++ b/engines/cge/metaengine.cpp
@@ -141,11 +141,6 @@ SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int sl
 				desc.setPlayTime(header.playTime * 1000);
 			}
 
-			// Slot 0 is used for the 'automatic save on exit' save in Soltys, thus
-			// we prevent it from being deleted or overwritten by accident.
-			desc.setDeletableFlag(slot != 0);
-			desc.setWriteProtectedFlag(slot == 0);
-
 			return desc;
 		}
 	}
diff --git a/engines/cge2/metaengine.cpp b/engines/cge2/metaengine.cpp
index 336e52d2cb..3bb447ce76 100644
--- a/engines/cge2/metaengine.cpp
+++ b/engines/cge2/metaengine.cpp
@@ -141,11 +141,6 @@ SaveStateDescriptor CGE2MetaEngine::querySaveMetaInfos(const char *target, int s
 				desc.setPlayTime(header.playTime * 1000);
 			}
 
-			// Slot 0 is used for the 'automatic save on exit' save in Soltys, thus
-			// we prevent it from being deleted or overwritten by accident.
-			desc.setDeletableFlag(slot != 0);
-			desc.setWriteProtectedFlag(slot == 0);
-
 			return desc;
 		}
 	}
diff --git a/engines/cine/metaengine.cpp b/engines/cine/metaengine.cpp
index 9783596027..074ad73579 100644
--- a/engines/cine/metaengine.cpp
+++ b/engines/cine/metaengine.cpp
@@ -128,8 +128,6 @@ SaveStateList CineMetaEngine::listSaves(const char *target) const {
 				saveDesc[sizeof(CommandeType) - 1] = 0;
 
 				SaveStateDescriptor saveStateDesc(slotNum, saveDesc);
-				saveStateDesc.setAutosave(slotNum == getAutosaveSlot());
-				saveStateDesc.setWriteProtectedFlag(saveStateDesc.isAutosave());
 
 				if (saveStateDesc.getDescription().empty()) {
 					if (saveStateDesc.isAutosave()) {
@@ -152,10 +150,7 @@ SaveStateList CineMetaEngine::listSaves(const char *target) const {
 
 	// No saving on empty autosave slot
 	if (!foundAutosave) {
-		SaveStateDescriptor desc;
-		desc.setDescription(_("Empty autosave"));
-		desc.setSaveSlot(getAutosaveSlot());
-		desc.setWriteProtectedFlag(true);
+		SaveStateDescriptor desc(getAutosaveSlot(), _("Empty autosave"));
 		saveList.push_back(desc);
 	}
 
@@ -184,7 +179,7 @@ SaveStateDescriptor CineMetaEngine::querySaveMetaInfos(const char *target, int s
 
 	if (f) {
 		// Create the return descriptor
-		SaveStateDescriptor desc;
+		SaveStateDescriptor desc(slot, Common::U32String());
 
 		ExtendedSavegameHeader header;
 		if (readSavegameHeader(f.get(), &header, false)) {
@@ -213,21 +208,12 @@ SaveStateDescriptor CineMetaEngine::querySaveMetaInfos(const char *target, int s
 			desc.setDescription(_("Unnamed savegame"));
 		}
 
-		desc.setSaveSlot(slot);
-		desc.setAutosave(slot == getAutosaveSlot());
-		desc.setWriteProtectedFlag(desc.isAutosave());
-
 		return desc;
 	}
 
 	// No saving on empty autosave slot
 	if (slot == getAutosaveSlot()) {
-		SaveStateDescriptor desc;
-		desc.setDescription(_("Empty autosave"));
-		desc.setSaveSlot(slot);
-		desc.setAutosave(true);
-		desc.setWriteProtectedFlag(true);
-		return desc;
+		return SaveStateDescriptor(slot, _("Empty autosave"));
 	}
 
 	return SaveStateDescriptor();
diff --git a/engines/dragons/metaengine.cpp b/engines/dragons/metaengine.cpp
index d841644a09..f3d2bc2a69 100644
--- a/engines/dragons/metaengine.cpp
+++ b/engines/dragons/metaengine.cpp
@@ -100,9 +100,6 @@ SaveStateDescriptor DragonsMetaEngine::querySaveMetaInfos(const char *target, in
 		delete in;
 		if (error == Dragons::kRSHENoError) {
 			SaveStateDescriptor desc(slot, header.description);
-			// Slot 0 is used for the "Continue" save
-			desc.setDeletableFlag(slot != 0);
-			desc.setWriteProtectedFlag(slot == 0);
 			desc.setThumbnail(header.thumbnail);
 			desc.setSaveDate(header.saveDate & 0xFFFF, (header.saveDate >> 16) & 0xFF, (header.saveDate >> 24) & 0xFF);
 			desc.setSaveTime((header.saveTime >> 16) & 0xFF, (header.saveTime >> 8) & 0xFF);
diff --git a/engines/drascula/metaengine.cpp b/engines/drascula/metaengine.cpp
index a1cd28b40d..de743cb934 100644
--- a/engines/drascula/metaengine.cpp
+++ b/engines/drascula/metaengine.cpp
@@ -124,12 +124,7 @@ SaveStateDescriptor DrasculaMetaEngine::querySaveMetaInfos(const char *target, i
 
 	Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
 
-	SaveStateDescriptor desc;
-	// Do not allow save slot 0 (used for auto-saving) to be deleted or
-	// overwritten.
-	desc.setDeletableFlag(slot != 0);
-	desc.setWriteProtectedFlag(slot == 0);
-
+	SaveStateDescriptor desc(slot, Common::U32String());
 	if (in) {
 		desc = Drascula::loadMetaData(in, slot, false);
 		if (desc.getSaveSlot() != slot) {
diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp
index 7305f92197..3da19af000 100644
--- a/engines/drascula/saveload.cpp
+++ b/engines/drascula/saveload.cpp
@@ -105,7 +105,7 @@ SaveStateDescriptor loadMetaData(Common::ReadStream *s, int slot, bool setPlayTi
 	uint32 sig = s->readUint32BE();
 	byte version = s->readByte();
 
-	SaveStateDescriptor desc(-1, "");	// init to an invalid save slot
+	SaveStateDescriptor desc;	// init to an invalid save slot
 
 	if (sig != MAGIC_HEADER || version > SAVEGAME_VERSION)
 		return desc;
diff --git a/engines/hugo/metaengine.cpp b/engines/hugo/metaengine.cpp
index 731bc5e479..ae48574d30 100644
--- a/engines/hugo/metaengine.cpp
+++ b/engines/hugo/metaengine.cpp
@@ -164,11 +164,6 @@ SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int s
 
 		desc.setSaveTime(hour, minutes);
 
-		// Slot 0 is used for the 'restart game' save in all Hugo games, thus
-		// we prevent it from being deleted.
-		desc.setDeletableFlag(slot != 0);
-		desc.setWriteProtectedFlag(slot == 0);
-
 		delete file;
 		return desc;
 	}
diff --git a/engines/illusions/metaengine.cpp b/engines/illusions/metaengine.cpp
index 0c84a87483..3ac5efa25d 100644
--- a/engines/illusions/metaengine.cpp
+++ b/engines/illusions/metaengine.cpp
@@ -114,9 +114,6 @@ SaveStateDescriptor IllusionsMetaEngine::querySaveMetaInfos(const char *target,
 		delete in;
 		if (error == Illusions::IllusionsEngine::kRSHENoError) {
 			SaveStateDescriptor desc(slot, header.description);
-			// Slot 0 is used for the "Continue" save
-			desc.setDeletableFlag(slot != 0);
-			desc.setWriteProtectedFlag(slot == 0);
 			desc.setThumbnail(header.thumbnail);
 			desc.setSaveDate(header.saveDate & 0xFFFF, (header.saveDate >> 16) & 0xFF, (header.saveDate >> 24) & 0xFF);
 			desc.setSaveTime((header.saveTime >> 16) & 0xFF, (header.saveTime >> 8) & 0xFF);
diff --git a/engines/kyra/metaengine.cpp b/engines/kyra/metaengine.cpp
index f2c1686ac8..f931ff17d1 100644
--- a/engines/kyra/metaengine.cpp
+++ b/engines/kyra/metaengine.cpp
@@ -212,6 +212,8 @@ SaveStateDescriptor KyraMetaEngine::querySaveMetaInfos(const char *target, int s
 			// The same goes for the 'Autosave', which is slot 999. Slot 0 will also
 			// be protected in Kyra 1-3, since it's the 'restart game' save.
 			desc.setWriteProtectedFlag((slot == 0 && !nonKyraGame) || slot >= 990);
+			if (slot == 0 && !nonKyraGame)
+				desc.setAutosave(true);
 			desc.setThumbnail(header.thumbnail);
 
 			return desc;
@@ -224,6 +226,8 @@ SaveStateDescriptor KyraMetaEngine::querySaveMetaInfos(const char *target, int s
 	// The same goes for the 'Autosave', which is slot 999. Slot 0 will also
 	// be protected in Kyra 1-3, since it's the 'restart game' save.
 	desc.setWriteProtectedFlag((slot == 0 && !nonKyraGame) || slot >= 990);
+	if (slot == 0 && !nonKyraGame)
+		desc.setAutosave(true);
 
 	return desc;
 }
diff --git a/engines/lab/metaengine.cpp b/engines/lab/metaengine.cpp
index edc35a7042..ed3325c4a4 100644
--- a/engines/lab/metaengine.cpp
+++ b/engines/lab/metaengine.cpp
@@ -131,11 +131,6 @@ SaveStateDescriptor LabMetaEngine::querySaveMetaInfos(const char *target, int sl
 
 		if (successfulRead) {
 			SaveStateDescriptor desc(slot, header._descr.getDescription());
-			// Do not allow save slot 0 (used for auto-saving) to be deleted or
-			// overwritten.
-			//desc.setDeletableFlag(slot != 0);
-			//desc.setWriteProtectedFlag(slot == 0);
-
 			return header._descr;
 		}
 	}
diff --git a/engines/lilliput/metaengine.cpp b/engines/lilliput/metaengine.cpp
index a33b44833b..72836cc895 100644
--- a/engines/lilliput/metaengine.cpp
+++ b/engines/lilliput/metaengine.cpp
@@ -156,9 +156,6 @@ SaveStateDescriptor LilliputMetaEngine::querySaveMetaInfos(const char *target, i
 		}
 		desc.setThumbnail(thumbnail);
 
-		desc.setDeletableFlag(true);
-		desc.setWriteProtectedFlag(false);
-
 		uint32 saveDate = file->readUint32BE();
 		uint16 saveTime = file->readUint16BE();
 
@@ -173,11 +170,6 @@ SaveStateDescriptor LilliputMetaEngine::querySaveMetaInfos(const char *target, i
 
 		desc.setSaveTime(hour, minutes);
 
-		// Slot 0 is used for the 'restart game' save in all Robin games, thus
-		// we prevent it from being deleted.
-		desc.setDeletableFlag(slot != 0);
-		desc.setWriteProtectedFlag(slot == 0);
-
 		delete file;
 		return desc;
 	}
diff --git a/engines/macventure/metaengine.cpp b/engines/macventure/metaengine.cpp
index 42bed3b36b..aa76d77ac8 100644
--- a/engines/macventure/metaengine.cpp
+++ b/engines/macventure/metaengine.cpp
@@ -85,12 +85,7 @@ SaveStateList MacVentureMetaEngine::listSaves(const char *target) const {
 	SaveStateList saveList;
 	for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
 		int slotNum = atoi(file->c_str() + file->size() - 3);
-		SaveStateDescriptor desc;
-		// Do not allow save slot 0 (used for auto-saving) to be deleted or
-		// overwritten.
-		desc.setDeletableFlag(slotNum != 0);
-		desc.setWriteProtectedFlag(slotNum == 0);
-
+		SaveStateDescriptor desc(slotNum, Common::U32String());
 		if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) {
 			Common::InSaveFile *in = saveFileMan->openForLoading(*file);
 			if (in) {
@@ -143,7 +138,7 @@ SaveStateDescriptor MacVentureMetaEngine::querySaveMetaInfos(const char *target,
 		delete in;
 		return desc;
 	}
-	return SaveStateDescriptor(-1, "");
+	return SaveStateDescriptor();
 }
 
 } // End of namespace MacVenture
diff --git a/engines/macventure/saveload.cpp b/engines/macventure/saveload.cpp
index 687b96a020..c4f9fbea8a 100644
--- a/engines/macventure/saveload.cpp
+++ b/engines/macventure/saveload.cpp
@@ -52,7 +52,7 @@ SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot, bool s
 	uint32 sig = s->readUint32BE();
 	byte version = s->readByte();
 
-	SaveStateDescriptor desc(-1, "");	// init to an invalid save slot
+	SaveStateDescriptor desc;	// init to an invalid save slot
 
 	if (sig != MACVENTURE_SAVE_HEADER || version > MACVENTURE_SAVE_VERSION)
 		return desc;
diff --git a/engines/metaengine.cpp b/engines/metaengine.cpp
index 0ef1431dc0..4821ca0066 100644
--- a/engines/metaengine.cpp
+++ b/engines/metaengine.cpp
@@ -331,21 +331,14 @@ SaveStateList MetaEngine::listSaves(const char *target, bool saveMode) const {
 
 	// Check to see if an autosave is present
 	for (SaveStateList::iterator it = saveList.begin(); it != saveList.end(); ++it) {
-		int slot = it->getSaveSlot();
-		if (slot == autosaveSlot) {
-			// It has an autosave
-			it->setWriteProtectedFlag(true);
+		// It has an autosave
+		if (it->isAutosave())
 			return saveList;
-		}
 	}
 
 	// No autosave yet. We want to add a dummy one in so that it can be marked as'
 	// write protected, and thus be prevented from being saved in
-	SaveStateDescriptor desc;
-	desc.setDescription(_("Autosave"));
-	desc.setSaveSlot(autosaveSlot);
-	desc.setWriteProtectedFlag(true);
-
+	SaveStateDescriptor desc(autosaveSlot, _("Autosave"));
 	saveList.push_back(desc);
 	Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
 
@@ -393,16 +386,9 @@ SaveStateDescriptor MetaEngine::querySaveMetaInfos(const char *target, int slot)
 		}
 
 		// Create the return descriptor
-		SaveStateDescriptor desc;
-
+		SaveStateDescriptor desc(slot, Common::U32String());
 		parseSavegameHeader(&header, &desc);
-
-		desc.setSaveSlot(slot);
 		desc.setThumbnail(header.thumbnail);
-		desc.setAutosave(header.isAutosave);
-		if (slot == getAutosaveSlot())
-			desc.setWriteProtectedFlag(true);
-
 		return desc;
 	}
 
diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp
index 574f6c32a8..d3115d1bd7 100644
--- a/engines/mohawk/myst_state.cpp
+++ b/engines/mohawk/myst_state.cpp
@@ -269,8 +269,7 @@ bool MystGameState::saveMetadata(int slot, const Graphics::Surface *thumbnail) {
 }
 
 SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) {
-	SaveStateDescriptor desc;
-	desc.setWriteProtectedFlag(slot == kAutoSaveSlot);
+	SaveStateDescriptor desc(slot, Common::U32String());
 
 	// Open the save file
 	Common::String filename = buildSaveFilename(slot);
@@ -281,8 +280,6 @@ SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) {
 	delete saveFile;
 
 	// There is a save in the slot
-	desc.setSaveSlot(slot);
-
 	// Open the metadata file
 	filename = buildMetadataFilename(slot);
 	Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename);
diff --git a/engines/mortevielle/saveload.cpp b/engines/mortevielle/saveload.cpp
index d96ecbb0b0..598c706869 100644
--- a/engines/mortevielle/saveload.cpp
+++ b/engines/mortevielle/saveload.cpp
@@ -303,10 +303,7 @@ SaveStateDescriptor SavegameManager::querySaveMetaInfos(const Common::String &fi
 			// Original savegame perhaps?
 			delete f;
 
-			SaveStateDescriptor desc(slot, Common::String::format("Savegame - %03d", slot));
-			desc.setDeletableFlag(slot != 0);
-			desc.setWriteProtectedFlag(slot == 0);
-			return desc;
+			return SaveStateDescriptor(slot, Common::String::format("Savegame - %03d", slot));
 		} else {
 			// Get the savegame header information
 			SavegameHeader header;
diff --git a/engines/neverhood/metaengine.cpp b/engines/neverhood/metaengine.cpp
index b0da9288c2..6aad3daf43 100644
--- a/engines/neverhood/metaengine.cpp
+++ b/engines/neverhood/metaengine.cpp
@@ -148,8 +148,6 @@ SaveStateDescriptor NeverhoodMetaEngine::querySaveMetaInfos(const char *target,
 		if (error == Neverhood::NeverhoodEngine::kRSHENoError) {
 			SaveStateDescriptor desc(slot, header.description);
 
-			desc.setDeletableFlag(false);
-			desc.setWriteProtectedFlag(false);
 			desc.setThumbnail(header.thumbnail);
 			int day = (header.saveDate >> 24) & 0xFF;
 			int month = (header.saveDate >> 16) & 0xFF;
diff --git a/engines/savestate.cpp b/engines/savestate.cpp
index e63a89a3e1..83d5bccb79 100644
--- a/engines/savestate.cpp
+++ b/engines/savestate.cpp
@@ -21,7 +21,9 @@
  */
 
 #include "engines/savestate.h"
+#include "engines/engine.h"
 #include "graphics/surface.h"
+#include "common/config-manager.h"
 #include "common/textconsole.h"
 #include "common/translation.h"
 
@@ -32,16 +34,24 @@ SaveStateDescriptor::SaveStateDescriptor()
 	_thumbnail(), _saveType(kSaveTypeUndetermined) {
 }
 
-SaveStateDescriptor::SaveStateDescriptor(int s, const Common::U32String &d)
-	: _slot(s), _description(d), _isDeletable(true), _isWriteProtected(false),
-	  _isLocked(false), _saveDate(), _saveTime(), _playTime(), _playTimeMSecs(0),
-	_thumbnail(), _saveType(kSaveTypeUndetermined) {
+SaveStateDescriptor::SaveStateDescriptor(int slot, const Common::U32String &d)
+	: _slot(slot), _description(d), _isLocked(false), _playTimeMSecs(0) {
+	initSaveType();
 }
 
-SaveStateDescriptor::SaveStateDescriptor(int s, const Common::String &d)
-	: _slot(s), _description(Common::U32String(d)), _isDeletable(true), _isWriteProtected(false),
-	_isLocked(false), _saveDate(), _saveTime(), _playTime(), _playTimeMSecs(0),
-	_thumbnail(), _saveType(kSaveTypeUndetermined) {
+SaveStateDescriptor::SaveStateDescriptor(int slot, const Common::String &d)
+	: _slot(slot), _description(Common::U32String(d)), _isLocked(false), _playTimeMSecs(0) {
+	initSaveType();
+}
+
+void SaveStateDescriptor::initSaveType()
+{
+	// Do not allow auto-save slot to be deleted or overwritten.
+	const bool autosave =
+			g_engine && ConfMan.getInt("autosave_period") && _slot == g_engine->getAutosaveSlot();
+	_isWriteProtected = autosave;
+	_saveType = autosave ? kSaveTypeAutosave : kSaveTypeRegular;
+	_isDeletable = !autosave;
 }
 
 void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) {
diff --git a/engines/savestate.h b/engines/savestate.h
index 59532040e5..fa126877b4 100644
--- a/engines/savestate.h
+++ b/engines/savestate.h
@@ -59,10 +59,12 @@ private:
 		kSaveTypeRegular,
 		kSaveTypeAutosave
 	};
+
+	void initSaveType();
 public:
 	SaveStateDescriptor();
-	SaveStateDescriptor(int s, const Common::U32String &d);
-	SaveStateDescriptor(int s, const Common::String &d);
+	SaveStateDescriptor(int slot, const Common::U32String &d);
+	SaveStateDescriptor(int slot, const Common::String &d);
 
 	/**
 	 * @param slot The saveslot id, as it would be passed to the "-x" command line switch.
diff --git a/engines/sci/metaengine.cpp b/engines/sci/metaengine.cpp
index 1edd321699..2b4e22ed9d 100644
--- a/engines/sci/metaengine.cpp
+++ b/engines/sci/metaengine.cpp
@@ -353,12 +353,8 @@ SaveStateList SciMetaEngine::listSaves(const char *target) const {
 				}
 				SaveStateDescriptor descriptor(slotNr, meta.name);
 
-				if (slotNr == 0) {
-					// ScummVM auto-save slot
-					descriptor.setWriteProtectedFlag(true);
+				if (descriptor.isAutosave()) {
 					hasAutosave = true;
-				} else {
-					descriptor.setWriteProtectedFlag(false);
 				}
 
 				saveList.push_back(descriptor);
@@ -383,15 +379,6 @@ SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int sl
 	Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
 	SaveStateDescriptor descriptor(slotNr, "");
 
-	if (slotNr == 0) {
-		// ScummVM auto-save slot
-		descriptor.setWriteProtectedFlag(true);
-		descriptor.setDeletableFlag(false);
-	} else {
-		descriptor.setWriteProtectedFlag(false);
-		descriptor.setDeletableFlag(true);
-	}
-
 	if (in) {
 		SavegameMetadata meta;
 
diff --git a/engines/scumm/metaengine.cpp b/engines/scumm/metaengine.cpp
index 904ed55798..2ab4cc051d 100644
--- a/engines/scumm/metaengine.cpp
+++ b/engines/scumm/metaengine.cpp
@@ -505,14 +505,6 @@ SaveStateDescriptor ScummMetaEngine::querySaveMetaInfos(const char *target, int
 	}
 
 	SaveStateDescriptor desc(slot, saveDesc);
-
-	// Do not allow save slot 0 (used for auto-saving) to be deleted or
-	// overwritten.
-	if (slot == 0) {
-		desc.setWriteProtectedFlag(true);
-		desc.setDeletableFlag(false);
-	}
-
 	desc.setThumbnail(thumbnail);
 
 	if (infoPtr) {
diff --git a/engines/startrek/metaengine.cpp b/engines/startrek/metaengine.cpp
index e6902e091b..ceba864b2a 100644
--- a/engines/startrek/metaengine.cpp
+++ b/engines/startrek/metaengine.cpp
@@ -163,16 +163,6 @@ SaveStateDescriptor StarTrekMetaEngine::querySaveMetaInfos(const char *target, i
 
 		SaveStateDescriptor descriptor(slotNr, meta.description);
 
-		// Do not allow save slot 0 (used for auto-saving) to be deleted or
-		// overwritten.
-		if (slotNr == 0) {
-			descriptor.setWriteProtectedFlag(true);
-			descriptor.setDeletableFlag(false);
-		} else {
-			descriptor.setWriteProtectedFlag(false);
-			descriptor.setDeletableFlag(true);
-		}
-
 		if (meta.thumbnail == nullptr) {
 			return SaveStateDescriptor();
 		}
@@ -185,13 +175,7 @@ SaveStateDescriptor StarTrekMetaEngine::querySaveMetaInfos(const char *target, i
 		return descriptor;
 
 	} else {
-		SaveStateDescriptor emptySave;
-		// Do not allow save slot 0 (used for auto-saving) to be overwritten.
-		if (slotNr == 0) {
-			emptySave.setWriteProtectedFlag(true);
-		} else {
-			emptySave.setWriteProtectedFlag(false);
-		}
+		SaveStateDescriptor emptySave(slotNr, Common::U32String());
 		return emptySave;
 	}
 }
diff --git a/engines/trecision/metaengine.cpp b/engines/trecision/metaengine.cpp
index 0e751e7d45..165bfd6d05 100644
--- a/engines/trecision/metaengine.cpp
+++ b/engines/trecision/metaengine.cpp
@@ -62,9 +62,6 @@ SaveStateDescriptor TrecisionMetaEngine::querySaveMetaInfos(const char *target,
 			Common::String saveName = saveFile->readString(0, 40);
 
 			SaveStateDescriptor desc(slot, saveName);
-			desc.setAutosave(false);
-			if (slot == getAutosaveSlot())
-				desc.setWriteProtectedFlag(true);
 
 			// This is freed inside SaveStateDescriptor
 			const Graphics::PixelFormat kImageFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
diff --git a/engines/zvision/metaengine.cpp b/engines/zvision/metaengine.cpp
index dd6cbf494a..31feac4360 100644
--- a/engines/zvision/metaengine.cpp
+++ b/engines/zvision/metaengine.cpp
@@ -297,11 +297,6 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in
 		if (successfulRead) {
 			SaveStateDescriptor desc(slot, header.saveName);
 
-			// Do not allow save slot 0 (used for auto-saving) to be deleted or
-			// overwritten.
-			desc.setDeletableFlag(slot != 0);
-			desc.setWriteProtectedFlag(slot == 0);
-
 			desc.setThumbnail(header.thumbnail);
 
 			if (header.version >= 1) {


Commit: fb8f233ed7a75f0df982807c13465198be45a2ed
    https://github.com/scummvm/scummvm/commit/fb8f233ed7a75f0df982807c13465198be45a2ed
Author: Orgad Shaneh (orgads at gmail.com)
Date: 2021-08-23T13:34:35+02:00

Commit Message:
BACKENDS: Replace virtual with override in SaveFileManager subclasses

Changed paths:
    backends/platform/dc/vmsave.cpp
    backends/platform/n64/framfs_save_manager.h
    backends/platform/n64/pakfs_save_manager.h
    backends/saves/default/default-saves.h


diff --git a/backends/platform/dc/vmsave.cpp b/backends/platform/dc/vmsave.cpp
index ab5a3e77a2..2c98b65dd2 100644
--- a/backends/platform/dc/vmsave.cpp
+++ b/backends/platform/dc/vmsave.cpp
@@ -306,7 +306,7 @@ public:
 		vmsfs_name_compare_function = nameCompare;
 	}
 
-	virtual Common::InSaveFile *openRawFile(const Common::String &filename) {
+	Common::InSaveFile *openRawFile(const Common::String &filename) override {
 		InVMSave *s = new InVMSave();
 		if (s->readSaveGame(filename.c_str())) {
 			return s;
@@ -316,26 +316,26 @@ public:
 		}
 	}
 
-	virtual Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true) {
+	Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true) override {
 		OutVMSave *s = new OutVMSave(filename.c_str());
 		return new Common::OutSaveFile(compress ? Common::wrapCompressedWriteStream(s) : s);
 	}
 
-  virtual Common::InSaveFile *openForLoading(const Common::String &filename) {
-	InVMSave *s = new InVMSave();
-	if (s->readSaveGame(filename.c_str())) {
-	  return Common::wrapCompressedReadStream(s);
-	} else {
-	  delete s;
-	  return NULL;
+	Common::InSaveFile *openForLoading(const Common::String &filename) override {
+		InVMSave *s = new InVMSave();
+		if (s->readSaveGame(filename.c_str())) {
+			return Common::wrapCompressedReadStream(s);
+		} else {
+			delete s;
+			return NULL;
+		}
 	}
-  }
 
-  virtual bool removeSavefile(const Common::String &filename) {
-	return ::deleteSaveGame(filename.c_str());
-  }
+	bool removeSavefile(const Common::String &filename) override {
+		return ::deleteSaveGame(filename.c_str());
+	}
 
-  virtual Common::StringArray listSavefiles(const Common::String &pattern);
+	Common::StringArray listSavefiles(const Common::String &pattern) override;
 };
 
 void OutVMSave::finalize()
diff --git a/backends/platform/n64/framfs_save_manager.h b/backends/platform/n64/framfs_save_manager.h
index 209d53a08b..b7c5ebfbd2 100644
--- a/backends/platform/n64/framfs_save_manager.h
+++ b/backends/platform/n64/framfs_save_manager.h
@@ -102,13 +102,13 @@ public:
 
 class FRAMSaveManager : public Common::SaveFileManager {
 public:
-	virtual void updateSavefilesList(Common::StringArray &lockedFiles) {
+	void updateSavefilesList(Common::StringArray &lockedFiles) override {
 		// this method is used to lock saves while cloud syncing
 		// as there is no network on N64, this method wouldn't be used
 		// thus it's not implemtented
 	}
 
-	virtual Common::InSaveFile *openRawFile(const Common::String &filename) {
+	Common::InSaveFile *openRawFile(const Common::String &filename) override {
 		InFRAMSave *s = new InFRAMSave();
 		if (s->readSaveGame(filename.c_str())) {
 			return s;
@@ -118,7 +118,7 @@ public:
 		}
 	}
 
-	virtual Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true) {
+	Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true) override {
 		OutFRAMSave *s = new OutFRAMSave(filename.c_str());
 		if (!s->err()) {
 			return new Common::OutSaveFile(compress ? Common::wrapCompressedWriteStream(s) : s);
@@ -128,7 +128,7 @@ public:
 		}
 	}
 
-	virtual Common::InSaveFile *openForLoading(const Common::String &filename) {
+	Common::InSaveFile *openForLoading(const Common::String &filename) override {
 		InFRAMSave *s = new InFRAMSave();
 		if (s->readSaveGame(filename.c_str())) {
 			return Common::wrapCompressedReadStream(s);
@@ -138,11 +138,11 @@ public:
 		}
 	}
 
-	virtual bool removeSavefile(const Common::String &filename) {
+	bool removeSavefile(const Common::String &filename) override {
 		return ::fram_deleteSaveGame(filename.c_str());
 	}
 
-	virtual Common::StringArray listSavefiles(const Common::String &pattern);
+	Common::StringArray listSavefiles(const Common::String &pattern) override;
 };
 
 
diff --git a/backends/platform/n64/pakfs_save_manager.h b/backends/platform/n64/pakfs_save_manager.h
index 56b49ebcf8..d6f33e597a 100644
--- a/backends/platform/n64/pakfs_save_manager.h
+++ b/backends/platform/n64/pakfs_save_manager.h
@@ -104,13 +104,13 @@ public:
 
 class PAKSaveManager : public Common::SaveFileManager {
 public:
-	virtual void updateSavefilesList(Common::StringArray &lockedFiles) {
+	void updateSavefilesList(Common::StringArray &lockedFiles) override {
 		// this method is used to lock saves while cloud syncing
 		// as there is no network on N64, this method wouldn't be used
 		// thus it's not implemtented
 	}
 
-	virtual Common::InSaveFile *openRawFile(const Common::String &filename) {
+	Common::InSaveFile *openRawFile(const Common::String &filename) override {
 		InPAKSave *s = new InPAKSave();
 		if (s->readSaveGame(filename.c_str())) {
 			return s;
@@ -120,7 +120,7 @@ public:
 		}
 	}
 
-	virtual Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true) {
+	Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true) override {
 		OutPAKSave *s = new OutPAKSave(filename.c_str());
 		if (!s->err()) {
 			return new Common::OutSaveFile(compress ? Common::wrapCompressedWriteStream(s) : s);
@@ -130,7 +130,7 @@ public:
 		}
 	}
 
-	virtual Common::InSaveFile *openForLoading(const Common::String &filename) {
+	Common::InSaveFile *openForLoading(const Common::String &filename) override {
 		InPAKSave *s = new InPAKSave();
 		if (s->readSaveGame(filename.c_str())) {
 			return Common::wrapCompressedReadStream(s);
@@ -140,11 +140,11 @@ public:
 		}
 	}
 
-	virtual bool removeSavefile(const Common::String &filename) {
+	bool removeSavefile(const Common::String &filename) override {
 		return ::pakfs_deleteSaveGame(filename.c_str());
 	}
 
-	virtual Common::StringArray listSavefiles(const Common::String &pattern);
+	Common::StringArray listSavefiles(const Common::String &pattern) override;
 };
 
 
diff --git a/backends/saves/default/default-saves.h b/backends/saves/default/default-saves.h
index 2801dd5e01..1bd8e3d618 100644
--- a/backends/saves/default/default-saves.h
+++ b/backends/saves/default/default-saves.h
@@ -38,12 +38,12 @@ public:
 	DefaultSaveFileManager();
 	DefaultSaveFileManager(const Common::String &defaultSavepath);
 
-	virtual void updateSavefilesList(Common::StringArray &lockedFiles);
-	virtual Common::StringArray listSavefiles(const Common::String &pattern);
-	virtual Common::InSaveFile *openRawFile(const Common::String &filename);
-	virtual Common::InSaveFile *openForLoading(const Common::String &filename);
-	virtual Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true);
-	virtual bool removeSavefile(const Common::String &filename);
+	void updateSavefilesList(Common::StringArray &lockedFiles) override;
+	Common::StringArray listSavefiles(const Common::String &pattern) override;
+	Common::InSaveFile *openRawFile(const Common::String &filename) override;
+	Common::InSaveFile *openForLoading(const Common::String &filename) override;
+	Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true) override;
+	bool removeSavefile(const Common::String &filename) override;
 
 #ifdef USE_LIBCURL
 


Commit: a0c818bde6c472130eaead85f2f2bc3cdf0ce997
    https://github.com/scummvm/scummvm/commit/a0c818bde6c472130eaead85f2f2bc3cdf0ce997
Author: Orgad Shaneh (orgads at gmail.com)
Date: 2021-08-23T13:34:35+02:00

Commit Message:
COMMON: Introduce SaveFileManager::exists

Checks if a savefile with given name exists.

Implement on all backends.

Changed paths:
    backends/platform/dc/vmsave.cpp
    backends/platform/n64/framfs_save_manager.h
    backends/platform/n64/pakfs_save_manager.h
    backends/saves/default/default-saves.cpp
    backends/saves/default/default-saves.h
    common/savefile.h


diff --git a/backends/platform/dc/vmsave.cpp b/backends/platform/dc/vmsave.cpp
index 2c98b65dd2..44daba90a4 100644
--- a/backends/platform/dc/vmsave.cpp
+++ b/backends/platform/dc/vmsave.cpp
@@ -336,6 +336,10 @@ public:
 	}
 
 	Common::StringArray listSavefiles(const Common::String &pattern) override;
+
+	bool exists(const Common::String &filename) override {
+		return InVMSave().readSaveGame(filename.c_str());
+	}
 };
 
 void OutVMSave::finalize()
diff --git a/backends/platform/n64/framfs_save_manager.h b/backends/platform/n64/framfs_save_manager.h
index b7c5ebfbd2..7b92cc874d 100644
--- a/backends/platform/n64/framfs_save_manager.h
+++ b/backends/platform/n64/framfs_save_manager.h
@@ -143,6 +143,10 @@ public:
 	}
 
 	Common::StringArray listSavefiles(const Common::String &pattern) override;
+
+	bool exists(const Common::String &filename) override {
+		return InFRAMSave().readSaveGame(filename.c_str());
+	}
 };
 
 
diff --git a/backends/platform/n64/pakfs_save_manager.h b/backends/platform/n64/pakfs_save_manager.h
index d6f33e597a..0ee2d8b4c0 100644
--- a/backends/platform/n64/pakfs_save_manager.h
+++ b/backends/platform/n64/pakfs_save_manager.h
@@ -145,6 +145,10 @@ public:
 	}
 
 	Common::StringArray listSavefiles(const Common::String &pattern) override;
+
+	bool exists(const Common::String &filename) override {
+		return InPAKSave().readSaveGame(filename.c_str());
+	}
 };
 
 
diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp
index eb5e89bf63..d6129a224c 100644
--- a/backends/saves/default/default-saves.cpp
+++ b/backends/saves/default/default-saves.cpp
@@ -222,6 +222,20 @@ bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {
 	}
 }
 
+bool DefaultSaveFileManager::exists(const Common::String &filename) {
+	// Assure the savefile name cache is up-to-date.
+	assureCached(getSavePath());
+	if (getError().getCode() != Common::kNoError)
+		return false;
+
+	for (Common::StringArray::const_iterator i = _lockedFiles.begin(), end = _lockedFiles.end(); i != end; ++i) {
+		if (filename == *i)
+			return true;
+	}
+
+	return _saveFileCache.contains(filename);
+}
+
 Common::String DefaultSaveFileManager::getSavePath() const {
 
 	Common::String dir;
diff --git a/backends/saves/default/default-saves.h b/backends/saves/default/default-saves.h
index 1bd8e3d618..0557ffdc38 100644
--- a/backends/saves/default/default-saves.h
+++ b/backends/saves/default/default-saves.h
@@ -44,6 +44,7 @@ public:
 	Common::InSaveFile *openForLoading(const Common::String &filename) override;
 	Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true) override;
 	bool removeSavefile(const Common::String &filename) override;
+	bool exists(const Common::String &filename) override;
 
 #ifdef USE_LIBCURL
 
diff --git a/common/savefile.h b/common/savefile.h
index 0894022c8c..4253d715b0 100644
--- a/common/savefile.h
+++ b/common/savefile.h
@@ -268,6 +268,15 @@ public:
 	 * for saving or loading because they are being synced by CloudManager.
 	 */
 	virtual void updateSavefilesList(StringArray &lockedFiles) = 0;
+
+	/**
+	 * Checks if the savefile exists.
+	 *
+	 * @param name Name of the save file.
+	 *
+	 * @return true if the file exists. false otherwise.
+	 */
+	virtual bool exists(const String &name) = 0;
 };
 
 /** @} */


Commit: 6aeda1224741b4b07935f6932355c5decc7ce0b9
    https://github.com/scummvm/scummvm/commit/6aeda1224741b4b07935f6932355c5decc7ce0b9
Author: Orgad Shaneh (orgads at gmail.com)
Date: 2021-08-23T13:34:35+02:00

Commit Message:
ENGINES: Warn when overwriting a non-autosave on autosave

Changed paths:
    engines/engine.cpp
    engines/engine.h
    engines/metaengine.cpp
    engines/metaengine.h
    engines/savestate.cpp
    engines/savestate.h


diff --git a/engines/engine.cpp b/engines/engine.cpp
index b3877c24c9..89ef64c5db 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -149,6 +149,7 @@ Engine::Engine(OSystem *syst)
 		_pauseLevel(0),
 		_pauseStartTime(0),
 		_saveSlotToLoad(-1),
+		_autoSaving(false),
 		_engineStartTime(_system->getMillis()),
 		_mainMenuDialog(NULL),
 		_debugger(NULL),
@@ -541,34 +542,68 @@ void Engine::handleAutoSave() {
 	}
 }
 
-void Engine::saveAutosaveIfEnabled() {
-	// Reset the last autosave time first.
-	// Doing it here rather than after saving the game prevents recursive calls if saving the game
-	// causes the engine to poll events (as is the case with the AGS engine for example).
-	_lastAutosaveTime = _system->getMillis();
-
-	if (_autosaveInterval != 0) {
-		bool saveFlag = canSaveAutosaveCurrently();
-
-		if (saveFlag) {
-			// First check for an existing savegame in the slot, and if present, if it's an autosave
-			SaveStateDescriptor desc = getMetaEngine()->querySaveMetaInfos(
-				_targetName.c_str(), getAutosaveSlot());
-			saveFlag = desc.getSaveSlot() == -1 || desc.isAutosave();
+bool Engine::warnBeforeOverwritingAutosave() {
+	SaveStateDescriptor desc = getMetaEngine()->querySaveMetaInfos(
+		_targetName.c_str(), getAutosaveSlot());
+	if (desc.getSaveSlot() == -1)
+		return true;
+	if (desc.hasAutosaveName())
+		return true;
+	Common::U32StringArray altButtons;
+	altButtons.push_back(_("Overwrite"));
+	altButtons.push_back(_("Cancel autosave"));
+	const Common::U32String message = Common::U32String::format(
+				_("WARNING: The autosave slot has a saved game named %s. "
+				  "You can either move the existing save to a new slot, "
+				  "Overwrite the existing save, "
+				  "or cancel autosave (will not prompt again until restart)"), desc.getDescription().c_str());
+	GUI::MessageDialog warn(message, _("Move"), altButtons);
+	switch (runDialog(warn)) {
+	case GUI::kMessageOK:
+		if (!getMetaEngine()->copySaveFileToFreeSlot(_targetName.c_str(), getAutosaveSlot())) {
+			GUI::MessageDialog error(_("ERROR: Could not copy the savegame to a new slot"));
+			error.runModal();
+			return false;
 		}
+		return true;
+	case GUI::kMessageAlt: // Overwrite
+		return true;
+	case GUI::kMessageAlt + 1: // Cancel autosave
+		_autosaveInterval = 0;
+		return false;
+	default: // Hitting Escape returns -1. On this case, don't save but do prompt again later.
+		return false;
+	}
+}
 
-		if (saveFlag && saveGameState(getAutosaveSlot(), Common::convertFromU32String(_("Autosave")), true).getCode() != Common::kNoError) {
-			// Couldn't autosave at the designated time
-			g_system->displayMessageOnOSD(_("Error occurred making autosave"));
-			saveFlag = false;
-		}
+void Engine::saveAutosaveIfEnabled() {
+	// Prevents recursive calls if saving the game causes the engine to poll events
+	// (as is the case with the AGS engine for example, or when showing a prompt).
+	if (_autoSaving || _autosaveInterval == 0)
+		return;
+	_autoSaving = true;
 
-		if (!saveFlag) {
-			// Set the next autosave interval to be in 5 minutes, rather than whatever
-			// full autosave interval the user has selected
-			_lastAutosaveTime += (5 * 60 * 1000) - _autosaveInterval;
-		}
+	bool saveFlag = canSaveAutosaveCurrently();
+	const Common::String autoSaveName = Common::convertFromU32String(_("Autosave"));
+
+	// First check for an existing savegame in the slot, and if present, if it's an autosave
+	if (saveFlag)
+		saveFlag = warnBeforeOverwritingAutosave();
+
+	if (saveFlag && saveGameState(getAutosaveSlot(), autoSaveName, true).getCode() != Common::kNoError) {
+		// Couldn't autosave at the designated time
+		g_system->displayMessageOnOSD(_("Error occurred making autosave"));
+		saveFlag = false;
+	}
+
+	if (saveFlag) {
+		_lastAutosaveTime = _system->getMillis();
+	} else {
+		// Set the next autosave interval to be in 5 minutes, rather than whatever
+		// full autosave interval the user has selected
+		_lastAutosaveTime += (5 * 60 * 1000) - _autosaveInterval;
 	}
+	_autoSaving = false;
 }
 
 void Engine::errorString(const char *buf1, char *buf2, int size) {
diff --git a/engines/engine.h b/engines/engine.h
index 33d62c5c78..01d57ccff1 100644
--- a/engines/engine.h
+++ b/engines/engine.h
@@ -203,7 +203,7 @@ private:
 	/**
 	 * Autosave interval.
 	 */
-	const int _autosaveInterval;
+	int _autosaveInterval;
 
 	/**
 	 * The last time an autosave was done.
@@ -218,6 +218,11 @@ private:
 	 */
 	int _saveSlotToLoad;
 
+	/**
+	 * Used for preventing recursion during autosave.
+	 */
+	bool _autoSaving;
+
 	/**
 	 * Optional debugger for the engine.
 	 */
@@ -526,6 +531,13 @@ private:
 	 */
 	friend class PauseToken;
 
+	/**
+	 * Warns before overwriting autosave.
+	 *
+	 * @return true if it is safe to save, false to avoid saving.
+	 */
+	bool warnBeforeOverwritingAutosave();
+
 public:
 
 	/**
diff --git a/engines/metaengine.cpp b/engines/metaengine.cpp
index 4821ca0066..c9eb46c92c 100644
--- a/engines/metaengine.cpp
+++ b/engines/metaengine.cpp
@@ -209,6 +209,15 @@ void MetaEngine::appendExtendedSaveToStream(Common::WriteStream *saveFile, uint3
 	saveFile->writeUint32LE(headerPos);	// Store where the header starts
 }
 
+bool MetaEngine::copySaveFileToFreeSlot(const char *target, int slot)
+{
+	const int emptySlot = findEmptySaveSlot(target);
+	if (emptySlot == -1)
+		return false;
+	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+	return saveFileMan->copySavefile(getSavegameFile(slot, target), getSavegameFile(emptySlot, target));
+}
+
 void MetaEngine::getSavegameThumbnail(Graphics::Surface &thumb) {
 	::createThumbnailFromScreen(&thumb);
 }
@@ -295,6 +304,23 @@ WARN_UNUSED_RESULT bool MetaEngine::readSavegameHeader(Common::InSaveFile *in, E
 // MetaEngine default implementations
 //////////////////////////////////////////////
 
+int MetaEngine::findEmptySaveSlot(const char *target) {
+	if (!hasFeature(kSavesUseExtendedFormat))
+		return -1;
+
+	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+	const int maxSaveSlot = getMaximumSaveSlot();
+	const int autosaveSlot = getAutosaveSlot();
+	for (int slot = 0; slot <= maxSaveSlot; ++slot) {
+		if (slot == autosaveSlot)
+			continue;
+		const Common::String filename = getSavegameFile(slot, target);
+		if (!saveFileMan->exists(filename))
+			return slot;
+	}
+	return -1;
+}
+
 SaveStateList MetaEngine::listSaves(const char *target) const {
 	if (!hasFeature(kSavesUseExtendedFormat))
 		return SaveStateList();
@@ -336,7 +362,7 @@ SaveStateList MetaEngine::listSaves(const char *target, bool saveMode) const {
 			return saveList;
 	}
 
-	// No autosave yet. We want to add a dummy one in so that it can be marked as'
+	// No autosave yet. We want to add a dummy one in so that it can be marked as
 	// write protected, and thus be prevented from being saved in
 	SaveStateDescriptor desc(autosaveSlot, _("Autosave"));
 	saveList.push_back(desc);
diff --git a/engines/metaengine.h b/engines/metaengine.h
index 0c33c9b236..a0c72bac10 100644
--- a/engines/metaengine.h
+++ b/engines/metaengine.h
@@ -232,6 +232,15 @@ protected:
 	 * dialog so that it won't appear in the thumbnail.
 	 */
 	virtual void getSavegameThumbnail(Graphics::Surface &thumb);
+
+	/**
+	 * Finds the first empty save slot that can be used for this target
+	 * @param target Name of a config manager target.
+	 *
+	 * @return The first empty save slot, or -1 if all are occupied.
+	 */
+	int findEmptySaveSlot(const char *target);
+
 public:
 	virtual ~MetaEngine() {}
 
@@ -520,6 +529,15 @@ public:
 	 */
 	void appendExtendedSaveToStream(Common::WriteStream *saveFile, uint32 playtime, Common::String desc, bool isAutosave, uint32 offset = 0);
 
+	/**
+	 * Copies an existing save file to the first empty slot which is not autosave
+	 * @param target Name of a config manager target.
+	 * @param slot   Slot number of the save state.
+	 *
+	 * @return true if an empty slot was found and the save state was copied. false otherwise.
+	 */
+	bool copySaveFileToFreeSlot(const char *target, int slot);
+
 	/**
 	 * Parse the extended savegame header to retrieve the SaveStateDescriptor information.
 	 */
diff --git a/engines/savestate.cpp b/engines/savestate.cpp
index 83d5bccb79..08d4394bb4 100644
--- a/engines/savestate.cpp
+++ b/engines/savestate.cpp
@@ -44,8 +44,7 @@ SaveStateDescriptor::SaveStateDescriptor(int slot, const Common::String &d)
 	initSaveType();
 }
 
-void SaveStateDescriptor::initSaveType()
-{
+void SaveStateDescriptor::initSaveType() {
 	// Do not allow auto-save slot to be deleted or overwritten.
 	const bool autosave =
 			g_engine && ConfMan.getInt("autosave_period") && _slot == g_engine->getAutosaveSlot();
@@ -88,6 +87,11 @@ bool SaveStateDescriptor::isAutosave() const {
 	if (_saveType != kSaveTypeUndetermined) {
 		return _saveType == kSaveTypeAutosave;
 	} else {
-		return _description == _("Autosave");
+		return hasAutosaveName();
 	}
 }
+
+bool SaveStateDescriptor::hasAutosaveName() const
+{
+	return _description.contains(_("Autosave"));
+}
diff --git a/engines/savestate.h b/engines/savestate.h
index fa126877b4..c537ebb8d3 100644
--- a/engines/savestate.h
+++ b/engines/savestate.h
@@ -214,6 +214,11 @@ public:
 	 * Returns true whether the save is an autosave
 	 */
 	bool isAutosave() const;
+
+	/**
+	 * Returns true if the save has an autosave name
+	 */
+	bool hasAutosaveName() const;
 private:
 	/**
 	 * The saveslot id, as it would be passed to the "-x" command line switch.




More information about the Scummvm-git-logs mailing list