diff options
author | Paul Gilbert | 2018-01-12 21:22:06 -0500 |
---|---|---|
committer | Paul Gilbert | 2018-01-12 21:22:06 -0500 |
commit | 531467581f6ce923fda54eb8bf24cae28739b5ce (patch) | |
tree | f46a5afd99c465b9a48c91cc35423014fa37b525 /engines/xeen | |
parent | 10f1eab3c9f07390eb0e437948e4dfb3a927c93e (diff) | |
download | scummvm-rg350-531467581f6ce923fda54eb8bf24cae28739b5ce.tar.gz scummvm-rg350-531467581f6ce923fda54eb8bf24cae28739b5ce.tar.bz2 scummvm-rg350-531467581f6ce923fda54eb8bf24cae28739b5ce.zip |
XEEN: Further savegame logic
Diffstat (limited to 'engines/xeen')
-rw-r--r-- | engines/xeen/dialogs_party.cpp | 4 | ||||
-rw-r--r-- | engines/xeen/files.cpp | 125 | ||||
-rw-r--r-- | engines/xeen/files.h | 25 | ||||
-rw-r--r-- | engines/xeen/locations.cpp | 2 | ||||
-rw-r--r-- | engines/xeen/saves.cpp | 19 | ||||
-rw-r--r-- | engines/xeen/saves.h | 6 | ||||
-rw-r--r-- | engines/xeen/scripts.cpp | 2 |
7 files changed, 134 insertions, 49 deletions
diff --git a/engines/xeen/dialogs_party.cpp b/engines/xeen/dialogs_party.cpp index f4d95ca612..64f57d62e8 100644 --- a/engines/xeen/dialogs_party.cpp +++ b/engines/xeen/dialogs_party.cpp @@ -133,7 +133,7 @@ void PartyDialog::execute() { party._mazeId = party._priorMazeId; party.copyPartyToRoster(); - _vm->_saves->writeCharFile(); + //_vm->_saves->writeCharFile(); return; } break; @@ -208,7 +208,7 @@ void PartyDialog::execute() { createChar(); party.copyPartyToRoster(); - _vm->_saves->writeCharFile(); + //_vm->_saves->writeCharFile(); screen.fadeOut(); modeFlag = true; breakFlag = true; diff --git a/engines/xeen/files.cpp b/engines/xeen/files.cpp index 0ed6dbd8a2..912c9533d8 100644 --- a/engines/xeen/files.cpp +++ b/engines/xeen/files.cpp @@ -56,18 +56,17 @@ uint16 BaseCCArchive::convertNameToId(const Common::String &resourceName) { return total; } -void BaseCCArchive::loadIndex(Common::SeekableReadStream *stream) { - int count = stream->readUint16LE(); +void BaseCCArchive::loadIndex(Common::SeekableReadStream &stream) { + int count = stream.readUint16LE(); // Read in the data for the archive's index byte *rawIndex = new byte[count * 8]; - stream->read(rawIndex, count * 8); + stream.read(rawIndex, count * 8); // Decrypt the index - int ah = 0xac; - for (int i = 0; i < count * 8; ++i) { - rawIndex[i] = (byte)(((rawIndex[i] << 2 | rawIndex[i] >> 6) + ah) & 0xff); - ah += 0x67; + int seed = 0xac; + for (int i = 0; i < count * 8; ++i, seed += 0x67) { + rawIndex[i] = (byte)(((rawIndex[i] << 2 | rawIndex[i] >> 6) + seed) & 0xff); } // Extract the index data into entry structures @@ -86,14 +85,51 @@ void BaseCCArchive::loadIndex(Common::SeekableReadStream *stream) { delete[] rawIndex; } +void BaseCCArchive::saveIndex(Common::WriteStream &stream) { + // First caclculate file offsets for each resource, since replaced resources + // will shift file offsets for even the succeeding unchanged resources + for (uint idx = 1, pos = _index[0]._offset + _index[0]._size; idx < _index.size(); ++idx) { + _index[idx]._offset = pos; + pos += _index[idx]._size; + } + + // Fill up the data for the index entries into a raw data block + byte data[8]; + byte *rawIndex = new byte[_index.size() * 8]; + + byte *entryP = rawIndex; + for (uint i = 0; i < _index.size(); ++i, entryP += 8) { + CCEntry &entry = _index[i]; + WRITE_LE_UINT16(&entryP[0], entry._id); + WRITE_LE_UINT32(&entryP[2], entry._offset); + WRITE_LE_UINT16(&entryP[5], entry._size); + entryP[7] = 0; + } + + // Encrypt the index + int seed = 0xac; + for (uint i = 0; i < _index.size() * 8; ++i, seed += 0x67) { + byte b = (seed - rawIndex[i]) && 0xff; + rawIndex[i] = ((b >> 2) & 0x3f) | ((b & 3) << 6); + } + + // Write out the number of entries and the encrypted index data + stream.writeUint16LE(_index.size()); + stream.write(rawIndex, _index.size() * 8); + + delete[] rawIndex; +} + bool BaseCCArchive::hasFile(const Common::String &name) const { CCEntry ccEntry; return getHeaderEntry(name, ccEntry); } bool BaseCCArchive::getHeaderEntry(const Common::String &resourceName, CCEntry &ccEntry) const { - uint16 id = convertNameToId(resourceName); + return getHeaderEntry(convertNameToId(resourceName), ccEntry); +} +bool BaseCCArchive::getHeaderEntry(uint16 id, CCEntry &ccEntry) const { // Loop through the index for (uint i = 0; i < _index.size(); ++i) { if (_index[i]._id == id) { @@ -123,7 +159,7 @@ int BaseCCArchive::listMembers(Common::ArchiveMemberList &list) const { CCArchive::CCArchive(const Common::String &filename, bool encoded): BaseCCArchive(), _filename(filename), _encoded(encoded) { File f(filename, SearchMan); - loadIndex(&f); + loadIndex(f); } CCArchive::CCArchive(const Common::String &filename, const Common::String &prefix, @@ -131,7 +167,7 @@ CCArchive::CCArchive(const Common::String &filename, const Common::String &prefi _prefix(prefix), _encoded(encoded) { _prefix.toLowercase(); File f(filename, SearchMan); - loadIndex(&f); + loadIndex(f); } CCArchive::~CCArchive() { @@ -371,18 +407,22 @@ SaveArchive::~SaveArchive() { } Common::SeekableReadStream *SaveArchive::createReadStreamForMember(const Common::String &name) const { - CCEntry ccEntry; // If the given resource has already been perviously "written" to the // save manager, then return that new resource uint16 id = BaseCCArchive::convertNameToId(name); + return createReadStreamForMember(id); +} + +Common::SeekableReadStream *SaveArchive::createReadStreamForMember(uint16 id) const { if (_newData.contains(id)) { Common::MemoryWriteStreamDynamic *stream = _newData[id]; return new Common::MemoryReadStream(stream->getData(), stream->size()); } // Retrieve the resource from the loaded savefile - if (getHeaderEntry(name, ccEntry)) { + CCEntry ccEntry; + if (getHeaderEntry(id, ccEntry)) { // Open the correct CC entry return new Common::MemoryReadStream(_data + ccEntry._offset, ccEntry._size); } @@ -390,14 +430,14 @@ Common::SeekableReadStream *SaveArchive::createReadStreamForMember(const Common: return nullptr; } -void SaveArchive::load(Common::SeekableReadStream *stream) { +void SaveArchive::load(Common::SeekableReadStream &stream) { loadIndex(stream); delete[] _data; - _dataSize = stream->size(); + _dataSize = stream.size(); _data = new byte[_dataSize]; - stream->seek(0); - stream->read(_data, _dataSize); + stream.seek(0); + stream.read(_data, _dataSize); // Load in the character stats and active party Common::SeekableReadStream *chr = createReadStreamForMember("maze.chr"); @@ -434,12 +474,53 @@ void SaveArchive::reset(CCArchive *src) { assert(saveFile.size() > 0); Common::MemoryReadStream f(saveFile.getData(), saveFile.size()); - load(&f); + load(f); } void SaveArchive::save(Common::WriteStream &s) { - s.writeUint32LE(_dataSize); - s.write(_data, _dataSize); + // Save the character stats and active party + OutFile chr("maze.chr", this); + XeenSerializer sChr(nullptr, &chr); + _party->_roster.synchronize(sChr); + + OutFile pty("maze.pty", this); + Common::Serializer sPty(nullptr, &pty); + _party->synchronize(sPty); + + // Save out the index + saveIndex(s); + + // Save out each resource in turn + for (uint idx = 0; idx < _index.size(); ++idx) { + // Get the entry + Common::SeekableReadStream *entry = createReadStreamForMember(_index[idx]._id); + byte *data = new byte[entry->size()]; + entry->read(data, entry->size()); + + // Write it out to the savegame + s.write(data, entry->size()); + delete[] data; + delete entry; + } +} + +void SaveArchive::replaceEntry(uint16 id, const byte *data, size_t size) { + // Delete any prior set entry + if (_newData.contains(id)) + delete _newData[id]; + + // Create a new entry and write out the data to it + Common::MemoryWriteStreamDynamic *out = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES); + out->write(data, size); + _newData[id] = out; + + // Update the index with the entry's size for later convenience when creating savegames + for (uint idx = 0; idx < _index.size(); ++idx) { + if (_index[idx]._id == id) { + _index[idx]._size = size; + break; + } + } } /*------------------------------------------------------------------------*/ @@ -470,11 +551,7 @@ int32 OutFile::pos() const { void OutFile::finalize() { uint16 id = BaseCCArchive::convertNameToId(_filename); - if (!_archive->_newData.contains(id)) - _archive->_newData[id] = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES); - - Common::MemoryWriteStreamDynamic *out = _archive->_newData[id]; - out->write(_backingStream.getData(), _backingStream.size()); + _archive->replaceEntry(id, _backingStream.getData(), _backingStream.size()); } } // End of namespace Xeen diff --git a/engines/xeen/files.h b/engines/xeen/files.h index b5636b17ae..b528658566 100644 --- a/engines/xeen/files.h +++ b/engines/xeen/files.h @@ -213,13 +213,24 @@ protected: /** * Load the index of a given CC file */ - void loadIndex(Common::SeekableReadStream *stream); + void loadIndex(Common::SeekableReadStream &stream); + + /** + * Saves out the contents of the index. Used when creating savegames + */ + void saveIndex(Common::WriteStream &stream); /** * Given a resource name, returns whether an entry exists, and returns * the header index data for that entry */ virtual bool getHeaderEntry(const Common::String &resourceName, CCEntry &ccEntry) const; + + /** + * Given a resource Id, returns whether an entry exists, and returns + * the header index data for that entry + */ + virtual bool getHeaderEntry(uint16 id, CCEntry &ccEntry) const; public: /** * Hash a given filename to produce the Id that represents it @@ -275,14 +286,24 @@ public: virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; /** + * Archive implementation + */ + virtual Common::SeekableReadStream *createReadStreamForMember(uint16 id) const; + + /** * Loads a save archive from a stream */ - void load(Common::SeekableReadStream *stream); + void load(Common::SeekableReadStream &stream); /** * Saves a save archive to a savegame */ void save(Common::WriteStream &s); + + /** + * Sets a new resource entry + */ + void replaceEntry(uint16 id, const byte *data, size_t size); }; /** diff --git a/engines/xeen/locations.cpp b/engines/xeen/locations.cpp index 11391736d5..647eebac71 100644 --- a/engines/xeen/locations.cpp +++ b/engines/xeen/locations.cpp @@ -104,7 +104,7 @@ int BaseLocation::show() { party.addTime(_farewellTime); result = 0; } else { - _vm->_saves->saveChars(); + //_vm->_saves->saveChars(); result = 2; } diff --git a/engines/xeen/saves.cpp b/engines/xeen/saves.cpp index 0bc41293f7..2a6b7d6619 100644 --- a/engines/xeen/saves.cpp +++ b/engines/xeen/saves.cpp @@ -62,18 +62,6 @@ SavesManager::~SavesManager() { delete File::_darkSave; } -void SavesManager::readCharFile() { - warning("TODO: readCharFile"); -} - -void SavesManager::writeCharFile() { - warning("TODO: writeCharFile"); -} - -void SavesManager::saveChars() { - warning("TODO: saveChars"); -} - const char *const SAVEGAME_STR = "XEEN"; #define SAVEGAME_STR_SIZE 6 @@ -151,6 +139,11 @@ Common::Error SavesManager::saveGameState(int slot, const Common::String &desc) if (!out) return Common::kCreatingFileFailed; + // Push map and party data to the save archives + Map &map = *g_vm->_map; + map.saveMaze(); + + XeenSavegameHeader header; header._saveName = desc; writeSavegameHeader(out, header); @@ -199,7 +192,7 @@ Common::Error SavesManager::loadGameState(int slot) { if (archives[idx]) { Common::SeekableSubReadStream arcStream(saveFile, saveFile->pos(), saveFile->pos() + fileSize); - archives[idx]->load(&arcStream); + archives[idx]->load(arcStream); } else { assert(!fileSize); } diff --git a/engines/xeen/saves.h b/engines/xeen/saves.h index 334ea3de8a..c236bee0fe 100644 --- a/engines/xeen/saves.h +++ b/engines/xeen/saves.h @@ -62,12 +62,6 @@ public: SavesManager(const Common::String &targetName); ~SavesManager(); - void readCharFile(); - - void writeCharFile(); - - void saveChars(); - /** * Read in a savegame header */ diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp index 99603224c8..46485a543b 100644 --- a/engines/xeen/scripts.cpp +++ b/engines/xeen/scripts.cpp @@ -1425,7 +1425,7 @@ void Scripts::doWorldEnding() { } void Scripts::doEnding(const Common::String &endStr) { - _vm->_saves->saveChars(); + //_vm->_saves->saveChars(); Party &party = *_vm->_party; |