aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mohawk')
-rw-r--r--engines/mohawk/riven.cpp35
-rw-r--r--engines/mohawk/riven.h2
-rw-r--r--engines/mohawk/riven_saveload.cpp62
-rw-r--r--engines/mohawk/riven_saveload.h9
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();