[Scummvm-git-logs] scummvm master -> e301e69e575d29bda7e44cc0ed77bcbbb799f28a
elasota
noreply at scummvm.org
Sun Jul 3 18:08:15 UTC 2022
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
e301e69e57 MTROPOLIS: Add auto-saves for Obsidian
Commit: e301e69e575d29bda7e44cc0ed77bcbbb799f28a
https://github.com/scummvm/scummvm/commit/e301e69e575d29bda7e44cc0ed77bcbbb799f28a
Author: elasota (ejlasota at gmail.com)
Date: 2022-07-03T14:06:57-04:00
Commit Message:
MTROPOLIS: Add auto-saves for Obsidian
Changed paths:
engines/mtropolis/hacks.cpp
engines/mtropolis/hacks.h
engines/mtropolis/modifiers.cpp
engines/mtropolis/mtropolis.cpp
engines/mtropolis/mtropolis.h
engines/mtropolis/runtime.cpp
engines/mtropolis/runtime.h
engines/mtropolis/saveload.cpp
engines/mtropolis/saveload.h
diff --git a/engines/mtropolis/hacks.cpp b/engines/mtropolis/hacks.cpp
index a9e63161532..2c85b351448 100644
--- a/engines/mtropolis/hacks.cpp
+++ b/engines/mtropolis/hacks.cpp
@@ -20,11 +20,14 @@
*/
#include "common/system.h"
+#include "common/hashmap.h"
#include "mtropolis/assets.h"
#include "mtropolis/detection.h"
#include "mtropolis/hacks.h"
#include "mtropolis/runtime.h"
+#include "mtropolis/modifiers.h"
+#include "mtropolis/saveload.h"
namespace MTropolis {
@@ -47,6 +50,14 @@ void Hacks::addAssetHooks(const Common::SharedPtr<AssetHooks> &hooks) {
assetHooks.push_back(hooks);
}
+void Hacks::addSceneTransitionHooks(const Common::SharedPtr<SceneTransitionHooks> &hooks) {
+ sceneTransitionHooks.push_back(hooks);
+}
+
+void Hacks::addSaveLoadHooks(const Common::SharedPtr<SaveLoadHooks> &hooks) {
+ saveLoadHooks.push_back(hooks);
+}
+
namespace HackSuites {
class ObsidianCorruptedAirTowerTransitionFix : public AssetHooks {
@@ -231,6 +242,343 @@ void addObsidianImprovedWidescreen(const MTropolisGameDescription &desc, Hacks &
}
}
+// Auto-save triggers for Obsidian. Basically, we auto-save on reaching specific scenes when conditions are met.
+// There are two types of condition: One is the player reaches the scene from a one-way scene that can not be
+// revisited, such as a chapter transition.
+//
+// The other is a variable latch, which happens if the variable became true since the last time the reset scene
+// (the opening credits) was reached, or since the last time the game was loaded.
+//
+// Variable latches don't work if the latch becomes true and the player saves+reloads their game before they hit
+// the auto-save checkpoint, but that's okay.
+
+struct ObsidianAutoSaveTrigger {
+ const char *sceneName;
+ const char *priorSceneName; // If set, only save when transitioning from this scene
+ const char *varTrueLatch; // If set, only save when this variable was set to
+};
+
+static ObsidianAutoSaveTrigger kObsidianAutoSaveTriggers[] = {
+ // Arrive at campsite
+ {
+ "103.2L",
+ "102_103_Credits",
+ nullptr,
+ },
+ // Bureau start
+ {
+ "102.0L",
+ nullptr,
+ "cgst.clst.cl100st.bbossspoken"
+ },
+ // Win cube maze from side room
+ {
+ "445.2L",
+ nullptr,
+ "cgst.clst.cl400st.bcubiclewon",
+ },
+ // Win cube maze from back room
+ {
+ "445.0L",
+ nullptr,
+ "cgst.clst.cl400st.bcubiclewon",
+ },
+ // Stamp document and back away
+ {
+ "445.2L",
+ nullptr,
+ "cgst.clst.cinv.bstampedsd",
+ },
+ // Get repair document from cabinet + back away (English version)
+ {
+ "218.4L",
+ nullptr,
+ "cgst.clst.cinv.bhavesd",
+ },
+ // Get repair document from Bridge Repair + back away (non-English versions)
+ {
+ "109.6L",
+ nullptr,
+ "cgst.clst.cinv.bhavesd",
+ },
+ // Give document to Immediate Action + return to light
+ {
+ "306.6L",
+ nullptr,
+ "cgst.clst.cinv.bgavesd",
+ },
+ // Get rebel document + leave cabinet (English version)
+ {
+ "227.4L",
+ nullptr,
+ "cgst.clst.cinv.bhaveom",
+ },
+ // Solve dial puzzle
+ {
+ "699.0L",
+ nullptr,
+ "cgst.clst.cl308st.bwon",
+ },
+
+ // Spider start
+ {
+ "101.2L",
+ "710.0L",
+ nullptr,
+ },
+ // Leave elevator after completing any Spider puzzle
+ {
+ "121.0L",
+ "118.0L_121.0L-s1",
+ nullptr,
+ },
+
+ // Inspiration start
+ {
+ "101.4L",
+ "121.0L_Lunch_Time",
+ nullptr,
+ },
+ // Complete propulsion puzzle and leave engine room
+ {
+ "201.4L",
+ nullptr,
+ "cgst.cbst.cb2st.bengineon",
+ },
+ // Complete Church puzzle and leave robot
+ {
+ "412.4L",
+ nullptr,
+ "cgst.cbst.cb4st.bwon",
+ },
+ // Complete statue canvas puzzle
+ {
+ "523.2L_from_521.2L-s2",
+ nullptr,
+ "cgst.cbst.cb5st.bpaintedblank",
+ },
+
+ // Conductor start
+ {
+ "101.6L",
+ "203.4L_WIN",
+ nullptr,
+ },
+ // Freed Max
+ {
+ "104.0L_Max_Freed",
+ nullptr,
+ "cgst.ccst.cc1st.bmaxfreed",
+ },
+};
+
+class ObsidianAutoSaveVarsState {
+public:
+ ObsidianAutoSaveVarsState();
+
+ static const VariableModifier *findVar(Runtime *runtime, const Common::String &str);
+
+ bool getVarState(const Common::String &varName) const;
+ void resyncAllVars(Runtime *runtime);
+
+private:
+ Common::HashMap<Common::String, bool> _varState;
+};
+
+ObsidianAutoSaveVarsState::ObsidianAutoSaveVarsState() {
+ for (const ObsidianAutoSaveTrigger &trigger : kObsidianAutoSaveTriggers) {
+ if (trigger.varTrueLatch)
+ _varState[trigger.varTrueLatch] = false;
+ }
+}
+
+const VariableModifier *ObsidianAutoSaveVarsState::findVar(Runtime *runtime, const Common::String &str) {
+ size_t scanStartPos = 0;
+
+ const Modifier *modifierScan = nullptr;
+ const IModifierContainer *container = runtime->getProject();
+
+ for (;;) {
+ size_t dotPos = str.findFirstOf('.', scanStartPos);
+ if (dotPos == Common::String::npos)
+ dotPos = str.size();
+
+ Common::String childName = str.substr(scanStartPos, dotPos - scanStartPos);
+ if (!container)
+ return nullptr;
+
+ modifierScan = nullptr;
+ for (const Common::SharedPtr<Modifier> &modifier : container->getModifiers()) {
+ if (caseInsensitiveEqual(childName, modifier->getName())) {
+ modifierScan = modifier.get();
+ break;
+ }
+ }
+
+ if (!modifierScan)
+ return nullptr;
+
+ if (modifierScan->isCompoundVariable())
+ container = static_cast<const CompoundVariableModifier *>(modifierScan);
+
+ if (dotPos == str.size())
+ break;
+
+ scanStartPos = dotPos + 1;
+ }
+
+ if (modifierScan && modifierScan->isVariable())
+ return static_cast<const VariableModifier *>(modifierScan);
+
+ return nullptr;
+}
+
+bool ObsidianAutoSaveVarsState::getVarState(const Common::String &varName) const {
+ Common::HashMap<Common::String, bool>::const_iterator it = _varState.find(varName);
+ if (it == _varState.end())
+ return false;
+ return it->_value;
+}
+
+void ObsidianAutoSaveVarsState::resyncAllVars(Runtime *runtime) {
+ for (Common::HashMap<Common::String, bool>::iterator it = _varState.begin(), itEnd = _varState.end(); it != itEnd; ++it) {
+ const VariableModifier *var = findVar(runtime, it->_key);
+ if (var) {
+ DynamicValue varValue;
+ var->varGetValue(nullptr, varValue);
+ assert(varValue.getType() == DynamicValueTypes::kBoolean);
+
+ it->_value = varValue.getBool();
+ }
+ }
+}
+
+class ObsidianAutoSaveSceneTransitionHooks : public SceneTransitionHooks {
+public:
+ explicit ObsidianAutoSaveSceneTransitionHooks(const Common::SharedPtr<ObsidianAutoSaveVarsState> &vars, IAutoSaveProvider *autoSaveProvider);
+
+ void onSceneTransitionEnded(Runtime *runtime, const Common::WeakPtr<Structural> &newScene) override;
+
+private:
+ Common::SharedPtr<ObsidianAutoSaveVarsState> _varsState;
+ IAutoSaveProvider *_autoSaveProvider;
+
+ Common::String _currentSceneName;
+ Common::String _prevSceneName;
+
+ Common::String _resetSceneName;
+ Common::String _saveVarName;
+};
+
+ObsidianAutoSaveSceneTransitionHooks::ObsidianAutoSaveSceneTransitionHooks(const Common::SharedPtr<ObsidianAutoSaveVarsState> &vars, IAutoSaveProvider *autoSaveProvider)
+ : _varsState(vars), _autoSaveProvider(autoSaveProvider) {
+
+ _resetSceneName = Common::String("101_102_Credits");
+ _saveVarName = Common::String("cgst");
+}
+
+void ObsidianAutoSaveSceneTransitionHooks::onSceneTransitionEnded(Runtime *runtime, const Common::WeakPtr<Structural> &newScene) {
+ bool triggerAutoSave = false;
+
+ if (newScene.expired())
+ return;
+
+ _prevSceneName = _currentSceneName;
+ _currentSceneName = newScene.lock()->getName();
+
+ for (const ObsidianAutoSaveTrigger &trigger : kObsidianAutoSaveTriggers) {
+ Common::String triggerSceneName(trigger.sceneName);
+
+ if (!caseInsensitiveEqual(triggerSceneName, _currentSceneName))
+ continue;
+
+ if (trigger.priorSceneName && !caseInsensitiveEqual(trigger.priorSceneName, _prevSceneName))
+ continue;
+
+ if (trigger.varTrueLatch) {
+ Common::String varName(trigger.varTrueLatch);
+
+ // Variable must must have been false since the last game load or reset
+ if (_varsState->getVarState(varName))
+ continue;
+
+ bool passedLatchTest = false;
+
+ const VariableModifier *var = _varsState->findVar(runtime, varName);
+ if (var) {
+ DynamicValue varValue;
+ var->varGetValue(nullptr, varValue);
+ assert(varValue.getType() == DynamicValueTypes::kBoolean);
+
+ passedLatchTest = varValue.getBool();
+ }
+
+ if (!passedLatchTest)
+ continue;
+ }
+
+ triggerAutoSave = true;
+ break;
+ }
+
+ if (triggerAutoSave) {
+ Common::SharedPtr<Modifier> saveVar;
+
+ for (const Common::SharedPtr<Modifier> &child : runtime->getProject()->getModifiers()) {
+ if (caseInsensitiveEqual(child->getName(), _saveVarName)) {
+ saveVar = child;
+ break;
+ }
+ }
+
+ if (saveVar || saveVar->isModifier()) {
+ Modifier *modifier = static_cast<Modifier *>(saveVar.get());
+ Common::SharedPtr<ModifierSaveLoad> saveLoad = modifier->getSaveLoad();
+
+ if (saveLoad) {
+ CompoundVarSaver saver(saveVar.get());
+ _autoSaveProvider->autoSave(&saver);
+
+ _varsState->resyncAllVars(runtime);
+ }
+ }
+ }
+
+ if (caseInsensitiveEqual(_currentSceneName, _resetSceneName))
+ _varsState->resyncAllVars(runtime);
+}
+
+class ObsidianAutoSaveSaveLoadHooks : public SaveLoadHooks {
+public:
+ explicit ObsidianAutoSaveSaveLoadHooks(const Common::SharedPtr<ObsidianAutoSaveVarsState> &vars);
+
+ void onSave(Runtime *runtime, Modifier *saveLoadModifier, Modifier *varModifier) override;
+ void onLoad(Runtime *runtime, Modifier *saveLoadModifier, Modifier *varModifier) override;
+
+private:
+ Common::SharedPtr<ObsidianAutoSaveVarsState> _varsState;
+};
+
+
+ObsidianAutoSaveSaveLoadHooks::ObsidianAutoSaveSaveLoadHooks(const Common::SharedPtr<ObsidianAutoSaveVarsState> &vars) : _varsState(vars) {
+}
+
+void ObsidianAutoSaveSaveLoadHooks::onSave(Runtime *runtime, Modifier *saveLoadModifier, Modifier *varModifier) {
+ // Reset all variable latches on save
+ _varsState->resyncAllVars(runtime);
+}
+
+void ObsidianAutoSaveSaveLoadHooks::onLoad(Runtime *runtime, Modifier *saveLoadModifier, Modifier *varModifier) {
+ // Reset all variable latches on load
+ _varsState->resyncAllVars(runtime);
+}
+
+void addObsidianAutoSaves(const MTropolisGameDescription &desc, Hacks &hacks, IAutoSaveProvider *autoSaveProvider) {
+ Common::SharedPtr<ObsidianAutoSaveVarsState> varsState(new ObsidianAutoSaveVarsState());
+ hacks.addSceneTransitionHooks(Common::SharedPtr<SceneTransitionHooks>(new ObsidianAutoSaveSceneTransitionHooks(varsState, autoSaveProvider)));
+ hacks.addSaveLoadHooks(Common::SharedPtr<SaveLoadHooks>(new ObsidianAutoSaveSaveLoadHooks(varsState)));
+}
+
} // End of namespace HackSuites
} // End of namespace MTropolis
diff --git a/engines/mtropolis/hacks.h b/engines/mtropolis/hacks.h
index 3738bbf0a84..3320f2d3087 100644
--- a/engines/mtropolis/hacks.h
+++ b/engines/mtropolis/hacks.h
@@ -30,7 +30,10 @@ namespace MTropolis {
class AssetHooks;
class ModifierHooks;
+class SaveLoadHooks;
+class SceneTransitionHooks;
class StructuralHooks;
+struct IAutoSaveProvider;
struct MTropolisGameDescription;
struct Hacks {
@@ -40,6 +43,8 @@ struct Hacks {
void addStructuralHooks(uint32 guid, const Common::SharedPtr<StructuralHooks> &hooks);
void addModifierHooks(uint32 guid, const Common::SharedPtr<ModifierHooks> &hooks);
void addAssetHooks(const Common::SharedPtr<AssetHooks> &hooks);
+ void addSceneTransitionHooks(const Common::SharedPtr<SceneTransitionHooks> &hooks);
+ void addSaveLoadHooks(const Common::SharedPtr<SaveLoadHooks> &hooks);
bool ignoreMismatchedProjectNameInObjectLookups;
@@ -48,13 +53,15 @@ struct Hacks {
Common::HashMap<uint32, Common::SharedPtr<StructuralHooks> > structuralHooks;
Common::HashMap<uint32, Common::SharedPtr<ModifierHooks> > modifierHooks;
-
+ Common::Array<Common::SharedPtr<SceneTransitionHooks> > sceneTransitionHooks;
Common::Array<Common::SharedPtr<AssetHooks> > assetHooks;
+ Common::Array<Common::SharedPtr<SaveLoadHooks> > saveLoadHooks;
};
namespace HackSuites {
void addObsidianBugFixes(const MTropolisGameDescription &desc, Hacks &hacks);
+void addObsidianAutoSaves(const MTropolisGameDescription &desc, Hacks &hacks, IAutoSaveProvider *autoSaveProvider);
void addObsidianImprovedWidescreen(const MTropolisGameDescription &desc, Hacks &hacks);
} // End of namespace HackSuites
diff --git a/engines/mtropolis/modifiers.cpp b/engines/mtropolis/modifiers.cpp
index 550dcf019f1..2b223dd6e57 100644
--- a/engines/mtropolis/modifiers.cpp
+++ b/engines/mtropolis/modifiers.cpp
@@ -30,16 +30,6 @@
namespace MTropolis {
-class CompoundVarSaver : public ISaveWriter {
-public:
- explicit CompoundVarSaver(RuntimeObject *object);
-
- bool writeSave(Common::WriteStream *stream) override;
-
-private:
- RuntimeObject *_object;
-};
-
class CompoundVarLoader : public ISaveReader {
public:
explicit CompoundVarLoader(RuntimeObject *object);
@@ -50,22 +40,6 @@ private:
RuntimeObject *_object;
};
-CompoundVarSaver::CompoundVarSaver(RuntimeObject *object) : _object(object) {
-}
-
-bool CompoundVarSaver::writeSave(Common::WriteStream *stream) {
- if (_object == nullptr || !_object->isModifier())
- return false;
-
- Modifier *modifier = static_cast<Modifier *>(_object);
- Common::SharedPtr<ModifierSaveLoad> saveLoad = modifier->getSaveLoad();
- if (!saveLoad)
- return false;
-
- saveLoad->save(modifier, stream);
- return !stream->err();
-}
-
CompoundVarLoader::CompoundVarLoader(RuntimeObject *object) : _object(object) {
}
@@ -292,19 +266,29 @@ VThreadState SaveAndRestoreModifier::consumeMessage(Runtime *runtime, const Comm
var.resolve(this, objWeak);
if (objWeak.expired()) {
- warning("Save failed, couldn't resolve compound var");
+ warning("Save/load failed, couldn't resolve compound var");
return kVThreadError;
}
RuntimeObject *obj = objWeak.lock().get();
+ if (!obj->isModifier()) {
+ warning("Save/load failed, source wasn't a modifier");
+ return kVThreadError;
+ }
if (_saveWhen.respondsTo(msg->getEvent())) {
CompoundVarSaver saver(obj);
- runtime->getSaveProvider()->promptSave(&saver);
+ if (runtime->getSaveProvider()->promptSave(&saver)) {
+ for (const Common::SharedPtr<SaveLoadHooks> &hooks : runtime->getHacks().saveLoadHooks)
+ hooks->onSave(runtime, this, static_cast<Modifier *>(obj));
+ }
return kVThreadReturn;
} else if (_restoreWhen.respondsTo(msg->getEvent())) {
CompoundVarLoader loader(obj);
- runtime->getLoadProvider()->promptLoad(&loader);
+ if (runtime->getLoadProvider()->promptLoad(&loader)) {
+ for (const Common::SharedPtr<SaveLoadHooks> &hooks : runtime->getHacks().saveLoadHooks)
+ hooks->onLoad(runtime, this, static_cast<Modifier *>(obj));
+ }
return kVThreadReturn;
}
diff --git a/engines/mtropolis/mtropolis.cpp b/engines/mtropolis/mtropolis.cpp
index eece730ea73..a99247a3fd7 100644
--- a/engines/mtropolis/mtropolis.cpp
+++ b/engines/mtropolis/mtropolis.cpp
@@ -120,6 +120,7 @@ Common::Error MTropolisEngine::run() {
enhancedColorDepthMode = kColorDepthMode32Bit;
HackSuites::addObsidianBugFixes(*_gameDescription, _runtime->getHacks());
+ HackSuites::addObsidianAutoSaves(*_gameDescription, _runtime->getHacks(), this);
if (ConfMan.getBool("mtropolis_mod_obsidian_widescreen")) {
_runtime->getHacks().reportDisplaySize = Common::Point(640, 480);
diff --git a/engines/mtropolis/mtropolis.h b/engines/mtropolis/mtropolis.h
index fe62e4fba92..af743426c69 100644
--- a/engines/mtropolis/mtropolis.h
+++ b/engines/mtropolis/mtropolis.h
@@ -42,7 +42,7 @@ namespace MTropolis {
class Runtime;
class RuntimeObject;
-class MTropolisEngine : public ::Engine, public ISaveUIProvider, public ILoadUIProvider {
+class MTropolisEngine : public ::Engine, public ISaveUIProvider, public ILoadUIProvider, public IAutoSaveProvider {
protected:
// Engine APIs
Common::Error run() override;
@@ -60,6 +60,7 @@ public:
Common::Platform getPlatform() const;
bool promptSave(ISaveWriter *writer) override;
+ bool autoSave(ISaveWriter *writer) override;
bool promptLoad(ISaveReader *reader) override;
public:
diff --git a/engines/mtropolis/runtime.cpp b/engines/mtropolis/runtime.cpp
index ed24538dd49..abebdcfc820 100644
--- a/engines/mtropolis/runtime.cpp
+++ b/engines/mtropolis/runtime.cpp
@@ -3662,6 +3662,12 @@ const Common::KeyState &KeyboardInputEvent::getKeyState() const {
Runtime::SceneStackEntry::SceneStackEntry() {
}
+SceneTransitionHooks::~SceneTransitionHooks() {
+}
+
+void SceneTransitionHooks::onSceneTransitionEnded(Runtime *runtime, const Common::WeakPtr<Structural> &newScene) {
+}
+
Runtime::Runtime(OSystem *system, Audio::Mixer *mixer, ISaveUIProvider *saveProvider, ILoadUIProvider *loadProvider)
: _system(system), _mixer(mixer), _saveProvider(saveProvider), _loadProvider(loadProvider),
_nextRuntimeGUID(1), _realDisplayMode(kColorDepthModeInvalid), _fakeDisplayMode(kColorDepthModeInvalid),
@@ -3908,6 +3914,9 @@ bool Runtime::runFrame() {
for (const SceneStackEntry &sceneStackEntry : _sceneStack)
recursiveAutoPlayMedia(sceneStackEntry.scene.get());
+ for (const Common::SharedPtr<SceneTransitionHooks> &hooks : _hacks.sceneTransitionHooks)
+ hooks->onSceneTransitionEnded(this, _activeMainScene);
+
queueEventAsLowLevelSceneStateTransitionAction(Event::create(EventIDs::kSceneTransitionEnded, 0), _activeMainScene.get(), true, true);
continue;
}
diff --git a/engines/mtropolis/runtime.h b/engines/mtropolis/runtime.h
index 8410f2c9be5..1b3f4b94ef8 100644
--- a/engines/mtropolis/runtime.h
+++ b/engines/mtropolis/runtime.h
@@ -1452,6 +1452,13 @@ struct DragMotionProperties {
bool constrainToParent;
};
+class SceneTransitionHooks {
+public:
+ virtual ~SceneTransitionHooks();
+
+ virtual void onSceneTransitionEnded(Runtime *runtime, const Common::WeakPtr<Structural> &newScene);
+};
+
class Runtime {
public:
explicit Runtime(OSystem *system, Audio::Mixer *mixer, ISaveUIProvider *saveProvider, ILoadUIProvider *loadProvider);
diff --git a/engines/mtropolis/saveload.cpp b/engines/mtropolis/saveload.cpp
index 3bb93cb45e4..b4d3b28ee5c 100644
--- a/engines/mtropolis/saveload.cpp
+++ b/engines/mtropolis/saveload.cpp
@@ -25,9 +25,36 @@
#include "gui/saveload.h"
#include "mtropolis/mtropolis.h"
+#include "mtropolis/runtime.h"
namespace MTropolis {
+
+CompoundVarSaver::CompoundVarSaver(RuntimeObject *object) : _object(object) {
+}
+
+bool CompoundVarSaver::writeSave(Common::WriteStream *stream) {
+ if (_object == nullptr || !_object->isModifier())
+ return false;
+
+ Modifier *modifier = static_cast<Modifier *>(_object);
+ Common::SharedPtr<ModifierSaveLoad> saveLoad = modifier->getSaveLoad();
+ if (!saveLoad)
+ return false;
+
+ saveLoad->save(modifier, stream);
+ return !stream->err();
+}
+
+SaveLoadHooks::~SaveLoadHooks() {
+}
+
+void SaveLoadHooks::onLoad(Runtime *runtime, Modifier *saveLoadModifier, Modifier *varModifier) {
+}
+
+void SaveLoadHooks::onSave(Runtime *runtime, Modifier *saveLoadModifier, Modifier *varModifier) {
+}
+
bool MTropolisEngine::promptSave(ISaveWriter *writer) {
Common::String desc;
int slot;
@@ -77,4 +104,17 @@ bool MTropolisEngine::promptLoad(ISaveReader *reader) {
return true;
}
+bool MTropolisEngine::autoSave(ISaveWriter *writer) {
+ const int slot = 0;
+
+ Common::String saveFileName = getSaveStateName(slot);
+ Common::SharedPtr<Common::OutSaveFile> out(_saveFileMan->openForSaving(saveFileName, false));
+ if (!writer->writeSave(out.get()) || out->err())
+ warning("An error occurred while writing file '%s'", saveFileName.c_str());
+
+ getMetaEngine()->appendExtendedSave(out.get(), getTotalPlayTime(), "Auto Save", true);
+
+ return true;
+}
+
} // End of namespace MTropolis
diff --git a/engines/mtropolis/saveload.h b/engines/mtropolis/saveload.h
index 47159fa97a9..3342f3d9f41 100644
--- a/engines/mtropolis/saveload.h
+++ b/engines/mtropolis/saveload.h
@@ -33,6 +33,8 @@ class WriteStream;
namespace MTropolis {
+class Modifier;
+class Runtime;
class RuntimeObject;
struct ISaveWriter : public IInterfaceBase {
@@ -51,6 +53,28 @@ struct ILoadUIProvider : public IInterfaceBase {
virtual bool promptLoad(ISaveReader *reader) = 0;
};
+struct IAutoSaveProvider : public IInterfaceBase {
+ virtual bool autoSave(ISaveWriter *writer) = 0;
+};
+
+class CompoundVarSaver : public ISaveWriter {
+public:
+ explicit CompoundVarSaver(RuntimeObject *object);
+
+ bool writeSave(Common::WriteStream *stream) override;
+
+private:
+ RuntimeObject *_object;
+};
+
+class SaveLoadHooks {
+public:
+ virtual ~SaveLoadHooks();
+
+ virtual void onLoad(Runtime *runtime, Modifier *saveLoadModifier, Modifier *varModifier);
+ virtual void onSave(Runtime *runtime, Modifier *saveLoadModifier, Modifier *varModifier);
+};
+
} // End of namespace MTropolis
#endif /* MTROPOLIS_SAVELOAD_H */
More information about the Scummvm-git-logs
mailing list