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

sev- noreply at scummvm.org
Sun Jun 15 08:28:03 UTC 2025


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

Summary:
c536d85fa7 SLUDGE: Add support for extended saves
748fba130d SLUDGE: Support return to launcher
232c5c8f03 SLUDGE: Add Verbcoin2 to detection table
d820a6b249 SLUDGE: Fix condition in GraphicsManager::skipThumbnail()
537bc0a666 SLUDGE: Use MetaEngine::listSaves() when listing save files
c29e5f4175 SLUDGE: Fix coloured blank screens not being drawn
8c90b661c5 SLUDGE: Simulate right mouse click as CTRL+left mouse click
aa1df5bbc2 SLUDGE: Pop message box when trying to quit a game
6b7b14e13e SLUDGE: Fix savegame being undetected in builtIn(fileExists)
f620a0eeba SLUDGE: Fix occasional crashes during autosaves


Commit: c536d85fa7e10b0cbe7416046f3b8e33bbc1c18f
    https://github.com/scummvm/scummvm/commit/c536d85fa7e10b0cbe7416046f3b8e33bbc1c18f
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Add support for extended saves

Changed paths:
    engines/sludge/builtin.cpp
    engines/sludge/main_loop.cpp
    engines/sludge/metaengine.cpp
    engines/sludge/saveload.cpp
    engines/sludge/saveload.h
    engines/sludge/sludge.cpp
    engines/sludge/sludge.h
    engines/sludge/variable.cpp


diff --git a/engines/sludge/builtin.cpp b/engines/sludge/builtin.cpp
index 7e10ff54837..ac4d5473db3 100644
--- a/engines/sludge/builtin.cpp
+++ b/engines/sludge/builtin.cpp
@@ -24,6 +24,8 @@
 #include "common/savefile.h"
 #include "common/system.h"
 
+#include "engines/metaengine.h"
+
 #include "sludge/builtin.h"
 #include "sludge/cursors.h"
 #include "sludge/event.h"
@@ -38,6 +40,7 @@
 #include "sludge/people.h"
 #include "sludge/region.h"
 #include "sludge/savedata.h"
+#include "sludge/sludge.h"
 #include "sludge/sludger.h"
 #include "sludge/sound.h"
 #include "sludge/speech.h"
@@ -244,6 +247,15 @@ builtIn(fileExists) {
 	Common::String aaaaa = encodeFilename(g_sludge->loadNow);
 	g_sludge->loadNow.clear();
 
+	uint extensionLength = aaaaa.size() - aaaaa.rfind('.');
+
+	if (aaaaa.size() != extensionLength) {
+		Common::String nameWithoutExtension = aaaaa.substr(0, aaaaa.size() - extensionLength);
+		if (g_sludge->_saveNameToSlot.contains(nameWithoutExtension)) {
+			aaaaa = g_sludge->getSaveStateName(g_sludge->_saveNameToSlot[nameWithoutExtension]);
+		}
+	}
+
 	if (failSecurityCheck(aaaaa))
 		return BR_ERROR;
 
@@ -269,6 +281,40 @@ builtIn(fileExists) {
 builtIn(loadGame) {
 	UNUSEDALL
 	Common::String aaaaa = fun->stack->thisVar.getTextFromAnyVar();
+
+	uint extensionLength = aaaaa.size() - aaaaa.rfind('.');
+	Common::String nameWithoutExtension = aaaaa.substr(0, aaaaa.size() - extensionLength);
+
+	if (g_sludge->_saveNameToSlot.contains(nameWithoutExtension)) {
+		aaaaa = g_sludge->getSaveStateName(g_sludge->_saveNameToSlot[nameWithoutExtension]);
+	} else {
+		// If the game uses only one save (like robinsrescue)
+		Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+		int maxSaveSlot = g_sludge->getMetaEngine()->getMaximumSaveSlot();
+		int autosaveSlot = g_sludge->getMetaEngine()->getAutosaveSlot();
+		for (int slot = 0; slot <= maxSaveSlot; ++slot) {
+			if (slot == autosaveSlot)
+				continue;
+			const Common::String filename = g_sludge->getMetaEngine()->getSavegameFile(slot, g_sludge->getTargetName().c_str());
+			if (saveFileMan->exists(filename)) {
+				ExtendedSavegameHeader header;
+				Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(filename);
+
+				if (f && g_sludge->getMetaEngine()->readSavegameHeader(f, &header)) {
+					if (nameWithoutExtension == header.description) {
+						g_sludge->_saveNameToSlot[header.description] = slot;
+						aaaaa = g_sludge->getSaveStateName(slot);
+
+						delete f;
+						break;
+					}
+				}
+
+				delete f;
+			}
+		}
+	}
+
 	trimStack(fun->stack);
 	g_sludge->loadNow.clear();
 	g_sludge->loadNow = encodeFilename(aaaaa);
@@ -2426,6 +2472,13 @@ builtIn(showThumbnail) {
 
 	// Encode the name!Encode the name!
 	Common::String aaaaa = fun->stack->thisVar.getTextFromAnyVar();
+	uint extensionLength = aaaaa.size() - aaaaa.rfind('.');
+	aaaaa = aaaaa.substr(0, aaaaa.size() - extensionLength);
+
+	if (g_sludge->_saveNameToSlot.contains(aaaaa)) {
+		aaaaa = g_sludge->getSaveStateName(g_sludge->_saveNameToSlot[aaaaa]);
+	}
+
 	trimStack(fun->stack);
 	Common::String file = encodeFilename(aaaaa);
 	g_sludge->_gfxMan->showThumbnail(file, x, y);
diff --git a/engines/sludge/main_loop.cpp b/engines/sludge/main_loop.cpp
index 79742dbc1ab..aaa0f257fc0 100644
--- a/engines/sludge/main_loop.cpp
+++ b/engines/sludge/main_loop.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "common/config-manager.h"
 #include "common/system.h"
 
 #include "sludge/event.h"
@@ -48,6 +49,10 @@ int main_loop(Common::String filename) {
 	g_sludge->_evtMan->startGame();
 	g_sludge->_timer->init();
 
+	int saveSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
+	if (saveSlot != -1)
+		g_sludge->loadNow = g_sludge->getSaveStateName(saveSlot);
+
 	while (!g_sludge->_evtMan->quit()) {
 		g_sludge->_evtMan->checkInput();
 		g_sludge->_peopleMan->walkAllPeople();
diff --git a/engines/sludge/metaengine.cpp b/engines/sludge/metaengine.cpp
index cc1c32295d1..bd7d98525e2 100644
--- a/engines/sludge/metaengine.cpp
+++ b/engines/sludge/metaengine.cpp
@@ -42,12 +42,18 @@ public:
 		return "sludge";
 	}
 
+	bool hasFeature(MetaEngineFeature f) const override;
+
 	Common::Error createInstance(OSystem *syst, Engine **engine, const Sludge::SludgeGameDescription *desc) const override {
 		*engine = new Sludge::SludgeEngine(syst, desc);
 		return Common::kNoError;
 	}
 };
 
+bool SludgeMetaEngine::hasFeature(MetaEngineFeature f) const {
+	return checkExtendedSaves(f) || (f == kSupportsLoadingDuringStartup);
+}
+
 #if PLUGIN_ENABLED_DYNAMIC(SLUDGE)
 	REGISTER_PLUGIN_DYNAMIC(SLUDGE, PLUGIN_TYPE_ENGINE, SludgeMetaEngine);
 #else
diff --git a/engines/sludge/saveload.cpp b/engines/sludge/saveload.cpp
index f8361ed5d8e..34b75a8c820 100644
--- a/engines/sludge/saveload.cpp
+++ b/engines/sludge/saveload.cpp
@@ -23,6 +23,8 @@
 
 #include "common/savefile.h"
 
+#include "engines/metaengine.h"
+
 #include "sludge/cursors.h"
 #include "sludge/errors.h"
 #include "sludge/event.h"
@@ -63,7 +65,47 @@ extern bool allowAnyFilename;
 bool handleSaveLoad() {
 	if (!g_sludge->loadNow.empty()) {
 		if (g_sludge->loadNow[0] == ':') {
-			saveGame(g_sludge->loadNow.c_str() + 1);
+			Common::String saveName = g_sludge->loadNow.c_str() + 1;
+			uint extensionLength = saveName.size() - saveName.rfind('.');
+			saveName = saveName.substr(0, saveName.size() - extensionLength);
+
+			int slot = -1;
+			if (g_sludge->_saveNameToSlot.contains(saveName)) {
+				slot = g_sludge->_saveNameToSlot[saveName];
+			} else {
+				// Find next available save slot
+				Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+				int maxSaveSlot = g_sludge->getMetaEngine()->getMaximumSaveSlot();
+				int autosaveSlot = g_sludge->getMetaEngine()->getAutosaveSlot();
+				for (int i = 0; i <= maxSaveSlot; ++i) {
+					if (i == autosaveSlot)
+						continue;
+					const Common::String filename = g_sludge->getMetaEngine()->getSavegameFile(i, g_sludge->getTargetName().c_str());
+					if (!saveFileMan->exists(filename)) {
+						slot = i;
+						break;
+					} else {
+						// If the game uses only one save for everything (like robinsresque)
+						// use that save
+						Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(filename);
+						ExtendedSavegameHeader header;
+						if (MetaEngine::readSavegameHeader(fp, &header)) {
+							if (saveName == header.description) {
+								slot = i;
+								g_sludge->_saveNameToSlot[saveName] = slot;
+								delete fp;
+								break;
+							}
+						}
+						delete fp;
+					}
+				}
+				if (slot == -1) {
+					slot = g_sludge->getMetaEngine()->getMaximumSaveSlot();
+				}
+			}
+
+			g_sludge->saveGameState(slot, saveName, false);
 			saverFunc->reg.setVariable(SVT_INT, 1);
 		} else {
 			if (!loadGame(g_sludge->loadNow))
@@ -74,40 +116,38 @@ bool handleSaveLoad() {
 	return true;
 }
 
-bool saveGame(const Common::String &fname) {
-	Common::OutSaveFile *fp = g_system->getSavefileManager()->openForSaving(fname);
-
-	if (fp == NULL)
+bool saveGame(Common::OutSaveFile *saveFile) {
+	if (saveFile == NULL)
 		return false;
 
-	fp->writeString("SLUDSA");
-	fp->writeByte(0);
-	fp->writeByte(0);
-	fp->writeByte(MAJOR_VERSION);
-	fp->writeByte(MINOR_VERSION);
+	saveFile->writeString("SLUDSA");
+	saveFile->writeByte(0);
+	saveFile->writeByte(0);
+	saveFile->writeByte(MAJOR_VERSION);
+	saveFile->writeByte(MINOR_VERSION);
 
-	if (!g_sludge->_gfxMan->saveThumbnail(fp))
+	if (!g_sludge->_gfxMan->saveThumbnail(saveFile))
 		return false;
 
-	fp->write(&fileTime, sizeof(FILETIME));
+	saveFile->write(&fileTime, sizeof(FILETIME));
 
 	// DON'T ADD ANYTHING NEW BEFORE THIS POINT!
 
-	fp->writeByte(allowAnyFilename);
-	fp->writeByte(false); // deprecated captureAllKeys
-	fp->writeByte(true);
-	g_sludge->_txtMan->saveFont(fp);
+	saveFile->writeByte(allowAnyFilename);
+	saveFile->writeByte(false); // deprecated captureAllKeys
+	saveFile->writeByte(true);
+	g_sludge->_txtMan->saveFont(saveFile);
 
 	// Save backdrop
-	g_sludge->_gfxMan->saveBackdrop(fp);
+	g_sludge->_gfxMan->saveBackdrop(saveFile);
 
 	// Save event handlers
-	g_sludge->_evtMan->saveHandlers(fp);
+	g_sludge->_evtMan->saveHandlers(saveFile);
 
 	// Save regions
-	g_sludge->_regionMan->saveRegions(fp);
+	g_sludge->_regionMan->saveRegions(saveFile);
 
-	g_sludge->_cursorMan->saveCursor(fp);
+	g_sludge->_cursorMan->saveCursor(saveFile);
 
 	// Save functions
 	LoadedFunction *thisFunction = allRunningFunctions;
@@ -116,45 +156,41 @@ bool saveGame(const Common::String &fname) {
 		countFunctions++;
 		thisFunction = thisFunction->next;
 	}
-	fp->writeUint16BE(countFunctions);
+	saveFile->writeUint16BE(countFunctions);
 
 	thisFunction = allRunningFunctions;
 	while (thisFunction) {
-		saveFunction(thisFunction, fp);
+		saveFunction(thisFunction, saveFile);
 		thisFunction = thisFunction->next;
 	}
 
 	for (int a = 0; a < numGlobals; a++) {
-		globalVars[a].save(fp);
+		globalVars[a].save(saveFile);
 	}
 
-	g_sludge->_peopleMan->savePeople(fp);
+	g_sludge->_peopleMan->savePeople(saveFile);
 
-	g_sludge->_floorMan->save(fp);
+	g_sludge->_floorMan->save(saveFile);
 
-	g_sludge->_gfxMan->saveZBuffer(fp);
-	g_sludge->_gfxMan->saveLightMap(fp);
+	g_sludge->_gfxMan->saveZBuffer(saveFile);
+	g_sludge->_gfxMan->saveLightMap(saveFile);
 
-	g_sludge->_speechMan->save(fp);
-	g_sludge->_statusBar->saveStatusBars(fp);
-	g_sludge->_soundMan->saveSounds(fp);
+	g_sludge->_speechMan->save(saveFile);
+	g_sludge->_statusBar->saveStatusBars(saveFile);
+	g_sludge->_soundMan->saveSounds(saveFile);
 
-	fp->writeUint16BE(CustomSaveHelper::_saveEncoding);
+	saveFile->writeUint16BE(CustomSaveHelper::_saveEncoding);
 
-	g_sludge->_gfxMan->blur_saveSettings(fp);
+	g_sludge->_gfxMan->blur_saveSettings(saveFile);
 
-	g_sludge->_gfxMan->saveColors(fp);
+	g_sludge->_gfxMan->saveColors(saveFile);
 
-	g_sludge->_gfxMan->saveParallax(fp);
-	fp->writeByte(0);
+	g_sludge->_gfxMan->saveParallax(saveFile);
+	saveFile->writeByte(0);
 
-	g_sludge->_languageMan->saveLanguageSetting(fp);
+	g_sludge->_languageMan->saveLanguageSetting(saveFile);
 
-	g_sludge->_gfxMan->saveSnapshot(fp);
-
-	fp->flush();
-	fp->finalize();
-	delete fp;
+	g_sludge->_gfxMan->saveSnapshot(saveFile);
 
 	clearStackLib();
 	return true;
@@ -308,6 +344,10 @@ bool loadGame(const Common::String &fname) {
 		}
 	}
 
+	ExtendedSavegameHeader header;
+	if (MetaEngine::readSavegameHeader(fp, &header))
+		g_sludge->setTotalPlayTime(header.playtime);
+
 	delete fp;
 
 	clearStackLib();
diff --git a/engines/sludge/saveload.h b/engines/sludge/saveload.h
index 3996e0884b8..af419f5e04f 100644
--- a/engines/sludge/saveload.h
+++ b/engines/sludge/saveload.h
@@ -21,10 +21,14 @@
 #ifndef SLUDGE_LOADSAVE_H
 #define SLUDGE_LOADSAVE_H
 
+namespace Common {
+class OutSaveFile;
+}
+
 namespace Sludge {
 
 bool handleSaveLoad();
-bool saveGame(const Common::String &fname);
+bool saveGame(Common::OutSaveFile *saveFile);
 bool loadGame(const Common::String &fname);
 
 } // End of namespace Sludge
diff --git a/engines/sludge/sludge.cpp b/engines/sludge/sludge.cpp
index 2b8ac3e18f7..dd9377d7779 100644
--- a/engines/sludge/sludge.cpp
+++ b/engines/sludge/sludge.cpp
@@ -22,6 +22,9 @@
 #include "common/debug-channels.h"
 #include "common/error.h"
 #include "common/random.h"
+#include "common/savefile.h"
+
+#include "engines/metaengine.h"
 
 #include "sludge/cursors.h"
 #include "sludge/event.h"
@@ -35,6 +38,7 @@
 #include "sludge/objtypes.h"
 #include "sludge/people.h"
 #include "sludge/region.h"
+#include "sludge/saveload.h"
 #include "sludge/sludge.h"
 #include "sludge/sound.h"
 #include "sludge/speech.h"
@@ -129,6 +133,42 @@ SludgeEngine::~SludgeEngine() {
 	delete _timer;
 }
 
+bool SludgeEngine::canLoadGameStateCurrently(Common::U32String *msg) {
+	return !g_sludge->_evtMan->quit();
+}
+
+bool SludgeEngine::canSaveGameStateCurrently(Common::U32String *msg) {
+	return !g_sludge->_evtMan->quit();
+}
+
+Common::Error SludgeEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
+	Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(getSaveStateName(slot));
+
+	if (!saveFile)
+		return Common::kWritingFailed;
+
+	Common::Error result = saveGame(saveFile) ? Common::kNoError : Common::kWritingFailed;
+	if (result.getCode() == Common::kNoError) {
+		getMetaEngine()->appendExtendedSave(saveFile, getTotalPlayTime(), desc, isAutosave);
+
+		saveFile->finalize();
+	}
+
+	delete saveFile;
+	return result;
+}
+
+Common::Error SludgeEngine::loadGameState(int slot) {
+	saveAutosaveIfEnabled();
+
+	Common::Error result = loadGame(getSaveStateName(slot)) ? Common::kNoError : Common::kReadingFailed;
+	return result;
+}
+
+bool SludgeEngine::hasFeature(EngineFeature f) const {
+	return (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime);
+}
+
 Common::Error SludgeEngine::run() {
 	// set global variable
 	g_sludge = this;
diff --git a/engines/sludge/sludge.h b/engines/sludge/sludge.h
index 5e06cad43a8..d0e1e424d7c 100644
--- a/engines/sludge/sludge.h
+++ b/engines/sludge/sludge.h
@@ -22,6 +22,8 @@
 #ifndef SLUDGE_SLUDGE_H
 #define SLUDGE_SLUDGE_H
 
+#include "common/hash-str.h"
+
 #include "engines/engine.h"
 
 namespace Common {
@@ -103,6 +105,7 @@ public:
 	uint getLanguageID() const;
 	const char *getGameId() const;
 	uint32 getFeatures() const;
+	Common::String getTargetName() const { return _targetName; }
 	Common::Language getLanguage() const;
 	Graphics::PixelFormat *getScreenPixelFormat() const;
 	Graphics::PixelFormat *getOrigPixelFormat() const;
@@ -110,8 +113,18 @@ public:
 
 	const char *getGameFile() const;
 
+	bool hasFeature(EngineFeature f) const override;
+
+	bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
+	bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
+
+	Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave) override;
+	Common::Error loadGameState(int slot) override;
+
 	const SludgeGameDescription *_gameDescription;
 
+	Common::HashMap<Common::String, int> _saveNameToSlot;
+
 private:
 	Common::RandomSource *_rnd;
 	Graphics::PixelFormat *_pixelFormat;
diff --git a/engines/sludge/variable.cpp b/engines/sludge/variable.cpp
index 5142ed65be3..4e4366cd0b8 100644
--- a/engines/sludge/variable.cpp
+++ b/engines/sludge/variable.cpp
@@ -23,6 +23,8 @@
 #include "common/savefile.h"
 #include "common/system.h"
 
+#include "engines/metaengine.h"
+
 #include "sludge/fileset.h"
 #include "sludge/moreio.h"
 #include "sludge/newfatal.h"
@@ -194,22 +196,38 @@ static int stringCompareToIgnoreCase(const Common::String &s1, const Common::Str
 
 bool StackHandler::getSavedGamesStack(const Common::String &ext) {
 	// Make pattern
-	uint len = ext.size();
-	Common::String pattern = "*";
-	pattern += ext;
+	Common::String realExtension = ".###";
+	//uint len = realExtension.size();
+	Common::String pattern = g_sludge->getTargetName();
+	pattern += realExtension;
 
 	// Get all saved files
 	Common::StringArray sa = g_system->getSavefileManager()->listSavefiles(pattern);
+	Common::StringArray realNames;
+
+	g_sludge->_saveNameToSlot.clear();
+
+	for (auto &fname : sa) {
+		ExtendedSavegameHeader header;
+		Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fname);
+
+		if (f && g_sludge->getMetaEngine()->readSavegameHeader(f, &header)) {
+			realNames.push_back(header.description);
+			int slot = atoi(fname.substr(fname.size() - 3, 3).c_str());
+			g_sludge->_saveNameToSlot[header.description] = slot;
+		}
+
+		delete f;
+	}
 
-	Common::sort(sa.begin(), sa.end(), stringCompareToIgnoreCase);
+	Common::sort(realNames.begin(), realNames.end(), stringCompareToIgnoreCase);
 
 
 	// Save file names to stacks
 	Variable newName;
 	newName.varType = SVT_NULL;
 
-	for (Common::StringArray::iterator it = sa.begin(); it != sa.end(); ++it) {
-		(*it).erase((*it).size() - len, len);
+	for (Common::StringArray::iterator it = realNames.begin(); it != realNames.end(); ++it) {
 		newName.makeTextVar((*it));
 		if (!addVarToStack(newName, first))
 			return false;


Commit: 748fba130d43e9eee467a2a313b30830c62be7f2
    https://github.com/scummvm/scummvm/commit/748fba130d43e9eee467a2a313b30830c62be7f2
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Support return to launcher

Changed paths:
    engines/sludge/event.cpp
    engines/sludge/sludge.cpp


diff --git a/engines/sludge/event.cpp b/engines/sludge/event.cpp
index cdae7d31aa5..c2b8f8d596e 100644
--- a/engines/sludge/event.cpp
+++ b/engines/sludge/event.cpp
@@ -136,6 +136,7 @@ void EventManager::checkInput() {
 			break;
 
 		case Common::EVENT_QUIT:
+		case Common::EVENT_RETURN_TO_LAUNCHER:
 			_weAreDoneSoQuit = 1;
 			// TODO: if _reallyWantToQuit, popup a message box to confirm
 			break;
diff --git a/engines/sludge/sludge.cpp b/engines/sludge/sludge.cpp
index dd9377d7779..80fdb598188 100644
--- a/engines/sludge/sludge.cpp
+++ b/engines/sludge/sludge.cpp
@@ -166,7 +166,9 @@ Common::Error SludgeEngine::loadGameState(int slot) {
 }
 
 bool SludgeEngine::hasFeature(EngineFeature f) const {
-	return (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime);
+	return (f == kSupportsReturnToLauncher) ||
+		(f == kSupportsLoadingDuringRuntime) ||
+		(f == kSupportsSavingDuringRuntime);
 }
 
 Common::Error SludgeEngine::run() {


Commit: 232c5c8f03789db3dca6f6bb4ce5589c3eb34a15
    https://github.com/scummvm/scummvm/commit/232c5c8f03789db3dca6f6bb4ce5589c3eb34a15
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Add Verbcoin2 to detection table

Changed paths:
    engines/sludge/detection.cpp
    engines/sludge/detection_tables.h


diff --git a/engines/sludge/detection.cpp b/engines/sludge/detection.cpp
index e48fb5b15af..95cb92f8be7 100644
--- a/engines/sludge/detection.cpp
+++ b/engines/sludge/detection.cpp
@@ -40,6 +40,7 @@ static const PlainGameDescriptor sludgeGames[] = {
 	{ "sludge",			"Sludge Game" },
 	{ "welcome",		"Welcome Example" },
 	{ "verbcoin",		"Verb Coin" },
+	{ "verbcoin2",		"Verb Coin 2"},
 	{ "parallax",		"Parallax Demo" },
 	{ "robinsrescue",	"Robin's Rescue" },
 	{ "outoforder",		"Out Of Order" },
diff --git a/engines/sludge/detection_tables.h b/engines/sludge/detection_tables.h
index 77b2db1c879..d45e75f9dc0 100644
--- a/engines/sludge/detection_tables.h
+++ b/engines/sludge/detection_tables.h
@@ -32,6 +32,8 @@ static const SludgeGameDescription gameDescriptions[] = {
 
 	GAME1("verbcoin", "", "Verb Coin.slg", "e39ec315dcbf3a1137481f0a5fe1617d", 980270),
 	GAME1l("verbcoin", "", "Verb Coin.slg", "e39ec315dcbf3a1137481f0a5fe1617d", 980270, Common::DE_DEU, Common::kPlatformUnknown, 1),
+	GAME1("verbcoin2", "", "Verb Coin.slg", "483b315990309c718617c7c47fa132d8", 1067575),
+	GAME1l("verbcoin2", "", "Verb Coin.slg", "483b315990309c718617c7c47fa132d8", 1067575, Common::DE_DEU, Common::kPlatformUnknown, 1),
 
 	GAME1("parallax", "", "Parallax_demo.slg", "daae3f75c6695bed47e5e633cd406a47", 65881),
 


Commit: d820a6b2499b0cf2be12a19fcf9f99b8b082f8c0
    https://github.com/scummvm/scummvm/commit/d820a6b2499b0cf2be12a19fcf9f99b8b082f8c0
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Fix condition in GraphicsManager::skipThumbnail()

Changed paths:
    engines/sludge/thumbnail.cpp


diff --git a/engines/sludge/thumbnail.cpp b/engines/sludge/thumbnail.cpp
index 030c9d5df7c..af9e9a11220 100644
--- a/engines/sludge/thumbnail.cpp
+++ b/engines/sludge/thumbnail.cpp
@@ -126,7 +126,7 @@ bool GraphicsManager::skipThumbnail(Common::SeekableReadStream *stream) {
 
 	// Load image
 	Graphics::Surface tmp;
-	if (_thumbWidth & _thumbHeight) {
+	if (_thumbWidth && _thumbHeight) {
 		if (!ImgLoader::loadPNGImage(stream, &tmp))
 			return false;
 		else


Commit: 537bc0a6666d082f801ee9ce4c10a22138798f10
    https://github.com/scummvm/scummvm/commit/537bc0a6666d082f801ee9ce4c10a22138798f10
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Use MetaEngine::listSaves() when listing save files

Changed paths:
    engines/sludge/builtin.cpp
    engines/sludge/variable.cpp


diff --git a/engines/sludge/builtin.cpp b/engines/sludge/builtin.cpp
index ac4d5473db3..d2622502403 100644
--- a/engines/sludge/builtin.cpp
+++ b/engines/sludge/builtin.cpp
@@ -289,28 +289,15 @@ builtIn(loadGame) {
 		aaaaa = g_sludge->getSaveStateName(g_sludge->_saveNameToSlot[nameWithoutExtension]);
 	} else {
 		// If the game uses only one save (like robinsrescue)
-		Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
-		int maxSaveSlot = g_sludge->getMetaEngine()->getMaximumSaveSlot();
-		int autosaveSlot = g_sludge->getMetaEngine()->getAutosaveSlot();
-		for (int slot = 0; slot <= maxSaveSlot; ++slot) {
-			if (slot == autosaveSlot)
-				continue;
-			const Common::String filename = g_sludge->getMetaEngine()->getSavegameFile(slot, g_sludge->getTargetName().c_str());
-			if (saveFileMan->exists(filename)) {
-				ExtendedSavegameHeader header;
-				Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(filename);
-
-				if (f && g_sludge->getMetaEngine()->readSavegameHeader(f, &header)) {
-					if (nameWithoutExtension == header.description) {
-						g_sludge->_saveNameToSlot[header.description] = slot;
-						aaaaa = g_sludge->getSaveStateName(slot);
-
-						delete f;
-						break;
-					}
-				}
-
-				delete f;
+		SaveStateList saves = g_sludge->getMetaEngine()->listSaves(g_sludge->getTargetName().c_str());
+
+		for (auto &savestate : saves) {
+			Common::String desc = savestate.getDescription();
+			if (nameWithoutExtension == desc) {
+				int slot = savestate.getSaveSlot();
+				g_sludge->_saveNameToSlot[desc] = slot;
+				aaaaa = g_sludge->getSaveStateName(slot);
+				break;
 			}
 		}
 	}
diff --git a/engines/sludge/variable.cpp b/engines/sludge/variable.cpp
index 4e4366cd0b8..287127a79b6 100644
--- a/engines/sludge/variable.cpp
+++ b/engines/sludge/variable.cpp
@@ -196,28 +196,18 @@ static int stringCompareToIgnoreCase(const Common::String &s1, const Common::Str
 
 bool StackHandler::getSavedGamesStack(const Common::String &ext) {
 	// Make pattern
-	Common::String realExtension = ".###";
 	//uint len = realExtension.size();
-	Common::String pattern = g_sludge->getTargetName();
-	pattern += realExtension;
 
 	// Get all saved files
-	Common::StringArray sa = g_system->getSavefileManager()->listSavefiles(pattern);
+	SaveStateList sa = g_sludge->getMetaEngine()->listSaves(g_sludge->getTargetName().c_str());
 	Common::StringArray realNames;
 
 	g_sludge->_saveNameToSlot.clear();
 
-	for (auto &fname : sa) {
-		ExtendedSavegameHeader header;
-		Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fname);
-
-		if (f && g_sludge->getMetaEngine()->readSavegameHeader(f, &header)) {
-			realNames.push_back(header.description);
-			int slot = atoi(fname.substr(fname.size() - 3, 3).c_str());
-			g_sludge->_saveNameToSlot[header.description] = slot;
-		}
-
-		delete f;
+	for (auto &savestate : sa) {
+		Common::String name = savestate.getDescription();
+		realNames.push_back(name);
+		g_sludge->_saveNameToSlot[name] = savestate.getSaveSlot();
 	}
 
 	Common::sort(realNames.begin(), realNames.end(), stringCompareToIgnoreCase);


Commit: c29e5f417579fb54c620f2d890afb378ac9a3b08
    https://github.com/scummvm/scummvm/commit/c29e5f417579fb54c620f2d890afb378ac9a3b08
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Fix coloured blank screens not being drawn

GraphicsManager::blankScreen() fills backdrop with currentBlankColour
pixels, but does not set _backdropExists to true. This becomes an issue
when GraphicsManager::drawBackDrop() is called, where only
_backdropExists is checked for early exit. Additional check for existing
pixels in this commit helps with this

Changed paths:
    engines/sludge/backdrop.cpp


diff --git a/engines/sludge/backdrop.cpp b/engines/sludge/backdrop.cpp
index 02f0749ebd4..5d5a8621c0d 100644
--- a/engines/sludge/backdrop.cpp
+++ b/engines/sludge/backdrop.cpp
@@ -338,7 +338,7 @@ void GraphicsManager::drawBackDrop() {
 	// TODO: apply lightmap shader
 	drawParallax();
 
-	if (!_backdropExists)
+	if (!_backdropExists && !_backdropSurface.getPixels())
 		return;
 	// draw backdrop
 	Graphics::ManagedSurface tmp;


Commit: 8c90b661c5df436fb9b32150247898b56bbdf045
    https://github.com/scummvm/scummvm/commit/8c90b661c5df436fb9b32150247898b56bbdf045
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Simulate right mouse click as CTRL+left mouse click

Changed paths:
    engines/sludge/event.cpp


diff --git a/engines/sludge/event.cpp b/engines/sludge/event.cpp
index c2b8f8d596e..6d694f3fb11 100644
--- a/engines/sludge/event.cpp
+++ b/engines/sludge/event.cpp
@@ -68,9 +68,7 @@ void EventManager::kill() {
 
 void EventManager::checkInput() {
 	float cameraZoom = _vm->_gfxMan->getCamZoom();
-#if 0
 	static bool fakeRightclick = false;
-#endif
 	Common::Event event;
 
 	/* Check for events */
@@ -90,18 +88,16 @@ void EventManager::checkInput() {
 			break;
 
 		case Common::EVENT_LBUTTONDOWN:
-			_input.leftClick = true;
-			_input.mouseX = event.mouse.x * cameraZoom;
-			_input.mouseY = event.mouse.y * cameraZoom;
-#if 0
-			if (SDL_GetModState() & KMOD_CTRL) {
-				input.rightClick = true;
+			if (g_system->getEventManager()->getModifierState() & Common::KBD_CTRL) {
+				_input.rightClick = true;
 				fakeRightclick = true;
 			} else {
-				input.leftClick = true;
+				_input.leftClick = true;
 				fakeRightclick = false;
 			}
-#endif
+
+			_input.mouseX = event.mouse.x * cameraZoom;
+			_input.mouseY = event.mouse.y * cameraZoom;
 			break;
 
 		case Common::EVENT_RBUTTONDOWN:


Commit: aa1df5bbc29951ce89c6606cd04d75fbbae2a310
    https://github.com/scummvm/scummvm/commit/aa1df5bbc29951ce89c6606cd04d75fbbae2a310
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Pop message box when trying to quit a game

Changed paths:
    engines/sludge/event.cpp


diff --git a/engines/sludge/event.cpp b/engines/sludge/event.cpp
index 6d694f3fb11..4ae54f9da4e 100644
--- a/engines/sludge/event.cpp
+++ b/engines/sludge/event.cpp
@@ -21,8 +21,12 @@
 
 #include "common/events.h"
 #include "common/system.h"
+#include "common/translation.h"
+
+#include "gui/message.h"
 
 #include "sludge/event.h"
+#include "sludge/fileset.h"
 #include "sludge/graphics.h"
 #include "sludge/freeze.h"
 #include "sludge/function.h"
@@ -132,10 +136,19 @@ void EventManager::checkInput() {
 			break;
 
 		case Common::EVENT_QUIT:
-		case Common::EVENT_RETURN_TO_LAUNCHER:
-			_weAreDoneSoQuit = 1;
-			// TODO: if _reallyWantToQuit, popup a message box to confirm
+		case Common::EVENT_RETURN_TO_LAUNCHER: {
+			if (!_weAreDoneSoQuit) {
+				g_system->getEventManager()->resetQuit();
+				g_system->getEventManager()->resetReturnToLauncher();
+
+				GUI::MessageDialog dialog(_(g_sludge->_resMan->getNumberedString(2)), _("Yes"), _("No"));
+				if (dialog.runModal() == GUI::kMessageOK) {
+					_weAreDoneSoQuit = 1;
+					g_system->getEventManager()->pushEvent(event);
+				}
+			}
 			break;
+		}
 
 		default:
 			break;


Commit: 6b7b14e13e05e37d2aa37540300181b1ad43190c
    https://github.com/scummvm/scummvm/commit/6b7b14e13e05e37d2aa37540300181b1ad43190c
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Fix savegame being undetected in builtIn(fileExists)

Changed paths:
    engines/sludge/builtin.cpp


diff --git a/engines/sludge/builtin.cpp b/engines/sludge/builtin.cpp
index d2622502403..90f57934b33 100644
--- a/engines/sludge/builtin.cpp
+++ b/engines/sludge/builtin.cpp
@@ -253,6 +253,19 @@ builtIn(fileExists) {
 		Common::String nameWithoutExtension = aaaaa.substr(0, aaaaa.size() - extensionLength);
 		if (g_sludge->_saveNameToSlot.contains(nameWithoutExtension)) {
 			aaaaa = g_sludge->getSaveStateName(g_sludge->_saveNameToSlot[nameWithoutExtension]);
+		} else {
+			// If a game uses only one save
+			SaveStateList saves = g_sludge->getMetaEngine()->listSaves(g_sludge->getTargetName().c_str());
+
+			for (auto &savestate : saves) {
+				Common::String desc = savestate.getDescription();
+				if (nameWithoutExtension == desc) {
+					int slot = savestate.getSaveSlot();
+					g_sludge->_saveNameToSlot[desc] = slot;
+					aaaaa = g_sludge->getSaveStateName(slot);
+					break;
+				}
+			}
 		}
 	}
 


Commit: f620a0eebae0fa426c69efad62325ad4df3643d1
    https://github.com/scummvm/scummvm/commit/f620a0eebae0fa426c69efad62325ad4df3643d1
Author: Alikhan Balpykov (luxrage1990 at gmail.com)
Date: 2025-06-15T10:27:57+02:00

Commit Message:
SLUDGE: Fix occasional crashes during autosaves

Changed paths:
    engines/sludge/sludge.cpp


diff --git a/engines/sludge/sludge.cpp b/engines/sludge/sludge.cpp
index 80fdb598188..b9e91e55e70 100644
--- a/engines/sludge/sludge.cpp
+++ b/engines/sludge/sludge.cpp
@@ -31,6 +31,7 @@
 #include "sludge/fileset.h"
 #include "sludge/fonttext.h"
 #include "sludge/floor.h"
+#include "sludge/function.h"
 #include "sludge/graphics.h"
 #include "sludge/language.h"
 #include "sludge/main_loop.h"
@@ -47,6 +48,8 @@
 
 namespace Sludge {
 
+extern LoadedFunction *allRunningFunctions; // In function.cpp
+
 SludgeEngine *g_sludge;
 
 Graphics::PixelFormat *SludgeEngine::getScreenPixelFormat() const { return _pixelFormat; }
@@ -138,7 +141,21 @@ bool SludgeEngine::canLoadGameStateCurrently(Common::U32String *msg) {
 }
 
 bool SludgeEngine::canSaveGameStateCurrently(Common::U32String *msg) {
-	return !g_sludge->_evtMan->quit();
+	if (g_sludge->_evtMan->quit())
+		return false;
+
+	if (g_sludge->_gfxMan->isFrozen()) {
+		return false;
+	}
+
+	Sludge::LoadedFunction *thisFunction = allRunningFunctions;
+	while (thisFunction) {
+		if (thisFunction->freezerLevel)
+			return false;
+		thisFunction = thisFunction->next;
+	}
+
+	return true;
 }
 
 Common::Error SludgeEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {




More information about the Scummvm-git-logs mailing list