diff options
author | Filippos Karapetis | 2011-12-18 02:54:51 +0200 |
---|---|---|
committer | Filippos Karapetis | 2011-12-18 02:55:22 +0200 |
commit | 08fec8fa345cc3a76928059539ecd7ab5bd8a0e2 (patch) | |
tree | c5ffaabfe89febf4d9e9a16ee1413bd6abe85e71 | |
parent | 2e8490448e4add482d622fe2e83b5125372aa67d (diff) | |
download | scummvm-rg350-08fec8fa345cc3a76928059539ecd7ab5bd8a0e2.tar.gz scummvm-rg350-08fec8fa345cc3a76928059539ecd7ab5bd8a0e2.tar.bz2 scummvm-rg350-08fec8fa345cc3a76928059539ecd7ab5bd8a0e2.zip |
DREAMWEB: Add meta information to saved games
This information includes savegame versioning and the saved game's
date/time, played time and game thumbnail. This information is stored
into an unused data block of the original save format, so the
generated ScummVM saves are (hopefully) fully compatible with the
original ones and can be loaded in the original interpreter
-rw-r--r-- | engines/dreamweb/detection.cpp | 70 | ||||
-rw-r--r-- | engines/dreamweb/dreamweb.h | 4 | ||||
-rw-r--r-- | engines/dreamweb/saveload.cpp | 53 |
3 files changed, 123 insertions, 4 deletions
diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp index db2155fc4c..b3483f9248 100644 --- a/engines/dreamweb/detection.cpp +++ b/engines/dreamweb/detection.cpp @@ -25,7 +25,10 @@ #include "common/algorithm.h" #include "common/system.h" +#include "graphics/thumbnail.h" + #include "dreamweb/dreamweb.h" +#include "dreamweb/structs.h" static const PlainGameDescriptor dreamWebGames[] = { { "dreamweb", "DreamWeb" }, @@ -56,6 +59,7 @@ public: virtual SaveStateList listSaves(const char *target) const; virtual int getMaximumSaveSlot() const; virtual void removeSaveState(const char *target, int slot) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; }; bool DreamWebMetaEngine::hasFeature(MetaEngineFeature f) const { @@ -63,6 +67,10 @@ bool DreamWebMetaEngine::hasFeature(MetaEngineFeature f) const { case kSupportsListSaves: case kSupportsLoadingDuringStartup: case kSupportsDeleteSave: + case kSavesSupportMetaInfo: + case kSavesSupportThumbnail: + case kSavesSupportCreationDate: + case kSavesSupportPlayTime: return true; default: return false; @@ -120,6 +128,68 @@ void DreamWebMetaEngine::removeSaveState(const char *target, int slot) const { g_system->getSavefileManager()->removeSavefile(fileName); } +SaveStateDescriptor DreamWebMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String filename = Common::String::format("DREAMWEB.D%02d", slot); + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str()); + + if (in) { + DreamGen::FileHeader header; + in->read((uint8 *)&header, sizeof(DreamGen::FileHeader)); + + Common::String saveName; + byte descSize = header.len(0); + byte i; + + for (i = 0; i < descSize; i++) + saveName += (char)in->readByte(); + + SaveStateDescriptor desc(slot, saveName); + desc.setDeletableFlag(true); + desc.setWriteProtectedFlag(false); + + // Check if there is a ScummVM data block + if (header.len(6) == SCUMMVM_BLOCK_MAGIC_SIZE) { + // Skip the game data + for (i = 1; i <= 5; i++) + in->skip(header.len(i)); + + uint32 tag = in->readUint32BE(); + if (tag != SCUMMVM_HEADER) { + warning("ScummVM data block found, but the block header is incorrect - skipping"); + delete in; + return desc; + } + + byte version = in->readByte(); + if (version > SAVEGAME_VERSION) { + warning("ScummVM data block found, but it has been saved with a newer version of ScummVM - skipping"); + delete in; + return desc; + } + + uint32 saveDate = in->readUint32LE(); + uint32 saveTime = in->readUint32LE(); + uint32 playTime = in->readUint32LE(); + Graphics::Surface *thumbnail = Graphics::loadThumbnail(*in); + + int day = (saveDate >> 24) & 0xFF; + int month = (saveDate >> 16) & 0xFF; + int year = saveDate & 0xFFFF; + int hour = (saveTime >> 16) & 0xFF; + int minutes = (saveTime >> 8) & 0xFF; + + desc.setSaveDate(year, month, day); + desc.setSaveTime(hour, minutes); + desc.setPlayTime(playTime * 1000); + desc.setThumbnail(thumbnail); + } + + return desc; + } + + return SaveStateDescriptor(); +} // End of namespace Toltecs + #if PLUGIN_ENABLED_DYNAMIC(DREAMWEB) REGISTER_PLUGIN_DYNAMIC(DREAMWEB, PLUGIN_TYPE_ENGINE, DreamWebMetaEngine); #else diff --git a/engines/dreamweb/dreamweb.h b/engines/dreamweb/dreamweb.h index 7ff0005fa4..4d7bf5f0e4 100644 --- a/engines/dreamweb/dreamweb.h +++ b/engines/dreamweb/dreamweb.h @@ -42,6 +42,10 @@ #include "dreamweb/structs.h" +#define SCUMMVM_HEADER MKTAG('S', 'C', 'V', 'M') +#define SCUMMVM_BLOCK_MAGIC_SIZE 0x1234 +#define SAVEGAME_VERSION 1 + namespace DreamGen { // These are for ReelRoutine::reelPointer, which is a callback field. diff --git a/engines/dreamweb/saveload.cpp b/engines/dreamweb/saveload.cpp index 9cf3ea2c63..599ef45c66 100644 --- a/engines/dreamweb/saveload.cpp +++ b/engines/dreamweb/saveload.cpp @@ -22,6 +22,7 @@ #include "dreamweb/dreamweb.h" #include "engines/metaengine.h" +#include "graphics/thumbnail.h" #include "gui/saveload.h" #include "common/config-manager.h" #include "common/translation.h" @@ -216,7 +217,6 @@ void DreamGenContext::saveGame() { descbuf[++desclen] = 0; while (desclen < 16) descbuf[++desclen] = 1; - savePosition(savegameId, descbuf); // TODO: The below is copied from actualsave getRidOfTemp(); @@ -225,6 +225,12 @@ void DreamGenContext::saveGame() { data.word(kTextaddressy) = 182; data.byte(kTextlen) = 240; redrawMainScrn(); + workToScreenCPP(); // show the main screen without the mouse pointer + + // We need to save after the scene has been redrawn, to capture the + // correct screen thumbnail + savePosition(savegameId, descbuf); + workToScreenM(); data.byte(kGetback) = 4; } @@ -387,9 +393,6 @@ void DreamGenContext::savePosition(unsigned int slot, const char *descbuf) { madeUpRoom.facing = data.byte(kFacing); madeUpRoom.b27 = 255; - - engine->processEvents(); // TODO: Is this necessary? - Common::String filename = engine->getSavegameFilename(slot); debug(1, "savePosition: slot %d filename %s", slot, filename.c_str()); Common::OutSaveFile *outSaveFile = engine->getSaveFileManager()->openForSaving(filename); @@ -412,6 +415,11 @@ void DreamGenContext::savePosition(unsigned int slot, const char *descbuf) { for (int i = 0; i < 6; ++i) header.setLen(i, len[i]); + // Write a new section with data that we need for ScummVM (version, + // thumbnail, played time etc). We don't really care for its size, + // so we just set it to a magic number. + header.setLen(6, SCUMMVM_BLOCK_MAGIC_SIZE); + outSaveFile->write((const uint8 *)&header, sizeof(FileHeader)); outSaveFile->write(descbuf, len[0]); outSaveFile->write(data.ptr(kStartvars, len[1]), len[1]); @@ -429,6 +437,19 @@ void DreamGenContext::savePosition(unsigned int slot, const char *descbuf) { } outSaveFile->write(data.ptr(kReelroutines, len[5]), len[5]); + // ScummVM data block + outSaveFile->writeUint32BE(SCUMMVM_HEADER); + outSaveFile->writeByte(SAVEGAME_VERSION); + TimeDate curTime; + g_system->getTimeAndDate(curTime); + uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF); + uint32 saveTime = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF); + uint32 playTime = g_engine->getTotalPlayTime() / 1000; + outSaveFile->writeUint32LE(saveDate); + outSaveFile->writeUint32LE(saveTime); + outSaveFile->writeUint32LE(playTime); + Graphics::saveThumbnail(*outSaveFile); + outSaveFile->finalize(); if (outSaveFile->err()) { // TODO: Do proper error handling @@ -482,6 +503,30 @@ void DreamGenContext::loadPosition(unsigned int slot) { syncReelRoutine(s, (ReelRoutine*)data.ptr(kReelroutines + 8*i, 8)); } + // Check if there's a ScummVM data block + if (header.len(6) == SCUMMVM_BLOCK_MAGIC_SIZE) { + uint32 tag = inSaveFile->readUint32BE(); + if (tag != SCUMMVM_HEADER) { + warning("ScummVM data block found, but the block header is incorrect - skipping"); + delete inSaveFile; + return; + } + + byte version = inSaveFile->readByte(); + if (version > SAVEGAME_VERSION) { + warning("ScummVM data block found, but it has been saved with a newer version of ScummVM - skipping"); + delete inSaveFile; + return; + } + + inSaveFile->skip(4); // saveDate + inSaveFile->skip(4); // saveTime + uint32 playTime = inSaveFile->readUint32LE(); + g_engine->setTotalPlayTime(playTime * 1000); + + // The thumbnail data follows, but we don't need it here + } + delete inSaveFile; } |