MOHAWK: RIVEN: Add Autosave Support

The game will autosave to slot 0 using the save
period given in the scummvm config file.
Or when the user quits.

Autosaves are only allowed when an autosave is
in slot 0, there is no save in slot 0, or there
is a save, but it is corrupt.

This will not override any saves the player
has previously put in save slot 0. If there
is a save in slot 0 that is not an autosave
then there will be no autosaving.
This commit is contained in:
David Fioramonti 2018-05-19 12:46:36 -07:00 committed by Bastien Bouclet
parent 1606d6688d
commit 37791c4bd3
4 changed files with 95 additions and 13 deletions

View file

@ -38,10 +38,11 @@ RivenSaveMetadata::RivenSaveMetadata() {
saveHour = 0;
saveMinute = 0;
totalPlayTime = 0;
autoSave = false;
}
bool RivenSaveMetadata::sync(Common::Serializer &s) {
static const Common::Serializer::Version kCurrentVersion = 1;
static const Common::Serializer::Version kCurrentVersion = 2;
if (!s.syncVersion(kCurrentVersion)) {
return false;
@ -54,10 +55,13 @@ bool RivenSaveMetadata::sync(Common::Serializer &s) {
s.syncAsByte(saveMinute);
s.syncString(saveDescription);
s.syncAsUint32BE(totalPlayTime);
s.syncAsByte(autoSave, 2);
return true;
}
const int RivenSaveLoad::kAutoSaveSlot = 0;
RivenSaveLoad::RivenSaveLoad(MohawkEngine_Riven *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) {
}
@ -105,22 +109,25 @@ Common::String RivenSaveLoad::querySaveDescription(const int slot) {
SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) {
Common::String filename = buildSaveFilename(slot);
Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
SaveStateDescriptor descriptor;
descriptor.setWriteProtectedFlag(slot == kAutoSaveSlot);
if (!loadFile) {
return SaveStateDescriptor();
return descriptor;
}
MohawkArchive mhk;
if (!mhk.openStream(loadFile)) {
return SaveStateDescriptor();
return descriptor;
}
if (!mhk.hasResource(ID_META, 1)) {
return SaveStateDescriptor();
return descriptor;
}
Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1);
if (!metaStream) {
return SaveStateDescriptor();
return descriptor;
}
Common::Serializer serializer = Common::Serializer(metaStream, nullptr);
@ -128,14 +135,14 @@ SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) {
RivenSaveMetadata metadata;
if (!metadata.sync(serializer)) {
delete metaStream;
return SaveStateDescriptor();
return descriptor;
}
SaveStateDescriptor descriptor;
descriptor.setDescription(metadata.saveDescription);
descriptor.setPlayTime(metadata.totalPlayTime);
descriptor.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay);
descriptor.setSaveTime(metadata.saveHour, metadata.saveMinute);
descriptor.setDeletableFlag(slot != kAutoSaveSlot);
delete metaStream;
@ -159,6 +166,40 @@ SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) {
return descriptor;
}
bool RivenSaveLoad::isAutoSaveAllowed() {
// Open autosave slot and see if it an autosave
// Autosaving will be enabled if it is an autosave or if there is no save in that slot
Common::String filename = buildSaveFilename(kAutoSaveSlot);
Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
if (!loadFile) {
return true; // There is no save in the autosave slot, enable autosave
}
MohawkArchive mhk;
if (!mhk.openStream(loadFile)) {
return true; // Corrupt save, enable autosave
}
if (!mhk.hasResource(ID_META, 1)) {
return false; // don't autosave over saves that don't have a meta section (like saves from the original)
}
Common::ScopedPtr<Common::SeekableReadStream> metaStream(mhk.getResource(ID_META, 1));
if (!metaStream) {
return true; // corrupt save, enable autosave
}
Common::Serializer serializer = Common::Serializer(metaStream.get(), nullptr);
RivenSaveMetadata metadata;
if (!metadata.sync(serializer)) {
return true; // corrupt save, enable autosave
}
return metadata.autoSave;
}
Common::Error RivenSaveLoad::loadGame(const int slot) {
if (_vm->getFeatures() & GF_DEMO) // Don't load games in the demo
return Common::kNoError;
@ -379,7 +420,7 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genTHMBSection() const {
return stream;
}
Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::String &desc) const {
Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::String &desc, bool autoSave) const {
Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
Common::Serializer serializer = Common::Serializer(nullptr, stream);
@ -394,12 +435,13 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::St
metadata.saveMinute = t.tm_min;
metadata.saveDescription = desc;
metadata.totalPlayTime = _vm->getTotalPlayTime();
metadata.autoSave = autoSave;
metadata.sync(serializer);
return stream;
}
Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &description) {
Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &description, bool autoSave) {
// NOTE: This code is designed to only output a Mohawk archive
// for a Riven saved game. It's hardcoded to do this because
// (as of right now) this is the only place in the engine
@ -415,7 +457,7 @@ Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &desc
debug (0, "Saving game to \'%s\'", filename.c_str());
Common::MemoryWriteStreamDynamic *metaSection = genMETASection(description);
Common::MemoryWriteStreamDynamic *metaSection = genMETASection(description, autoSave);
Common::MemoryWriteStreamDynamic *nameSection = genNAMESection();
Common::MemoryWriteStreamDynamic *thmbSection = genTHMBSection();
Common::MemoryWriteStreamDynamic *varsSection = genVARSSection();