diff options
author | David Fioramonti | 2018-05-19 12:46:36 -0700 |
---|---|---|
committer | Bastien Bouclet | 2018-05-20 15:17:14 +0200 |
commit | 37791c4bd3b33aa042fc966d4ed2b1f5369b0939 (patch) | |
tree | 7e367e3ef0f063865ecda19073d08c584e20782b | |
parent | 1606d6688d665eccf7b2535cb42b84d684e98076 (diff) | |
download | scummvm-rg350-37791c4bd3b33aa042fc966d4ed2b1f5369b0939.tar.gz scummvm-rg350-37791c4bd3b33aa042fc966d4ed2b1f5369b0939.tar.bz2 scummvm-rg350-37791c4bd3b33aa042fc966d4ed2b1f5369b0939.zip |
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.
-rw-r--r-- | engines/mohawk/riven.cpp | 35 | ||||
-rw-r--r-- | engines/mohawk/riven.h | 2 | ||||
-rw-r--r-- | engines/mohawk/riven_saveload.cpp | 62 | ||||
-rw-r--r-- | engines/mohawk/riven_saveload.h | 9 |
4 files changed, 95 insertions, 13 deletions
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 0bf4024057..8139c1a92f 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -71,6 +71,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio _optionsDialog = nullptr; _card = nullptr; _inventory = nullptr; + _lastSaveTime = 0; DebugMan.addDebugChannel(kRivenDebugScript, "Script", "Track Script Execution"); DebugMan.addDebugChannel(kRivenDebugPatches, "Patches", "Track Script Patching"); @@ -240,6 +241,12 @@ void MohawkEngine_Riven::doFrame() { loadGameStateAndDisplayError(_optionsDialog->getLoadSlot()); if (_optionsDialog->getSaveSlot() >= 0) saveGameStateAndDisplayError(_optionsDialog->getSaveSlot(), _optionsDialog->getSaveDescription()); + + if (hasGameEnded()) { + // Attempt to autosave before exiting + tryAutoSaving(); + } + _gfx->setTransitionMode((RivenTransitionMode) _vars["transitionmode"]); _card->initializeZipMode(); break; @@ -281,6 +288,11 @@ void MohawkEngine_Riven::doFrame() { break; } break; + case Common::EVENT_QUIT: + case Common::EVENT_RTL: + // Attempt to autosave before exiting + tryAutoSaving(); + break; default: break; } @@ -294,6 +306,10 @@ void MohawkEngine_Riven::doFrame() { _scriptMan->runQueuedScripts(); } + if (shouldPerformAutoSave(_lastSaveTime)) { + tryAutoSaving(); + } + _inventory->onFrame(); // Update the screen once per frame @@ -575,7 +591,7 @@ void MohawkEngine_Riven::loadGameStateAndDisplayError(int slot) { } Common::Error MohawkEngine_Riven::saveGameState(int slot, const Common::String &desc) { - return _saveLoad->saveGame(slot, desc); + return _saveLoad->saveGame(slot, desc, false); } void MohawkEngine_Riven::saveGameStateAndDisplayError(int slot, const Common::String &desc) { @@ -589,6 +605,23 @@ void MohawkEngine_Riven::saveGameStateAndDisplayError(int slot, const Common::St } } +void MohawkEngine_Riven::tryAutoSaving() { + if (!canSaveGameStateCurrently()) { + return; // Can't save right now, try again on the next frame + } + + _lastSaveTime = _system->getMillis(); + + if (!_saveLoad->isAutoSaveAllowed()) { + return; // Can't autosave ever, try again after the next autosave delay + } + + Common::Error saveError = _saveLoad->saveGame(RivenSaveLoad::kAutoSaveSlot, "Autosave", true); + if (saveError.getCode() != Common::kNoError) + warning("Attempt to autosave has failed."); +} + + void MohawkEngine_Riven::addZipVisitedCard(uint16 cardId, uint16 cardNameId) { Common::String cardName = getStack()->getName(kCardNames, cardNameId); if (cardName.empty()) diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index 6ad1208cf3..3dc19c7ee4 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -121,6 +121,7 @@ private: RivenStack *_stack; bool _gameEnded; + uint32 _lastSaveTime; // Variables void initVars(); @@ -152,6 +153,7 @@ public: // Save / Load void runLoadDialog(); void runSaveDialog(); + void tryAutoSaving(); void loadGameStateAndDisplayError(int slot); void saveGameStateAndDisplayError(int slot, const Common::String &desc); diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp index 1d9ae211d9..5ba0e51f8c 100644 --- a/engines/mohawk/riven_saveload.cpp +++ b/engines/mohawk/riven_saveload.cpp @@ -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(); diff --git a/engines/mohawk/riven_saveload.h b/engines/mohawk/riven_saveload.h index 34bfbdc434..1432505b02 100644 --- a/engines/mohawk/riven_saveload.h +++ b/engines/mohawk/riven_saveload.h @@ -49,6 +49,8 @@ struct RivenSaveMetadata { uint32 totalPlayTime; + bool autoSave; + Common::String saveDescription; RivenSaveMetadata(); @@ -57,11 +59,14 @@ struct RivenSaveMetadata { class RivenSaveLoad { public: + static const int kAutoSaveSlot; + RivenSaveLoad(MohawkEngine_Riven*, Common::SaveFileManager*); ~RivenSaveLoad(); Common::Error loadGame(const int slot); - Common::Error saveGame(const int slot, const Common::String &description); + Common::Error saveGame(const int slot, const Common::String &description, bool autoSave); + bool isAutoSaveAllowed(); static void deleteSave(const int slot); static SaveStateDescriptor querySaveMetaInfos(const int slot); @@ -74,7 +79,7 @@ private: static Common::String buildSaveFilename(const int slot); Common::MemoryWriteStreamDynamic *genNAMESection(); - Common::MemoryWriteStreamDynamic *genMETASection(const Common::String &desc) const; + Common::MemoryWriteStreamDynamic *genMETASection(const Common::String &desc, bool autoSave) const; Common::MemoryWriteStreamDynamic *genTHMBSection() const; Common::MemoryWriteStreamDynamic *genVARSSection(); Common::MemoryWriteStreamDynamic *genVERSSection(); |