aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2017-12-22 08:52:31 -0500
committerPaul Gilbert2017-12-22 08:52:31 -0500
commit49de1602b0ddc87cbbf26181f83b3d41b253da65 (patch)
tree27b4841baea104863d41da7c17048e950d21312d
parentc8c804ccd78cbf7cbfb8934ed1dda1e5bf2f44f2 (diff)
downloadscummvm-rg350-49de1602b0ddc87cbbf26181f83b3d41b253da65.tar.gz
scummvm-rg350-49de1602b0ddc87cbbf26181f83b3d41b253da65.tar.bz2
scummvm-rg350-49de1602b0ddc87cbbf26181f83b3d41b253da65.zip
XEEN: Create a separate current state saver for each side
Previously, I only had a single savefile, which maintains the state of the party and mazes. But I've realised that I'll need a separate archive for each side of Xeen. I'm still not entirely happy with the cleanliness of the new structure, but it at least is now functionally separating the sides.
-rw-r--r--engines/xeen/detection.cpp4
-rw-r--r--engines/xeen/files.cpp139
-rw-r--r--engines/xeen/files.h93
-rw-r--r--engines/xeen/items.h34
-rw-r--r--engines/xeen/map.cpp12
-rw-r--r--engines/xeen/party.cpp12
-rw-r--r--engines/xeen/party.h1
-rw-r--r--engines/xeen/saves.cpp247
-rw-r--r--engines/xeen/saves.h74
-rw-r--r--engines/xeen/spells.cpp2
-rw-r--r--engines/xeen/xeen.cpp124
-rw-r--r--engines/xeen/xeen.h22
12 files changed, 395 insertions, 369 deletions
diff --git a/engines/xeen/detection.cpp b/engines/xeen/detection.cpp
index 0866d5f107..df3df4ffa7 100644
--- a/engines/xeen/detection.cpp
+++ b/engines/xeen/detection.cpp
@@ -144,7 +144,7 @@ SaveStateList XeenMetaEngine::listSaves(const char *target) const {
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
if (in) {
- Xeen::XeenEngine::readSavegameHeader(in, header);
+ Xeen::SavesManager::readSavegameHeader(in, header);
saveList.push_back(SaveStateDescriptor(slot, header._saveName));
header._thumbnail->free();
@@ -172,7 +172,7 @@ SaveStateDescriptor XeenMetaEngine::querySaveMetaInfos(const char *target, int s
if (f) {
Xeen::XeenSavegameHeader header;
- Xeen::XeenEngine::readSavegameHeader(f, header);
+ Xeen::SavesManager::readSavegameHeader(f, header);
delete f;
// Create the return descriptor
diff --git a/engines/xeen/files.cpp b/engines/xeen/files.cpp
index b62a0d8cd5..d63c63d651 100644
--- a/engines/xeen/files.cpp
+++ b/engines/xeen/files.cpp
@@ -186,8 +186,6 @@ Common::SeekableReadStream *CCArchive::createReadStreamForMember(const Common::S
FileManager::FileManager(XeenEngine *vm) {
Common::File f;
- int sideNum = 0;
-
_isDarkCc = vm->getGameID() == GType_DarkSide;
File::_xeenCc = (vm->getGameID() == GType_DarkSide) ? nullptr :
@@ -220,9 +218,12 @@ void FileManager::setGameCc(int ccMode) {
/*------------------------------------------------------------------------*/
-CCArchive *File::_currentArchive;
CCArchive *File::_xeenCc;
CCArchive *File::_darkCc;
+SaveArchive *File::_xeenSave;
+SaveArchive *File::_darkSave;
+BaseCCArchive *File::_currentArchive;
+SaveArchive *File::_currentSave;
File::File(const Common::String &filename) {
File::open(filename);
@@ -237,7 +238,7 @@ File::File(const Common::String &filename, int ccMode) {
}
bool File::open(const Common::String &filename) {
- if (!g_vm->_saves || !Common::File::open(filename, *g_vm->_saves)) {
+ if (!_currentSave || !Common::File::open(filename, *_currentSave)) {
if (!Common::File::open(filename, *_currentArchive)) {
// Could not find in current archive, so try intro.cc or in folder
if (!Common::File::open(filename))
@@ -269,10 +270,12 @@ void File::setCurrentArchive(int ccMode) {
switch (ccMode) {
case 0:
_currentArchive = _xeenCc;
+ _currentSave = _xeenSave;
break;
case 1:
_currentArchive = _darkCc;
+ _currentSave = _darkSave;
break;
default:
@@ -293,7 +296,7 @@ Common::String File::readString() {
}
bool File::exists(const Common::String &filename) {
- if (!g_vm->_saves || !g_vm->_saves->hasFile(filename)) {
+ if (!_currentSave || !_currentSave->hasFile(filename)) {
if (!_currentArchive->hasFile(filename)) {
// Could not find in current archive, so try intro.cc or in folder
return Common::File::exists(filename);
@@ -314,6 +317,28 @@ bool File::exists(const Common::String &filename, int ccMode) {
return result;
}
+void File::syncBitFlags(Common::Serializer &s, bool *startP, bool *endP) {
+ byte data = 0;
+
+ int bitCounter = 0;
+ for (bool *p = startP; p <= endP; ++p, bitCounter = (bitCounter + 1) % 8) {
+ if (p == endP || bitCounter == 0) {
+ if (p != endP || s.isSaving())
+ s.syncAsByte(data);
+ if (p == endP)
+ break;
+
+ if (s.isSaving())
+ data = 0;
+ }
+
+ if (s.isLoading())
+ *p = (data >> bitCounter) != 0;
+ else if (*p)
+ data |= 1 << bitCounter;
+ }
+}
+
/*------------------------------------------------------------------------*/
void StringArray::load(const Common::String &name) {
@@ -330,4 +355,108 @@ void StringArray::load(const Common::String &name, int ccMode) {
push_back(f.readString());
}
+/*------------------------------------------------------------------------*/
+
+SaveArchive::SaveArchive(Party *party) : BaseCCArchive(), _party(party) {
+ _data = nullptr;
+}
+
+SaveArchive::~SaveArchive() {
+ for (Common::HashMap<uint16, Common::MemoryWriteStreamDynamic *>::iterator it = _newData.begin(); it != _newData.end(); it++) {
+ delete (*it)._value;
+ }
+ delete[] _data;
+}
+
+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);
+ 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)) {
+ // Open the correct CC entry
+ return new Common::MemoryReadStream(_data + ccEntry._offset, ccEntry._size);
+ }
+
+ return nullptr;
+}
+
+void SaveArchive::load(Common::SeekableReadStream *stream) {
+ loadIndex(stream);
+
+ delete[] _data;
+ _data = new byte[stream->size()];
+ stream->seek(0);
+ stream->read(_data, stream->size());
+
+ // Load in the character stats and active party
+ Common::SeekableReadStream *chr = createReadStreamForMember("maze.chr");
+ Common::Serializer sChr(chr, nullptr);
+ _party->_roster.synchronize(sChr);
+ delete chr;
+
+ Common::SeekableReadStream *pty = createReadStreamForMember("maze.pty");
+ Common::Serializer sPty(pty, nullptr);
+ _party->synchronize(sPty);
+ delete pty;
+}
+
+void SaveArchive::reset(CCArchive *src) {
+ Common::MemoryWriteStreamDynamic saveFile(DisposeAfterUse::YES);
+ File fIn;
+
+ g_vm->_files->setGameCc(g_vm->getGameID() == GType_DarkSide ? 1 : 0);
+ const int RESOURCES[6] = { 0x2A0C, 0x2A1C, 0x2A2C, 0x2A3C, 0x284C, 0x2A5C };
+ for (int i = 0; i < 6; ++i) {
+ Common::String filename = Common::String::format("%.4x", RESOURCES[i]);
+ if (src->hasFile(filename)) {
+ // Read in the next resource
+ fIn.open(filename, *src);
+ byte *data = new byte[fIn.size()];
+ fIn.read(data, fIn.size());
+
+ // Copy it to the combined savefile resource
+ saveFile.write(data, fIn.size());
+ delete[] data;
+ fIn.close();
+ }
+ }
+
+ assert(saveFile.size() > 0);
+ Common::MemoryReadStream f(saveFile.getData(), saveFile.size());
+ load(&f);
+}
+
+/*------------------------------------------------------------------------*/
+
+OutFile::OutFile(const Common::String filename) :
+ _filename(filename), _backingStream(DisposeAfterUse::YES) {
+ _archive = File::_currentSave;
+}
+
+uint32 OutFile::write(const void *dataPtr, uint32 dataSize) {
+ return _backingStream.write(dataPtr, dataSize);
+}
+
+int32 OutFile::pos() const {
+ return _backingStream.pos();
+}
+
+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());
+}
+
} // End of namespace Xeen
diff --git a/engines/xeen/files.h b/engines/xeen/files.h
index 1fcfa6a7b8..f18d23671a 100644
--- a/engines/xeen/files.h
+++ b/engines/xeen/files.h
@@ -26,6 +26,8 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/file.h"
+#include "common/memstream.h"
+#include "common/savefile.h"
#include "common/serializer.h"
#include "common/str-array.h"
#include "graphics/surface.h"
@@ -34,7 +36,12 @@ namespace Xeen {
class XeenEngine;
class CCArchive;
+class BaseCCArchive;
class File;
+class SaveArchive;
+class Party;
+class OutFile;
+class SavesManager;
#define SYNC_AS(SUFFIX,STREAM,TYPE,SIZE) \
template<typename T> \
@@ -50,6 +57,20 @@ class File;
_bytesSynced += SIZE; \
}
+/**
+ * Details of a single entry in a CC file index
+ */
+struct CCEntry {
+ uint16 _id;
+ uint32 _offset;
+ uint16 _size;
+
+ CCEntry() : _id(0), _offset(0), _size(0) {}
+ CCEntry(uint16 id, uint32 offset, uint32 size)
+ : _id(id), _offset(offset), _size(size) {
+ }
+};
+
/*
* Main resource manager
*/
@@ -79,15 +100,23 @@ public:
*/
class File : public Common::File {
friend class FileManager;
+ friend class OutFile;
+ friend class SavesManager;
private:
- static CCArchive *_currentArchive;
- static CCArchive *_xeenCc;
- static CCArchive *_darkCc;
+ static CCArchive *_xeenCc, *_darkCc;
+ static SaveArchive *_xeenSave, *_darkSave;
+ static BaseCCArchive *_currentArchive;
+ static SaveArchive *_currentSave;
public:
/**
* Sets which archive is used by default
*/
static void setCurrentArchive(int ccMode);
+
+ /**
+ * Synchronizes a boolean array as a bitfield set
+ */
+ static void syncBitFlags(Common::Serializer &s, bool *startP, bool *endP);
public:
File() : Common::File() {}
File(const Common::String &filename);
@@ -175,22 +204,8 @@ public:
};
/**
-* Details of a single entry in a CC file index
-*/
-struct CCEntry {
- uint16 _id;
- uint32 _offset;
- uint16 _size;
-
- CCEntry() : _id(0), _offset(0), _size(0) {}
- CCEntry(uint16 id, uint32 offset, uint32 size)
- : _id(id), _offset(offset), _size(size) {
- }
-};
-
-/**
-* Base Xeen CC file implementation
-*/
+ * Base Xeen CC file implementation
+ */
class BaseCCArchive : public Common::Archive {
protected:
Common::Array<CCEntry> _index;
@@ -220,8 +235,8 @@ public:
};
/**
-* Xeen CC file implementation
-*/
+ * Xeen CC file implementation
+ */
class CCArchive : public BaseCCArchive {
private:
Common::String _filename;
@@ -238,6 +253,42 @@ public:
virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
};
+class SaveArchive : public BaseCCArchive {
+ friend class OutFile;
+private:
+ Party *_party;
+ byte *_data;
+ Common::HashMap<uint16, Common::MemoryWriteStreamDynamic *> _newData;
+
+ void load(Common::SeekableReadStream *stream);
+public:
+ SaveArchive(Party *party);
+ ~SaveArchive();
+
+ /**
+ * Sets up the dynamic data for the game for a new game
+ */
+ void reset(CCArchive *src);
+
+ // Archive implementation
+ virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+};
+
+class OutFile : public Common::WriteStream {
+private:
+ SaveArchive *_archive;
+ Common::String _filename;
+ Common::MemoryWriteStreamDynamic _backingStream;
+public:
+ OutFile(const Common::String filename);
+
+ void finalize();
+
+ uint32 write(const void *dataPtr, uint32 dataSize) override;
+
+ int32 pos() const override;
+};
+
} // End of namespace Xeen
#endif /* XEEN_FILES_H */
diff --git a/engines/xeen/items.h b/engines/xeen/items.h
deleted file mode 100644
index bfbd9e4481..0000000000
--- a/engines/xeen/items.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef XEEN_ITEMS_H
-#define XEEN_ITEMS_H
-
-#include "xeen/character.h"
-
-namespace Xeen {
-
-
-
-} // End of namespace Xeen
-
-#endif /* XEEN_ITEMS_H */
diff --git a/engines/xeen/map.cpp b/engines/xeen/map.cpp
index 6777178d31..6a442be247 100644
--- a/engines/xeen/map.cpp
+++ b/engines/xeen/map.cpp
@@ -620,9 +620,9 @@ void MazeData::synchronize(Common::SeekableReadStream &s) {
Common::Serializer ser(&s, nullptr);
for (int y = 0; y < MAP_HEIGHT; ++y)
- SavesManager::syncBitFlags(ser, &_seenTiles[y][0], &_seenTiles[y][MAP_WIDTH]);
+ File::syncBitFlags(ser, &_seenTiles[y][0], &_seenTiles[y][MAP_WIDTH]);
for (int y = 0; y < MAP_HEIGHT; ++y)
- SavesManager::syncBitFlags(ser, &_steppedOnTiles[y][0], &_steppedOnTiles[y][MAP_WIDTH]);
+ File::syncBitFlags(ser, &_steppedOnTiles[y][0], &_steppedOnTiles[y][MAP_WIDTH]);
}
void MazeData::setAllTilesStepped() {
@@ -1115,7 +1115,7 @@ void Map::load(int mapId) {
mapId = party._mazeId;
Common::String filename = Common::String::format("maze%c%03d.mob",
(mapId >= 100) ? 'x' : '0', mapId);
- File mobFile(filename, *_vm->_saves);
+ File mobFile(filename);
XeenSerializer sMob(&mobFile, nullptr);
_mobData.synchronize(sMob, _monsterData);
mobFile.close();
@@ -1395,7 +1395,7 @@ void Map::loadEvents(int mapId) {
// Load events
Common::String filename = Common::String::format("maze%c%03d.evt",
(mapId >= 100) ? 'x' : '0', mapId);
- File fEvents(filename, *_vm->_saves);
+ File fEvents(filename);
XeenSerializer sEvents(&fEvents, nullptr);
_events.synchronize(sEvents);
fEvents.close();
@@ -1418,7 +1418,7 @@ void Map::saveMaze() {
// Save the event data
Common::String filename = Common::String::format("maze%c%03d.evt",
(mazeNum >= 100) ? 'x' : '0', mazeNum);
- OutFile fEvents(_vm, filename);
+ OutFile fEvents(filename);
XeenSerializer sEvents(nullptr, &fEvents);
_events.synchronize(sEvents);
fEvents.finalize();
@@ -1426,7 +1426,7 @@ void Map::saveMaze() {
// Save the maze MOB file
filename = Common::String::format("maze%c%03d.mob",
(mazeNum >= 100) ? 'x' : '0', mazeNum);
- OutFile fMob(_vm, filename);
+ OutFile fMob(filename);
XeenSerializer sMob(nullptr, &fEvents);
_mobData.synchronize(sMob, _monsterData);
fEvents.finalize();
diff --git a/engines/xeen/party.cpp b/engines/xeen/party.cpp
index abedaa46ed..0a2e5b9f82 100644
--- a/engines/xeen/party.cpp
+++ b/engines/xeen/party.cpp
@@ -206,11 +206,11 @@ void Party::synchronize(Common::Serializer &s) {
s.syncAsUint32LE(_bankGems);
s.syncAsUint32LE(_totalTime);
s.syncAsByte(_rested);
- SavesManager::syncBitFlags(s, &_gameFlags[0][0], &_gameFlags[0][256]);
- SavesManager::syncBitFlags(s, &_gameFlags[1][0], &_gameFlags[1][256]);
- SavesManager::syncBitFlags(s, &_worldFlags[0], &_worldFlags[128]);
- SavesManager::syncBitFlags(s, &_questFlags[0][0], &_questFlags[0][30]);
- SavesManager::syncBitFlags(s, &_questFlags[1][0], &_questFlags[1][30]);
+ File::syncBitFlags(s, &_gameFlags[0][0], &_gameFlags[0][256]);
+ File::syncBitFlags(s, &_gameFlags[1][0], &_gameFlags[1][256]);
+ File::syncBitFlags(s, &_worldFlags[0], &_worldFlags[128]);
+ File::syncBitFlags(s, &_questFlags[0][0], &_questFlags[0][30]);
+ File::syncBitFlags(s, &_questFlags[1][0], &_questFlags[1][30]);
for (int i = 0; i < 85; ++i)
s.syncAsByte(_questItems[i]);
@@ -225,7 +225,7 @@ void Party::synchronize(Common::Serializer &s) {
_blacksmithMisc[1][i].synchronize(s);
for (int i = 0; i < TOTAL_CHARACTERS; ++i)
- SavesManager::syncBitFlags(s, &_characterFlags[i][0], &_characterFlags[i][24]);
+ File::syncBitFlags(s, &_characterFlags[i][0], &_characterFlags[i][24]);
s.syncBytes(&dummy[0], 30);
}
diff --git a/engines/xeen/party.h b/engines/xeen/party.h
index f6df5ff83e..31feaec503 100644
--- a/engines/xeen/party.h
+++ b/engines/xeen/party.h
@@ -30,7 +30,6 @@
#include "xeen/character.h"
#include "xeen/combat.h"
#include "xeen/dialogs_error.h"
-#include "xeen/items.h"
namespace Xeen {
diff --git a/engines/xeen/saves.cpp b/engines/xeen/saves.cpp
index 5126642df1..504bb18dd7 100644
--- a/engines/xeen/saves.cpp
+++ b/engines/xeen/saves.cpp
@@ -23,155 +23,176 @@
#include "common/scummsys.h"
#include "common/algorithm.h"
#include "common/memstream.h"
+#include "graphics/scaler.h"
+#include "graphics/thumbnail.h"
#include "xeen/saves.h"
#include "xeen/files.h"
#include "xeen/xeen.h"
namespace Xeen {
-OutFile::OutFile(XeenEngine *vm, const Common::String filename) :
- _vm(vm),
- _filename(filename),
- _backingStream(DisposeAfterUse::YES) {
-}
+SavesManager::SavesManager(const Common::String &targetName): _targetName(targetName),
+ _wonWorld(false), _wonDarkSide(false) {
+ File::_xeenSave = nullptr;
+ File::_darkSave = nullptr;
-uint32 OutFile::write(const void *dataPtr, uint32 dataSize) {
- return _backingStream.write(dataPtr, dataSize);
-}
+ if (g_vm->getGameID() != GType_Clouds) {
+ File::_darkSave = new SaveArchive(g_vm->_party);
+ File::_darkSave->reset(File::_darkCc);
+ }
+ if (g_vm->getGameID() != GType_DarkSide) {
+ File::_xeenSave = new SaveArchive(g_vm->_party);
+ File::_xeenSave->reset(File::_xeenCc);
+ }
-int32 OutFile::pos() const {
- return _backingStream.pos();
-}
+ File::_currentSave = g_vm->getGameID() == GType_DarkSide ?
+ File::_darkSave : File::_xeenSave;
+ assert(File::_currentSave);
-void OutFile::finalize() {
- uint16 id = BaseCCArchive::convertNameToId(_filename);
+ // Set any final initial values
+ Party &party = *g_vm->_party;
+ party.resetBlacksmithWares();
+ party._year = g_vm->getGameID() == GType_WorldOfXeen ? 610 : 850;
+ party._totalTime = 0;
+}
- if (!_vm->_saves->_newData.contains(id))
- _vm->_saves->_newData[id] = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
+SavesManager::~SavesManager() {
+ delete File::_xeenSave;
+ delete File::_darkSave;
+}
- Common::MemoryWriteStreamDynamic *out = _vm->_saves->_newData[id];
- out->write(_backingStream.getData(), _backingStream.size());
+void SavesManager::readCharFile() {
+ warning("TODO: readCharFile");
}
-/*------------------------------------------------------------------------*/
+void SavesManager::writeCharFile() {
+ warning("TODO: writeCharFile");
+}
-SavesManager::SavesManager(XeenEngine *vm, Party &party) :
- BaseCCArchive(), _vm(vm), _party(party) {
- _data = nullptr;
- _wonWorld = false;
- _wonDarkSide = false;
+void SavesManager::saveChars() {
+ warning("TODO: saveChars");
}
-SavesManager::~SavesManager() {
- for (Common::HashMap<uint16, Common::MemoryWriteStreamDynamic *>::iterator it = _newData.begin(); it != _newData.end(); it++) {
- delete (*it)._value;
- }
- delete[] _data;
+const char *const SAVEGAME_STR = "XEEN";
+#define SAVEGAME_STR_SIZE 6
+
+bool SavesManager::readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header) {
+ char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
+ header._thumbnail = nullptr;
+
+ // Validate the header Id
+ in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
+ if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE))
+ return false;
+
+ header._version = in->readByte();
+ if (header._version > XEEN_SAVEGAME_VERSION)
+ return false;
+
+ // Read in the string
+ header._saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0')
+ header._saveName += ch;
+
+ // Get the thumbnail
+ header._thumbnail = Graphics::loadThumbnail(*in);
+ if (!header._thumbnail)
+ return false;
+
+ // Read in save date/time
+ header._year = in->readSint16LE();
+ header._month = in->readSint16LE();
+ header._day = in->readSint16LE();
+ header._hour = in->readSint16LE();
+ header._minute = in->readSint16LE();
+ header._totalFrames = in->readUint32LE();
+
+ return true;
}
-void SavesManager::syncBitFlags(Common::Serializer &s, bool *startP, bool *endP) {
- byte data = 0;
-
- int bitCounter = 0;
- for (bool *p = startP; p <= endP; ++p, bitCounter = (bitCounter + 1) % 8) {
- if (p == endP || bitCounter == 0) {
- if (p != endP || s.isSaving())
- s.syncAsByte(data);
- if (p == endP)
- break;
-
- if (s.isSaving())
- data = 0;
- }
-
- if (s.isLoading())
- *p = (data >> bitCounter) != 0;
- else if (*p)
- data |= 1 << bitCounter;
- }
+void SavesManager::writeSavegameHeader(Common::OutSaveFile *out, XeenSavegameHeader &header) {
+ // Write out a savegame header
+ out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1);
+
+ out->writeByte(XEEN_SAVEGAME_VERSION);
+
+ // Write savegame name
+ out->writeString(header._saveName);
+ out->writeByte('\0');
+
+ // Write a thumbnail of the screen
+ /*
+ uint8 thumbPalette[768];
+ _screen->getPalette(thumbPalette);
+ Graphics::Surface saveThumb;
+ ::createThumbnail(&saveThumb, (const byte *)_screen->getPixels(),
+ _screen->w, _screen->h, thumbPalette);
+ Graphics::saveThumbnail(*out, saveThumb);
+ saveThumb.free();
+ */
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+ // out->writeUint32LE(_events->getFrameCounter());
}
-Common::SeekableReadStream *SavesManager::createReadStreamForMember(const Common::String &name) const {
- CCEntry ccEntry;
+Common::Error SavesManager::saveGameState(int slot, const Common::String &desc) {
+ Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(
+ generateSaveName(slot));
+ if (!out)
+ return Common::kCreatingFileFailed;
- // If the given resource has already been perviously "written" to the
- // save manager, then return that new resource
- uint16 id = BaseCCArchive::convertNameToId(name);
- if (_newData.contains(id)) {
- Common::MemoryWriteStreamDynamic *stream = _newData[id];
- return new Common::MemoryReadStream(stream->getData(), stream->size());
- }
+ XeenSavegameHeader header;
+ header._saveName = desc;
+ writeSavegameHeader(out, header);
- // Retrieve the resource from the loaded savefile
- if (getHeaderEntry(name, ccEntry)) {
- // Open the correct CC entry
- return new Common::MemoryReadStream(_data + ccEntry._offset, ccEntry._size);
- }
+ Common::Serializer s(nullptr, out);
+ synchronize(s);
- return nullptr;
-}
+ out->finalize();
+ delete out;
-void SavesManager::load(Common::SeekableReadStream *stream) {
- loadIndex(stream);
+ return Common::kNoError;
+}
- delete[] _data;
- _data = new byte[stream->size()];
- stream->seek(0);
- stream->read(_data, stream->size());
+Common::Error SavesManager::loadGameState(int slot) {
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(
+ generateSaveName(slot));
+ if (!saveFile)
+ return Common::kReadingFailed;
- // Load in the character stats and active party
- Common::SeekableReadStream *chr = createReadStreamForMember("maze.chr");
- Common::Serializer sChr(chr, nullptr);
- _party._roster.synchronize(sChr);
- delete chr;
+ Common::Serializer s(saveFile, nullptr);
- Common::SeekableReadStream *pty = createReadStreamForMember("maze.pty");
- Common::Serializer sPty(pty, nullptr);
- _party.synchronize(sPty);
- delete pty;
-}
+ // Load the savaegame header
+ XeenSavegameHeader header;
+ if (!readSavegameHeader(saveFile, header))
+ error("Invalid savegame");
-void SavesManager::reset() {
- Common::MemoryWriteStreamDynamic saveFile(DisposeAfterUse::YES);
- File fIn;
-
- g_vm->_files->setGameCc(g_vm->getGameID() == GType_DarkSide ? 1 : 0);
- const int RESOURCES[6] = { 0x2A0C, 0x2A1C, 0x2A2C, 0x2A3C, 0x284C, 0x2A5C };
- for (int i = 0; i < 6; ++i) {
- Common::String filename = Common::String::format("%.4x", RESOURCES[i]);
- if (fIn.exists(filename)) {
- // Read in the next resource
- fIn.open(filename);
- byte *data = new byte[fIn.size()];
- fIn.read(data, fIn.size());
-
- // Copy it to the combined savefile resource
- saveFile.write(data, fIn.size());
- delete[] data;
- fIn.close();
- }
+ if (header._thumbnail) {
+ header._thumbnail->free();
+ delete header._thumbnail;
}
- assert(saveFile.size() > 0);
- Common::MemoryReadStream f(saveFile.getData(), saveFile.size());
- load(&f);
+ // Load most of the savegame data
+ synchronize(s);
+ delete saveFile;
- // Set any final initial values
- _party.resetBlacksmithWares();
- _party._year = _vm->getGameID() == GType_WorldOfXeen ? 610 : 850;
- _party._totalTime = 0;
+ return Common::kNoError;
}
-void SavesManager::readCharFile() {
- warning("TODO: readCharFile");
+Common::String SavesManager::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
}
-void SavesManager::writeCharFile() {
- warning("TODO: writeCharFile");
+void SavesManager::synchronize(Common::Serializer &s) {
+ // TODO
}
-void SavesManager::saveChars() {
- warning("TODO: saveChars");
-}
} // End of namespace Xeen
diff --git a/engines/xeen/saves.h b/engines/xeen/saves.h
index 9c161c838c..2711cc7f2c 100644
--- a/engines/xeen/saves.h
+++ b/engines/xeen/saves.h
@@ -24,11 +24,11 @@
#define XEEN_SAVES_H
#include "common/scummsys.h"
-#include "common/memstream.h"
#include "common/savefile.h"
+#include "common/serializer.h"
+#include "common/str.h"
#include "graphics/surface.h"
#include "xeen/party.h"
-#include "xeen/files.h"
namespace Xeen {
@@ -41,59 +41,57 @@ struct XeenSavegameHeader {
int _totalFrames;
};
-class XeenEngine;
-class SavesManager;
-
-class OutFile : public Common::WriteStream {
+class SavesManager {
private:
- XeenEngine *_vm;
- Common::String _filename;
- Common::MemoryWriteStreamDynamic _backingStream;
-public:
- OutFile(XeenEngine *vm, const Common::String filename);
-
- void finalize();
-
- uint32 write(const void *dataPtr, uint32 dataSize) override;
-
- int32 pos() const override;
-};
-
-class SavesManager: public BaseCCArchive {
- friend class OutFile;
+ Common::String _targetName;
private:
- XeenEngine *_vm;
- Party &_party;
- byte *_data;
- Common::HashMap<uint16, Common::MemoryWriteStreamDynamic *> _newData;
+ /**
+ * Synchronize savegame data
+ */
+ void synchronize(Common::Serializer &s);
- void load(Common::SeekableReadStream *stream);
-public:
/**
- * Synchronizes a boolean array as a bitfield set
+ * Support method that generates a savegame name
+ * @param slot Slot number
*/
- static void syncBitFlags(Common::Serializer &s, bool *startP, bool *endP);
+ Common::String generateSaveName(int slot);
+
+ /**
+ * Initializes a new savegame
+ */
+ void reset();
public:
bool _wonWorld;
bool _wonDarkSide;
public:
- SavesManager(XeenEngine *vm, Party &party);
-
+ SavesManager(const Common::String &targetName);
~SavesManager();
- /**
- * Sets up the dynamic data for the game for a new game
- */
- void reset();
-
void readCharFile();
void writeCharFile();
void saveChars();
- // Archive implementation
- virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+ /**
+ * Read in a savegame header
+ */
+ static bool readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header);
+
+ /**
+ * Write out a savegame header
+ */
+ void writeSavegameHeader(Common::OutSaveFile *out, XeenSavegameHeader &header);
+
+ /**
+ * Load a savegame
+ */
+ Common::Error loadGameState(int slot);
+
+ /**
+ * Save the game
+ */
+ Common::Error saveGameState(int slot, const Common::String &desc);
};
} // End of namespace Xeen
diff --git a/engines/xeen/spells.cpp b/engines/xeen/spells.cpp
index 255e5ceb55..53303c384b 100644
--- a/engines/xeen/spells.cpp
+++ b/engines/xeen/spells.cpp
@@ -36,7 +36,7 @@ Spells::Spells(XeenEngine *vm) : _vm(vm) {
}
void Spells::load() {
- File f1("spells.xen");
+ File f1("spells.xen", 1);
while (f1.pos() < f1.size())
_spellNames.push_back(f1.readString());
f1.close();
diff --git a/engines/xeen/xeen.cpp b/engines/xeen/xeen.cpp
index 39e5f4b7b5..9a0e42e44c 100644
--- a/engines/xeen/xeen.cpp
+++ b/engines/xeen/xeen.cpp
@@ -25,8 +25,6 @@
#include "common/debug-channels.h"
#include "common/events.h"
#include "engines/util.h"
-#include "graphics/scaler.h"
-#include "graphics/thumbnail.h"
#include "xeen/xeen.h"
#include "xeen/files.h"
#include "xeen/resources.h"
@@ -99,14 +97,14 @@ void XeenEngine::initialize() {
_locations = new LocationManager();
_map = new Map(this);
_party = new Party(this);
- _saves = new SavesManager(this, *_party);
+ _saves = new SavesManager(_targetName);
_screen = new Screen(this);
_scripts = new Scripts(this);
_sound = new Sound(this, _mixer);
_spells = new Spells(this);
_windows = new Windows();
- File f("029.obj");
+ File f("029.obj", 1);
_eventData = f.readStream(f.size());
// Set graphics mode
@@ -137,51 +135,11 @@ int XeenEngine::getRandomNumber(int minNumber, int maxNumber) {
}
Common::Error XeenEngine::saveGameState(int slot, const Common::String &desc) {
- Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(
- generateSaveName(slot));
- if (!out)
- return Common::kCreatingFileFailed;
-
- XeenSavegameHeader header;
- header._saveName = desc;
- writeSavegameHeader(out, header);
-
- Common::Serializer s(nullptr, out);
- synchronize(s);
-
- out->finalize();
- delete out;
-
- return Common::kNoError;
+ return _saves->saveGameState(slot, desc);
}
Common::Error XeenEngine::loadGameState(int slot) {
- Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(
- generateSaveName(slot));
- if (!saveFile)
- return Common::kReadingFailed;
-
- Common::Serializer s(saveFile, nullptr);
-
- // Load the savaegame header
- XeenSavegameHeader header;
- if (!readSavegameHeader(saveFile, header))
- error("Invalid savegame");
-
- if (header._thumbnail) {
- header._thumbnail->free();
- delete header._thumbnail;
- }
-
- // Load most of the savegame data
- synchronize(s);
- delete saveFile;
-
- return Common::kNoError;
-}
-
-Common::String XeenEngine::generateSaveName(int slot) {
- return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+ return _saves->loadGameState(slot);
}
bool XeenEngine::canLoadGameStateCurrently() {
@@ -192,81 +150,7 @@ bool XeenEngine::canSaveGameStateCurrently() {
return true;
}
-void XeenEngine::synchronize(Common::Serializer &s) {
- // TODO
-}
-
-const char *const SAVEGAME_STR = "XEEN";
-#define SAVEGAME_STR_SIZE 6
-
-bool XeenEngine::readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header) {
- char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
- header._thumbnail = nullptr;
-
- // Validate the header Id
- in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
- if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE))
- return false;
-
- header._version = in->readByte();
- if (header._version > XEEN_SAVEGAME_VERSION)
- return false;
-
- // Read in the string
- header._saveName.clear();
- char ch;
- while ((ch = (char)in->readByte()) != '\0')
- header._saveName += ch;
-
- // Get the thumbnail
- header._thumbnail = Graphics::loadThumbnail(*in);
- if (!header._thumbnail)
- return false;
-
- // Read in save date/time
- header._year = in->readSint16LE();
- header._month = in->readSint16LE();
- header._day = in->readSint16LE();
- header._hour = in->readSint16LE();
- header._minute = in->readSint16LE();
- header._totalFrames = in->readUint32LE();
-
- return true;
-}
-
-void XeenEngine::writeSavegameHeader(Common::OutSaveFile *out, XeenSavegameHeader &header) {
- // Write out a savegame header
- out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1);
-
- out->writeByte(XEEN_SAVEGAME_VERSION);
-
- // Write savegame name
- out->writeString(header._saveName);
- out->writeByte('\0');
-
- // Write a thumbnail of the screen
-/*
- uint8 thumbPalette[768];
- _screen->getPalette(thumbPalette);
- Graphics::Surface saveThumb;
- ::createThumbnail(&saveThumb, (const byte *)_screen->getPixels(),
- _screen->w, _screen->h, thumbPalette);
- Graphics::saveThumbnail(*out, saveThumb);
- saveThumb.free();
-*/
- // Write out the save date/time
- TimeDate td;
- g_system->getTimeAndDate(td);
- out->writeSint16LE(td.tm_year + 1900);
- out->writeSint16LE(td.tm_mon + 1);
- out->writeSint16LE(td.tm_mday);
- out->writeSint16LE(td.tm_hour);
- out->writeSint16LE(td.tm_min);
-// out->writeUint32LE(_events->getFrameCounter());
-}
-
void XeenEngine::playGame() {
- _saves->reset();
_files->setGameCc(0);
_sound->stopAllAudio();
diff --git a/engines/xeen/xeen.h b/engines/xeen/xeen.h
index 022ad6673a..afbec4a7f9 100644
--- a/engines/xeen/xeen.h
+++ b/engines/xeen/xeen.h
@@ -27,7 +27,6 @@
#include "common/system.h"
#include "common/error.h"
#include "common/random.h"
-#include "common/savefile.h"
#include "common/serializer.h"
#include "common/util.h"
#include "engines/engine.h"
@@ -124,17 +123,6 @@ protected:
private:
void initialize();
- /**
- * Synchronize savegame data
- */
- void synchronize(Common::Serializer &s);
-
- /**
- * Support method that generates a savegame name
- * @param slot Slot number
- */
- Common::String generateSaveName(int slot);
-
// Engine APIs
virtual Common::Error run();
virtual bool hasFeature(EngineFeature f) const;
@@ -196,16 +184,6 @@ public:
*/
bool canSaveGameStateCurrently();
- /**
- * Read in a savegame header
- */
- static bool readSavegameHeader(Common::InSaveFile *in, XeenSavegameHeader &header);
-
- /**
- * Write out a savegame header
- */
- void writeSavegameHeader(Common::OutSaveFile *out, XeenSavegameHeader &header);
-
static Common::String printMil(uint value);
static Common::String printK(uint value);