diff options
Diffstat (limited to 'engines/mohawk/myst_state.cpp')
-rw-r--r-- | engines/mohawk/myst_state.cpp | 227 |
1 files changed, 197 insertions, 30 deletions
diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp index 3e54017df8..213a976413 100644 --- a/engines/mohawk/myst_state.cpp +++ b/engines/mohawk/myst_state.cpp @@ -26,11 +26,41 @@ #include "common/debug.h" #include "common/serializer.h" +#include "common/system.h" #include "common/textconsole.h" #include "common/util.h" +#include "graphics/thumbnail.h" + namespace Mohawk { +MystSaveMetadata::MystSaveMetadata() { + saveDay = 0; + saveMonth = 0; + saveYear = 0; + saveHour = 0; + saveMinute = 0; + totalPlayTime = 0; +} + +bool MystSaveMetadata::sync(Common::Serializer &s) { + static const Common::Serializer::Version kCurrentVersion = 1; + + if (!s.syncVersion(kCurrentVersion)) { + return false; + } + + s.syncAsByte(saveDay); + s.syncAsByte(saveMonth); + s.syncAsUint16LE(saveYear); + s.syncAsByte(saveHour); + s.syncAsByte(saveMinute); + s.syncString(saveDescription); + s.syncAsUint32LE(totalPlayTime); + + return true; +} + MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) { // Most of the variables are zero at game start. memset(&_globals, 0, sizeof(_globals)); @@ -76,14 +106,39 @@ MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *sav MystGameState::~MystGameState() { } -Common::StringArray MystGameState::generateSaveGameList() { - return _saveFileMan->listSavefiles("*.mys"); +bool MystGameState::load(int slot) { + if (!loadState(slot)) { + return false; + } + + loadMetadata(slot); + + // Set Channelwood elevator state to down, because we start on the lower level + _channelwood.elevatorState = 0; + + // Switch us back to the intro stack, to the linking book + _vm->changeToStack(kIntroStack, 5, 0, 0); + + // Set our default cursor + _vm->_cursor->showCursor(); + if (_globals.heldPage == 0 || _globals.heldPage > 13) + _vm->setMainCursor(kDefaultMystCursor); + else if (_globals.heldPage < 7) + _vm->setMainCursor(kBluePageCursor); + else if (_globals.heldPage < 13) + _vm->setMainCursor(kRedPageCursor); + else // if (globals.heldPage == 13) + _vm->setMainCursor(kWhitePageCursor); + + return true; } -bool MystGameState::load(const Common::String &filename) { +bool MystGameState::loadState(int slot) { + Common::String filename = buildSaveFilename(slot); Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); - if (!loadFile) + if (!loadFile) { return false; + } debugC(kDebugSaveLoad, "Loading game from '%s'", filename.c_str()); @@ -96,42 +151,54 @@ bool MystGameState::load(const Common::String &filename) { return false; } - Common::Serializer s(loadFile, 0); + Common::Serializer s(loadFile, nullptr); syncGameState(s, size == 664); delete loadFile; - // Set Channelwood elevator state to down, because we start on the lower level - _channelwood.elevatorState = 0; + return true; +} - // Switch us back to the intro stack, to the linking book - _vm->changeToStack(kIntroStack, 5, 0, 0); +void MystGameState::loadMetadata(int slot) { + // Open the metadata file + Common::String filename = buildMetadataFilename(slot); + Common::InSaveFile *metadataFile = _vm->getSaveFileManager()->openForLoading(filename); + if (!metadataFile) { + return; + } - // Set our default cursor - if (_globals.heldPage == 0 || _globals.heldPage > 13) - _vm->setMainCursor(kDefaultMystCursor); - else if (_globals.heldPage < 7) - _vm->setMainCursor(kBluePageCursor); - else if (_globals.heldPage < 13) - _vm->setMainCursor(kRedPageCursor); - else // if (globals.heldPage == 13) - _vm->setMainCursor(kWhitePageCursor); + debugC(kDebugSaveLoad, "Loading metadata from '%s'", filename.c_str()); - return true; + Common::Serializer m(metadataFile, nullptr); + + // Read the metadata file + if (_metadata.sync(m)) { + _vm->setTotalPlayTime(_metadata.totalPlayTime); + } + + delete metadataFile; } -bool MystGameState::save(const Common::String &fname) { - Common::String filename(fname); - // Make sure we have the right extension - if (!filename.hasSuffix(".mys") && !filename.hasSuffix(".MYS")) - filename += ".mys"; +bool MystGameState::save(int slot, const Common::String &desc) { + if (!saveState(slot)) { + return false; + } + + updateMetadateForSaving(desc); + + return saveMetadata(slot); +} +bool MystGameState::saveState(int slot) { + // Make sure we have the right extension + Common::String filename = buildSaveFilename(slot); Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(filename); - if (!saveFile) + if (!saveFile) { return false; + } debugC(kDebugSaveLoad, "Saving game to '%s'", filename.c_str()); - Common::Serializer s(0, saveFile); + Common::Serializer s(nullptr, saveFile); syncGameState(s, _vm->getFeatures() & GF_ME); saveFile->finalize(); delete saveFile; @@ -139,6 +206,101 @@ bool MystGameState::save(const Common::String &fname) { return true; } +Common::String MystGameState::buildSaveFilename(int slot) { + return Common::String::format("myst-%03d.mys", slot); +} + +Common::String MystGameState::buildMetadataFilename(int slot) { + return Common::String::format("myst-%03d.mym", slot); +} + +void MystGameState::updateMetadateForSaving(const Common::String &desc) { + // Update save creation info + TimeDate t; + g_system->getTimeAndDate(t); + _metadata.saveYear = t.tm_year + 1900; + _metadata.saveMonth = t.tm_mon + 1; + _metadata.saveDay = t.tm_mday; + _metadata.saveHour = t.tm_hour; + _metadata.saveMinute = t.tm_min; + _metadata.saveDescription = desc; + _metadata.totalPlayTime = _vm->getTotalPlayTime(); +} + +bool MystGameState::saveMetadata(int slot) { + // Write the metadata to a separate file so that the save files + // are still compatible with the original engine + Common::String metadataFilename = buildMetadataFilename(slot); + Common::OutSaveFile *metadataFile = _saveFileMan->openForSaving(metadataFilename); + if (!metadataFile) { + return false; + } + + // Save the metadata + Common::Serializer m(nullptr, metadataFile); + _metadata.sync(m); + + // Append a thumbnail + Graphics::saveThumbnail(*metadataFile); + + metadataFile->finalize(); + delete metadataFile; + + return true; +} + +SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) { + // Open the metadata file + Common::String filename = buildMetadataFilename(slot); + Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename); + if (!metadataFile) { + return SaveStateDescriptor(); + } + + Common::Serializer m(metadataFile, nullptr); + + // Read the metadata file + Mohawk::MystSaveMetadata metadata; + if (!metadata.sync(m)) { + delete metadataFile; + return SaveStateDescriptor(); + } + + // Set the save description + SaveStateDescriptor desc; + desc.setDescription(metadata.saveDescription); + desc.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay); + desc.setSaveTime(metadata.saveHour, metadata.saveMinute); + desc.setPlayTime(metadata.totalPlayTime); + desc.setThumbnail(Graphics::loadThumbnail(*metadataFile)); + + delete metadataFile; + + return desc; +} + +Common::String MystGameState::querySaveDescription(int slot) { + // Open the metadata file + Common::String filename = buildMetadataFilename(slot); + Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename); + if (!metadataFile) { + return ""; + } + + Common::Serializer m(metadataFile, nullptr); + + // Read the metadata file + Mohawk::MystSaveMetadata metadata; + if (!metadata.sync(m)) { + delete metadataFile; + return ""; + } + + delete metadataFile; + + return metadata.saveDescription; +} + void MystGameState::syncGameState(Common::Serializer &s, bool isME) { // Globals first s.syncAsUint16LE(_globals.u0); @@ -315,13 +477,18 @@ void MystGameState::syncGameState(Common::Serializer &s, bool isME) { warning("Unexpected File Position 0x%03X At End of Save/Load", s.bytesSynced()); } -void MystGameState::deleteSave(const Common::String &saveName) { - debugC(kDebugSaveLoad, "Deleting save file \'%s\'", saveName.c_str()); - _saveFileMan->removeSavefile(saveName.c_str()); +void MystGameState::deleteSave(int slot) { + Common::String filename = buildSaveFilename(slot); + Common::String metadataFilename = buildMetadataFilename(slot); + + debugC(kDebugSaveLoad, "Deleting save file \'%s\'", filename.c_str()); + + g_system->getSavefileManager()->removeSavefile(filename); + g_system->getSavefileManager()->removeSavefile(metadataFilename); } void MystGameState::addZipDest(uint16 stack, uint16 view) { - ZipDests *zipDests = 0; + ZipDests *zipDests = nullptr; // The demo has no zip dest storage if (_vm->getFeatures() & GF_DEMO) |