aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2017-12-22 08:52:31 -0500
committerPaul Gilbert2017-12-22 08:52:31 -0500
commit49de1602b0ddc87cbbf26181f83b3d41b253da65 (patch)
tree27b4841baea104863d41da7c17048e950d21312d /engines
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.
Diffstat (limited to 'engines')
-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);