Permalink
Browse files

XEEN: Further savegame logic

  • Loading branch information...
dreammaster committed Jan 13, 2018
1 parent 10f1eab commit 531467581f6ce923fda54eb8bf24cae28739b5ce
@@ -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;
View
@@ -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,15 +159,15 @@ 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,
bool encoded): BaseCCArchive(), _filename(filename),
_prefix(prefix), _encoded(encoded) {
_prefix.toLowercase();
File f(filename, SearchMan);
loadIndex(&f);
loadIndex(f);
}
CCArchive::~CCArchive() {
@@ -371,33 +407,37 @@ 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);
}
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
View
@@ -213,13 +213,24 @@ class BaseCCArchive : public Common::Archive {
/**
* 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
@@ -274,15 +285,25 @@ class SaveArchive : public BaseCCArchive {
*/
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);
};
/**
@@ -104,7 +104,7 @@ int BaseLocation::show() {
party.addTime(_farewellTime);
result = 0;
} else {
_vm->_saves->saveChars();
//_vm->_saves->saveChars();
result = 2;
}
View
@@ -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);
}
View
@@ -62,12 +62,6 @@ class SavesManager {
SavesManager(const Common::String &targetName);
~SavesManager();
void readCharFile();
void writeCharFile();
void saveChars();
/**
* Read in a savegame header
*/
View
@@ -1425,7 +1425,7 @@ void Scripts::doWorldEnding() {
}
void Scripts::doEnding(const Common::String &endStr) {
_vm->_saves->saveChars();
//_vm->_saves->saveChars();
Party &party = *_vm->_party;

0 comments on commit 5314675

Please sign in to comment.