MTROPOLIS: Add auto-save option and add versioning to save files.

This commit is contained in:
elasota 2022-07-09 01:55:56 -04:00
parent 47226d69f9
commit cd54d61de7
12 changed files with 92 additions and 36 deletions

View File

@ -59,6 +59,17 @@ static const ADExtraGuiOptionsMap optionsList[] = {
0
}
},
{
GAMEOPTION_AUTO_SAVE,
{
_s("Save Progress Automatically"),
_s("Automatically saves the game at certain progress points."),
"mtropolis_mod_auto_save",
true,
0,
0
}
},
{
GAMEOPTION_LAUNCH_DEBUG,
{

View File

@ -30,6 +30,7 @@
#define GAMEOPTION_DYNAMIC_MIDI GUIO_GAMEOPTIONS2
#define GAMEOPTION_LAUNCH_DEBUG GUIO_GAMEOPTIONS3
#define GAMEOPTION_LAUNCH_BREAK GUIO_GAMEOPTIONS4
#define GAMEOPTION_AUTO_SAVE GUIO_GAMEOPTIONS5
namespace MTropolis {
@ -51,7 +52,7 @@ static const MTropolisGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformMacintosh,
ADGF_UNSTABLE,
GUIO1(GAMEOPTION_WIDESCREEN_MOD)
GUIO2(GAMEOPTION_WIDESCREEN_MOD, GAMEOPTION_AUTO_SAVE)
},
GID_OBSIDIAN,
0,
@ -78,7 +79,7 @@ static const MTropolisGameDescription gameDescriptions[] = {
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GAMEOPTION_WIDESCREEN_MOD)
GUIO2(GAMEOPTION_WIDESCREEN_MOD, GAMEOPTION_AUTO_SAVE)
},
GID_OBSIDIAN,
0,

View File

@ -34,7 +34,7 @@ class CompoundVarLoader : public ISaveReader {
public:
explicit CompoundVarLoader(RuntimeObject *object);
bool readSave(Common::ReadStream *stream) override;
bool readSave(Common::ReadStream *stream, uint32 saveFileVersion) override;
private:
RuntimeObject *_object;
@ -43,7 +43,7 @@ private:
CompoundVarLoader::CompoundVarLoader(RuntimeObject *object) : _object(object) {
}
bool CompoundVarLoader::readSave(Common::ReadStream *stream) {
bool CompoundVarLoader::readSave(Common::ReadStream *stream, uint32 saveFileVersion) {
if (_object == nullptr || !_object->isModifier())
return false;
@ -52,7 +52,7 @@ bool CompoundVarLoader::readSave(Common::ReadStream *stream) {
if (!saveLoad)
return false;
if (!saveLoad->load(modifier, stream))
if (!saveLoad->load(modifier, stream, saveFileVersion))
return false;
if (stream->err())
@ -63,9 +63,6 @@ bool CompoundVarLoader::readSave(Common::ReadStream *stream) {
return true;
}
bool BehaviorModifier::load(ModifierLoaderContext &context, const Data::BehaviorModifier &data) {
if (data.numChildren > 0) {
ChildLoaderContext loaderContext;
@ -1733,7 +1730,7 @@ void CompoundVariableModifier::SaveLoad::saveInternal(Common::WriteStream *strea
childSL.saveLoad->save(childSL.modifier, stream);
}
bool CompoundVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool CompoundVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
const uint32 numChildren = stream->readUint32BE();
if (stream->err())
return false;
@ -1742,7 +1739,7 @@ bool CompoundVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream
return false;
for (const ChildSaveLoad &childSL : _childrenSaveLoad) {
if (!childSL.saveLoad->load(childSL.modifier, stream))
if (!childSL.saveLoad->load(childSL.modifier, stream, saveFileVersion))
return false;
}
@ -1825,7 +1822,7 @@ void BooleanVariableModifier::SaveLoad::saveInternal(Common::WriteStream *stream
stream->writeByte(_value ? 1 : 0);
}
bool BooleanVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool BooleanVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
byte b = stream->readByte();
if (stream->err())
return false;
@ -1896,7 +1893,7 @@ void IntegerVariableModifier::SaveLoad::saveInternal(Common::WriteStream *stream
stream->writeSint32BE(_value);
}
bool IntegerVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool IntegerVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
_value = stream->readSint32BE();
if (stream->err())
@ -1985,7 +1982,7 @@ void IntegerRangeVariableModifier::SaveLoad::saveInternal(Common::WriteStream *s
stream->writeSint32BE(_range.max);
}
bool IntegerRangeVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool IntegerRangeVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
_range.min = stream->readSint32BE();
_range.max = stream->readSint32BE();
@ -2075,7 +2072,7 @@ void VectorVariableModifier::SaveLoad::saveInternal(Common::WriteStream *stream)
stream->writeDoubleBE(_vector.magnitude);
}
bool VectorVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool VectorVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
_vector.angleDegrees = stream->readDoubleBE();
_vector.magnitude = stream->readDoubleBE();
@ -2167,7 +2164,7 @@ void PointVariableModifier::SaveLoad::saveInternal(Common::WriteStream *stream)
stream->writeSint16BE(_value.y);
}
bool PointVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool PointVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
_value.x = stream->readSint16BE();
_value.y = stream->readSint16BE();
@ -2233,7 +2230,7 @@ void FloatingPointVariableModifier::SaveLoad::saveInternal(Common::WriteStream *
stream->writeDoubleBE(_value);
}
bool FloatingPointVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool FloatingPointVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
_value = stream->readDoubleBE();
if (stream->err())
@ -2297,7 +2294,7 @@ void StringVariableModifier::SaveLoad::saveInternal(Common::WriteStream *stream)
stream->writeString(_value);
}
bool StringVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool StringVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
uint32 size = stream->readUint32BE();
if (stream->err())

View File

@ -690,7 +690,7 @@ private:
explicit SaveLoad(CompoundVariableModifier *modifier);
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
void commitLoad() const override;
private:
@ -744,7 +744,7 @@ private:
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
BooleanVariableModifier *_modifier;
bool _value;
@ -779,7 +779,7 @@ private:
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
IntegerVariableModifier *_modifier;
int32 _value;
@ -817,7 +817,7 @@ private:
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
IntegerRangeVariableModifier *_modifier;
IntRange _range;
@ -855,7 +855,7 @@ private:
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
VectorVariableModifier *_modifier;
AngleMagVector _vector;
@ -893,7 +893,7 @@ private:
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
PointVariableModifier *_modifier;
Common::Point _value;
@ -928,7 +928,7 @@ private:
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
FloatingPointVariableModifier *_modifier;
double _value;
@ -963,7 +963,7 @@ private:
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
StringVariableModifier *_modifier;
Common::String _value;

View File

@ -120,7 +120,9 @@ Common::Error MTropolisEngine::run() {
enhancedColorDepthMode = kColorDepthMode32Bit;
HackSuites::addObsidianBugFixes(*_gameDescription, _runtime->getHacks());
HackSuites::addObsidianAutoSaves(*_gameDescription, _runtime->getHacks(), this);
if (ConfMan.getBool("mtropolis_mod_auto_save"))
HackSuites::addObsidianAutoSaves(*_gameDescription, _runtime->getHacks(), this);
if (ConfMan.getBool("mtropolis_mod_obsidian_widescreen")) {
_runtime->getHacks().reportDisplaySize = Common::Point(640, 480);

View File

@ -70,6 +70,9 @@ protected:
void pauseEngineIntern(bool pause) override;
private:
static const uint kCurrentSaveFileVersion = 1;
static const uint kSavegameSignature = 0x6d545356; // mTSV
Common::ScopedPtr<Runtime> _runtime;
};

View File

@ -2201,7 +2201,7 @@ void ObjectReferenceVariableModifier::SaveLoad::saveInternal(Common::WriteStream
stream->writeString(_objectPath);
}
bool ObjectReferenceVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool ObjectReferenceVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
uint32 stringLen = stream->readUint32BE();
if (stream->err())
return false;
@ -2805,7 +2805,7 @@ void ListVariableModifier::SaveLoad::saveInternal(Common::WriteStream *stream) c
recursiveWriteList(_list.get(), stream);
}
bool ListVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream) {
bool ListVariableModifier::SaveLoad::loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) {
Common::SharedPtr<DynamicList> list = recursiveReadList(stream);
if (list) {
_list = list;

View File

@ -178,7 +178,7 @@ private:
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
ObjectReferenceVariableModifier *_modifier;
Common::String _objectPath;
@ -326,7 +326,7 @@ private:
private:
void commitLoad() const override;
void saveInternal(Common::WriteStream *stream) const override;
bool loadInternal(Common::ReadStream *stream) override;
bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) override;
static void recursiveWriteList(DynamicList *list, Common::WriteStream *stream);
static Common::SharedPtr<DynamicList> recursiveReadList(Common::ReadStream *stream);

View File

@ -7520,7 +7520,7 @@ void ModifierSaveLoad::save(Modifier *modifier, Common::WriteStream *stream) {
saveInternal(stream);
}
bool ModifierSaveLoad::load(Modifier *modifier, Common::ReadStream *stream) {
bool ModifierSaveLoad::load(Modifier *modifier, Common::ReadStream *stream, uint32 saveFileVersion) {
uint32 checkGUID = stream->readUint32BE();
uint16 nameLen = stream->readUint16BE();
@ -7544,7 +7544,7 @@ bool ModifierSaveLoad::load(Modifier *modifier, Common::ReadStream *stream) {
if (modifier->getStaticGUID() != checkGUID)
return false;
return loadInternal(stream);
return loadInternal(stream, saveFileVersion);
}
ModifierHooks::~ModifierHooks() {

View File

@ -2547,7 +2547,7 @@ public:
virtual ~ModifierSaveLoad();
void save(Modifier *modifier, Common::WriteStream *stream);
bool load(Modifier *modifier, Common::ReadStream *stream);
bool load(Modifier *modifier, Common::ReadStream *stream, uint32 saveFileVersion);
virtual void commitLoad() const = 0;
protected:
@ -2556,7 +2556,7 @@ protected:
// Loads the modifier state from a stream into the save/load state and returns true
// if successful. This will not trigger any actual changes until "commit" is called.
virtual bool loadInternal(Common::ReadStream *stream) = 0;
virtual bool loadInternal(Common::ReadStream *stream, uint32 saveFileVersion) = 0;
};
class ModifierHooks {

View File

@ -20,8 +20,10 @@
*/
#include "common/savefile.h"
#include "common/system.h"
#include "common/translation.h"
#include "gui/message.h"
#include "gui/saveload.h"
#include "mtropolis/mtropolis.h"
@ -74,6 +76,10 @@ bool MTropolisEngine::promptSave(ISaveWriter *writer) {
Common::String saveFileName = getSaveStateName(slot);
Common::SharedPtr<Common::OutSaveFile> out(_saveFileMan->openForSaving(saveFileName, false));
out->writeUint32BE(kSavegameSignature);
out->writeUint32BE(kCurrentSaveFileVersion);
if (!writer->writeSave(out.get()) || out->err())
warning("An error occurred while writing file '%s'", saveFileName.c_str());
@ -96,7 +102,37 @@ bool MTropolisEngine::promptLoad(ISaveReader *reader) {
Common::String saveFileName = getSaveStateName(slot);
Common::SharedPtr<Common::InSaveFile> in(_saveFileMan->openForLoading(saveFileName));
if (!reader->readSave(in.get())) {
uint32 signature = in->readUint32BE();
uint32 saveFileVersion = in->readUint32BE();
if (in->err()) {
GUI::MessageDialog dialog(_("Failed to read version information from save file"));
dialog.runModal();
warning("An error occurred while reading the save file version from '%s'", saveFileName.c_str());
return false;
}
if (signature != kSavegameSignature) {
GUI::MessageDialog dialog(_("Failed to load save, the save file doesn't contain valid version information."));
dialog.runModal();
warning("Save file '%s' version is above the current save file version", saveFileName.c_str());
return false;
}
if (saveFileVersion > kCurrentSaveFileVersion) {
GUI::MessageDialog dialog(_("Failed to load save, the save file was created by a newer version of ScummVM."));
dialog.runModal();
warning("Save file '%s' version is above the current save file version", saveFileName.c_str());
return false;
}
if (!reader->readSave(in.get(), saveFileVersion)) {
GUI::MessageDialog dialog(_("Failed to load save, an error occurred when reading the save game data."));
dialog.runModal();
warning("An error occurred while reading file '%s'", saveFileName.c_str());
return false;
}
@ -109,11 +145,17 @@ bool MTropolisEngine::autoSave(ISaveWriter *writer) {
Common::String saveFileName = getSaveStateName(slot);
Common::SharedPtr<Common::OutSaveFile> out(_saveFileMan->openForSaving(saveFileName, false));
out->writeUint32BE(kSavegameSignature);
out->writeUint32BE(kCurrentSaveFileVersion);
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);
g_system->displayMessageOnOSD(_("Progress Saved"));
return true;
}

View File

@ -42,7 +42,7 @@ struct ISaveWriter : public IInterfaceBase {
};
struct ISaveReader : public IInterfaceBase {
virtual bool readSave(Common::ReadStream *stream) = 0;
virtual bool readSave(Common::ReadStream *stream, uint32 saveFileVersion) = 0;
};
struct ISaveUIProvider : public IInterfaceBase {