diff options
-rw-r--r-- | engines/agi/agi.h | 6 | ||||
-rw-r--r-- | engines/agi/detection.cpp | 104 | ||||
-rw-r--r-- | engines/agi/preagi.h | 2 | ||||
-rw-r--r-- | engines/agi/saveload.cpp | 41 |
4 files changed, 142 insertions, 11 deletions
diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 2e4710744b..0dd20be283 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -724,6 +724,8 @@ public: virtual void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, int16 p4, int16 p5, int16 p6, int16 p7) = 0; virtual void releaseImageStack() = 0; + virtual int saveGame(const char *fileName, const char *saveName) = 0; + virtual int loadGame(const char *fileName, bool checkId = true) = 0; int _soundemu; @@ -738,6 +740,10 @@ public: uint16 getGameType() const; Common::Language getLanguage() const; Common::Platform getPlatform() const; + Common::Error loadGameState(int slot); + Common::Error saveGameState(int slot, const char *desc); + bool canLoadGameStateCurrently(); + bool canSaveGameStateCurrently(); }; class AgiEngine : public AgiBase { diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index bcc2b60d74..a9f49b64c6 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -28,6 +28,7 @@ #include "common/advancedDetector.h" #include "common/config-manager.h" #include "common/file.h" +#include "graphics/thumbnail.h" #include "agi/agi.h" #include "agi/preagi.h" @@ -2127,7 +2128,8 @@ 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; + const Common::ADGameDescription *fallbackDetect(const Common::FSList &fslist) const; }; @@ -2135,11 +2137,17 @@ bool AgiMetaEngine::hasFeature(MetaEngineFeature f) const { return (f == kSupportsListSaves) || (f == kSupportsLoadingDuringStartup) || - (f == kSupportsDeleteSave); + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSavesSupportCreationDate); } bool AgiBase::hasFeature(EngineFeature f) const { - return (f == kSupportsRTL); + return + (f == kSupportsRTL) || + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime); } @@ -2197,13 +2205,67 @@ SaveStateList AgiMetaEngine::listSaves(const char *target) const { int AgiMetaEngine::getMaximumSaveSlot() const { return 999; } void AgiMetaEngine::removeSaveState(const char *target, int slot) const { - char extension[6]; - snprintf(extension, sizeof(extension), ".%03d", slot); + char fileName[MAX_PATH]; + sprintf(fileName, "%s.%03d", target, slot); + g_system->getSavefileManager()->removeSavefile(fileName); +} + +SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + const uint32 AGIflag = MKID_BE('AGI:'); + char fileName[MAX_PATH]; + sprintf(fileName, "%s.%03d", target, slot); + + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName); + + if (in) { + if (in->readUint32BE() != AGIflag) { + delete in; + return SaveStateDescriptor(); + } + + char name[32]; + in->read(name, 31); + + SaveStateDescriptor desc(slot, name); + + desc.setDeletableFlag(true); + desc.setWriteProtectedFlag(false); + + char saveVersion = in->readByte(); + if (saveVersion >= 4) { + Graphics::Surface *thumbnail = new Graphics::Surface(); + assert(thumbnail); + if (!Graphics::loadThumbnail(*in, *thumbnail)) { + delete thumbnail; + thumbnail = 0; + } + + desc.setThumbnail(thumbnail); + + uint32 saveDate = in->readUint32BE(); + uint16 saveTime = in->readUint16BE(); + + int day = (saveDate >> 24) & 0xFF; + int month = (saveDate >> 16) & 0xFF; + int year = saveDate & 0xFFFF; + + desc.setSaveDate(year, month, day); + + int hour = (saveTime >> 8) & 0xFF; + int minutes = saveTime & 0xFF; - Common::String filename = target; - filename += extension; + desc.setSaveTime(hour, minutes); - g_system->getSavefileManager()->removeSavefile(filename.c_str()); + // TODO: played time + } + + + delete in; + + return desc; + } + + return SaveStateDescriptor(); } const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const Common::FSList &fslist) const { @@ -2375,3 +2437,29 @@ const Common::ADGameDescription *AgiMetaEngine::fallbackDetect(const Common::FSL #else REGISTER_PLUGIN_STATIC(AGI, PLUGIN_TYPE_ENGINE, AgiMetaEngine); #endif + +namespace Agi { + +Common::Error AgiBase::loadGameState(int slot) { + static char saveLoadSlot[12]; + sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); + loadGame(saveLoadSlot); + return Common::kNoError; // TODO: return success/failure +} + +Common::Error AgiBase::saveGameState(int slot, const char *desc) { + static char saveLoadSlot[12]; + sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), slot); + saveGame(saveLoadSlot, desc); + return Common::kNoError; // TODO: return success/failure +} + +bool AgiBase::canLoadGameStateCurrently() { + return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork)); +} + +bool AgiBase::canSaveGameStateCurrently() { + return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork)); +} + +} // End of namespace Agi diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h index 10a46aa6ec..d7a1101c68 100644 --- a/engines/agi/preagi.h +++ b/engines/agi/preagi.h @@ -61,6 +61,8 @@ public: void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, int16 p4, int16 p5, int16 p6, int16 p7) {} void releaseImageStack() {} + int saveGame(const char *fileName, const char *saveName) { return -1; } + int loadGame(const char *fileName, bool checkId = true) { return -1; } // Game Common::String getTargetName() { return _targetName; } diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index 179db94a71..e8fb2522b1 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -28,8 +28,10 @@ * Multi-slots by Claudio Matsuoka <claudio@helllabs.org> */ +#include <time.h> // for extended infos #include "common/file.h" +#include "graphics/thumbnail.h" #include "agi/agi.h" #include "agi/graphics.h" @@ -37,13 +39,14 @@ #include "agi/keyboard.h" #include "agi/menu.h" -#define SAVEGAME_VERSION 3 +#define SAVEGAME_VERSION 4 /* * Version 0 (Sarien): view table has 64 entries * Version 1 (Sarien): view table has 256 entries (needed in KQ3) * Version 2 (ScummVM): first ScummVM version - * Version 3 (ScummVM): adding AGIPAL save/load support + * Version 3 (ScummVM): added AGIPAL save/load support + * Version 4 (ScummVM): added thumbnails and save creation date/time */ namespace Agi { @@ -70,6 +73,22 @@ int AgiEngine::saveGame(const char *fileName, const char *description) { out->writeByte(SAVEGAME_VERSION); debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing save game version (%d)", SAVEGAME_VERSION); + // Thumbnail + Graphics::saveThumbnail(*out); + + // Creation date/time + tm curTime; + _system->getTimeAndDate(curTime); + + uint32 saveDate = (curTime.tm_mday & 0xFF) << 24 | ((curTime.tm_mon + 1) & 0xFF) << 16 | (curTime.tm_year + 1900) & 0xFFFF; + uint16 saveTime = (curTime.tm_hour & 0xFF) << 8 | (curTime.tm_min) & 0xFF; + + out->writeUint32BE(saveDate); + debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing save date (%d)", saveDate); + out->writeUint16BE(saveTime); + debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing save time (%d)", saveTime); + // TODO: played time + out->writeByte(_game.state); debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing game state (%d)", _game.state); @@ -250,9 +269,25 @@ int AgiEngine::loadGame(const char *fileName, bool checkId) { debugC(6, kDebugLevelMain | kDebugLevelSavegame, "Description is: %s", description); saveVersion = in->readByte(); - if (saveVersion != SAVEGAME_VERSION) + if (saveVersion < 2) // is the save game pre-ScummVM? warning("Old save game version (%d, current version is %d). Will try and read anyway, but don't be surprised if bad things happen", saveVersion, SAVEGAME_VERSION); + if (saveVersion < 3) + warning("This save game contains no AGIPAL data, if the game is using the AGIPAL hack, it won't work correctly"); + + if (saveVersion >= 4) { + // We don't need the thumbnail here, so just read it and discard it + Graphics::Surface *thumbnail = new Graphics::Surface(); + assert(thumbnail); + Graphics::loadThumbnail(*in, *thumbnail); + delete thumbnail; + thumbnail = 0; + + in->readUint32BE(); // save date + in->readUint16BE(); // save time + // TODO: played time + } + _game.state = in->readByte(); in->read(loadId, 8); |