diff options
-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(); |