aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippos Karapetis2011-12-18 02:54:51 +0200
committerFilippos Karapetis2011-12-18 02:55:22 +0200
commit08fec8fa345cc3a76928059539ecd7ab5bd8a0e2 (patch)
treec5ffaabfe89febf4d9e9a16ee1413bd6abe85e71
parent2e8490448e4add482d622fe2e83b5125372aa67d (diff)
downloadscummvm-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.cpp70
-rw-r--r--engines/dreamweb/dreamweb.h4
-rw-r--r--engines/dreamweb/saveload.cpp53
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;
}