aboutsummaryrefslogtreecommitdiff
path: root/engines/xeen
diff options
context:
space:
mode:
authorPaul Gilbert2018-01-12 21:22:06 -0500
committerPaul Gilbert2018-01-12 21:22:06 -0500
commit531467581f6ce923fda54eb8bf24cae28739b5ce (patch)
treef46a5afd99c465b9a48c91cc35423014fa37b525 /engines/xeen
parent10f1eab3c9f07390eb0e437948e4dfb3a927c93e (diff)
downloadscummvm-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.cpp4
-rw-r--r--engines/xeen/files.cpp125
-rw-r--r--engines/xeen/files.h25
-rw-r--r--engines/xeen/locations.cpp2
-rw-r--r--engines/xeen/saves.cpp19
-rw-r--r--engines/xeen/saves.h6
-rw-r--r--engines/xeen/scripts.cpp2
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;