From ae2c4b7cd209b310ae9e01edafa9613c06ff421f Mon Sep 17 00:00:00 2001 From: Julien Templier Date: Tue, 26 Oct 2010 00:41:42 +0000 Subject: LASTEXPRESS: Savegame support update - Implement Menu::startGame() properly - Add stubs functions for game restart - Made savegame headers serializable and moved validity checks inside struct definition - Implement create/init savegame functions - Add SavegameStream to be able to read/write to the same memory stream - Add stubs for setup, writeEntry & loadEntry functions svn-id: r53841 --- engines/lastexpress/game/savegame.h | 211 +++++++++++++++++++++++++++--------- 1 file changed, 162 insertions(+), 49 deletions(-) (limited to 'engines/lastexpress/game/savegame.h') diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h index a5af760846..ecb976b38c 100644 --- a/engines/lastexpress/game/savegame.h +++ b/engines/lastexpress/game/savegame.h @@ -77,95 +77,208 @@ #include "lastexpress/shared.h" #include "common/savefile.h" +#include "common/serializer.h" namespace LastExpress { +// Savegame signatures +#define SAVEGAME_SIGNATURE 0x12001200 +#define SAVEGAME_HEADER 0xE660E660 + class LastExpressEngine; class SaveLoad { public: - enum HeaderType { - kHeaderTypeNone = 0, - kHeaderType1 = 1, - kHeaderType2 = 2, - kHeaderType3 = 3, - kHeaderType4 = 4, - kHeaderType5 = 5 + SaveLoad(LastExpressEngine *engine); + ~SaveLoad(); + + // Init + void create(GameId id); + void clear(); + uint32 init(GameId id, bool resetHeaders); + + // Save & Load + bool loadGame(GameId id); + bool loadGame2(GameId id); + void saveGame(SavegameType type, EntityIndex entity, uint32 value); + + void saveVolumeBrightness(); + + // Getting information + static bool isSavegamePresent(GameId id); + static bool isSavegameValid(GameId id); + + bool isGameFinished(uint32 menuIndex, uint32 savegameIndex); + + // Accessors + TimeValue getTime(uint32 index) { return getEntry(index)->time; } + ChapterIndex getChapter(uint32 index) { return getEntry(index)->chapter; } + uint32 getValue(uint32 index) { return getEntry(index)->value; } + uint32 getLastSavegameTicks() const { return _gameTicksLastSavegame; } + +private: + class SavegameStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream { + public: + SavegameStream() : MemoryWriteStreamDynamic(DisposeAfterUse::YES), + _eos(false) {} + + int32 pos() const { return MemoryWriteStreamDynamic::pos(); } + int32 size() const { return MemoryWriteStreamDynamic::size(); } + bool seek(int32 offset, int whence = SEEK_SET) { return MemoryWriteStreamDynamic::seek(offset, whence); } + bool eos() const { return _eos; } + uint32 read(void *dataPtr, uint32 dataSize) { + if ((int32)dataSize > size() - pos()) { + dataSize = size() - pos(); + _eos = true; + } + memcpy(dataPtr, getData() + pos(), dataSize); + + seek(dataSize, SEEK_CUR); + + return dataSize; + } + private: + bool _eos; }; - struct SavegameMainHeader { + LastExpressEngine *_engine; + + struct SavegameMainHeader : Common::Serializable { uint32 signature; - uint32 index; - uint32 time; - uint32 field_C; - uint32 field_10; + uint32 count; + uint32 offset; + uint32 offsetEntry; + uint32 keepIndex; int32 brightness; int32 volume; uint32 field_1C; + + SavegameMainHeader() { + signature = SAVEGAME_SIGNATURE; + count = 0; + offset = 32; + offsetEntry = 32; + keepIndex = 0; + brightness = 3; + volume = 7; + field_1C = 9; + } + + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(signature); + s.syncAsUint32LE(count); + s.syncAsUint32LE(offset); + s.syncAsUint32LE(offsetEntry); + s.syncAsUint32LE(keepIndex); + s.syncAsUint32LE(brightness); + s.syncAsUint32LE(volume); + s.syncAsUint32LE(field_1C); + } + + bool isValid() { + if (signature != SAVEGAME_SIGNATURE) + return false; + + /* Check not needed as it can never be < 0 + if (header.chapter < 0) + return false;*/ + + if (offset < 32) + return false; + + if (offsetEntry < 32) + return false; + + if (keepIndex != 1 && keepIndex != 0) + return false; + + if (brightness < 0 || brightness > 6) + return false; + + if (volume < 0 || volume > 7) + return false; + + if (field_1C != 9) + return false; + + return true; + } }; - struct SavegameEntryHeader { + struct SavegameEntryHeader : Common::Serializable { uint32 signature; - HeaderType type; - uint32 time; + SavegameType type; + TimeValue time; int field_C; ChapterIndex chapter; - EventIndex event; + uint32 value; int field_18; int field_1C; SavegameEntryHeader() { signature = 0; - type = kHeaderTypeNone; - time = 0; + type = kSavegameTypeIndex; + time = kTimeNone; field_C = 0; chapter = kChapterAll; - event = kEventNone; + value = 0; field_18 = 0; field_1C = 0; } - }; - - SaveLoad(LastExpressEngine *engine); - ~SaveLoad(); - - // Save & Load - bool loadGame(GameId id); - void saveGame(SavegameType type, EntityIndex entity, uint32 value); - void saveVolumeBrightness(); + void saveLoadWithSerializer(Common::Serializer &s) { + s.syncAsUint32LE(signature); + s.syncAsUint32LE(type); + s.syncAsUint32LE(time); + s.syncAsUint32LE(field_C); + s.syncAsUint32LE(chapter); + s.syncAsUint32LE(value); + s.syncAsUint32LE(field_18); + s.syncAsUint32LE(field_1C); + } - // Init - void initSavegame(GameId id, bool resetHeaders); - static void writeMainHeader(GameId id); + bool isValid() { + if (signature != SAVEGAME_HEADER) + return false; - // Getting information - static bool isSavegamePresent(GameId id); - static bool isSavegameValid(GameId id); + if (type < kSavegameTypeTime || type > kSavegameTypeTickInterval) + return false; - // Opening save files - static Common::InSaveFile *openForLoading(GameId id); - static Common::OutSaveFile *openForSaving(GameId id); + if (time < kTimeStartGame || time > kTimeCityConstantinople) + return false; - // Headers - static bool loadMainHeader(GameId id, SavegameMainHeader *header); - SavegameEntryHeader *getEntry(uint32 index); - void clearEntries(); + if (field_C <= 0 || field_C >= 15) + return false; - uint32 getLastSavegameTicks() const { return _gameTicksLastSavegame; } + /* No check for < 0, as it cannot happen normaly */ + if (chapter == 0) + return false; -private: - LastExpressEngine *_engine; + return true; + } + }; - uint32 _gameTicksLastSavegame; + SavegameStream *_savegame; Common::Array _gameHeaders; + uint32 _gameTicksLastSavegame; + + // Headers + static bool loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *header); + void loadEntryHeader(SavegameEntryHeader *header); - static Common::String getSavegameName(GameId id); + // Entries + void writeEntry(SavegameType type, EntityIndex entity, uint32 value); + void readEntry(SavegameType type, EntityIndex entity, uint32 value); + SavegameEntryHeader *getEntry(uint32 index); - static void loadEntryHeader(Common::InSaveFile *save, SavegameEntryHeader *header); + // Opening save files + static Common::String getFilename(GameId id); + static Common::InSaveFile *openForLoading(GameId id); + static Common::OutSaveFile *openForSaving(GameId id); - static bool validateMainHeader(const SavegameMainHeader &header); - static bool validateEntryHeader(const SavegameEntryHeader &header); + // Savegame stream + void initStream(); + void flushStream(GameId id); }; } // End of namespace LastExpress -- cgit v1.2.3