Initial commit
This commit is contained in:
443
engines/gob/save/saveconverter.cpp
Normal file
443
engines/gob/save/saveconverter.cpp
Normal file
@@ -0,0 +1,443 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "gob/gob.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/save/savefile.h"
|
||||
#include "gob/save/savehandler.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveConverter::SaveConverter(GobEngine *vm, const Common::String &fileName)
|
||||
: _vm(vm), _fileName(fileName) {
|
||||
|
||||
_data = nullptr;
|
||||
_stream = nullptr;
|
||||
}
|
||||
|
||||
SaveConverter::~SaveConverter() {
|
||||
delete _stream;
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
void SaveConverter::clear() {
|
||||
delete[] _data;
|
||||
delete _stream;
|
||||
|
||||
_data = nullptr;
|
||||
_stream = nullptr;
|
||||
}
|
||||
|
||||
void SaveConverter::setFileName(const Common::String &fileName) {
|
||||
clear();
|
||||
_fileName = fileName;
|
||||
}
|
||||
|
||||
Common::InSaveFile *SaveConverter::openSave() const {
|
||||
if (_fileName.empty())
|
||||
return nullptr;
|
||||
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
return saveMan->openForLoading(_fileName);
|
||||
}
|
||||
|
||||
void SaveConverter::displayWarning() const {
|
||||
warning("Old save format detected, trying to convert. If this does not work, your "
|
||||
"save is broken and can't be used anymore. Sorry for the inconvenience");
|
||||
}
|
||||
|
||||
char *SaveConverter::getDescription(const Common::String &fileName) {
|
||||
setFileName(fileName);
|
||||
return getDescription();
|
||||
}
|
||||
|
||||
char *SaveConverter::getDescription() const {
|
||||
Common::InSaveFile *save;
|
||||
|
||||
// Test if it's an old savd
|
||||
if (!isOldSave(&save) || !save)
|
||||
return nullptr;
|
||||
|
||||
char *desc = getDescription(*save);
|
||||
|
||||
delete save;
|
||||
return desc;
|
||||
}
|
||||
|
||||
uint32 SaveConverter::getActualSize(Common::InSaveFile **save) const {
|
||||
Common::InSaveFile *saveFile = openSave();
|
||||
|
||||
if (!saveFile)
|
||||
return false;
|
||||
|
||||
// Is it a valid new save?
|
||||
if (SaveContainer::isSave(*saveFile)) {
|
||||
delete saveFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 saveSize = saveFile->size();
|
||||
|
||||
if (saveSize <= 0) {
|
||||
delete saveFile;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (save)
|
||||
*save = saveFile;
|
||||
else
|
||||
delete saveFile;
|
||||
|
||||
return saveSize;
|
||||
}
|
||||
|
||||
bool SaveConverter::swapDataEndian(byte *data, const byte *sizes, uint32 count) {
|
||||
if (!data || !sizes || (count == 0))
|
||||
return false;
|
||||
|
||||
while (count-- > 0) {
|
||||
if (*sizes == 3) // 32bit value (3 additional bytes)
|
||||
WRITE_UINT32(data, SWAP_BYTES_32(READ_UINT32(data)));
|
||||
else if (*sizes == 1) // 16bit value (1 additional byte)
|
||||
WRITE_UINT16(data, SWAP_BYTES_16(READ_UINT16(data)));
|
||||
else if (*sizes != 0) // else, it has to be an 8bit value
|
||||
return false;
|
||||
|
||||
count -= *sizes;
|
||||
data += *sizes + 1;
|
||||
sizes += *sizes + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SavePartInfo *SaveConverter::readInfo(Common::SeekableReadStream &stream,
|
||||
uint32 descLength, bool hasSizes) const {
|
||||
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return nullptr;
|
||||
|
||||
char *desc = getDescription(stream);
|
||||
if (!desc)
|
||||
return nullptr;
|
||||
|
||||
// If it has sizes, skip them
|
||||
if (hasSizes)
|
||||
if (!stream.skip(descLength)) {
|
||||
delete[] desc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SavePartInfo *info = new SavePartInfo(descLength, (uint32) _vm->getGameType(),
|
||||
0, _vm->getEndianness(), varSize);
|
||||
|
||||
info->setDesc(desc);
|
||||
|
||||
delete[] desc;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
byte *SaveConverter::readData(Common::SeekableReadStream &stream,
|
||||
uint32 count, bool endian) const {
|
||||
|
||||
byte *data = new byte[count];
|
||||
|
||||
// Read variable data
|
||||
if (stream.read(data, count) != count) {
|
||||
delete[] data;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Check the endianness. The old save data was always written
|
||||
* as little endian, so we might need to swap the bytes. */
|
||||
|
||||
if (endian && (_vm->getEndianness() == kEndiannessBE)) {
|
||||
// Big endian => swapping needed
|
||||
|
||||
// Read variable sizes
|
||||
byte *sizes = new byte[count];
|
||||
if (stream.read(sizes, count) != count) {
|
||||
delete[] data;
|
||||
delete[] sizes;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Swap bytes
|
||||
if (!swapDataEndian(data, sizes, count)) {
|
||||
delete[] data;
|
||||
delete[] sizes;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
delete[] sizes;
|
||||
|
||||
} else {
|
||||
// Little endian => just skip the sizes part
|
||||
|
||||
if (!stream.skip(count)) {
|
||||
delete[] data;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
SavePartVars *SaveConverter::readVars(Common::SeekableReadStream &stream,
|
||||
uint32 count, bool endian) const {
|
||||
|
||||
byte *data = readData(stream, count, endian);
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
SavePartVars *vars = new SavePartVars(_vm, count);
|
||||
|
||||
// Read variables into part
|
||||
if (!vars->readFromRaw(data, 0, count)) {
|
||||
delete[] data;
|
||||
delete vars;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
return vars;
|
||||
}
|
||||
|
||||
SavePartMem *SaveConverter::readMem(Common::SeekableReadStream &stream,
|
||||
uint32 count, bool endian) const {
|
||||
|
||||
byte *data = readData(stream, count, endian);
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
SavePartMem *mem = new SavePartMem(count);
|
||||
|
||||
// Read mem into part
|
||||
if (!mem->readFrom(data, 0, count)) {
|
||||
delete[] data;
|
||||
delete mem;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
return mem;
|
||||
}
|
||||
|
||||
SavePartSprite *SaveConverter::readSprite(Common::SeekableReadStream &stream,
|
||||
uint32 width, uint32 height, bool palette) const {
|
||||
|
||||
assert((width > 0) && (height > 0));
|
||||
|
||||
uint32 spriteSize = width * height;
|
||||
|
||||
byte pal[768];
|
||||
if (palette)
|
||||
if (stream.read(pal, 768) != 768)
|
||||
return nullptr;
|
||||
|
||||
byte *data = new byte[spriteSize];
|
||||
|
||||
// Read variable data
|
||||
if (stream.read(data, spriteSize) != spriteSize) {
|
||||
delete[] data;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SavePartSprite *sprite = new SavePartSprite(width, height);
|
||||
|
||||
if (!sprite->readSpriteRaw(data, spriteSize)) {
|
||||
delete[] data;
|
||||
delete sprite;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
|
||||
if (palette)
|
||||
if (!sprite->readPalette(pal)) {
|
||||
delete sprite;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sprite;
|
||||
}
|
||||
|
||||
bool SaveConverter::createStream(SaveWriter &writer) {
|
||||
// Allocate memory for the internal new save data
|
||||
uint32 contSize = writer.getSize();
|
||||
_data = new byte[contSize];
|
||||
|
||||
// Save the newly created new save data
|
||||
Common::MemoryWriteStream writeStream(_data, contSize);
|
||||
if (!writer.save(writeStream))
|
||||
return false;
|
||||
|
||||
// Create a reading stream upon that new save data
|
||||
_stream = new Common::MemoryReadStream(_data, contSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Stream functions. If the new save data stream is available, redirect the stream
|
||||
* operations to that stream. Normal stream error behavior if not. */
|
||||
|
||||
bool SaveConverter::err() const {
|
||||
if (!_data || !_stream)
|
||||
return true;
|
||||
|
||||
return _stream->err();
|
||||
}
|
||||
|
||||
void SaveConverter::clearErr() {
|
||||
if (!_data || !_stream)
|
||||
return;
|
||||
|
||||
_stream->clearErr();
|
||||
}
|
||||
|
||||
bool SaveConverter::eos() const {
|
||||
if (!_data || !_stream)
|
||||
return true;
|
||||
|
||||
return _stream->eos();
|
||||
}
|
||||
|
||||
uint32 SaveConverter::read(void *dataPtr, uint32 dataSize) {
|
||||
if (!_data || !_stream)
|
||||
return 0;
|
||||
|
||||
return _stream->read(dataPtr, dataSize);
|
||||
}
|
||||
|
||||
int64 SaveConverter::pos() const {
|
||||
if (!_data || !_stream)
|
||||
return -1;
|
||||
|
||||
return _stream->pos();
|
||||
}
|
||||
|
||||
int64 SaveConverter::size() const {
|
||||
if (!_data || !_stream)
|
||||
return -1;
|
||||
|
||||
return _stream->size();
|
||||
}
|
||||
|
||||
bool SaveConverter::seek(int64 offset, int whence) {
|
||||
if (!_data || !_stream)
|
||||
return false;
|
||||
|
||||
return _stream->seek(offset, whence);
|
||||
}
|
||||
|
||||
|
||||
SaveConverter_Notes::SaveConverter_Notes(GobEngine *vm, uint32 notesSize,
|
||||
const Common::String &fileName) : SaveConverter(vm, fileName) {
|
||||
|
||||
_size = notesSize;
|
||||
}
|
||||
|
||||
SaveConverter_Notes::~SaveConverter_Notes() {
|
||||
}
|
||||
|
||||
int SaveConverter_Notes::isOldSave(Common::InSaveFile **save) const {
|
||||
if (_size == 0)
|
||||
return 0;
|
||||
|
||||
uint32 saveSize = getActualSize(save);
|
||||
if (saveSize == 0)
|
||||
return 0;
|
||||
|
||||
// The size of the old save always follows that rule
|
||||
if (saveSize == (_size * 2))
|
||||
return 1;
|
||||
|
||||
// Not an old save, clean up
|
||||
if (save) {
|
||||
delete *save;
|
||||
*save = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *SaveConverter_Notes::getDescription(Common::SeekableReadStream &save) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SaveConverter_Notes::loadFail(SavePartVars *vars, Common::InSaveFile *save) {
|
||||
delete vars;
|
||||
delete save;
|
||||
|
||||
clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loads the old save by constructing a new save containing the old save's data
|
||||
bool SaveConverter_Notes::load() {
|
||||
if (_size == 0)
|
||||
return false;
|
||||
|
||||
Common::InSaveFile *save;
|
||||
|
||||
// Test if it's an old savd
|
||||
if (!isOldSave(&save) || !save)
|
||||
return false;
|
||||
|
||||
displayWarning();
|
||||
|
||||
SaveWriter writer(1, 0);
|
||||
|
||||
SavePartVars *vars = readVars(*save, _size, false);
|
||||
if (!vars)
|
||||
return loadFail(nullptr, save);
|
||||
|
||||
// We don't need the save anymore
|
||||
delete save;
|
||||
|
||||
// Write all parts
|
||||
if (!writer.writePart(0, vars))
|
||||
return loadFail(nullptr, nullptr);
|
||||
|
||||
// We don't need this anymore
|
||||
delete vars;
|
||||
|
||||
// Create the final read stream
|
||||
if (!createStream(writer))
|
||||
return loadFail(nullptr, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
189
engines/gob/save/saveconverter.h
Normal file
189
engines/gob/save/saveconverter.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GOB_SAVE_SAVECONVERTER_H
|
||||
#define GOB_SAVE_SAVECONVERTER_H
|
||||
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
class GobEngine;
|
||||
class SavePartInfo;
|
||||
class SavePartVars;
|
||||
class SavePartMem;
|
||||
class SavePartSprite;
|
||||
class SaveWriter;
|
||||
|
||||
/** A wrapping stream class for old saves. */
|
||||
class SaveConverter : public Common::SeekableReadStream {
|
||||
public:
|
||||
SaveConverter(GobEngine *vm, const Common::String &fileName);
|
||||
~SaveConverter() override;
|
||||
|
||||
/** Clear the converter. */
|
||||
virtual void clear();
|
||||
/** Set the filename on which to operate. */
|
||||
virtual void setFileName(const Common::String &fileName);
|
||||
|
||||
/** Is it actually an old save? */
|
||||
virtual int isOldSave(Common::InSaveFile **save = 0) const = 0;
|
||||
/** Directly return the description without processing the whole save. */
|
||||
virtual char *getDescription(Common::SeekableReadStream &save) const = 0;
|
||||
/** Load the whole save. */
|
||||
virtual bool load() = 0;
|
||||
|
||||
/** Set the name and return the description. */
|
||||
char *getDescription(const Common::String &fileName);
|
||||
/** Get the current fileName's description. */
|
||||
char *getDescription() const;
|
||||
|
||||
// Stream
|
||||
bool err() const override;
|
||||
void clearErr() override;
|
||||
// ReadStream
|
||||
bool eos() const override;
|
||||
uint32 read(void *dataPtr, uint32 dataSize) override;
|
||||
// SeekableReadStream
|
||||
int64 pos() const override;
|
||||
int64 size() const override;
|
||||
bool seek(int64 offset, int whence = SEEK_SET) override;
|
||||
|
||||
protected:
|
||||
GobEngine *_vm;
|
||||
|
||||
Common::String _fileName;
|
||||
|
||||
byte *_data;
|
||||
Common::SeekableReadStream *_stream;
|
||||
|
||||
Common::InSaveFile *openSave() const;
|
||||
|
||||
/** Write a warning to stdout to notify the user what's going on. */
|
||||
virtual void displayWarning() const;
|
||||
|
||||
virtual uint32 getActualSize(Common::InSaveFile **save = 0) const;
|
||||
|
||||
SavePartInfo *readInfo(Common::SeekableReadStream &stream,
|
||||
uint32 descLength, bool hasSizes = true) const;
|
||||
SavePartVars *readVars(Common::SeekableReadStream &stream,
|
||||
uint32 count, bool endian) const;
|
||||
SavePartMem *readMem(Common::SeekableReadStream &stream,
|
||||
uint32 count, bool endian) const;
|
||||
SavePartSprite *readSprite(Common::SeekableReadStream &stream,
|
||||
uint32 width, uint32 height, bool palette) const;
|
||||
|
||||
bool createStream(SaveWriter &writer);
|
||||
|
||||
/** Swap the endianness of the complete data area. */
|
||||
static bool swapDataEndian(byte *data, const byte *sizes, uint32 count);
|
||||
|
||||
private:
|
||||
byte *readData(Common::SeekableReadStream &stream,
|
||||
uint32 count, bool endian) const;
|
||||
};
|
||||
|
||||
/** A wrapper for old notes saves. */
|
||||
class SaveConverter_Notes : public SaveConverter {
|
||||
public:
|
||||
SaveConverter_Notes(GobEngine *vm, uint32 notesSize, const Common::String &fileName = "");
|
||||
~SaveConverter_Notes() override;
|
||||
|
||||
int isOldSave(Common::InSaveFile **save = 0) const override;
|
||||
char *getDescription(Common::SeekableReadStream &save) const override;
|
||||
|
||||
bool load() override;
|
||||
|
||||
private:
|
||||
uint32 _size;
|
||||
|
||||
bool loadFail(SavePartVars *vars, Common::InSaveFile *save);
|
||||
};
|
||||
|
||||
/** A wrapper for old v2-style saves (Gobliins 2, Ween: The Prophecy and Bargon Attack). */
|
||||
class SaveConverter_v2 : public SaveConverter {
|
||||
public:
|
||||
SaveConverter_v2(GobEngine *vm, const Common::String &fileName = "");
|
||||
~SaveConverter_v2() override;
|
||||
|
||||
int isOldSave(Common::InSaveFile **save = 0) const override;
|
||||
char *getDescription(Common::SeekableReadStream &save) const override;
|
||||
|
||||
bool load() override;
|
||||
|
||||
private:
|
||||
static const uint32 kSlotCount = 15;
|
||||
static const uint32 kSlotNameLength = 40;
|
||||
|
||||
bool loadFail(SavePartInfo *info, SavePartVars *vars,
|
||||
Common::InSaveFile *save);
|
||||
};
|
||||
|
||||
/** A wrapper for old v3-style saves (Goblins 3 and Lost in Time). */
|
||||
class SaveConverter_v3 : public SaveConverter {
|
||||
public:
|
||||
SaveConverter_v3(GobEngine *vm, const Common::String &fileName = "");
|
||||
~SaveConverter_v3() override;
|
||||
|
||||
int isOldSave(Common::InSaveFile **save = 0) const override;
|
||||
char *getDescription(Common::SeekableReadStream &save) const override;
|
||||
|
||||
bool load() override;
|
||||
|
||||
private:
|
||||
static const uint32 kSlotCount = 30;
|
||||
static const uint32 kSlotNameLength = 40;
|
||||
|
||||
bool loadFail(SavePartInfo *info, SavePartVars *vars,
|
||||
SavePartSprite *sprite, Common::InSaveFile *save);
|
||||
|
||||
void getScreenShotProps(int type,
|
||||
bool &used, uint32 &width, uint32 &height);
|
||||
};
|
||||
|
||||
/** A wrapper for old v4-style saves (Woodruff). */
|
||||
class SaveConverter_v4 : public SaveConverter {
|
||||
public:
|
||||
SaveConverter_v4(GobEngine *vm, const Common::String &fileName = "");
|
||||
~SaveConverter_v4() override;
|
||||
|
||||
int isOldSave(Common::InSaveFile **save = 0) const override;
|
||||
char *getDescription(Common::SeekableReadStream &save) const override;
|
||||
|
||||
bool load() override;
|
||||
|
||||
private:
|
||||
static const uint32 kSlotCount = 60;
|
||||
static const uint32 kSlotNameLength = 40;
|
||||
|
||||
bool loadFail(SavePartInfo *info, SavePartVars *vars,
|
||||
SavePartMem *props, Common::InSaveFile *save);
|
||||
};
|
||||
|
||||
} // End of namespace Gob
|
||||
|
||||
#endif // GOB_SAVE_SAVECONVERTER_H
|
||||
137
engines/gob/save/saveconverter_v2.cpp
Normal file
137
engines/gob/save/saveconverter_v2.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "gob/gob.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/save/savefile.h"
|
||||
#include "gob/save/savehandler.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveConverter_v2::SaveConverter_v2(GobEngine *vm, const Common::String &fileName) :
|
||||
SaveConverter(vm, fileName) {
|
||||
}
|
||||
|
||||
SaveConverter_v2::~SaveConverter_v2() {
|
||||
}
|
||||
|
||||
int SaveConverter_v2::isOldSave(Common::InSaveFile **save) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return 0;
|
||||
|
||||
uint32 saveSize = getActualSize(save);
|
||||
if (saveSize == 0)
|
||||
return 0;
|
||||
|
||||
// The size of the old save always follows that rule
|
||||
if (saveSize == (varSize * 2 + kSlotNameLength * 2))
|
||||
return 1;
|
||||
|
||||
// Not an old save, clean up
|
||||
if (save) {
|
||||
delete *save;
|
||||
*save = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *SaveConverter_v2::getDescription(Common::SeekableReadStream &save) const {
|
||||
char *desc = new char[kSlotNameLength];
|
||||
|
||||
// Read the description
|
||||
if (save.read(desc, kSlotNameLength) != kSlotNameLength) {
|
||||
delete[] desc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
bool SaveConverter_v2::loadFail(SavePartInfo *info, SavePartVars *vars,
|
||||
Common::InSaveFile *save) {
|
||||
|
||||
delete info;
|
||||
delete vars;
|
||||
delete save;
|
||||
|
||||
clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loads the old save by constructing a new save containing the old save's data
|
||||
bool SaveConverter_v2::load() {
|
||||
clear();
|
||||
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
Common::InSaveFile *save;
|
||||
|
||||
// Test if it's an old savd
|
||||
if (!isOldSave(&save) || !save)
|
||||
return false;
|
||||
|
||||
displayWarning();
|
||||
|
||||
SaveWriter writer(2, 0);
|
||||
|
||||
SavePartInfo *info = readInfo(*save, kSlotNameLength);
|
||||
if (!info)
|
||||
return loadFail(nullptr, nullptr, save);
|
||||
|
||||
SavePartVars *vars = readVars(*save, varSize, true);
|
||||
if (!vars)
|
||||
return loadFail(info, nullptr, save);
|
||||
|
||||
// We don't need the save anymore
|
||||
delete save;
|
||||
|
||||
// Write all parts
|
||||
if (!writer.writePart(0, info))
|
||||
return loadFail(info, vars, nullptr);
|
||||
if (!writer.writePart(1, vars))
|
||||
return loadFail(info, vars, nullptr);
|
||||
|
||||
// We don't need those anymore
|
||||
delete info;
|
||||
delete vars;
|
||||
|
||||
// Create the final read stream
|
||||
if (!createStream(writer))
|
||||
return loadFail(nullptr, nullptr, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
190
engines/gob/save/saveconverter_v3.cpp
Normal file
190
engines/gob/save/saveconverter_v3.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "gob/gob.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/save/savefile.h"
|
||||
#include "gob/save/savehandler.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveConverter_v3::SaveConverter_v3(GobEngine *vm, const Common::String &fileName) :
|
||||
SaveConverter(vm, fileName) {
|
||||
}
|
||||
|
||||
SaveConverter_v3::~SaveConverter_v3() {
|
||||
}
|
||||
|
||||
int SaveConverter_v3::isOldSave(Common::InSaveFile **save) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return 0;
|
||||
|
||||
uint32 saveSize = getActualSize(save);
|
||||
if (saveSize == 0)
|
||||
return 0;
|
||||
|
||||
// The size of the old save always follows one of these rules
|
||||
if (saveSize == (varSize * 2 + kSlotNameLength + 1000))
|
||||
return 1; // No screenshot
|
||||
if (saveSize == (varSize * 2 + kSlotNameLength + 1000 + 19968))
|
||||
return 2; // Big screenshot, Goblins 3
|
||||
if (saveSize == (varSize * 2 + kSlotNameLength + 1000 + 4768))
|
||||
return 3; // Small screenshot, Lost in Time
|
||||
|
||||
// Not an old save, clean up
|
||||
if (save) {
|
||||
delete *save;
|
||||
*save = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *SaveConverter_v3::getDescription(Common::SeekableReadStream &save) const {
|
||||
// The description starts at 1000
|
||||
if (!save.seek(1000))
|
||||
return nullptr;
|
||||
|
||||
char *desc = new char[kSlotNameLength];
|
||||
|
||||
// Read the description
|
||||
if (save.read(desc, kSlotNameLength) != kSlotNameLength) {
|
||||
delete[] desc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
bool SaveConverter_v3::loadFail(SavePartInfo *info, SavePartVars *vars,
|
||||
SavePartSprite *sprite, Common::InSaveFile *save) {
|
||||
|
||||
delete info;
|
||||
delete vars;
|
||||
delete sprite;
|
||||
delete save;
|
||||
|
||||
clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SaveConverter_v3::getScreenShotProps(int type,
|
||||
bool &used, uint32 &width, uint32 &height) {
|
||||
|
||||
switch (type) {
|
||||
case 2:
|
||||
used = true;
|
||||
width = 120;
|
||||
height = 160;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
used = true;
|
||||
width = 80;
|
||||
height = 50;
|
||||
break;
|
||||
|
||||
default:
|
||||
used = false;
|
||||
width = 0;
|
||||
height = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Loads the old save by constructing a new save containing the old save's data
|
||||
bool SaveConverter_v3::load() {
|
||||
clear();
|
||||
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
Common::InSaveFile *save;
|
||||
|
||||
int type = isOldSave(&save);
|
||||
|
||||
// Test if it's an old savd
|
||||
if ((type == 0) || !save)
|
||||
return false;
|
||||
|
||||
displayWarning();
|
||||
|
||||
bool screenShot;
|
||||
uint32 screenShotWidth;
|
||||
uint32 screenShotHeight;
|
||||
|
||||
getScreenShotProps(type, screenShot, screenShotWidth, screenShotHeight);
|
||||
|
||||
SaveWriter writer(screenShot ? 3 : 2, 0);
|
||||
|
||||
SavePartInfo *info = readInfo(*save, kSlotNameLength, false);
|
||||
if (!info)
|
||||
return loadFail(nullptr, nullptr, nullptr, save);
|
||||
|
||||
SavePartVars *vars = readVars(*save, varSize, true);
|
||||
if (!vars)
|
||||
return loadFail(info, nullptr, nullptr, save);
|
||||
|
||||
if (screenShot) {
|
||||
SavePartSprite *sprite = readSprite(*save, screenShotWidth, screenShotHeight, true);
|
||||
|
||||
if (!sprite)
|
||||
return loadFail(info, vars, nullptr, save);
|
||||
|
||||
if (!writer.writePart(2, sprite))
|
||||
return loadFail(info, vars, sprite, save);
|
||||
|
||||
delete sprite;
|
||||
}
|
||||
|
||||
// We don't need the save anymore
|
||||
delete save;
|
||||
|
||||
// Write all parts
|
||||
if (!writer.writePart(0, info))
|
||||
return loadFail(info, vars, nullptr, nullptr);
|
||||
if (!writer.writePart(1, vars))
|
||||
return loadFail(info, vars, nullptr, nullptr);
|
||||
|
||||
// We don't need those anymore
|
||||
delete info;
|
||||
delete vars;
|
||||
|
||||
// Create the final read stream
|
||||
if (!createStream(writer))
|
||||
return loadFail(nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
149
engines/gob/save/saveconverter_v4.cpp
Normal file
149
engines/gob/save/saveconverter_v4.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "gob/gob.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/save/savefile.h"
|
||||
#include "gob/save/savehandler.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveConverter_v4::SaveConverter_v4(GobEngine *vm, const Common::String &fileName) :
|
||||
SaveConverter(vm, fileName) {
|
||||
}
|
||||
|
||||
SaveConverter_v4::~SaveConverter_v4() {
|
||||
}
|
||||
|
||||
int SaveConverter_v4::isOldSave(Common::InSaveFile **save) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return 0;
|
||||
|
||||
uint32 saveSize = getActualSize(save);
|
||||
if (saveSize == 0)
|
||||
return 0;
|
||||
|
||||
// The size of the old save always follows that rule
|
||||
if (saveSize == (varSize * 2 + kSlotNameLength + 1000 + 512000))
|
||||
return 1;
|
||||
|
||||
// Not an old save, clean up
|
||||
if (save) {
|
||||
delete *save;
|
||||
*save = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *SaveConverter_v4::getDescription(Common::SeekableReadStream &save) const {
|
||||
// The description starts at 1000
|
||||
if (!save.seek(1000))
|
||||
return nullptr;
|
||||
|
||||
char *desc = new char[kSlotNameLength];
|
||||
|
||||
// Read the description
|
||||
if (save.read(desc, kSlotNameLength) != kSlotNameLength) {
|
||||
delete[] desc;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
bool SaveConverter_v4::loadFail(SavePartInfo *info, SavePartVars *vars,
|
||||
SavePartMem *props, Common::InSaveFile *save) {
|
||||
|
||||
delete info;
|
||||
delete vars;
|
||||
delete props;
|
||||
delete save;
|
||||
|
||||
clear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loads the old save by constructing a new save containing the old save's data
|
||||
bool SaveConverter_v4::load() {
|
||||
clear();
|
||||
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
Common::InSaveFile *save;
|
||||
|
||||
// Test if it's an old savd
|
||||
if (!isOldSave(&save) || !save)
|
||||
return false;
|
||||
|
||||
displayWarning();
|
||||
|
||||
SaveWriter writer(3, 0);
|
||||
|
||||
SavePartInfo *info = readInfo(*save, kSlotNameLength, false);
|
||||
if (!info)
|
||||
return loadFail(nullptr, nullptr, nullptr, save);
|
||||
|
||||
SavePartVars *vars = readVars(*save, varSize, true);
|
||||
if (!vars)
|
||||
return loadFail(info, nullptr, nullptr, save);
|
||||
|
||||
SavePartMem *props = readMem(*save, 256000, true);
|
||||
if (!props)
|
||||
return loadFail(info, vars, nullptr, save);
|
||||
|
||||
// We don't need the save anymore
|
||||
delete save;
|
||||
|
||||
// Write all parts
|
||||
if (!writer.writePart(0, info))
|
||||
return loadFail(info, vars, props, nullptr);
|
||||
if (!writer.writePart(1, vars))
|
||||
return loadFail(info, vars, props, nullptr);
|
||||
if (!writer.writePart(2, props))
|
||||
return loadFail(info, vars, props, nullptr);
|
||||
|
||||
// We don't need those anymore
|
||||
delete info;
|
||||
delete vars;
|
||||
delete props;
|
||||
|
||||
// Create the final read stream
|
||||
if (!createStream(writer))
|
||||
return loadFail(nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
1051
engines/gob/save/savefile.cpp
Normal file
1051
engines/gob/save/savefile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
365
engines/gob/save/savefile.h
Normal file
365
engines/gob/save/savefile.h
Normal file
@@ -0,0 +1,365 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GOB_SAVE_SAVEFILE_H
|
||||
#define GOB_SAVE_SAVEFILE_H
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/array.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
class GobEngine;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* A class wrapping a save part header.
|
||||
*
|
||||
* A save part header consists of 4 fields:
|
||||
* ID : The 8 character ID \0SCVMGOB
|
||||
* Type : The 4 character ID for this part's type
|
||||
* Version : This part's version. Each type has its own version counter
|
||||
* Size : The size of the contents, i.e. excluding this header
|
||||
*/
|
||||
class SaveHeader {
|
||||
public:
|
||||
/** The size of the header. */
|
||||
static const int kSize = 20;
|
||||
static const uint32 kID1 = MKTAG(0,'S','C','V');
|
||||
static const uint32 kID2 = MKTAG('M','G','O','B');
|
||||
|
||||
SaveHeader(uint32 type = 0, uint32 version = 0, uint32 size = 0);
|
||||
|
||||
bool operator==(const SaveHeader &header) const;
|
||||
bool operator!=(const SaveHeader &header) const;
|
||||
|
||||
/** Read the header out of a stream into this class. */
|
||||
bool read(Common::ReadStream &stream);
|
||||
/** Read the header out of a stream and checks it against this class's contents. */
|
||||
bool verify(Common::ReadStream &stream) const;
|
||||
/** Read the header out of a stream and checks it against this class's contents,
|
||||
* but read the size field instead.
|
||||
*/
|
||||
bool verifyReadSize(Common::ReadStream &stream);
|
||||
/** Write this class's contents into a stream. */
|
||||
bool write(Common::WriteStream &stream) const;
|
||||
|
||||
uint32 getType() const;
|
||||
uint32 getVersion() const;
|
||||
uint32 getSize() const;
|
||||
|
||||
void setType(uint32 type);
|
||||
void setVersion(uint32 version);
|
||||
void setSize(uint32 size);
|
||||
|
||||
private:
|
||||
/** An ID specifying the part's type. */
|
||||
uint32 _type;
|
||||
/** The part's version. */
|
||||
uint32 _version;
|
||||
/** The size of the contents. */
|
||||
uint32 _size;
|
||||
};
|
||||
|
||||
/** An abstract class for a part in a save file. */
|
||||
class SavePart {
|
||||
public:
|
||||
SavePart();
|
||||
virtual ~SavePart();
|
||||
|
||||
/** Return the total size of the part. */
|
||||
virtual uint32 getSize() const;
|
||||
|
||||
/** Read the part (with header) out of the stream. */
|
||||
virtual bool read(Common::ReadStream &stream) = 0;
|
||||
/** Write the part (with header) into the stream. */
|
||||
virtual bool write(Common::WriteStream &stream) const = 0;
|
||||
|
||||
protected:
|
||||
SaveHeader _header;
|
||||
};
|
||||
|
||||
/** A save part consisting of plain memory. */
|
||||
class SavePartMem : public SavePart {
|
||||
public:
|
||||
static const uint32 kVersion = 1;
|
||||
static const uint32 kID = MKTAG('P','M','E','M');
|
||||
|
||||
SavePartMem(uint32 size);
|
||||
~SavePartMem() override;
|
||||
|
||||
bool read(Common::ReadStream &stream) override;
|
||||
bool write(Common::WriteStream &stream) const override;
|
||||
|
||||
/** Read size bytes of data into the part at the specified offset. */
|
||||
bool readFrom(const byte *data, uint32 offset, uint32 size);
|
||||
/** Write size bytes of the part at the specified offset int data. */
|
||||
bool writeInto(byte *data, uint32 offset, uint32 size) const;
|
||||
|
||||
private:
|
||||
uint32 _size;
|
||||
byte *_data;
|
||||
};
|
||||
|
||||
/** A save part holding script variables. */
|
||||
class SavePartVars : public SavePart {
|
||||
public:
|
||||
static const uint32 kVersion = 1;
|
||||
static const uint32 kID = MKTAG('V','A','R','S');
|
||||
|
||||
SavePartVars(GobEngine *vm, uint32 size);
|
||||
~SavePartVars() override;
|
||||
|
||||
bool read(Common::ReadStream &stream) override;
|
||||
bool write(Common::WriteStream &stream) const override;
|
||||
|
||||
/** Read size bytes of variables starting at var into the part at the specified offset. */
|
||||
bool readFrom(uint32 var, uint32 offset, uint32 size);
|
||||
/** Write size bytes of the part at the specified offset into the variable starting at var. */
|
||||
bool writeInto(uint32 var, uint32 offset, uint32 size) const;
|
||||
|
||||
/** Read size bytes of raw data into the part. */
|
||||
bool readFromRaw(const byte *data, uint32 offset, uint32 size);
|
||||
|
||||
/** Write size bytes of the part at the specified offset into a raw buffer. */
|
||||
bool writeIntoRaw(byte *data, uint32 offset, uint32 size) const;
|
||||
|
||||
const byte* data() const { return _data; }
|
||||
|
||||
private:
|
||||
GobEngine *_vm;
|
||||
|
||||
uint32 _size;
|
||||
byte *_data;
|
||||
};
|
||||
|
||||
/** A save part holding a sprite. */
|
||||
class SavePartSprite : public SavePart {
|
||||
public:
|
||||
static const uint32 kVersion = 2;
|
||||
static const uint32 kID = MKTAG('S','P','R','T');
|
||||
|
||||
SavePartSprite(uint32 width, uint32 height, bool trueColor = false);
|
||||
~SavePartSprite() override;
|
||||
|
||||
bool read(Common::ReadStream &stream) override;
|
||||
bool write(Common::WriteStream &stream) const override;
|
||||
|
||||
/** Read a palette into the part. */
|
||||
bool readPalette(const byte *palette);
|
||||
/** Read a sprite into the part. */
|
||||
bool readSprite(const Surface &sprite);
|
||||
|
||||
/** Read size bytes of raw data into the sprite. */
|
||||
bool readSpriteRaw(const byte *data, uint32 size);
|
||||
|
||||
/** Write a palette out of the part. */
|
||||
bool writePalette(byte *palette) const;
|
||||
/** Write a sprite out of the part. */
|
||||
bool writeSprite(Surface &sprite) const;
|
||||
|
||||
private:
|
||||
uint32 _width;
|
||||
uint32 _height;
|
||||
|
||||
uint32 _spriteSize;
|
||||
|
||||
bool _oldFormat;
|
||||
bool _trueColor;
|
||||
|
||||
byte *_dataSprite;
|
||||
byte *_dataPalette;
|
||||
};
|
||||
|
||||
/** A save part containing informations about the save's game. */
|
||||
class SavePartInfo : public SavePart {
|
||||
public:
|
||||
static const uint32 kVersion = 1;
|
||||
static const uint32 kID = MKTAG('I','N','F','O');
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
* @param descMaxLength The maximal number of bytes that fit into the description.
|
||||
* @param gameID An ID for the game (Gob1, Gob2, Gob3, ...).
|
||||
* @param gameVersion An ID for game specific versioning
|
||||
* @param endian Endianness of the platform the game originally ran on.
|
||||
* @param varCount The number of script variables.
|
||||
*/
|
||||
SavePartInfo(uint32 descMaxLength, uint32 gameID,
|
||||
uint32 gameVersion, byte endian, uint32 varCount);
|
||||
~SavePartInfo() override;
|
||||
|
||||
/** Return the save's description. */
|
||||
const char *getDesc() const;
|
||||
/** Return the description's maximal length. */
|
||||
uint32 getDescMaxLength() const;
|
||||
|
||||
/** Set the variable count. */
|
||||
void setVarCount(uint32 varCount);
|
||||
/** Set the save's description. */
|
||||
void setDesc(const char *desc = 0);
|
||||
/** Set the save's description. */
|
||||
void setDesc(const byte *desc, uint32 size);
|
||||
|
||||
bool read(Common::ReadStream &stream) override;
|
||||
bool write(Common::WriteStream &stream) const override;
|
||||
|
||||
private:
|
||||
char *_desc;
|
||||
uint32 _descMaxLength;
|
||||
uint32 _gameID;
|
||||
uint32 _gameVersion;
|
||||
uint32 _varCount;
|
||||
byte _endian;
|
||||
};
|
||||
|
||||
/** A container for several save parts. */
|
||||
class SaveContainer {
|
||||
public:
|
||||
static const uint32 kVersion = 1;
|
||||
static const uint32 kID = MKTAG('C','O','N','T');
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
* @param partCount The number parts this container shall hold.
|
||||
* @param slot The save slot this save's for.
|
||||
*/
|
||||
SaveContainer(uint32 partCount, uint32 slot);
|
||||
~SaveContainer();
|
||||
|
||||
uint32 getSlot() const;
|
||||
uint32 getSize() const;
|
||||
|
||||
/** All parts filled? */
|
||||
bool hasAllParts() const;
|
||||
|
||||
/** Empty all parts. */
|
||||
void clear();
|
||||
|
||||
/** Write a SavePart into the container's part. */
|
||||
bool writePart(uint32 partN, const SavePart *part);
|
||||
/** Read the container's part's content into a SavePart. */
|
||||
bool readPart(uint32 partN, SavePart *part) const;
|
||||
/** Read only the container's part's header. */
|
||||
bool readPartHeader(uint32 partN, SaveHeader *header) const;
|
||||
|
||||
/** Checks if the stream is a valid save container. */
|
||||
static bool isSave(Common::SeekableReadStream &stream);
|
||||
|
||||
protected:
|
||||
/** A part. */
|
||||
struct Part {
|
||||
uint32 size;
|
||||
byte *data;
|
||||
|
||||
Part(uint32 s);
|
||||
~Part();
|
||||
|
||||
Common::WriteStream *createWriteStream();
|
||||
Common::ReadStream *createReadStream() const;
|
||||
};
|
||||
|
||||
/** Basic information about a part. */
|
||||
struct PartInfo {
|
||||
uint32 id;
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
};
|
||||
|
||||
typedef Common::Array<Part *>::iterator PartIterator;
|
||||
typedef Common::Array<Part *>::const_iterator PartConstIterator;
|
||||
|
||||
uint32 _partCount;
|
||||
uint32 _slot;
|
||||
|
||||
SaveHeader _header;
|
||||
Common::Array<Part *> _parts;
|
||||
|
||||
uint32 calcSize() const;
|
||||
|
||||
bool read(Common::ReadStream &stream);
|
||||
bool write(Common::WriteStream &stream) const;
|
||||
|
||||
/** Get an array containing basic information about all parts in the container in the stream. */
|
||||
static Common::Array<PartInfo> *getPartsInfo(Common::SeekableReadStream &stream);
|
||||
};
|
||||
|
||||
/** Reads a save. */
|
||||
class SaveReader : public SaveContainer {
|
||||
public:
|
||||
SaveReader(uint32 partCount, uint32 slot, const Common::String &fileName);
|
||||
SaveReader(uint32 partCount, uint32 slot, Common::SeekableReadStream &stream);
|
||||
~SaveReader();
|
||||
|
||||
bool load();
|
||||
|
||||
bool readPart(uint32 partN, SavePart *part) const;
|
||||
bool readPartHeader(uint32 partN, SaveHeader *header) const;
|
||||
|
||||
/** Find and read the save's info part. */
|
||||
static bool getInfo(Common::SeekableReadStream &stream, SavePartInfo &info);
|
||||
/** Find and read the save's info part. */
|
||||
static bool getInfo(const Common::String &fileName, SavePartInfo &info);
|
||||
|
||||
protected:
|
||||
Common::String _fileName;
|
||||
Common::SeekableReadStream *_stream;
|
||||
|
||||
bool _loaded;
|
||||
|
||||
static Common::InSaveFile *openSave(const Common::String &fileName);
|
||||
Common::InSaveFile *openSave();
|
||||
};
|
||||
|
||||
/** Writes a save. */
|
||||
class SaveWriter: public SaveContainer {
|
||||
public:
|
||||
SaveWriter(uint32 partCount, uint32 slot);
|
||||
SaveWriter(uint32 partCount, uint32 slot, const Common::String &fileName);
|
||||
~SaveWriter();
|
||||
|
||||
bool writePart(uint32 partN, const SavePart *part);
|
||||
|
||||
bool save(Common::WriteStream &stream);
|
||||
bool deleteFile();
|
||||
|
||||
protected:
|
||||
bool save();
|
||||
|
||||
Common::String _fileName;
|
||||
|
||||
/** Is everything ready for saving? */
|
||||
bool canSave() const;
|
||||
|
||||
static Common::OutSaveFile *openSave(const Common::String &fileName);
|
||||
Common::OutSaveFile *openSave();
|
||||
};
|
||||
|
||||
} // End of namespace Gob
|
||||
|
||||
#endif // GOB_SAVE_SAVEFILE_H
|
||||
599
engines/gob/save/savehandler.cpp
Normal file
599
engines/gob/save/savehandler.cpp
Normal file
@@ -0,0 +1,599 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
#include "gob/gob.h"
|
||||
#include "gob/save/savehandler.h"
|
||||
#include "gob/save/savefile.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/global.h"
|
||||
#include "gob/video.h"
|
||||
#include "gob/draw.h"
|
||||
#include "gob/variables.h"
|
||||
#include "gob/inter.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SlotFile::SlotFile(GobEngine *vm, uint32 slotCount, const Common::String &base) : _vm(vm) {
|
||||
_base = base;
|
||||
_slotCount = slotCount;
|
||||
}
|
||||
|
||||
SlotFile::~SlotFile() {
|
||||
}
|
||||
|
||||
uint32 SlotFileIndexed::getSlotMax() const {
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::InSaveFile *in;
|
||||
|
||||
// Find the last filled save slot and base the save file size calculate on that
|
||||
for (int i = (_slotCount - 1); i >= 0; i--) {
|
||||
Common::String slotFile = build(i);
|
||||
|
||||
if (slotFile.empty())
|
||||
continue;
|
||||
|
||||
in = saveMan->openForLoading(slotFile);
|
||||
|
||||
if (in) {
|
||||
delete in;
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 SlotFileIndexed::tallyUpFiles(uint32 slotSize, uint32 indexSize) const {
|
||||
uint32 maxSlot = getSlotMax();
|
||||
|
||||
if (maxSlot == 0)
|
||||
return -1;
|
||||
|
||||
return ((maxSlot * slotSize) + indexSize);
|
||||
}
|
||||
|
||||
void SlotFileIndexed::buildIndex(byte *buffer, SavePartInfo &info,
|
||||
SaveConverter *converter, bool setLongest) const {
|
||||
|
||||
uint32 descLength = info.getDescMaxLength();
|
||||
|
||||
uint32 longest = 0;
|
||||
byte *bufferStart = buffer;
|
||||
|
||||
// Iterate over all files
|
||||
for (uint32 i = 0; i < _slotCount; i++, buffer += descLength) {
|
||||
Common::String slotFile = build(i);
|
||||
|
||||
if (!slotFile.empty()) {
|
||||
char *desc = nullptr;
|
||||
|
||||
if (converter && (desc = converter->getDescription(slotFile)))
|
||||
// Old style save
|
||||
memcpy(buffer, desc, descLength);
|
||||
else if (SaveReader::getInfo(slotFile, info))
|
||||
// New style save
|
||||
memcpy(buffer, info.getDesc(), descLength);
|
||||
else
|
||||
// No known format, fill with 0
|
||||
memset(buffer, 0, descLength);
|
||||
|
||||
delete[] desc;
|
||||
|
||||
longest = MAX<uint32>(longest, strlen((const char *) buffer));
|
||||
|
||||
} else
|
||||
// No valid slot, fill with 0
|
||||
memset(buffer, 0, descLength);
|
||||
}
|
||||
|
||||
if (setLongest) {
|
||||
uint32 slot0Len;
|
||||
for (slot0Len = strlen((const char *) bufferStart); slot0Len < longest; slot0Len++)
|
||||
bufferStart[slot0Len] = ' ';
|
||||
bufferStart[slot0Len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
bool SlotFileIndexed::exists(int slot) const {
|
||||
Common::InSaveFile *in = openRead(slot);
|
||||
bool result = (in != nullptr);
|
||||
delete in;
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::InSaveFile *SlotFileIndexed::openRead(int slot) const {
|
||||
Common::String name = build(slot);
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::InSaveFile *result = saveMan->openForLoading(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::OutSaveFile *SlotFileIndexed::openWrite(int slot) const {
|
||||
Common::String name = build(slot);
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::OutSaveFile *result = saveMan->openForSaving(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
SlotFileIndexed::SlotFileIndexed(GobEngine *vm, uint32 slotCount,
|
||||
const Common::String &base, const Common::String &extStub) : SlotFile(vm, slotCount, base) {
|
||||
|
||||
_ext = extStub;
|
||||
}
|
||||
|
||||
SlotFileIndexed::~SlotFileIndexed() {
|
||||
}
|
||||
|
||||
Common::String SlotFileIndexed::build(int slot) const {
|
||||
if ((slot < 0) || (((uint32) slot) >= _slotCount))
|
||||
return Common::String();
|
||||
|
||||
Common::String buf = Common::String::format("%02d", slot);
|
||||
|
||||
return _base + "." + _ext + buf;
|
||||
}
|
||||
|
||||
SlotFileStatic::SlotFileStatic(GobEngine *vm, const Common::String &base,
|
||||
const Common::String &ext) : SlotFile(vm, 1, base) {
|
||||
|
||||
_ext = "." + ext;
|
||||
}
|
||||
|
||||
SlotFileStatic::~SlotFileStatic() {
|
||||
}
|
||||
|
||||
int SlotFileStatic::getSlot(int32 offset) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SlotFileStatic::getSlotRemainder(int32 offset) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Common::String SlotFileStatic::build() const {
|
||||
return _base + _ext;
|
||||
}
|
||||
|
||||
bool SlotFileStatic::exists() const {
|
||||
Common::InSaveFile *in = openRead();
|
||||
bool result = (in != nullptr);
|
||||
delete in;
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::InSaveFile *SlotFileStatic::openRead() const {
|
||||
Common::String name = build();
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::InSaveFile *result = saveMan->openForLoading(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::OutSaveFile *SlotFileStatic::openWrite() const {
|
||||
Common::String name = build();
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::OutSaveFile *result = saveMan->openForSaving(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
SaveHandler::SaveHandler(GobEngine *vm) : _vm(vm) {
|
||||
}
|
||||
|
||||
SaveHandler::~SaveHandler() {
|
||||
}
|
||||
|
||||
uint32 SaveHandler::getVarSize(GobEngine *vm) {
|
||||
// Sanity checks
|
||||
if (!vm || !vm->_inter || !vm->_inter->_variables)
|
||||
return 0;
|
||||
|
||||
return vm->_inter->_variables->getSize();
|
||||
}
|
||||
|
||||
bool SaveHandler::deleteFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveHandler::loadToRaw(byte *ptr, int32 size, int32 offset) {
|
||||
warning("SaveHandler::loadToRaw() not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SaveHandler::saveFromRaw(const byte *ptr, int32 size, int32 offset) {
|
||||
warning("SaveHandler::saveFromRaw() not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
TempSpriteHandler::TempSpriteHandler(GobEngine *vm) : SaveHandler(vm) {
|
||||
_sprite = nullptr;
|
||||
}
|
||||
|
||||
TempSpriteHandler::~TempSpriteHandler() {
|
||||
delete _sprite;
|
||||
}
|
||||
|
||||
int32 TempSpriteHandler::getSize() {
|
||||
if (!_sprite)
|
||||
return -1;
|
||||
|
||||
return _sprite->getSize();
|
||||
}
|
||||
|
||||
bool TempSpriteHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (isDummy(size))
|
||||
return true;
|
||||
|
||||
// Sprite available?
|
||||
if (!_sprite)
|
||||
return false;
|
||||
|
||||
// Sprite requested?
|
||||
if (!isSprite(size))
|
||||
return false;
|
||||
|
||||
// Index sane?
|
||||
int index = getIndex(size);
|
||||
if ((index < 0) || (index >= Draw::kSpriteCount))
|
||||
return false;
|
||||
|
||||
SurfacePtr sprite = _vm->_draw->_spritesArray[index];
|
||||
|
||||
// Target sprite exists?
|
||||
if (!sprite)
|
||||
return false;
|
||||
|
||||
// Load the sprite
|
||||
if (!_sprite->writeSprite(*sprite))
|
||||
return false;
|
||||
|
||||
// Handle palette
|
||||
if (usesPalette(size)) {
|
||||
if (!_sprite->writePalette((byte *)_vm->_global->_pPaletteDesc->vgaPal))
|
||||
return false;
|
||||
|
||||
_vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
|
||||
}
|
||||
|
||||
if (index == 21) {
|
||||
// We wrote into the backbuffer, blit
|
||||
_vm->_draw->forceBlit();
|
||||
_vm->_video->retrace();
|
||||
} else if (index == 20)
|
||||
// We wrote into the frontbuffer, retrace
|
||||
_vm->_video->retrace();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TempSpriteHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (isDummy(size))
|
||||
return true;
|
||||
|
||||
SurfacePtr sprite = createSprite(dataVar, size, offset);
|
||||
if (!sprite)
|
||||
return false;
|
||||
|
||||
// Save the sprite
|
||||
if (!_sprite->readSprite(*sprite))
|
||||
return false;
|
||||
|
||||
// Handle palette
|
||||
if (usesPalette(size))
|
||||
if (!_sprite->readPalette((const byte *)_vm->_global->_pPaletteDesc->vgaPal))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TempSpriteHandler::create(uint32 width, uint32 height, bool trueColor) {
|
||||
delete _sprite;
|
||||
_sprite = nullptr;
|
||||
|
||||
// Create a new temporary sprite
|
||||
_sprite = new SavePartSprite(width, height, trueColor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TempSpriteHandler::loadToRaw(byte *ptr, int32 size, int32 offset) {
|
||||
// Sprite available?
|
||||
if (!_sprite)
|
||||
return false;
|
||||
|
||||
Surface destSprite(1, size, 1);
|
||||
|
||||
// Load the sprite
|
||||
if (!_sprite->writeSprite(destSprite))
|
||||
return false;
|
||||
|
||||
// Copy the sprite to the buffer
|
||||
memcpy(ptr, destSprite.getData(), size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TempSpriteHandler::saveFromRaw(const byte *ptr, int32 size, int32 offset) {
|
||||
create(1, size, false);
|
||||
|
||||
if (!_sprite->readSpriteRaw(ptr, size))
|
||||
return false;
|
||||
|
||||
// Assume no palette used
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TempSpriteHandler::createFromSprite(int16 dataVar, int32 size, int32 offset) {
|
||||
return createSprite(dataVar, size, offset) != nullptr;
|
||||
}
|
||||
|
||||
SurfacePtr TempSpriteHandler::createSprite(int16 dataVar, int32 size, int32 offset) {
|
||||
SurfacePtr sprt;
|
||||
|
||||
// Sprite requested?
|
||||
if (!isSprite(size))
|
||||
return sprt;
|
||||
|
||||
// Index sane?
|
||||
int index = getIndex(size);
|
||||
if ((index < 0) || (index >= Draw::kSpriteCount))
|
||||
return sprt;
|
||||
|
||||
// Sprite exists?
|
||||
if (!(sprt = _vm->_draw->_spritesArray[index]))
|
||||
return sprt;
|
||||
|
||||
if (!create(sprt->getWidth(), sprt->getHeight(), sprt->getBPP() > 1))
|
||||
sprt.reset();
|
||||
|
||||
return sprt;
|
||||
}
|
||||
|
||||
// A size of 0 means no proper sprite should be saved/loaded,
|
||||
// but no error should be thrown either.
|
||||
bool TempSpriteHandler::isDummy(int32 size) {
|
||||
return (size == 0);
|
||||
}
|
||||
|
||||
// A negative size is the flag for using a sprite
|
||||
bool TempSpriteHandler::isSprite(int32 size) {
|
||||
return (size < 0);
|
||||
}
|
||||
|
||||
// Contruct the index
|
||||
int TempSpriteHandler::getIndex(int32 size) {
|
||||
// Palette flag
|
||||
if (size < -3000)
|
||||
size += 3000;
|
||||
if (size < -1000)
|
||||
size += 1000;
|
||||
|
||||
return (-size - 1);
|
||||
}
|
||||
|
||||
// A size smaller than -1000 indicates palette usage
|
||||
bool TempSpriteHandler::usesPalette(int32 size) {
|
||||
return (size < -1000);
|
||||
}
|
||||
|
||||
|
||||
NotesHandler::File::File(GobEngine *vm, const Common::String &base) :
|
||||
SlotFileStatic(vm, base, "blo") {
|
||||
}
|
||||
|
||||
NotesHandler::File::~File() {
|
||||
}
|
||||
|
||||
NotesHandler::NotesHandler(uint32 notesSize, GobEngine *vm, const Common::String &target) :
|
||||
SaveHandler(vm) {
|
||||
|
||||
_notesSize = notesSize;
|
||||
|
||||
_file = new File(vm, target);
|
||||
|
||||
_notes = new SavePartVars(vm, _notesSize);
|
||||
}
|
||||
|
||||
NotesHandler::~NotesHandler() {
|
||||
delete _file;
|
||||
delete _notes;
|
||||
}
|
||||
|
||||
int32 NotesHandler::getSize() {
|
||||
Common::String fileName = _file->build();
|
||||
|
||||
if (fileName.empty())
|
||||
return -1;
|
||||
|
||||
Common::InSaveFile *saveFile;
|
||||
|
||||
SaveConverter_Notes converter(_vm, _notesSize, fileName);
|
||||
if (converter.isOldSave(&saveFile)) {
|
||||
// Old save, get the size olden-style
|
||||
|
||||
int32 size = saveFile->size();
|
||||
|
||||
delete saveFile;
|
||||
return size;
|
||||
}
|
||||
|
||||
SaveReader reader(1, 0, fileName);
|
||||
SaveHeader header;
|
||||
|
||||
if (!reader.load())
|
||||
return -1;
|
||||
|
||||
if (!reader.readPartHeader(0, &header))
|
||||
return -1;
|
||||
|
||||
// Return the part's size
|
||||
return header.getSize();
|
||||
}
|
||||
|
||||
bool NotesHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if ((dataVar < 0) || (size < 0) || (offset < 0))
|
||||
return false;
|
||||
|
||||
Common::String fileName = _file->build();
|
||||
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
SaveReader *reader;
|
||||
|
||||
SaveConverter_Notes converter(_vm, _notesSize, fileName);
|
||||
if (converter.isOldSave()) {
|
||||
// Old save, plug the converter in
|
||||
if (!converter.load())
|
||||
return false;
|
||||
|
||||
reader = new SaveReader(1, 0, converter);
|
||||
|
||||
} else
|
||||
// New save, load directly
|
||||
reader = new SaveReader(1, 0, fileName);
|
||||
|
||||
SavePartVars vars(_vm, _notesSize);
|
||||
|
||||
if (!reader->load()) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reader->readPart(0, &vars)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vars.writeInto(dataVar, offset, size)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete reader;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NotesHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if ((dataVar < 0) || (size < 0) || (offset < 0))
|
||||
return false;
|
||||
|
||||
Common::String fileName = _file->build();
|
||||
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
SaveWriter writer(1, 0, fileName);
|
||||
SavePartVars vars(_vm, _notesSize);
|
||||
|
||||
if (!vars.readFrom(dataVar, offset, size))
|
||||
return false;
|
||||
|
||||
return writer.writePart(0, &vars);
|
||||
}
|
||||
|
||||
|
||||
FakeFileHandler::FakeFileHandler(GobEngine *vm) : SaveHandler(vm) {
|
||||
}
|
||||
|
||||
FakeFileHandler::~FakeFileHandler() {
|
||||
}
|
||||
|
||||
int32 FakeFileHandler::getSize() {
|
||||
if (_data.empty())
|
||||
return -1;
|
||||
|
||||
return _data.size();
|
||||
}
|
||||
|
||||
bool FakeFileHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
if ((uint32)(offset + size) > _data.size())
|
||||
return false;
|
||||
|
||||
_vm->_inter->_variables->copyFrom((uint16) dataVar, &_data[0] + offset, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FakeFileHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
if ((uint32)(offset + size) > _data.size())
|
||||
_data.resize(offset + size);
|
||||
|
||||
_vm->_inter->_variables->copyTo((uint16) dataVar, &_data[0] + offset, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FakeFileHandler::loadToRaw(byte *ptr, int32 size, int32 offset) {
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
if ((uint32)(offset + size) > _data.size())
|
||||
return false;
|
||||
|
||||
memcpy(ptr, &_data[0] + offset, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FakeFileHandler::saveFromRaw(const byte *ptr, int32 size, int32 offset) {
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
if ((uint32)(offset + size) > _data.size())
|
||||
_data.resize(offset + size);
|
||||
|
||||
memcpy(&_data[0] + offset, ptr, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FakeFileHandler::deleteFile() {
|
||||
_data.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
213
engines/gob/save/savehandler.h
Normal file
213
engines/gob/save/savehandler.h
Normal file
@@ -0,0 +1,213 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GOB_SAVE_SAVEHANDLER_H
|
||||
#define GOB_SAVE_SAVEHANDLER_H
|
||||
|
||||
#include "common/savefile.h"
|
||||
#include "common/array.h"
|
||||
|
||||
#include "engines/gob/video.h" // for SurfacePtr
|
||||
|
||||
namespace Gob {
|
||||
|
||||
class GobEngine;
|
||||
class SavePartInfo;
|
||||
class SavePartVars;
|
||||
class SavePartSprite;
|
||||
class SaveConverter;
|
||||
|
||||
/** Slot file related class. */
|
||||
class SlotFile {
|
||||
public:
|
||||
/** The constructor.
|
||||
*
|
||||
* @param slotCount Number of slots.
|
||||
* @param base The file's base string.
|
||||
*/
|
||||
SlotFile(GobEngine *vm, uint32 slotCount, const Common::String &base);
|
||||
virtual ~SlotFile();
|
||||
|
||||
/** Calculates which slot to use. */
|
||||
virtual int getSlot(int32 offset) const = 0;
|
||||
/** Calculates the slot remainder, for error checking. */
|
||||
virtual int getSlotRemainder(int32 offset) const = 0;
|
||||
|
||||
protected:
|
||||
GobEngine *_vm;
|
||||
Common::String _base;
|
||||
|
||||
uint32 _slotCount;
|
||||
};
|
||||
|
||||
/** An indexed slot file ("foobar.s00", "foobar.s01", ...). */
|
||||
class SlotFileIndexed : public SlotFile {
|
||||
public:
|
||||
SlotFileIndexed(GobEngine *vm, uint32 slotCount, const Common::String &base,
|
||||
const Common::String &extStub);
|
||||
~SlotFileIndexed() override;
|
||||
|
||||
/** Build the save file name. */
|
||||
Common::String build(int slot) const;
|
||||
|
||||
/** Returns the highest filled slot number. */
|
||||
virtual uint32 getSlotMax() const;
|
||||
|
||||
/** Returns the size of all existing slots + the index. */
|
||||
virtual int32 tallyUpFiles(uint32 slotSize, uint32 indexSize) const;
|
||||
|
||||
/** Creates an index in buffer. */
|
||||
virtual void buildIndex(byte *buffer, SavePartInfo &info,
|
||||
SaveConverter *converter = 0, bool setLongest = false) const;
|
||||
|
||||
virtual bool exists(int slot) const;
|
||||
virtual Common::InSaveFile *openRead(int slot) const;
|
||||
virtual Common::OutSaveFile *openWrite(int slot) const;
|
||||
|
||||
protected:
|
||||
Common::String _ext;
|
||||
};
|
||||
|
||||
/** A static slot file ("foo.bar"). */
|
||||
class SlotFileStatic : public SlotFile {
|
||||
public:
|
||||
SlotFileStatic(GobEngine *vm, const Common::String &base, const Common::String &ext);
|
||||
~SlotFileStatic() override;
|
||||
|
||||
int getSlot(int32 offset) const override;
|
||||
int getSlotRemainder(int32 offset) const override;
|
||||
|
||||
/** Build the save file name. */
|
||||
Common::String build() const;
|
||||
|
||||
virtual bool exists() const;
|
||||
virtual Common::InSaveFile *openRead() const;
|
||||
virtual Common::OutSaveFile *openWrite() const;
|
||||
|
||||
protected:
|
||||
Common::String _ext;
|
||||
};
|
||||
|
||||
/** A handler for a specific save file. */
|
||||
class SaveHandler {
|
||||
public:
|
||||
SaveHandler(GobEngine *vm);
|
||||
virtual ~SaveHandler();
|
||||
|
||||
/** Returns the file's (virtual) size. */
|
||||
virtual int32 getSize() = 0;
|
||||
/** Loads (parts of) the file. */
|
||||
virtual bool load(int16 dataVar, int32 size, int32 offset) = 0;
|
||||
/** Saves (parts of) the file. */
|
||||
virtual bool save(int16 dataVar, int32 size, int32 offset) = 0;
|
||||
|
||||
virtual bool loadToRaw(byte *ptr, int32 size, int32 offset);
|
||||
virtual bool saveFromRaw(const byte *ptr, int32 size, int32 offset);
|
||||
|
||||
/** Deletes the file. */
|
||||
virtual bool deleteFile();
|
||||
|
||||
static uint32 getVarSize(GobEngine *vm);
|
||||
|
||||
protected:
|
||||
GobEngine *_vm;
|
||||
};
|
||||
|
||||
/** A handler for temporary sprites. */
|
||||
class TempSpriteHandler : public SaveHandler {
|
||||
public:
|
||||
TempSpriteHandler(GobEngine *vm);
|
||||
~TempSpriteHandler() override;
|
||||
|
||||
int32 getSize() override;
|
||||
bool load(int16 dataVar, int32 size, int32 offset) override;
|
||||
bool save(int16 dataVar, int32 size, int32 offset) override;
|
||||
|
||||
bool loadToRaw(byte *ptr, int32 size, int32 offset) override;
|
||||
bool saveFromRaw(const byte *ptr, int32 size, int32 offset) override;
|
||||
|
||||
bool create(uint32 width, uint32 height, bool trueColor);
|
||||
bool createFromSprite(int16 dataVar, int32 size, int32 offset);
|
||||
|
||||
protected:
|
||||
SavePartSprite *_sprite;
|
||||
|
||||
/** Determine whether it's a dummy sprite save/load. */
|
||||
static bool isDummy(int32 size);
|
||||
/** Determine whether using a sprite was requested. */
|
||||
static bool isSprite(int32 size);
|
||||
/** Determine which sprite is meant. */
|
||||
static int getIndex(int32 size);
|
||||
/** Determine whether the palette should be used too. */
|
||||
static bool usesPalette(int32 size);
|
||||
|
||||
SurfacePtr createSprite(int16 dataVar, int32 size, int32 offset);
|
||||
};
|
||||
|
||||
/** A handler for notes. */
|
||||
class NotesHandler : public SaveHandler {
|
||||
public:
|
||||
NotesHandler(uint32 notesSize, GobEngine *vm, const Common::String &target);
|
||||
~NotesHandler() override;
|
||||
|
||||
int32 getSize() override;
|
||||
bool load(int16 dataVar, int32 size, int32 offset) override;
|
||||
bool save(int16 dataVar, int32 size, int32 offset) override;
|
||||
|
||||
private:
|
||||
class File : public SlotFileStatic {
|
||||
public:
|
||||
File(GobEngine *vm, const Common::String &base);
|
||||
~File() override;
|
||||
};
|
||||
|
||||
uint32 _notesSize;
|
||||
File *_file;
|
||||
SavePartVars *_notes;
|
||||
};
|
||||
|
||||
/** A handler that behaves like a file but keeps the contents in memory. */
|
||||
class FakeFileHandler : public SaveHandler {
|
||||
public:
|
||||
FakeFileHandler(GobEngine *vm);
|
||||
~FakeFileHandler() override;
|
||||
|
||||
int32 getSize() override;
|
||||
bool load(int16 dataVar, int32 size, int32 offset) override;
|
||||
bool save(int16 dataVar, int32 size, int32 offset) override;
|
||||
bool loadToRaw(byte *ptr, int32 size, int32 offset) override;
|
||||
bool saveFromRaw(const byte *ptr, int32 size, int32 offset) override;
|
||||
|
||||
bool deleteFile() override;
|
||||
|
||||
private:
|
||||
Common::Array<byte> _data;
|
||||
};
|
||||
|
||||
} // End of namespace Gob
|
||||
|
||||
#endif // GOB_SAVE_SAVEHANDLER_H
|
||||
272
engines/gob/save/saveload.cpp
Normal file
272
engines/gob/save/saveload.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/gob.h"
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/global.h"
|
||||
#include "gob/video.h"
|
||||
#include "gob/draw.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad::SaveLoad(GobEngine *vm) : _vm(vm) {
|
||||
}
|
||||
|
||||
SaveLoad::~SaveLoad() {
|
||||
}
|
||||
|
||||
const char *SaveLoad::stripPath(const char *fileName, char separator) {
|
||||
const char *backSlash;
|
||||
if ((backSlash = strrchr(fileName, separator)))
|
||||
return backSlash + 1;
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
|
||||
Common::String SaveLoad::replacePathSeparators(const char *path, char newSeparator) {
|
||||
Common::String result = path;
|
||||
for (char &c : result) {
|
||||
if (c != newSeparator && (c == '\\' || c == '/' || c == ':'))
|
||||
c = newSeparator;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::List<Common::Path> SaveLoad::getFilesMatchingPattern(const Common::Path &pattern) const {
|
||||
warning("SaveLoad::getFilesMatchingPattern not implemented");
|
||||
return Common::List<Common::Path>();
|
||||
}
|
||||
|
||||
int32 SaveLoad::getSize(const char *fileName) {
|
||||
debugC(3, kDebugSaveLoad, "Requested size of save file \"%s\"", fileName);
|
||||
|
||||
SaveHandler *handler = getHandler(fileName);
|
||||
|
||||
if (!handler) {
|
||||
warning("No save handler for \"%s\"", fileName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 size = handler->getSize();
|
||||
|
||||
debugC(4, kDebugSaveLoad, "Size is %d", size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool SaveLoad::load(const char *fileName, int16 dataVar, int32 size, int32 offset) {
|
||||
debugC(3, kDebugSaveLoad, "Requested loading of save file \"%s\" - %d, %d, %d",
|
||||
fileName, dataVar, size, offset);
|
||||
|
||||
SaveHandler *handler = getHandler(fileName);
|
||||
|
||||
if (!handler) {
|
||||
warning("No save handler for \"%s\" (%d, %d, %d)", fileName, dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!handler->load(dataVar, size, offset)) {
|
||||
const char *desc = getDescription(fileName);
|
||||
|
||||
if (!desc)
|
||||
desc = "Unknown";
|
||||
|
||||
warning("Could not load %s (\"%s\" (%d, %d, %d))",
|
||||
desc, fileName, dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Successfully loaded game");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad::loadToRaw(const char *fileName, byte *ptr, int32 size, int32 offset) {
|
||||
debugC(3, kDebugSaveLoad, "Requested loading of save file \"%s\" - raw %p, %d, %d",
|
||||
fileName, (void *)ptr, size, offset);
|
||||
|
||||
SaveHandler *handler = getHandler(fileName);
|
||||
|
||||
if (!handler) {
|
||||
warning("No save handler for \"%s\" (raw %p, %d, %d)", fileName, (void*) ptr, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!handler->loadToRaw(ptr, size, offset)) {
|
||||
const char *desc = getDescription(fileName);
|
||||
|
||||
if (!desc)
|
||||
desc = "Unknown";
|
||||
|
||||
warning("Could not load %s (\"%s\" (raw %p, %d, %d))",
|
||||
desc, fileName, (void*) ptr, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Successfully loaded game");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad::save(const char *fileName, int16 dataVar, int32 size, int32 offset) {
|
||||
debugC(3, kDebugSaveLoad, "Requested saving of save file \"%s\" - %d, %d, %d",
|
||||
fileName, dataVar, size, offset);
|
||||
|
||||
SaveHandler *handler = getHandler(fileName);
|
||||
|
||||
if (!handler) {
|
||||
warning("No save handler for \"%s\" (%d, %d, %d)", fileName, dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!handler->save(dataVar, size, offset)) {
|
||||
const char *desc = getDescription(fileName);
|
||||
|
||||
if (!desc)
|
||||
desc = "Unknown";
|
||||
|
||||
warning("Could not save %s (\"%s\" (%d, %d, %d))",
|
||||
desc, fileName, dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Successfully saved game");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad::saveFromRaw(const char *fileName, byte *ptr, int32 size, int32 offset) {
|
||||
debugC(3, kDebugSaveLoad, "Requested saving of save file \"%s\" - raw %p, %d, %d",
|
||||
fileName, (void*) ptr, size, offset);
|
||||
|
||||
SaveHandler *handler = getHandler(fileName);
|
||||
|
||||
if (!handler) {
|
||||
warning("No save handler for \"%s\" (raw %p, %d, %d)", fileName, (void*) ptr, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!handler->saveFromRaw(ptr, size, offset)) {
|
||||
const char *desc = getDescription(fileName);
|
||||
|
||||
if (!desc)
|
||||
desc = "Unknown";
|
||||
|
||||
warning("Could not save %s (\"%s\" (raw %p, %d, %d))",
|
||||
desc, fileName, (void*) ptr, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Successfully saved game");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad::copySaveGame(const char *fileNameSrc, const char *fileNameDest) {
|
||||
SaveHandler *handlerSrc = getHandler(fileNameSrc);
|
||||
|
||||
if (!handlerSrc) {
|
||||
warning("copySaveGame: no save handler for source \"%s\" ", fileNameSrc);
|
||||
return false;
|
||||
}
|
||||
|
||||
SaveHandler *handlerDest = getHandler(fileNameDest);
|
||||
if (!handlerDest) {
|
||||
warning("copySaveGame: no save handler for destination \"%s\" ", fileNameDest);
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 size = handlerSrc->getSize();
|
||||
if (size == -1) {
|
||||
warning("copySaveGame: source file \"%s\" does not exists", fileNameSrc);
|
||||
return false;
|
||||
}
|
||||
|
||||
byte *buffer = new byte[size];
|
||||
|
||||
if (!handlerSrc->loadToRaw(buffer, size, 0)) {
|
||||
const char *desc = getDescription(fileNameSrc);
|
||||
|
||||
if (!desc)
|
||||
desc = "Unknown";
|
||||
|
||||
warning("Could not load %s (\"%s\") for copying to %s", desc, fileNameSrc, fileNameDest);
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!handlerDest->saveFromRaw(buffer, size, 0)) {
|
||||
const char *desc = getDescription(fileNameDest);
|
||||
|
||||
if (!desc)
|
||||
desc = "Unknown";
|
||||
|
||||
warning("Could not save %s (\"%s\") when copying from %s", desc, fileNameDest, fileNameSrc);
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Successfully copied saved game");
|
||||
delete[] buffer;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad::deleteFile(const char *fileName) {
|
||||
debugC(3, kDebugSaveLoad, "Requested deletion save file \"%s\"", fileName);
|
||||
|
||||
SaveHandler *handler = getHandler(fileName);
|
||||
|
||||
if (!handler) {
|
||||
warning("No save handler for \"%s\"", fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!handler->deleteFile()) {
|
||||
const char *desc = getDescription(fileName);
|
||||
|
||||
if (!desc)
|
||||
desc = "Unknown";
|
||||
|
||||
warning("Could not delete %s (\"%s\")", desc, fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Successfully deleted file");
|
||||
return true;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad::getSaveMode(const char *fileName) const {
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad::getHandler(const char *fileName) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *SaveLoad::getDescription(const char *fileName) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
1131
engines/gob/save/saveload.h
Normal file
1131
engines/gob/save/saveload.h
Normal file
File diff suppressed because it is too large
Load Diff
401
engines/gob/save/saveload_adibou1.cpp
Normal file
401
engines/gob/save/saveload_adibou1.cpp
Normal file
@@ -0,0 +1,401 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/inter.h"
|
||||
#include "gob/variables.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad_Adibou1::SaveFile SaveLoad_Adibou1::_saveFiles[] = {
|
||||
{ "bou.inf", kSaveModeSave, nullptr, "adibou1"},
|
||||
{ "dessin.inf", kSaveModeSave, nullptr, "paint game drawing"},
|
||||
{ "const.inf", kSaveModeSave, nullptr, "construction game"},
|
||||
{ "menu.inf", kSaveModeSave, nullptr, "temporary sprite"},
|
||||
{ "dessin1.inf", kSaveModeSave, nullptr, "paint game drawing"},
|
||||
{ "dessin2.inf", kSaveModeSave, nullptr, "paint game drawing"},
|
||||
{ "dessin3.inf", kSaveModeSave, nullptr, "paint game drawing"},
|
||||
{ "dessin4.inf", kSaveModeSave, nullptr, "paint game drawing"},
|
||||
{ "dessin5.inf", kSaveModeSave, nullptr, "paint game drawing"},
|
||||
{ "dessin6.inf", kSaveModeSave, nullptr, "paint game drawing"},
|
||||
{ "dessin7.inf", kSaveModeSave, nullptr, "paint game drawing"},
|
||||
{ "dessin8.inf", kSaveModeSave, nullptr, "paint game drawing"},
|
||||
{ "a:\\bou.inf", kSaveModeIgnore, nullptr, "copy of the savegame to be sent "
|
||||
"to Coktel Vision on a floppy"
|
||||
"when completing the game"},
|
||||
};
|
||||
|
||||
SaveLoad_Adibou1::SaveLoad_Adibou1(GobEngine *vm, const char *targetName) :
|
||||
SaveLoad(vm) {
|
||||
|
||||
uint32 index = 0;
|
||||
_saveFiles[index++].handler = _bouHandler = new GameFileHandler(vm, targetName, "bouinf");
|
||||
_saveFiles[index++].handler = _drawingHandler = new SpriteHandler(vm, targetName, "drawing");
|
||||
_saveFiles[index++].handler = _constructionHandler = new GameFileHandler(vm, targetName, "construction");
|
||||
_saveFiles[index++].handler = _menuHandler = new TempSpriteHandler(vm);
|
||||
for (int i = 0; i < kAdibou1NbrOfDrawings; i++) {
|
||||
_saveFiles[index++].handler = _drawingWithThumbnailHandler[i] = new DrawingWithThumbnailHandler(vm,
|
||||
targetName,
|
||||
Common::String::format("drawing%02d", i + 1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::~SaveLoad_Adibou1() {
|
||||
delete _bouHandler;
|
||||
delete _drawingHandler;
|
||||
delete _constructionHandler;
|
||||
delete _menuHandler;
|
||||
for (int i = 0; i < kAdibou1NbrOfDrawings; i++)
|
||||
delete _drawingWithThumbnailHandler[i];
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::SpriteHandler::File::File(GobEngine *vm, const Common::String &base, const Common::String &ext) :
|
||||
SlotFileStatic(vm, base, ext) {
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::SpriteHandler::File::~File() {
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::SpriteHandler::SpriteHandler(GobEngine *vm, const Common::String &target, const Common::String &ext)
|
||||
: TempSpriteHandler(vm), _file(vm, target, ext) {
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::SpriteHandler::~SpriteHandler() {
|
||||
}
|
||||
|
||||
int32 SaveLoad_Adibou1::SpriteHandler::getSize() {
|
||||
Common::String fileName = _file.build();
|
||||
|
||||
if (fileName.empty())
|
||||
return -1;
|
||||
|
||||
SaveReader reader(1, 0, fileName);
|
||||
SaveHeader header;
|
||||
|
||||
if (!reader.load())
|
||||
return -1;
|
||||
|
||||
if (!reader.readPartHeader(0, &header))
|
||||
return -1;
|
||||
|
||||
// Return the part's size
|
||||
return header.getSize();
|
||||
}
|
||||
|
||||
bool SaveLoad_Adibou1::SpriteHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (!TempSpriteHandler::createFromSprite(dataVar, size, offset))
|
||||
return false;
|
||||
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
SaveReader reader(1, 0, fileName);
|
||||
if (!reader.load())
|
||||
return false;
|
||||
|
||||
if (!reader.readPart(0, _sprite))
|
||||
return false;
|
||||
|
||||
return TempSpriteHandler::load(dataVar, size, offset);
|
||||
}
|
||||
|
||||
bool SaveLoad_Adibou1::SpriteHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (!TempSpriteHandler::save(dataVar, size, offset))
|
||||
return false;
|
||||
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
SaveWriter writer(1, 0, fileName);
|
||||
return writer.writePart(0, _sprite);
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::DrawingWithThumbnailHandler::File::File(GobEngine *vm, const Common::String &base, const Common::String &ext) :
|
||||
SlotFileStatic(vm, base, ext) {
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::DrawingWithThumbnailHandler::File::~File() {
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::DrawingWithThumbnailHandler::DrawingWithThumbnailHandler(GobEngine *vm,
|
||||
const Common::String &target,
|
||||
const Common::String &ext)
|
||||
: TempSpriteHandler(vm), _file(vm, target, ext) {
|
||||
|
||||
Common::String fileName = _file.build();
|
||||
_reader = new SaveReader(2, 0, fileName); // Two parts: the thumbnail + the actual drawing
|
||||
_writer = new SaveWriter(2, 0, fileName);
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::DrawingWithThumbnailHandler::~DrawingWithThumbnailHandler() {
|
||||
delete _reader;
|
||||
delete _writer;
|
||||
}
|
||||
|
||||
int32 SaveLoad_Adibou1::DrawingWithThumbnailHandler::getSize() {
|
||||
if (!_reader)
|
||||
return -1;
|
||||
|
||||
if (!_reader->load())
|
||||
return -1;
|
||||
|
||||
SaveHeader header1, header2;
|
||||
if (!_reader->readPartHeader(0, &header1))
|
||||
return -1;
|
||||
|
||||
if (!_reader->readPartHeader(1, &header2))
|
||||
return -1;
|
||||
|
||||
return header1.getSize() + header2.getSize();
|
||||
}
|
||||
|
||||
bool SaveLoad_Adibou1::DrawingWithThumbnailHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (!TempSpriteHandler::createFromSprite(dataVar, size, offset))
|
||||
return false;
|
||||
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
if (!_reader->load())
|
||||
return false;
|
||||
|
||||
uint32 part = (offset == 0) ? 0 : 1;
|
||||
if (!_reader->readPart(part, _sprite))
|
||||
return false;
|
||||
|
||||
return TempSpriteHandler::load(dataVar, size, offset);
|
||||
}
|
||||
|
||||
bool SaveLoad_Adibou1::DrawingWithThumbnailHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (!TempSpriteHandler::save(dataVar, size, offset))
|
||||
return false;
|
||||
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
uint32 part = (offset == 0) ? 0 : 1;
|
||||
return _writer->writePart(part, _sprite);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Adibou1::GameFileHandler::File::File(GobEngine *vm, const Common::String &base, const Common::String &ext) :
|
||||
SlotFileStatic(vm, base, ext) {
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::GameFileHandler::File::~File() {
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Adibou1::GameFileHandler::GameFileHandler(GobEngine *vm, const Common::String &target, const Common::String &ext) :
|
||||
SaveHandler(vm), _file(vm, target, ext) {
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::GameFileHandler::~GameFileHandler() {
|
||||
}
|
||||
|
||||
int32 SaveLoad_Adibou1::GameFileHandler::getSize() {
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return -1;
|
||||
|
||||
SaveReader reader(1, 0, fileName);
|
||||
SaveHeader header;
|
||||
|
||||
if (!reader.load())
|
||||
return -1;
|
||||
|
||||
if (!reader.readPartHeader(0, &header))
|
||||
return -1;
|
||||
|
||||
// Return the part's size
|
||||
return header.getSize();
|
||||
}
|
||||
|
||||
bool SaveLoad_Adibou1::GameFileHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
if (size < 0) {
|
||||
// Hack in original game, using a bitmap memory as a temporary buffer to make
|
||||
// a copy the savegame. We do not need this copy, so we can just ignore it.
|
||||
debugC(1, kDebugSaveLoad, "Ignoring bou.inf save with negative size");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
// Indicator to load all variables
|
||||
dataVar = 0;
|
||||
size = (int32) varSize;
|
||||
}
|
||||
|
||||
int32 fileSize = getSize();
|
||||
if (fileSize < 0)
|
||||
return false;
|
||||
|
||||
SaveReader reader(1, 0, fileName);
|
||||
SavePartVars vars(_vm, fileSize);
|
||||
|
||||
if (!reader.load()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reader.readPart(0, &vars)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vars.writeInto((uint16) dataVar, offset, size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_Adibou1::GameFileHandler::save(const byte *ptrRaw, int16 dataVar, int32 size, int32 offset) {
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to save all variables
|
||||
dataVar = 0;
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
size = (int32) varSize;
|
||||
}
|
||||
|
||||
int32 fileSize = getSize();
|
||||
int32 newFileSize = size;
|
||||
if (fileSize > 0) {
|
||||
newFileSize = MAX<int32>(fileSize, size + offset);
|
||||
}
|
||||
|
||||
SavePartVars vars(_vm, newFileSize);
|
||||
if (fileSize > 0
|
||||
&&
|
||||
(offset > 0 || size < fileSize)) {
|
||||
// Load data from file, as some of it will not be overwritten
|
||||
SaveReader reader(1, 0, fileName);
|
||||
if (!reader.load()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileSize == newFileSize) {
|
||||
// We can use the same SavePartVars object
|
||||
if (!reader.readPart(0, &vars)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// We need to use a temporary SavePartVars object to load data
|
||||
SavePartVars vars_from_file(_vm, fileSize);
|
||||
if (!reader.readPart(0, &vars_from_file)) {;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy data from temporary SavePartVars object to the real one
|
||||
vars.readFromRaw(vars_from_file.data(), 0, fileSize);
|
||||
}
|
||||
}
|
||||
|
||||
SaveWriter writer(1, 0, fileName);
|
||||
if (ptrRaw) {
|
||||
// Write data from raw pointer
|
||||
vars.readFromRaw(ptrRaw, offset, size);
|
||||
} else {
|
||||
// Write data from variables
|
||||
if (!vars.readFrom((uint16) dataVar, offset, size))
|
||||
return false;
|
||||
}
|
||||
|
||||
return writer.writePart(0, &vars);
|
||||
}
|
||||
|
||||
bool SaveLoad_Adibou1::GameFileHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
return save(nullptr, dataVar, size, offset);
|
||||
}
|
||||
|
||||
bool SaveLoad_Adibou1::GameFileHandler::deleteFile() {
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
SaveWriter writer(1, 0, fileName);
|
||||
return writer.deleteFile();
|
||||
}
|
||||
|
||||
const SaveLoad_Adibou1::SaveFile *SaveLoad_Adibou1::getSaveFile(const char *fileName) const {
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SaveLoad_Adibou1::SaveFile *SaveLoad_Adibou1::getSaveFile(const char *fileName) {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad_Adibou1::getHandler(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *SaveLoad_Adibou1::getDescription(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->description;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad_Adibou1::getSaveMode(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->mode;
|
||||
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
324
engines/gob/save/saveload_fascin.cpp
Normal file
324
engines/gob/save/saveload_fascin.cpp
Normal file
@@ -0,0 +1,324 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/inter.h"
|
||||
#include "gob/variables.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad_Fascination::SaveFile SaveLoad_Fascination::_saveFiles[] = {
|
||||
{ "cat.cat", kSaveModeSave, -1, nullptr, "savegame catalog"},
|
||||
{ "save0.inf", kSaveModeSave, 0, nullptr, "savegame"},
|
||||
{ "save1.inf", kSaveModeSave, 1, nullptr, "savegame"},
|
||||
{ "save2.inf", kSaveModeSave, 2, nullptr, "savegame"},
|
||||
{ "save3.inf", kSaveModeSave, 3, nullptr, "savegame"},
|
||||
{ "save4.inf", kSaveModeSave, 4, nullptr, "savegame"},
|
||||
{ "save5.inf", kSaveModeSave, 5, nullptr, "savegame"},
|
||||
{ "save6.inf", kSaveModeSave, 6, nullptr, "savegame"},
|
||||
{ "save7.inf", kSaveModeSave, 7, nullptr, "savegame"},
|
||||
{ "save8.inf", kSaveModeSave, 8, nullptr, "savegame"},
|
||||
{ "save9.inf", kSaveModeSave, 9, nullptr, "savegame"},
|
||||
{ "save10.inf", kSaveModeSave, 10, nullptr, "savegame"},
|
||||
{ "save11.inf", kSaveModeSave, 11, nullptr, "savegame"},
|
||||
{ "save12.inf", kSaveModeSave, 12, nullptr, "savegame"},
|
||||
{ "save13.inf", kSaveModeSave, 13, nullptr, "savegame"},
|
||||
{ "save14.inf", kSaveModeSave, 14, nullptr, "savegame"},
|
||||
};
|
||||
|
||||
|
||||
SaveLoad_Fascination::GameHandler::File::File(GobEngine *vm, const char *base) :
|
||||
SlotFileIndexed(vm, SaveLoad_Fascination::kSlotCount, base, "s") {
|
||||
}
|
||||
|
||||
SaveLoad_Fascination::GameHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_Fascination::GameHandler::File::getSlot(int32 offset) const {
|
||||
return ((offset - kIndexSize) / 320);
|
||||
}
|
||||
|
||||
int SaveLoad_Fascination::GameHandler::File::getSlotRemainder(int32 offset) const {
|
||||
return ((offset - kIndexSize) % 320);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Fascination::GameHandler::GameHandler(GobEngine *vm, const char *target,
|
||||
int slot, byte *index, bool *hasIndex) : SaveHandler(vm) {
|
||||
|
||||
_index = index;
|
||||
_hasIndex = hasIndex;
|
||||
|
||||
_slot = slot;
|
||||
|
||||
_slotFile = new File(vm, target);
|
||||
}
|
||||
|
||||
SaveLoad_Fascination::GameHandler::~GameHandler() {
|
||||
delete _slotFile;
|
||||
}
|
||||
|
||||
int32 SaveLoad_Fascination::GameHandler::getSize() {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return _slotFile->tallyUpFiles(varSize, kIndexSize);
|
||||
}
|
||||
|
||||
bool SaveLoad_Fascination::GameHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to load all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if ((offset == 0) && (_slot == -1)) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Requested index has wrong size (%d)", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create/Fake the index
|
||||
buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar));
|
||||
|
||||
} else {
|
||||
// Load slot
|
||||
|
||||
uint32 slot = _slot;
|
||||
int slotRem = 0;
|
||||
if (_slot == -1) {
|
||||
slot = _slotFile->getSlot(offset);
|
||||
slotRem = _slotFile->getSlotRemainder(offset);
|
||||
}
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Loading from slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) || (size != 320)) {
|
||||
warning("Invalid loading procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
SaveReader *reader = nullptr;
|
||||
|
||||
// New save, load directly
|
||||
reader = new SaveReader(2, slot, slotFile);
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, size);
|
||||
|
||||
if (!reader->load()) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reader->readPart(0, &info)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
if (!reader->readPart(1, &vars)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get all variables
|
||||
if (!vars.writeInto(dataVar, 0, size)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete reader;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_Fascination::GameHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if ((_slot == -1) && (offset == 0) && (size == 5400))
|
||||
// Initialize empty file
|
||||
return true;
|
||||
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to save all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if ((offset == 0) && (_slot == -1)) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Requested index has wrong size (%d)", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just copy the index into our buffer
|
||||
_vm->_inter->_variables->copyTo(dataVar, _index, kIndexSize);
|
||||
*_hasIndex = true;
|
||||
|
||||
} else {
|
||||
// Save slot
|
||||
|
||||
uint32 slot = _slot;
|
||||
int slotRem = 0;
|
||||
if (_slot == -1) {
|
||||
slot = _slotFile->getSlot(offset);
|
||||
slotRem = _slotFile->getSlotRemainder(offset);
|
||||
}
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Saving to slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) || (size != 320)) {
|
||||
warning("Invalid saving procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
// An index is needed for the save slot description
|
||||
if (!*_hasIndex) {
|
||||
warning("No index written yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
*_hasIndex = false;
|
||||
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
SaveWriter writer(2, slot, slotFile);
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, size);
|
||||
|
||||
// Write the description
|
||||
info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength);
|
||||
// Write all variables
|
||||
if (!vars.readFrom(dataVar, 0, size))
|
||||
return false;
|
||||
|
||||
if (!writer.writePart(0, &info))
|
||||
return false;
|
||||
if (!writer.writePart(1, &vars))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SaveLoad_Fascination::GameHandler::buildIndex(byte *buffer) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(),
|
||||
0, _vm->getEndianness(), varSize);
|
||||
|
||||
_slotFile->buildIndex(buffer, info, nullptr);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Fascination::SaveLoad_Fascination(GobEngine *vm, const char *targetName) :
|
||||
SaveLoad(vm) {
|
||||
|
||||
memset(_index, 0, kIndexSize);
|
||||
_hasIndex = false;
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
_saveFiles[i].handler = new GameHandler(vm, targetName, _saveFiles[i].slot, _index, &_hasIndex);
|
||||
}
|
||||
|
||||
SaveLoad_Fascination::~SaveLoad_Fascination() {
|
||||
for (int i = 0; i < 16; i++)
|
||||
delete _saveFiles[i].handler;
|
||||
}
|
||||
|
||||
const SaveLoad_Fascination::SaveFile *SaveLoad_Fascination::getSaveFile(const char *fileName) const {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_Fascination::SaveFile *SaveLoad_Fascination::getSaveFile(const char *fileName) {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad_Fascination::getHandler(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->handler;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *SaveLoad_Fascination::getDescription(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->description;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad_Fascination::getSaveMode(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->mode;
|
||||
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
220
engines/gob/save/saveload_geisha.cpp
Normal file
220
engines/gob/save/saveload_geisha.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/inter.h"
|
||||
#include "gob/variables.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad_Geisha::SaveFile SaveLoad_Geisha::_saveFiles[] = {
|
||||
{"save.inf", kSaveModeSave, nullptr, "savegame"},
|
||||
};
|
||||
|
||||
|
||||
SaveLoad_Geisha::GameHandler::File::File(GobEngine *vm, const Common::String &base) :
|
||||
SlotFileIndexed(vm, SaveLoad_Geisha::kSlotCount, base, "s") {
|
||||
|
||||
}
|
||||
|
||||
SaveLoad_Geisha::GameHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_Geisha::GameHandler::File::getSlot(int32 offset) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveLoad_Geisha::GameHandler::File::getSlotRemainder(int32 offset) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Geisha::GameHandler::GameHandler(GobEngine *vm, const Common::String &target) :
|
||||
SaveHandler(vm), _file(vm, target) {
|
||||
|
||||
}
|
||||
|
||||
SaveLoad_Geisha::GameHandler::~GameHandler() {
|
||||
}
|
||||
|
||||
int32 SaveLoad_Geisha::GameHandler::getSize() {
|
||||
if (_file.getSlotMax() == 0)
|
||||
return -1;
|
||||
|
||||
return SaveLoad_Geisha::kSaveFileSize;
|
||||
}
|
||||
|
||||
bool SaveLoad_Geisha::GameHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if ((size != 0) || (offset != 0)) {
|
||||
warning("Invalid loading procedure: %d, %d, %d", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(_vm->_inter->_variables->getAddressOff8(dataVar), 0, SaveLoad_Geisha::kSaveFileSize);
|
||||
|
||||
for (uint32 slot = 0; slot < SaveLoad_Geisha::kSlotCount;
|
||||
slot++, dataVar += SaveLoad_Geisha::kSlotSize) {
|
||||
|
||||
if (!_file.exists(slot))
|
||||
continue;
|
||||
|
||||
Common::String slotFile = _file.build(slot);
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
SaveReader reader(2, slot, slotFile);
|
||||
if (!reader.load()) {
|
||||
warning("Save slot %d contains corrupted save", slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
SavePartInfo info(20, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), _vm->_inter->_variables->getSize());
|
||||
SavePartVars vars(_vm, SaveLoad_Geisha::kSlotSize);
|
||||
|
||||
if (!reader.readPart(0, &info) || !reader.readPart(1, &vars)) {
|
||||
warning("Save slot %d contains corrupted save", slot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!vars.writeInto(dataVar, 0, SaveLoad_Geisha::kSlotSize)) {
|
||||
warning("Save slot %d contains corrupted save", slot);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_Geisha::GameHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (((uint32)size != SaveLoad_Geisha::kSaveFileSize) || (offset != 0)) {
|
||||
warning("Invalid saving procedure: %d, %d, %d", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32 slot = 0; slot < SaveLoad_Geisha::kSlotCount;
|
||||
slot++, dataVar += SaveLoad_Geisha::kSlotSize) {
|
||||
|
||||
const byte *slotData = _vm->_inter->_variables->getAddressOff8(dataVar);
|
||||
|
||||
// Check of the slot's data is empty
|
||||
bool empty = true;
|
||||
for (uint32 j = 0; j < SaveLoad_Geisha::kSlotSize; j++) {
|
||||
if (slotData[j] != 0) {
|
||||
empty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't save empty slots
|
||||
if (empty)
|
||||
continue;
|
||||
|
||||
Common::String slotFile = _file.build(slot);
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
SaveWriter writer(2, slot, slotFile);
|
||||
|
||||
SavePartInfo info(20, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), _vm->_inter->_variables->getSize());
|
||||
SavePartVars vars(_vm, SaveLoad_Geisha::kSlotSize);
|
||||
|
||||
info.setDesc(Common::String::format("Geisha, slot %d", slot).c_str());
|
||||
if (!vars.readFrom(dataVar, 0, SaveLoad_Geisha::kSlotSize))
|
||||
return false;
|
||||
|
||||
if (!writer.writePart(0, &info))
|
||||
return false;
|
||||
if (!writer.writePart(1, &vars))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Geisha::SaveLoad_Geisha(GobEngine *vm, const char *targetName) :
|
||||
SaveLoad(vm) {
|
||||
|
||||
_saveFiles[0].handler = new GameHandler(vm, targetName);
|
||||
}
|
||||
|
||||
SaveLoad_Geisha::~SaveLoad_Geisha() {
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
delete _saveFiles[i].handler;
|
||||
}
|
||||
|
||||
const SaveLoad_Geisha::SaveFile *SaveLoad_Geisha::getSaveFile(const char *fileName) const {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_Geisha::SaveFile *SaveLoad_Geisha::getSaveFile(const char *fileName) {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad_Geisha::getHandler(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->handler;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *SaveLoad_Geisha::getDescription(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->description;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad_Geisha::getSaveMode(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->mode;
|
||||
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
454
engines/gob/save/saveload_inca2.cpp
Normal file
454
engines/gob/save/saveload_inca2.cpp
Normal file
@@ -0,0 +1,454 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/global.h"
|
||||
#include "gob/inter.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad_Inca2::SaveFile SaveLoad_Inca2::_saveFiles[] = {
|
||||
{"speak.inf", kSaveModeExists, nullptr, nullptr}, // Exists = speech enabled
|
||||
{"voice.inf", kSaveModeSave , nullptr, nullptr}, // Contains the language of the voices
|
||||
{"intro.$$$", kSaveModeSave , nullptr, "temporary sprite"},
|
||||
{ "cat.inf", kSaveModeSave , nullptr, "savegame"},
|
||||
{ "ima.inf", kSaveModeSave , nullptr, "screenshot"},
|
||||
};
|
||||
|
||||
|
||||
SaveLoad_Inca2::GameHandler::File::File(GobEngine *vm, const char *base) :
|
||||
SlotFileIndexed(vm, SaveLoad_Inca2::kSlotCount, base, "s") {
|
||||
}
|
||||
|
||||
SaveLoad_Inca2::GameHandler::File::File(const File &file) :
|
||||
SlotFileIndexed(file._vm, file._slotCount, file._base, file._ext) {
|
||||
}
|
||||
|
||||
SaveLoad_Inca2::GameHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_Inca2::GameHandler::File::getSlot(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return offset - kPropsSize;
|
||||
}
|
||||
|
||||
int SaveLoad_Inca2::GameHandler::File::getSlotRemainder(int32 offset) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Inca2::GameHandler::GameHandler(GobEngine *vm, const char *target) :
|
||||
SaveHandler(vm) {
|
||||
|
||||
_slotFile = new File(vm, target);
|
||||
|
||||
memset(_props, 0x00, kPropsSize);
|
||||
memset(_props, 0x20, 10);
|
||||
|
||||
_props[43] = 0x01;
|
||||
_props[79] = 0x03;
|
||||
|
||||
buildIndex();
|
||||
|
||||
_writer = nullptr;
|
||||
_reader = nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_Inca2::GameHandler::~GameHandler() {
|
||||
delete _slotFile;
|
||||
delete _reader;
|
||||
delete _writer;
|
||||
}
|
||||
|
||||
int32 SaveLoad_Inca2::GameHandler::getSize() {
|
||||
return _slotFile->tallyUpFiles(1, kPropsSize);
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::GameHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Global properties, like joker usage
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Loading global properties");
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong global properties list size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((uint32) (offset + size)) >= kPropsSize)
|
||||
buildIndex();
|
||||
|
||||
_vm->_inter->_variables->copyFrom(dataVar, _props + offset, size);
|
||||
|
||||
} else {
|
||||
int32 slot = offset - kPropsSize;
|
||||
|
||||
if ((size != 1) || (slot < 0) || ((uint32)slot >= kSlotCount)) {
|
||||
warning("Invalid loading procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
WRITE_VARO_UINT8(dataVar, 0);
|
||||
if (!createReader(slot))
|
||||
return true;
|
||||
|
||||
SavePartInfo info(0, (uint32) _vm->getGameType(), 0, _vm->getEndianness(), 1);
|
||||
SavePartVars vars(_vm, 1);
|
||||
|
||||
if (!_reader->readPart(0, &info))
|
||||
return true;
|
||||
if (!_reader->readPart(1, &vars))
|
||||
return true;
|
||||
|
||||
// Read the save point number
|
||||
if (!vars.writeInto(dataVar, 0, 1)) {
|
||||
WRITE_VARO_UINT8(dataVar, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::GameHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Global properties, like joker usage
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Saving global properties");
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong global properties list size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyTo(dataVar, _props + offset, size);
|
||||
|
||||
} else {
|
||||
// Save point flag
|
||||
|
||||
int32 slot = offset - kPropsSize;
|
||||
|
||||
if ((size != 1) || (slot < 0) || ((uint32)slot >= kSlotCount)) {
|
||||
warning("Invalid saving procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!createWriter(slot))
|
||||
return false;
|
||||
|
||||
SavePartInfo info(0, (uint32) _vm->getGameType(), 0, _vm->getEndianness(), 1);
|
||||
SavePartVars vars(_vm, 1);
|
||||
|
||||
// Write the save point number
|
||||
if (!vars.readFrom(dataVar, 0, 1))
|
||||
return false;
|
||||
|
||||
if (!_writer->writePart(0, &info))
|
||||
return false;
|
||||
if (!_writer->writePart(1, &vars))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::GameHandler::saveScreenshot(int slot,
|
||||
const SavePartSprite *screenshot) {
|
||||
|
||||
if (!createWriter(slot))
|
||||
return false;
|
||||
|
||||
return _writer->writePart(2, screenshot);
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::GameHandler::loadScreenshot(int slot,
|
||||
SavePartSprite *screenshot) {
|
||||
|
||||
if (!createReader(slot))
|
||||
return false;
|
||||
|
||||
return _reader->readPart(2, screenshot);
|
||||
}
|
||||
|
||||
void SaveLoad_Inca2::GameHandler::buildIndex() {
|
||||
_props[499] = _slotFile->getSlotMax();
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::GameHandler::createReader(int slot) {
|
||||
// If slot < 0, just check if a reader exists
|
||||
if (slot < 0)
|
||||
return (_reader != nullptr);
|
||||
|
||||
if (!_reader || (_reader->getSlot() != ((uint32) slot))) {
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
delete _reader;
|
||||
|
||||
_reader = new SaveReader(3, slot, slotFile);
|
||||
|
||||
if (!_reader->load()) {
|
||||
delete _reader;
|
||||
_reader = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::GameHandler::createWriter(int slot) {
|
||||
// If slot < 0, just check if a writer exists
|
||||
if (slot < 0)
|
||||
return (_writer != nullptr);
|
||||
|
||||
if (!_writer || (_writer->getSlot() != ((uint32) slot))) {
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
delete _writer;
|
||||
_writer = new SaveWriter(3, slot, slotFile);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Inca2::ScreenshotHandler::File::File(const SaveLoad_Inca2::GameHandler::File &file) : SaveLoad_Inca2::GameHandler::File(file) {
|
||||
|
||||
}
|
||||
|
||||
SaveLoad_Inca2::ScreenshotHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_Inca2::ScreenshotHandler::File::getSlot(int32 offset) const {
|
||||
return (offset - 80) / 15168;
|
||||
}
|
||||
|
||||
int SaveLoad_Inca2::ScreenshotHandler::File::getSlotRemainder(int32 offset) const {
|
||||
return (offset - 80) % 15168;
|
||||
}
|
||||
|
||||
void SaveLoad_Inca2::ScreenshotHandler::File::buildScreenshotIndex(byte *buffer) const {
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::InSaveFile *in;
|
||||
|
||||
for (uint32 i = 0; i < 40; i++, buffer++) {
|
||||
Common::String slotFile = build(i);
|
||||
|
||||
if (!slotFile.empty() && ((in = saveMan->openForLoading(slotFile)))) {
|
||||
delete in;
|
||||
*buffer = 1;
|
||||
} else
|
||||
*buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Inca2::ScreenshotHandler::ScreenshotHandler(GobEngine *vm,
|
||||
GameHandler *gameHandler) : TempSpriteHandler(vm) {
|
||||
|
||||
assert(gameHandler);
|
||||
|
||||
_gameHandler = gameHandler;
|
||||
|
||||
_file = new File(*_gameHandler->_slotFile);
|
||||
|
||||
memset(_index, 0, 80);
|
||||
}
|
||||
|
||||
SaveLoad_Inca2::ScreenshotHandler::~ScreenshotHandler() {
|
||||
delete _file;
|
||||
}
|
||||
|
||||
int32 SaveLoad_Inca2::ScreenshotHandler::getSize() {
|
||||
return _file->tallyUpFiles(15168, 80);
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::ScreenshotHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (offset < 80) {
|
||||
// Screenshot index list
|
||||
|
||||
if ((size + offset) > 80) {
|
||||
warning("Wrong screenshot index offset (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create/Fake the index
|
||||
_file->buildScreenshotIndex(_index + 40);
|
||||
|
||||
_vm->_inter->_variables->copyFrom(dataVar, _index + offset, size);
|
||||
|
||||
} else {
|
||||
// Screenshot
|
||||
|
||||
uint32 slot = _file->getSlot(offset);
|
||||
int slotRem = _file->getSlotRemainder(offset);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0)) {
|
||||
warning("Invalid screenshot loading procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TempSpriteHandler::createFromSprite(dataVar, size, offset))
|
||||
return false;
|
||||
|
||||
if (!_gameHandler->loadScreenshot(slot, _sprite))
|
||||
return false;
|
||||
|
||||
if (!TempSpriteHandler::load(dataVar, size, offset))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::ScreenshotHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (offset < 80) {
|
||||
// Index, we'll ignore that
|
||||
|
||||
} else {
|
||||
// Screenshot
|
||||
|
||||
uint32 slot = _file->getSlot(offset);
|
||||
int slotRem = _file->getSlotRemainder(offset);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0)) {
|
||||
warning("Invalid screenshot saving procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TempSpriteHandler::save(dataVar, size, offset))
|
||||
return false;
|
||||
|
||||
return _gameHandler->saveScreenshot(slot, _sprite);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Inca2::VoiceHandler::VoiceHandler(GobEngine *vm) : SaveHandler(vm) {
|
||||
}
|
||||
|
||||
SaveLoad_Inca2::VoiceHandler::~VoiceHandler() {
|
||||
}
|
||||
|
||||
int32 SaveLoad_Inca2::VoiceHandler::getSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::VoiceHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if ((size != 1) || (offset != 0)) {
|
||||
warning("Invalid voice language loading?!? (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
WRITE_VARO_UINT8(dataVar, _vm->_global->_language);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_Inca2::VoiceHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Inca2::SaveLoad_Inca2(GobEngine *vm, const char *targetName) : SaveLoad(vm) {
|
||||
_voiceHandler = new VoiceHandler(vm);
|
||||
_tempSpriteHandler = new TempSpriteHandler(vm);
|
||||
_gameHandler = new GameHandler(vm, targetName);
|
||||
_screenshotHandler = new ScreenshotHandler(vm, _gameHandler);
|
||||
|
||||
_saveFiles[1].handler = _voiceHandler;
|
||||
_saveFiles[2].handler = _tempSpriteHandler;
|
||||
_saveFiles[3].handler = _gameHandler;
|
||||
_saveFiles[4].handler = _screenshotHandler;
|
||||
}
|
||||
|
||||
SaveLoad_Inca2::~SaveLoad_Inca2() {
|
||||
delete _voiceHandler;
|
||||
}
|
||||
|
||||
const SaveLoad_Inca2::SaveFile *SaveLoad_Inca2::getSaveFile(const char *fileName) const {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_Inca2::SaveFile *SaveLoad_Inca2::getSaveFile(const char *fileName) {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad_Inca2::getHandler(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->handler;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *SaveLoad_Inca2::getDescription(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->description;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad_Inca2::getSaveMode(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->mode;
|
||||
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
364
engines/gob/save/saveload_playtoons.cpp
Normal file
364
engines/gob/save/saveload_playtoons.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/inter.h"
|
||||
#include "gob/variables.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad_Playtoons::SaveFile SaveLoad_Playtoons::_saveFiles[] = {
|
||||
{ "did.inf", kSaveModeSave, nullptr, nullptr}, // Purpose ignored at the moment, intensively used to save things.
|
||||
{ "dan.itk", kSaveModeNone, nullptr, nullptr}, // Playtoons CK detection file
|
||||
{ "cat.inf", kSaveModeNone, nullptr, nullptr},
|
||||
{ "titre.009", kSaveModeIgnore, nullptr, nullptr}, // Playtoons theoritical title files that are checked for nothing
|
||||
{ "titre.010", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.011", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.012", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.013", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.014", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.015", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.016", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.017", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.018", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.019", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.020", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.021", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.022", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.023", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.024", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.025", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.026", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.027", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.028", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.029", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.030", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.031", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.032", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.033", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.034", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.035", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.036", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.037", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.038", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "titre.039", kSaveModeIgnore, nullptr, nullptr},
|
||||
};
|
||||
|
||||
SaveLoad_Playtoons::GameHandler::File::File(GobEngine *vm, const char *base) :
|
||||
SlotFileIndexed(vm, SaveLoad_Playtoons::kSlotCount, base, "s") {
|
||||
}
|
||||
|
||||
SaveLoad_Playtoons::GameHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_Playtoons::GameHandler::File::getSlot(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - (kPropsSize + kIndexSize)) / varSize);
|
||||
}
|
||||
|
||||
int SaveLoad_Playtoons::GameHandler::File::getSlotRemainder(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - (kPropsSize + kIndexSize)) % varSize);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Playtoons::GameHandler::GameHandler(GobEngine *vm, const char *target) : SaveHandler(vm) {
|
||||
memset(_props, 0, kPropsSize);
|
||||
memset(_index, 0, kIndexSize);
|
||||
|
||||
_tempSpriteHandler = new TempSpriteHandler(vm);
|
||||
_slotFile = new File(vm, target);
|
||||
}
|
||||
|
||||
SaveLoad_Playtoons::GameHandler::~GameHandler() {
|
||||
delete _slotFile;
|
||||
delete _tempSpriteHandler;
|
||||
}
|
||||
|
||||
int32 SaveLoad_Playtoons::GameHandler::getSize() {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return _slotFile->tallyUpFiles(varSize, kPropsSize + kIndexSize);
|
||||
}
|
||||
|
||||
bool SaveLoad_Playtoons::GameHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize;
|
||||
|
||||
if (size < 0) {
|
||||
// Load a temporary sprite
|
||||
debugC(2, kDebugSaveLoad, "Loading temporary sprite %d at pos %d", size, offset);
|
||||
_tempSpriteHandler->load(dataVar, size, offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to load all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Properties
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong index size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyFrom(dataVar, _props + offset, size);
|
||||
|
||||
} else if (((uint32) offset) < kPropsSize + kIndexSize) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Wrong index size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar));
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Loading from slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid loading procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
SaveReader *reader = nullptr;
|
||||
|
||||
// New save, load directly
|
||||
reader = new SaveReader(2, slot, slotFile);
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
if (!reader->load()) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reader->readPart(0, &info)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
if (!reader->readPart(1, &vars)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get all variables
|
||||
if (!vars.writeInto(0, 0, varSize)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete reader;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_Playtoons::GameHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize;
|
||||
|
||||
if (size < 0) {
|
||||
// Save a temporary sprite
|
||||
debugC(2, kDebugSaveLoad, "Saving temporary sprite %d at pos %d", size, offset);
|
||||
_tempSpriteHandler->save(dataVar, size, offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to save all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Properties
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong index size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyTo(dataVar, _props + offset, size);
|
||||
|
||||
} else if (((uint32) offset) < kPropsSize + kIndexSize) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Wrong index size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just copy the index into our buffer
|
||||
_vm->_inter->_variables->copyTo(dataVar, _index, kIndexSize);
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Saving to slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid saving procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
SaveWriter writer(2, slot, slotFile);
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
// Write the description
|
||||
info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength);
|
||||
// Write all variables
|
||||
if (!vars.readFrom(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
if (!writer.writePart(0, &info))
|
||||
return false;
|
||||
if (!writer.writePart(1, &vars))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SaveLoad_Playtoons::GameHandler::buildIndex(byte *buffer) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(),
|
||||
0, _vm->getEndianness(), varSize);
|
||||
|
||||
_slotFile->buildIndex(buffer, info, nullptr);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_Playtoons::SaveLoad_Playtoons(GobEngine *vm, const char *targetName) :
|
||||
SaveLoad(vm) {
|
||||
|
||||
_gameHandler = new GameHandler(vm, targetName);
|
||||
|
||||
_saveFiles[0].handler = _gameHandler;
|
||||
}
|
||||
|
||||
SaveLoad_Playtoons::~SaveLoad_Playtoons() {
|
||||
delete _gameHandler;
|
||||
}
|
||||
|
||||
const SaveLoad_Playtoons::SaveFile *SaveLoad_Playtoons::getSaveFile(const char *fileName) const {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_Playtoons::SaveFile *SaveLoad_Playtoons::getSaveFile(const char *fileName) {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad_Playtoons::getHandler(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->handler;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *SaveLoad_Playtoons::getDescription(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->description;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad_Playtoons::getSaveMode(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->mode;
|
||||
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
325
engines/gob/save/saveload_v2.cpp
Normal file
325
engines/gob/save/saveload_v2.cpp
Normal file
@@ -0,0 +1,325 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/inter.h"
|
||||
#include "gob/variables.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad_v2::SaveFile SaveLoad_v2::_saveFiles[] = {
|
||||
{ "cat.inf", kSaveModeSave, nullptr, "savegame"},
|
||||
{ "cat.cat", kSaveModeSave, nullptr, "savegame"}, // Alternative file
|
||||
{ "save.inf", kSaveModeSave, nullptr, "temporary sprite"},
|
||||
{ "bloc.inf", kSaveModeSave, nullptr, "notes"},
|
||||
};
|
||||
|
||||
|
||||
SaveLoad_v2::GameHandler::File::File(GobEngine *vm, const char *base) :
|
||||
SlotFileIndexed(vm, SaveLoad_v2::kSlotCount, base, "s") {
|
||||
}
|
||||
|
||||
SaveLoad_v2::GameHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_v2::GameHandler::File::getSlot(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - kIndexSize) / varSize);
|
||||
}
|
||||
|
||||
int SaveLoad_v2::GameHandler::File::getSlotRemainder(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - kIndexSize) % varSize);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v2::GameHandler::GameHandler(GobEngine *vm, const char *target) : SaveHandler(vm) {
|
||||
memset(_index, 0, kIndexSize);
|
||||
_hasIndex = false;
|
||||
|
||||
_slotFile = new File(vm, target);
|
||||
}
|
||||
|
||||
SaveLoad_v2::GameHandler::~GameHandler() {
|
||||
delete _slotFile;
|
||||
}
|
||||
|
||||
int32 SaveLoad_v2::GameHandler::getSize() {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return _slotFile->tallyUpFiles(varSize, kIndexSize);
|
||||
}
|
||||
|
||||
bool SaveLoad_v2::GameHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to load all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (offset == 0) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Requested index has wrong size (%d)", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create/Fake the index
|
||||
buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar));
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Loading from slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid loading procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
SaveReader *reader = nullptr;
|
||||
SaveConverter_v2 converter(_vm, slotFile);
|
||||
|
||||
if (converter.isOldSave()) {
|
||||
// Old save, plug the converter in
|
||||
if (!converter.load())
|
||||
return false;
|
||||
|
||||
reader = new SaveReader(2, slot, converter);
|
||||
|
||||
} else
|
||||
// New save, load directly
|
||||
reader = new SaveReader(2, slot, slotFile);
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
if (!reader->load()) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reader->readPart(0, &info)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
if (!reader->readPart(1, &vars)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get all variables
|
||||
if (!vars.writeInto(0, 0, varSize)) {
|
||||
delete reader;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete reader;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v2::GameHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to save all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (offset == 0) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Requested index has wrong size (%d)", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just copy the index into our buffer
|
||||
_vm->_inter->_variables->copyTo(dataVar, _index, kIndexSize);
|
||||
_hasIndex = true;
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Saving to slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid saving procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
// An index is needed for the save slot description
|
||||
if (!_hasIndex) {
|
||||
warning("No index written yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
_hasIndex = false;
|
||||
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
SaveWriter writer(2, slot, slotFile);
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
// Write the description
|
||||
info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength);
|
||||
// Write all variables
|
||||
if (!vars.readFrom(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
if (!writer.writePart(0, &info))
|
||||
return false;
|
||||
if (!writer.writePart(1, &vars))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SaveLoad_v2::GameHandler::buildIndex(byte *buffer) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(),
|
||||
0, _vm->getEndianness(), varSize);
|
||||
|
||||
SaveConverter_v2 converter(_vm);
|
||||
|
||||
_slotFile->buildIndex(buffer, info, &converter);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v2::SaveLoad_v2(GobEngine *vm, const char *targetName) :
|
||||
SaveLoad(vm) {
|
||||
|
||||
_gameHandler = new GameHandler(vm, targetName);
|
||||
_notesHandler = new NotesHandler(600, vm, targetName);
|
||||
_tempSpriteHandler = new TempSpriteHandler(vm);
|
||||
|
||||
_saveFiles[0].handler = _gameHandler;
|
||||
_saveFiles[1].handler = _gameHandler;
|
||||
_saveFiles[2].handler = _tempSpriteHandler;
|
||||
_saveFiles[3].handler = _notesHandler;
|
||||
}
|
||||
|
||||
SaveLoad_v2::~SaveLoad_v2() {
|
||||
delete _gameHandler;
|
||||
delete _notesHandler;
|
||||
delete _tempSpriteHandler;
|
||||
}
|
||||
|
||||
const SaveLoad_v2::SaveFile *SaveLoad_v2::getSaveFile(const char *fileName) const {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_v2::SaveFile *SaveLoad_v2::getSaveFile(const char *fileName) {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad_v2::getHandler(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->handler;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *SaveLoad_v2::getDescription(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->description;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad_v2::getSaveMode(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->mode;
|
||||
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
564
engines/gob/save/saveload_v3.cpp
Normal file
564
engines/gob/save/saveload_v3.cpp
Normal file
@@ -0,0 +1,564 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/inter.h"
|
||||
#include "gob/variables.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad_v3::SaveFile SaveLoad_v3::_saveFiles[] = {
|
||||
{ "cat.inf", kSaveModeSave , nullptr, "savegame"},
|
||||
{ "ima.inf", kSaveModeSave , nullptr, "screenshot"},
|
||||
{ "intro.$$$", kSaveModeSave , nullptr, "temporary sprite"},
|
||||
{ "bloc.inf", kSaveModeSave , nullptr, "notes"},
|
||||
{ "prot", kSaveModeIgnore, nullptr, nullptr},
|
||||
{ "config", kSaveModeIgnore, nullptr, nullptr},
|
||||
};
|
||||
|
||||
|
||||
SaveLoad_v3::GameHandler::File::File(GobEngine *vm, const char *base) :
|
||||
SlotFileIndexed(vm, SaveLoad_v3::kSlotCount, base, "s") {
|
||||
}
|
||||
|
||||
SaveLoad_v3::GameHandler::File::File(const File &file) :
|
||||
SlotFileIndexed(file._vm, file._slotCount, file._base, file._ext) {
|
||||
}
|
||||
|
||||
SaveLoad_v3::GameHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_v3::GameHandler::File::getSlot(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - (kPropsSize + kIndexSize)) / varSize);
|
||||
}
|
||||
|
||||
int SaveLoad_v3::GameHandler::File::getSlotRemainder(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - (kPropsSize + kIndexSize)) % varSize);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v3::GameHandler::GameHandler(GobEngine *vm, const char *target,
|
||||
bool usesScreenshots) : SaveHandler(vm) {
|
||||
|
||||
_slotFile = new File(vm, target);
|
||||
|
||||
_usesScreenshots = usesScreenshots;
|
||||
|
||||
_firstSize = true;
|
||||
memset(_props, 0, kPropsSize);
|
||||
memset(_index, 0, kIndexSize);
|
||||
_hasIndex = false;
|
||||
|
||||
_writer = nullptr;
|
||||
_reader = nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_v3::GameHandler::~GameHandler() {
|
||||
delete _slotFile;
|
||||
delete _reader;
|
||||
delete _writer;
|
||||
}
|
||||
|
||||
int32 SaveLoad_v3::GameHandler::getSize() {
|
||||
// Fake an empty save file for the very first query, to get clear properties
|
||||
if (_firstSize) {
|
||||
_firstSize = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return _slotFile->tallyUpFiles(varSize, kPropsSize + kIndexSize);
|
||||
}
|
||||
|
||||
bool SaveLoad_v3::GameHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to load all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Global properties, like joker usage
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Loading global properties");
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong global properties list size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyFrom(dataVar, _props + offset, size);
|
||||
|
||||
} else if (((uint32) offset) == kPropsSize) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Requested index has wrong size (%d)", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create/Fake the index
|
||||
buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar));
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Loading from slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid saving procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
_hasIndex = false;
|
||||
|
||||
if (!createReader(slot))
|
||||
return false;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
if (!_reader->readPart(0, &info))
|
||||
return false;
|
||||
if (!_reader->readPart(1, &vars))
|
||||
return false;
|
||||
|
||||
// Get all variables
|
||||
if (!vars.writeInto(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v3::GameHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to save all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Global properties, like joker usage
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Saving global properties");
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong global properties list size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyTo(dataVar, _props + offset, size);
|
||||
|
||||
} else if (((uint32) offset) == kPropsSize) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Requested index has wrong size (%d)", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just copy the index into our buffer
|
||||
_vm->_inter->_variables->copyTo(dataVar, _index, kIndexSize);
|
||||
_hasIndex = true;
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Saving to slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid saving procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
// An index is needed for the save slot description
|
||||
if (!_hasIndex) {
|
||||
warning("No index written yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
_hasIndex = false;
|
||||
|
||||
if (!createWriter(slot))
|
||||
return false;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
// Write the description
|
||||
info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength);
|
||||
// Write all variables
|
||||
if (!vars.readFrom(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
if (!_writer->writePart(0, &info))
|
||||
return false;
|
||||
if (!_writer->writePart(1, &vars))
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v3::GameHandler::saveScreenshot(int slot,
|
||||
const SavePartSprite *screenshot) {
|
||||
|
||||
if (!createWriter(slot))
|
||||
return false;
|
||||
|
||||
return _writer->writePart(2, screenshot);
|
||||
}
|
||||
|
||||
bool SaveLoad_v3::GameHandler::loadScreenshot(int slot,
|
||||
SavePartSprite *screenshot) {
|
||||
|
||||
if (!createReader(slot))
|
||||
return false;
|
||||
|
||||
return _reader->readPart(2, screenshot);
|
||||
}
|
||||
|
||||
void SaveLoad_v3::GameHandler::buildIndex(byte *buffer) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return;
|
||||
|
||||
SavePartInfo info(40, (uint32) _vm->getGameType(), 0, _vm->getEndianness(), varSize);
|
||||
|
||||
SaveConverter_v3 converter(_vm);
|
||||
|
||||
_slotFile->buildIndex(buffer, info, &converter);
|
||||
}
|
||||
|
||||
bool SaveLoad_v3::GameHandler::createReader(int slot) {
|
||||
// If slot < 0, just check if a reader exists
|
||||
if (slot < 0)
|
||||
return (_reader != nullptr);
|
||||
|
||||
if (!_reader || (_reader->getSlot() != ((uint32) slot))) {
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
delete _reader;
|
||||
|
||||
SaveConverter_v3 converter(_vm, slotFile);
|
||||
if (converter.isOldSave()) {
|
||||
// Old save, plug the converter in
|
||||
if (!converter.load()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_reader = new SaveReader(_usesScreenshots ? 3 : 2, slot, converter);
|
||||
|
||||
} else
|
||||
_reader = new SaveReader(_usesScreenshots ? 3 : 2, slot, slotFile);
|
||||
|
||||
if (!_reader->load()) {
|
||||
delete _reader;
|
||||
_reader = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v3::GameHandler::createWriter(int slot) {
|
||||
// If slot < 0, just check if a writer exists
|
||||
if (slot < 0)
|
||||
return (_writer != nullptr);
|
||||
|
||||
if (!_writer || (_writer->getSlot() != ((uint32) slot))) {
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
delete _writer;
|
||||
_writer = new SaveWriter(_usesScreenshots ? 3 : 2, slot, slotFile);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v3::ScreenshotHandler::File::File(const SaveLoad_v3::GameHandler::File &file,
|
||||
uint32 shotSize, uint32 shotIndexSize) : SaveLoad_v3::GameHandler::File(file) {
|
||||
|
||||
_shotSize = shotSize;
|
||||
_shotIndexSize = shotIndexSize;
|
||||
}
|
||||
|
||||
SaveLoad_v3::ScreenshotHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_v3::ScreenshotHandler::File::getSlot(int32 offset) const {
|
||||
return ((offset - _shotIndexSize) / _shotSize);
|
||||
}
|
||||
|
||||
int SaveLoad_v3::ScreenshotHandler::File::getSlotRemainder(int32 offset) const {
|
||||
return ((offset - _shotIndexSize) % _shotSize);
|
||||
}
|
||||
|
||||
void SaveLoad_v3::ScreenshotHandler::File::buildScreenshotIndex(byte *buffer) const {
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::InSaveFile *in;
|
||||
|
||||
for (uint32 i = 0; i < _slotCount; i++, buffer++) {
|
||||
Common::String slotFile = build(i);
|
||||
|
||||
if (!slotFile.empty() && ((in = saveMan->openForLoading(slotFile)))) {
|
||||
delete in;
|
||||
*buffer = 1;
|
||||
} else
|
||||
*buffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v3::ScreenshotHandler::ScreenshotHandler(GobEngine *vm,
|
||||
GameHandler *gameHandler, ScreenshotType sShotType) : TempSpriteHandler(vm) {
|
||||
|
||||
assert(gameHandler);
|
||||
|
||||
_gameHandler = gameHandler;
|
||||
_sShotType = sShotType;
|
||||
|
||||
_shotSize = (_sShotType == kScreenshotTypeLost) ? 4768 : 19968;
|
||||
_shotIndexSize = (_sShotType == kScreenshotTypeLost) ? 50 : 80;
|
||||
|
||||
_file = new File(*_gameHandler->_slotFile, _shotSize, _shotIndexSize);
|
||||
|
||||
memset(_index, 0, 80);
|
||||
}
|
||||
|
||||
SaveLoad_v3::ScreenshotHandler::~ScreenshotHandler() {
|
||||
delete _file;
|
||||
}
|
||||
|
||||
int32 SaveLoad_v3::ScreenshotHandler::getSize() {
|
||||
return _file->tallyUpFiles(_shotSize, _shotIndexSize);
|
||||
}
|
||||
|
||||
bool SaveLoad_v3::ScreenshotHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (offset < _shotIndexSize) {
|
||||
// Screenshot index list
|
||||
|
||||
if ((size + offset) > _shotIndexSize) {
|
||||
warning("Wrong screenshot index offset (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_sShotType == kScreenshotTypeGob3) {
|
||||
// Create/Fake the index
|
||||
_file->buildScreenshotIndex(_index + 40);
|
||||
// The last 10 bytes are 0
|
||||
memset(_index + 70, 0, 10);
|
||||
} else if (_sShotType == kScreenshotTypeLost) {
|
||||
// Create/Fake the index
|
||||
_file->buildScreenshotIndex(_index);
|
||||
// The last byte is 0
|
||||
_index[30] = 0;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyFrom(dataVar, _index + offset, size);
|
||||
|
||||
} else {
|
||||
// Screenshot
|
||||
|
||||
uint32 slot = _file->getSlot(offset);
|
||||
int slotRem = _file->getSlotRemainder(offset);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0))
|
||||
return false;
|
||||
|
||||
if (!TempSpriteHandler::createFromSprite(dataVar, size, offset))
|
||||
return false;
|
||||
|
||||
if (!_gameHandler->loadScreenshot(slot, _sprite))
|
||||
return false;
|
||||
|
||||
if (!TempSpriteHandler::load(dataVar, size, offset))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v3::ScreenshotHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (offset < _shotIndexSize) {
|
||||
// Screenshot index list
|
||||
|
||||
if ((size + offset) > _shotIndexSize) {
|
||||
warning("Wrong screenshot index offset (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyTo(dataVar, _index + offset, size);
|
||||
|
||||
} else {
|
||||
// Screenshot
|
||||
|
||||
if (!TempSpriteHandler::save(dataVar, size, offset))
|
||||
return false;
|
||||
|
||||
uint32 slot = _file->getSlot(offset);
|
||||
int slotRem = _file->getSlotRemainder(offset);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0))
|
||||
return false;
|
||||
|
||||
return _gameHandler->saveScreenshot(slot, _sprite);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName, ScreenshotType sShotType) :
|
||||
SaveLoad(vm) {
|
||||
|
||||
_sShotType = sShotType;
|
||||
|
||||
// The Amiga version doesn't use screenshots
|
||||
if (_vm->getPlatform() == Common::kPlatformAmiga) {
|
||||
_gameHandler = new GameHandler(vm, targetName, false);
|
||||
_screenshotHandler = nullptr;
|
||||
} else {
|
||||
_gameHandler = new GameHandler(vm, targetName, true);
|
||||
_screenshotHandler = new ScreenshotHandler(vm, _gameHandler, sShotType);
|
||||
}
|
||||
|
||||
_tempSpriteHandler = new TempSpriteHandler(vm);
|
||||
_notesHandler = new NotesHandler(2560, vm, targetName);
|
||||
|
||||
_saveFiles[0].handler = _gameHandler;
|
||||
_saveFiles[1].handler = _screenshotHandler;
|
||||
_saveFiles[2].handler = _tempSpriteHandler;
|
||||
_saveFiles[3].handler = _notesHandler;
|
||||
}
|
||||
|
||||
SaveLoad_v3::~SaveLoad_v3() {
|
||||
delete _screenshotHandler;
|
||||
delete _gameHandler;
|
||||
delete _notesHandler;
|
||||
delete _tempSpriteHandler;
|
||||
}
|
||||
|
||||
const SaveLoad_v3::SaveFile *SaveLoad_v3::getSaveFile(const char *fileName) const {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_v3::SaveFile *SaveLoad_v3::getSaveFile(const char *fileName) {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad_v3::getHandler(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->handler;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *SaveLoad_v3::getDescription(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->description;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad_v3::getSaveMode(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->mode;
|
||||
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
566
engines/gob/save/saveload_v4.cpp
Normal file
566
engines/gob/save/saveload_v4.cpp
Normal file
@@ -0,0 +1,566 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/inter.h"
|
||||
#include "gob/variables.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad_v4::SaveFile SaveLoad_v4::_saveFiles[] = {
|
||||
{ "cat.inf", kSaveModeSave, nullptr, "savegame"},
|
||||
{ "save.tmp", kSaveModeSave, nullptr, "current screen properties"},
|
||||
{ "save0.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 0
|
||||
{ "save1.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 1
|
||||
{ "save2.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 2
|
||||
{ "save3.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 3
|
||||
{ "save4.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 4
|
||||
{ "save5.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 5
|
||||
{ "save6.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 6
|
||||
{ "save7.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 7
|
||||
{ "save8.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 8
|
||||
{ "save9.tmp", kSaveModeSave, nullptr, "savegame screen properties"}, // Slot 9
|
||||
};
|
||||
|
||||
|
||||
SaveLoad_v4::GameHandler::File::File(GobEngine *vm, const char *base) :
|
||||
SlotFileIndexed(vm, SaveLoad_v4::kSlotCount, base, "s") {
|
||||
}
|
||||
|
||||
SaveLoad_v4::GameHandler::File::File(const File &file) :
|
||||
SlotFileIndexed(file._vm, file._slotCount, file._base, file._ext) {
|
||||
}
|
||||
|
||||
SaveLoad_v4::GameHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_v4::GameHandler::File::getSlot(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - (kPropsSize + kIndexSize)) / varSize);
|
||||
}
|
||||
|
||||
int SaveLoad_v4::GameHandler::File::getSlotRemainder(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - (kPropsSize + kIndexSize)) % varSize);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v4::GameHandler::GameHandler(GobEngine *vm, const char *target) : SaveHandler(vm) {
|
||||
_firstSize = true;
|
||||
memset(_props, 0, kPropsSize);
|
||||
memset(_index, 0, kIndexSize);
|
||||
_hasIndex = false;
|
||||
|
||||
_slotFile = new File(vm, target);
|
||||
|
||||
_lastSlot = -1;
|
||||
|
||||
_writer = nullptr;
|
||||
_reader = nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_v4::GameHandler::~GameHandler() {
|
||||
delete _slotFile;
|
||||
delete _reader;
|
||||
delete _writer;
|
||||
}
|
||||
|
||||
int SaveLoad_v4::GameHandler::getLastSlot() const {
|
||||
return _lastSlot;
|
||||
}
|
||||
|
||||
int32 SaveLoad_v4::GameHandler::getSize() {
|
||||
// Fake an empty save file for the very first query, to get clear properties
|
||||
if (_firstSize) {
|
||||
_firstSize = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return _slotFile->tallyUpFiles(varSize, kPropsSize + kIndexSize);
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::GameHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to load all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Global properties
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Loading global properties");
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong global properties list size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyFrom(dataVar, _props + offset, size);
|
||||
|
||||
} else if (((uint32) offset) == kPropsSize) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Requested index has wrong size (%d)", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create/Fake the index
|
||||
buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar));
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Loading from slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid saving procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
_hasIndex = false;
|
||||
|
||||
if (!createReader(slot))
|
||||
return false;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
if (!_reader->readPart(0, &info))
|
||||
return false;
|
||||
if (!_reader->readPart(1, &vars))
|
||||
return false;
|
||||
|
||||
// Get all variables
|
||||
if (!vars.writeInto(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
_lastSlot = slot;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::GameHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to load all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Global properties
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Saving global properties");
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong global properties list size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyTo(dataVar, _props + offset, size);
|
||||
|
||||
} else if (((uint32) offset) == kPropsSize) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Requested index has wrong size (%d)", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just copy the index into our buffer
|
||||
_vm->_inter->_variables->copyTo(dataVar, _index, kIndexSize);
|
||||
_hasIndex = true;
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Saving to slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid saving procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
// An index is needed for the save slot description
|
||||
if (!_hasIndex) {
|
||||
warning("No index written yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
_hasIndex = false;
|
||||
|
||||
if (!createWriter(slot))
|
||||
return false;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
// Write the description
|
||||
info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength);
|
||||
// Write all variables
|
||||
if (!vars.readFrom(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
if (!_writer->writePart(0, &info))
|
||||
return false;
|
||||
if (!_writer->writePart(1, &vars))
|
||||
return false;
|
||||
|
||||
_lastSlot = slot;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::GameHandler::saveScreenProps(int slot, const byte *props) {
|
||||
if (!createWriter(slot))
|
||||
return false;
|
||||
|
||||
SavePartMem mem(256000);
|
||||
|
||||
if (!mem.readFrom(props, 0, 256000))
|
||||
return false;
|
||||
|
||||
return _writer->writePart(2, &mem);
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::GameHandler::loadScreenProps(int slot, byte *props) {
|
||||
if (!createReader(slot))
|
||||
return false;
|
||||
|
||||
SavePartMem mem(256000);
|
||||
|
||||
if (!_reader->readPart(2, &mem))
|
||||
return false;
|
||||
|
||||
if (!mem.writeInto(props, 0, 256000))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SaveLoad_v4::GameHandler::buildIndex(byte *buffer) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(),
|
||||
0, _vm->getEndianness(), varSize);
|
||||
|
||||
SaveConverter_v4 converter(_vm);
|
||||
|
||||
_slotFile->buildIndex(buffer, info, &converter);
|
||||
|
||||
// 400 bytes index + 800 bytes 0
|
||||
memset(buffer + 400, 0, 800);
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::GameHandler::createReader(int slot) {
|
||||
// If slot < 0, just check if a reader exists
|
||||
if (slot < 0)
|
||||
return (_reader != nullptr);
|
||||
|
||||
if (!_reader || (_reader->getSlot() != ((uint32) slot))) {
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
delete _reader;
|
||||
|
||||
SaveConverter_v4 converter(_vm, slotFile);
|
||||
if (converter.isOldSave()) {
|
||||
// Old save, plug the converter in
|
||||
if (!converter.load()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_reader = new SaveReader(3, slot, converter);
|
||||
|
||||
} else
|
||||
_reader = new SaveReader(3, slot, slotFile);
|
||||
|
||||
if (!_reader->load()) {
|
||||
delete _reader;
|
||||
_reader = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::GameHandler::createWriter(int slot) {
|
||||
// If slot < 0, just check if a writer exists
|
||||
if (slot < 0)
|
||||
return (_writer != nullptr);
|
||||
|
||||
if (!_writer || (_writer->getSlot() != ((uint32) slot))) {
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
delete _writer;
|
||||
_writer = new SaveWriter(3, slot, slotFile);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v4::CurScreenPropsHandler::CurScreenPropsHandler(GobEngine *vm) :
|
||||
SaveHandler(vm) {
|
||||
|
||||
_props = new byte[256000]();
|
||||
}
|
||||
|
||||
SaveLoad_v4::CurScreenPropsHandler::~CurScreenPropsHandler() {
|
||||
delete[] _props;
|
||||
}
|
||||
|
||||
int32 SaveLoad_v4::CurScreenPropsHandler::getSize() {
|
||||
return 256000;
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::CurScreenPropsHandler::load(int16 dataVar,
|
||||
int32 size, int32 offset) {
|
||||
|
||||
// Using a sprite as a buffer
|
||||
if (size <= 0)
|
||||
return true;
|
||||
|
||||
if ((offset < 0) || (size + offset) > 256000) {
|
||||
warning("Invalid size (%d) or offset (%d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Loading screen properties (%d, %d, %d)",
|
||||
dataVar, size, offset);
|
||||
|
||||
_vm->_inter->_variables->copyFrom(dataVar, _props + offset, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::CurScreenPropsHandler::save(int16 dataVar,
|
||||
int32 size, int32 offset) {
|
||||
|
||||
// Using a sprite as a buffer
|
||||
if (size <= 0)
|
||||
return true;
|
||||
|
||||
if ((offset < 0) || (size + offset) > 256000) {
|
||||
warning("Invalid size (%d) or offset (%d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(3, kDebugSaveLoad, "Saving screen properties (%d, %d, %d)",
|
||||
dataVar, size, offset);
|
||||
|
||||
_vm->_inter->_variables->copyTo(dataVar, _props + offset, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v4::ScreenPropsHandler::File::File(const SaveLoad_v4::GameHandler::File &file,
|
||||
uint32 slot) : SaveLoad_v4::GameHandler::File(file) {
|
||||
|
||||
_slot = slot;
|
||||
}
|
||||
|
||||
SaveLoad_v4::ScreenPropsHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_v4::ScreenPropsHandler::File::getSlot(int32 offset) const {
|
||||
return _slot;
|
||||
}
|
||||
|
||||
int SaveLoad_v4::ScreenPropsHandler::File::getSlotRemainder(int32 offset) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v4::ScreenPropsHandler::ScreenPropsHandler(GobEngine *vm, uint32 slot,
|
||||
CurScreenPropsHandler *curProps, GameHandler *gameHandler) : SaveHandler(vm) {
|
||||
|
||||
_slot = slot;
|
||||
_curProps = curProps;
|
||||
_gameHandler = gameHandler;
|
||||
|
||||
_file = new File(*_gameHandler->_slotFile, _slot);
|
||||
}
|
||||
|
||||
SaveLoad_v4::ScreenPropsHandler::~ScreenPropsHandler() {
|
||||
delete _file;
|
||||
}
|
||||
|
||||
int32 SaveLoad_v4::ScreenPropsHandler::getSize() {
|
||||
if (_file->exists(_slot))
|
||||
return 256000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::ScreenPropsHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (size != -5) {
|
||||
warning("Invalid saving procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
int slot = _gameHandler->getLastSlot();
|
||||
if (slot == -1)
|
||||
slot = _file->getSlot(offset);
|
||||
|
||||
return _gameHandler->loadScreenProps(slot, _curProps->_props);
|
||||
}
|
||||
|
||||
bool SaveLoad_v4::ScreenPropsHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (size != -5) {
|
||||
warning("Invalid saving procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
int slot = _gameHandler->getLastSlot();
|
||||
if (slot == -1)
|
||||
slot = _file->getSlot(offset);
|
||||
|
||||
return _gameHandler->saveScreenProps(slot, _curProps->_props);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v4::SaveLoad_v4(GobEngine *vm, const char *targetName) :
|
||||
SaveLoad(vm) {
|
||||
|
||||
_gameHandler = new GameHandler(vm, targetName);
|
||||
_curProps = new CurScreenPropsHandler(vm);
|
||||
for (int i = 0; i < 10; i++)
|
||||
_props[i] = new ScreenPropsHandler(vm, i, _curProps, _gameHandler);
|
||||
|
||||
_saveFiles[0].handler = _gameHandler;
|
||||
_saveFiles[1].handler = _curProps;
|
||||
for (int i = 0; i < 10; i++)
|
||||
_saveFiles[i + 2].handler = _props[i];
|
||||
}
|
||||
|
||||
SaveLoad_v4::~SaveLoad_v4() {
|
||||
delete _gameHandler;
|
||||
delete _curProps;
|
||||
for (int i = 0; i < 10; i++)
|
||||
delete _props[i];
|
||||
}
|
||||
|
||||
const SaveLoad_v4::SaveFile *SaveLoad_v4::getSaveFile(const char *fileName) const {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_v4::SaveFile *SaveLoad_v4::getSaveFile(const char *fileName) {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad_v4::getHandler(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->handler;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *SaveLoad_v4::getDescription(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->description;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad_v4::getSaveMode(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->mode;
|
||||
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
942
engines/gob/save/saveload_v6.cpp
Normal file
942
engines/gob/save/saveload_v6.cpp
Normal file
@@ -0,0 +1,942 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/save/saveload.h"
|
||||
#include "gob/save/saveconverter.h"
|
||||
#include "gob/inter.h"
|
||||
#include "gob/variables.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
SaveLoad_v6::SaveFile SaveLoad_v6::_saveFiles[] = {
|
||||
{ "cat.inf", kSaveModeSave, nullptr, "savegame" }, // Save file
|
||||
{ "cata1.inf", kSaveModeSave, nullptr, "autosave" }, // Autosave file
|
||||
{ "mdo.def", kSaveModeExists, nullptr, nullptr },
|
||||
{ "no_cd.txt", kSaveModeExists, nullptr, nullptr },
|
||||
{ "vide.inf", kSaveModeIgnore, nullptr, nullptr },
|
||||
{"fenetre.txt", kSaveModeIgnore, nullptr, nullptr },
|
||||
{ "music.txt", kSaveModeIgnore, nullptr, nullptr },
|
||||
{ "cata2.inf", kSaveModeSave, nullptr, "temp save" },
|
||||
{ "cata3.inf", kSaveModeSave, nullptr, "temp save" },
|
||||
{ "cata2.000", kSaveModeSave, nullptr, "extra save" }, // Slot 00
|
||||
{ "cata2.001", kSaveModeSave, nullptr, "extra save" }, // Slot 01
|
||||
{ "cata2.002", kSaveModeSave, nullptr, "extra save" }, // Slot 02
|
||||
{ "cata2.003", kSaveModeSave, nullptr, "extra save" }, // Slot 03
|
||||
{ "cata2.004", kSaveModeSave, nullptr, "extra save" }, // Slot 04
|
||||
{ "cata2.005", kSaveModeSave, nullptr, "extra save" }, // Slot 05
|
||||
{ "cata2.006", kSaveModeSave, nullptr, "extra save" }, // Slot 06
|
||||
{ "cata2.007", kSaveModeSave, nullptr, "extra save" }, // Slot 07
|
||||
{ "cata2.008", kSaveModeSave, nullptr, "extra save" }, // Slot 08
|
||||
{ "cata2.009", kSaveModeSave, nullptr, "extra save" }, // Slot 09
|
||||
{ "cata2.010", kSaveModeSave, nullptr, "extra save" }, // Slot 10
|
||||
{ "cata2.011", kSaveModeSave, nullptr, "extra save" }, // Slot 11
|
||||
{ "cata2.012", kSaveModeSave, nullptr, "extra save" }, // Slot 12
|
||||
{ "cata2.013", kSaveModeSave, nullptr, "extra save" }, // Slot 13
|
||||
{ "cata2.014", kSaveModeSave, nullptr, "extra save" }, // Slot 14
|
||||
{ "cata2.015", kSaveModeSave, nullptr, "extra save" }, // Slot 15
|
||||
{ "cata2.016", kSaveModeSave, nullptr, "extra save" }, // Slot 16
|
||||
{ "cata2.017", kSaveModeSave, nullptr, "extra save" }, // Slot 17
|
||||
{ "cata2.018", kSaveModeSave, nullptr, "extra save" }, // Slot 18
|
||||
{ "cata2.019", kSaveModeSave, nullptr, "extra save" }, // Slot 19
|
||||
{ "cata2.020", kSaveModeSave, nullptr, "extra save" }, // Slot 20
|
||||
{ "cata2.021", kSaveModeSave, nullptr, "extra save" }, // Slot 21
|
||||
{ "cata2.022", kSaveModeSave, nullptr, "extra save" }, // Slot 22
|
||||
{ "cata2.023", kSaveModeSave, nullptr, "extra save" }, // Slot 23
|
||||
{ "cata2.024", kSaveModeSave, nullptr, "extra save" }, // Slot 24
|
||||
{ "cata2.025", kSaveModeSave, nullptr, "extra save" }, // Slot 25
|
||||
{ "cata2.026", kSaveModeSave, nullptr, "extra save" }, // Slot 26
|
||||
{ "cata2.027", kSaveModeSave, nullptr, "extra save" }, // Slot 27
|
||||
{ "cata2.028", kSaveModeSave, nullptr, "extra save" }, // Slot 28
|
||||
{ "cata2.029", kSaveModeSave, nullptr, "extra save" }, // Slot 29
|
||||
{ "cata2.030", kSaveModeSave, nullptr, "extra save" }, // Slot 30
|
||||
{ "cata2.031", kSaveModeSave, nullptr, "extra save" }, // Slot 31
|
||||
{ "cata2.032", kSaveModeSave, nullptr, "extra save" }, // Slot 32
|
||||
{ "cata2.033", kSaveModeSave, nullptr, "extra save" }, // Slot 33
|
||||
{ "cata2.034", kSaveModeSave, nullptr, "extra save" }, // Slot 34
|
||||
{ "cata2.035", kSaveModeSave, nullptr, "extra save" }, // Slot 35
|
||||
{ "cata2.036", kSaveModeSave, nullptr, "extra save" }, // Slot 36
|
||||
{ "cata2.037", kSaveModeSave, nullptr, "extra save" }, // Slot 37
|
||||
{ "cata2.038", kSaveModeSave, nullptr, "extra save" }, // Slot 38
|
||||
{ "cata2.039", kSaveModeSave, nullptr, "extra save" }, // Slot 39
|
||||
{ "cata2.040", kSaveModeSave, nullptr, "extra save" }, // Slot 40
|
||||
{ "cata2.041", kSaveModeSave, nullptr, "extra save" }, // Slot 41
|
||||
{ "cata2.042", kSaveModeSave, nullptr, "extra save" }, // Slot 42
|
||||
{ "cata2.043", kSaveModeSave, nullptr, "extra save" }, // Slot 43
|
||||
{ "cata2.044", kSaveModeSave, nullptr, "extra save" }, // Slot 44
|
||||
{ "cata2.045", kSaveModeSave, nullptr, "extra save" }, // Slot 45
|
||||
{ "cata2.046", kSaveModeSave, nullptr, "extra save" }, // Slot 46
|
||||
{ "cata2.047", kSaveModeSave, nullptr, "extra save" }, // Slot 47
|
||||
{ "cata2.048", kSaveModeSave, nullptr, "extra save" }, // Slot 48
|
||||
{ "cata2.049", kSaveModeSave, nullptr, "extra save" }, // Slot 49
|
||||
{ "cata2.050", kSaveModeSave, nullptr, "extra save" }, // Slot 50
|
||||
{ "cata2.051", kSaveModeSave, nullptr, "extra save" }, // Slot 51
|
||||
{ "cata2.052", kSaveModeSave, nullptr, "extra save" }, // Slot 52
|
||||
{ "cata2.053", kSaveModeSave, nullptr, "extra save" }, // Slot 53
|
||||
{ "cata2.054", kSaveModeSave, nullptr, "extra save" }, // Slot 54
|
||||
{ "cata2.055", kSaveModeSave, nullptr, "extra save" }, // Slot 55
|
||||
{ "cata2.056", kSaveModeSave, nullptr, "extra save" }, // Slot 56
|
||||
{ "cata2.057", kSaveModeSave, nullptr, "extra save" }, // Slot 57
|
||||
{ "cata2.058", kSaveModeSave, nullptr, "extra save" }, // Slot 58
|
||||
{ "cata2.059", kSaveModeSave, nullptr, "extra save" }, // Slot 59
|
||||
{ "cata3.000", kSaveModeSave, nullptr, "extra save" }, // Slot 00
|
||||
{ "cata3.001", kSaveModeSave, nullptr, "extra save" }, // Slot 01
|
||||
{ "cata3.002", kSaveModeSave, nullptr, "extra save" }, // Slot 02
|
||||
{ "cata3.003", kSaveModeSave, nullptr, "extra save" }, // Slot 03
|
||||
{ "cata3.004", kSaveModeSave, nullptr, "extra save" }, // Slot 04
|
||||
{ "cata3.005", kSaveModeSave, nullptr, "extra save" }, // Slot 05
|
||||
{ "cata3.006", kSaveModeSave, nullptr, "extra save" }, // Slot 06
|
||||
{ "cata3.007", kSaveModeSave, nullptr, "extra save" }, // Slot 07
|
||||
{ "cata3.008", kSaveModeSave, nullptr, "extra save" }, // Slot 08
|
||||
{ "cata3.009", kSaveModeSave, nullptr, "extra save" }, // Slot 09
|
||||
{ "cata3.010", kSaveModeSave, nullptr, "extra save" }, // Slot 10
|
||||
{ "cata3.011", kSaveModeSave, nullptr, "extra save" }, // Slot 11
|
||||
{ "cata3.012", kSaveModeSave, nullptr, "extra save" }, // Slot 12
|
||||
{ "cata3.013", kSaveModeSave, nullptr, "extra save" }, // Slot 13
|
||||
{ "cata3.014", kSaveModeSave, nullptr, "extra save" }, // Slot 14
|
||||
{ "cata3.015", kSaveModeSave, nullptr, "extra save" }, // Slot 15
|
||||
{ "cata3.016", kSaveModeSave, nullptr, "extra save" }, // Slot 16
|
||||
{ "cata3.017", kSaveModeSave, nullptr, "extra save" }, // Slot 17
|
||||
{ "cata3.018", kSaveModeSave, nullptr, "extra save" }, // Slot 18
|
||||
{ "cata3.019", kSaveModeSave, nullptr, "extra save" }, // Slot 19
|
||||
{ "cata3.020", kSaveModeSave, nullptr, "extra save" }, // Slot 20
|
||||
{ "cata3.021", kSaveModeSave, nullptr, "extra save" }, // Slot 21
|
||||
{ "cata3.022", kSaveModeSave, nullptr, "extra save" }, // Slot 22
|
||||
{ "cata3.023", kSaveModeSave, nullptr, "extra save" }, // Slot 23
|
||||
{ "cata3.024", kSaveModeSave, nullptr, "extra save" }, // Slot 24
|
||||
{ "cata3.025", kSaveModeSave, nullptr, "extra save" }, // Slot 25
|
||||
{ "cata3.026", kSaveModeSave, nullptr, "extra save" }, // Slot 26
|
||||
{ "cata3.027", kSaveModeSave, nullptr, "extra save" }, // Slot 27
|
||||
{ "cata3.028", kSaveModeSave, nullptr, "extra save" }, // Slot 28
|
||||
{ "cata3.029", kSaveModeSave, nullptr, "extra save" }, // Slot 29
|
||||
{ "cata3.030", kSaveModeSave, nullptr, "extra save" }, // Slot 30
|
||||
{ "cata3.031", kSaveModeSave, nullptr, "extra save" }, // Slot 31
|
||||
{ "cata3.032", kSaveModeSave, nullptr, "extra save" }, // Slot 32
|
||||
{ "cata3.033", kSaveModeSave, nullptr, "extra save" }, // Slot 33
|
||||
{ "cata3.034", kSaveModeSave, nullptr, "extra save" }, // Slot 34
|
||||
{ "cata3.035", kSaveModeSave, nullptr, "extra save" }, // Slot 35
|
||||
{ "cata3.036", kSaveModeSave, nullptr, "extra save" }, // Slot 36
|
||||
{ "cata3.037", kSaveModeSave, nullptr, "extra save" }, // Slot 37
|
||||
{ "cata3.038", kSaveModeSave, nullptr, "extra save" }, // Slot 38
|
||||
{ "cata3.039", kSaveModeSave, nullptr, "extra save" }, // Slot 39
|
||||
{ "cata3.040", kSaveModeSave, nullptr, "extra save" }, // Slot 40
|
||||
{ "cata3.041", kSaveModeSave, nullptr, "extra save" }, // Slot 41
|
||||
{ "cata3.042", kSaveModeSave, nullptr, "extra save" }, // Slot 42
|
||||
{ "cata3.043", kSaveModeSave, nullptr, "extra save" }, // Slot 43
|
||||
{ "cata3.044", kSaveModeSave, nullptr, "extra save" }, // Slot 44
|
||||
{ "cata3.045", kSaveModeSave, nullptr, "extra save" }, // Slot 45
|
||||
{ "cata3.046", kSaveModeSave, nullptr, "extra save" }, // Slot 46
|
||||
{ "cata3.047", kSaveModeSave, nullptr, "extra save" }, // Slot 47
|
||||
{ "cata3.048", kSaveModeSave, nullptr, "extra save" }, // Slot 48
|
||||
{ "cata3.049", kSaveModeSave, nullptr, "extra save" }, // Slot 49
|
||||
{ "cata3.050", kSaveModeSave, nullptr, "extra save" }, // Slot 50
|
||||
{ "cata3.051", kSaveModeSave, nullptr, "extra save" }, // Slot 51
|
||||
{ "cata3.052", kSaveModeSave, nullptr, "extra save" }, // Slot 52
|
||||
{ "cata3.053", kSaveModeSave, nullptr, "extra save" }, // Slot 53
|
||||
{ "cata3.054", kSaveModeSave, nullptr, "extra save" }, // Slot 54
|
||||
{ "cata3.055", kSaveModeSave, nullptr, "extra save" }, // Slot 55
|
||||
{ "cata3.056", kSaveModeSave, nullptr, "extra save" }, // Slot 56
|
||||
{ "cata3.057", kSaveModeSave, nullptr, "extra save" }, // Slot 57
|
||||
{ "cata3.058", kSaveModeSave, nullptr, "extra save" }, // Slot 58
|
||||
{ "cata3.059", kSaveModeSave, nullptr, "extra save" }, // Slot 59
|
||||
{ "intro.0xx", kSaveModeSave, nullptr, "temp sprite"}, // Autosave sprite
|
||||
{ "intro.000", kSaveModeSave, nullptr, "temp sprite"}, // Slot 00
|
||||
{ "intro.001", kSaveModeSave, nullptr, "temp sprite"}, // Slot 01
|
||||
{ "intro.002", kSaveModeSave, nullptr, "temp sprite"}, // Slot 02
|
||||
{ "intro.003", kSaveModeSave, nullptr, "temp sprite"}, // Slot 03
|
||||
{ "intro.004", kSaveModeSave, nullptr, "temp sprite"}, // Slot 04
|
||||
{ "intro.005", kSaveModeSave, nullptr, "temp sprite"}, // Slot 05
|
||||
{ "intro.006", kSaveModeSave, nullptr, "temp sprite"}, // Slot 06
|
||||
{ "intro.007", kSaveModeSave, nullptr, "temp sprite"}, // Slot 07
|
||||
{ "intro.008", kSaveModeSave, nullptr, "temp sprite"}, // Slot 08
|
||||
{ "intro.009", kSaveModeSave, nullptr, "temp sprite"}, // Slot 09
|
||||
{ "intro.010", kSaveModeSave, nullptr, "temp sprite"}, // Slot 10
|
||||
{ "intro.011", kSaveModeSave, nullptr, "temp sprite"}, // Slot 11
|
||||
{ "intro.012", kSaveModeSave, nullptr, "temp sprite"}, // Slot 12
|
||||
{ "intro.013", kSaveModeSave, nullptr, "temp sprite"}, // Slot 13
|
||||
{ "intro.014", kSaveModeSave, nullptr, "temp sprite"}, // Slot 14
|
||||
{ "intro.015", kSaveModeSave, nullptr, "temp sprite"}, // Slot 15
|
||||
{ "intro.016", kSaveModeSave, nullptr, "temp sprite"}, // Slot 16
|
||||
{ "intro.017", kSaveModeSave, nullptr, "temp sprite"}, // Slot 17
|
||||
{ "intro.018", kSaveModeSave, nullptr, "temp sprite"}, // Slot 18
|
||||
{ "intro.019", kSaveModeSave, nullptr, "temp sprite"}, // Slot 19
|
||||
{ "intro.020", kSaveModeSave, nullptr, "temp sprite"}, // Slot 20
|
||||
{ "intro.021", kSaveModeSave, nullptr, "temp sprite"}, // Slot 21
|
||||
{ "intro.022", kSaveModeSave, nullptr, "temp sprite"}, // Slot 22
|
||||
{ "intro.023", kSaveModeSave, nullptr, "temp sprite"}, // Slot 23
|
||||
{ "intro.024", kSaveModeSave, nullptr, "temp sprite"}, // Slot 24
|
||||
{ "intro.025", kSaveModeSave, nullptr, "temp sprite"}, // Slot 25
|
||||
{ "intro.026", kSaveModeSave, nullptr, "temp sprite"}, // Slot 26
|
||||
{ "intro.027", kSaveModeSave, nullptr, "temp sprite"}, // Slot 27
|
||||
{ "intro.028", kSaveModeSave, nullptr, "temp sprite"}, // Slot 28
|
||||
{ "intro.029", kSaveModeSave, nullptr, "temp sprite"}, // Slot 29
|
||||
{ "intro.030", kSaveModeSave, nullptr, "temp sprite"}, // Slot 30
|
||||
{ "intro.031", kSaveModeSave, nullptr, "temp sprite"}, // Slot 31
|
||||
{ "intro.032", kSaveModeSave, nullptr, "temp sprite"}, // Slot 32
|
||||
{ "intro.033", kSaveModeSave, nullptr, "temp sprite"}, // Slot 33
|
||||
{ "intro.034", kSaveModeSave, nullptr, "temp sprite"}, // Slot 34
|
||||
{ "intro.035", kSaveModeSave, nullptr, "temp sprite"}, // Slot 35
|
||||
{ "intro.036", kSaveModeSave, nullptr, "temp sprite"}, // Slot 36
|
||||
{ "intro.037", kSaveModeSave, nullptr, "temp sprite"}, // Slot 37
|
||||
{ "intro.038", kSaveModeSave, nullptr, "temp sprite"}, // Slot 38
|
||||
{ "intro.039", kSaveModeSave, nullptr, "temp sprite"}, // Slot 39
|
||||
{ "intro.040", kSaveModeSave, nullptr, "temp sprite"}, // Slot 40
|
||||
{ "intro.041", kSaveModeSave, nullptr, "temp sprite"}, // Slot 41
|
||||
{ "intro.042", kSaveModeSave, nullptr, "temp sprite"}, // Slot 42
|
||||
{ "intro.043", kSaveModeSave, nullptr, "temp sprite"}, // Slot 43
|
||||
{ "intro.044", kSaveModeSave, nullptr, "temp sprite"}, // Slot 44
|
||||
{ "intro.045", kSaveModeSave, nullptr, "temp sprite"}, // Slot 45
|
||||
{ "intro.046", kSaveModeSave, nullptr, "temp sprite"}, // Slot 46
|
||||
{ "intro.047", kSaveModeSave, nullptr, "temp sprite"}, // Slot 47
|
||||
{ "intro.048", kSaveModeSave, nullptr, "temp sprite"}, // Slot 48
|
||||
{ "intro.049", kSaveModeSave, nullptr, "temp sprite"}, // Slot 49
|
||||
{ "intro.050", kSaveModeSave, nullptr, "temp sprite"}, // Slot 50
|
||||
{ "intro.051", kSaveModeSave, nullptr, "temp sprite"}, // Slot 51
|
||||
{ "intro.052", kSaveModeSave, nullptr, "temp sprite"}, // Slot 52
|
||||
{ "intro.053", kSaveModeSave, nullptr, "temp sprite"}, // Slot 53
|
||||
{ "intro.054", kSaveModeSave, nullptr, "temp sprite"}, // Slot 54
|
||||
{ "intro.055", kSaveModeSave, nullptr, "temp sprite"}, // Slot 55
|
||||
{ "intro.056", kSaveModeSave, nullptr, "temp sprite"}, // Slot 56
|
||||
{ "intro.057", kSaveModeSave, nullptr, "temp sprite"}, // Slot 57
|
||||
{ "intro.058", kSaveModeSave, nullptr, "temp sprite"}, // Slot 58
|
||||
{ "intro.059", kSaveModeSave, nullptr, "temp sprite"}, // Slot 59
|
||||
};
|
||||
|
||||
|
||||
SaveLoad_v6::SpriteHandler::SpriteHandler(GobEngine *vm) : TempSpriteHandler(vm) {
|
||||
}
|
||||
|
||||
SaveLoad_v6::SpriteHandler::~SpriteHandler() {
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::SpriteHandler::set(SaveReader *reader, uint32 part) {
|
||||
if (!TempSpriteHandler::create(624, 272, true))
|
||||
return false;
|
||||
|
||||
return reader->readPart(part, _sprite);
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::SpriteHandler::get(SaveWriter *writer, uint32 part) {
|
||||
if (getSize() < 0)
|
||||
if (!TempSpriteHandler::create(624, 272, true))
|
||||
return false;
|
||||
|
||||
return writer->writePart(part, _sprite);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v6::GameHandler::File::File(GobEngine *vm, const char *base) :
|
||||
SlotFileIndexed(vm, SaveLoad_v6::kSlotCount, base, "s") {
|
||||
}
|
||||
|
||||
SaveLoad_v6::GameHandler::File::~File() {
|
||||
}
|
||||
|
||||
int SaveLoad_v6::GameHandler::File::getSlot(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - (kPropsSize + kIndexSize)) / varSize);
|
||||
}
|
||||
|
||||
int SaveLoad_v6::GameHandler::File::getSlotRemainder(int32 offset) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return ((offset - (kPropsSize + kIndexSize)) % varSize);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v6::GameHandler::GameHandler(GobEngine *vm, const char *target,
|
||||
SpriteHandler &spriteHandler) : SaveHandler(vm), _spriteHandler(&spriteHandler),
|
||||
_reader(nullptr), _writer(nullptr), _hasExtra(false) {
|
||||
|
||||
memset(_props, 0, kPropsSize);
|
||||
memset(_index, 0, kIndexSize);
|
||||
|
||||
_slotFile = new File(vm, target);
|
||||
}
|
||||
|
||||
SaveLoad_v6::GameHandler::~GameHandler() {
|
||||
delete _slotFile;
|
||||
|
||||
delete _reader;
|
||||
delete _writer;
|
||||
}
|
||||
|
||||
int32 SaveLoad_v6::GameHandler::getSize() {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return -1;
|
||||
|
||||
return _slotFile->tallyUpFiles(varSize, kPropsSize + kIndexSize);
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::GameHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to load all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Properties
|
||||
|
||||
refreshProps();
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong index size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyFrom(dataVar, _props + offset, size);
|
||||
|
||||
} else if (((uint32) offset) < kPropsSize + kIndexSize) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Wrong index size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar));
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Loading from slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid loading procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!createReader(slot))
|
||||
return false;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
if (!_reader->load())
|
||||
return false;
|
||||
|
||||
if (!_reader->readPart(0, &info))
|
||||
return false;
|
||||
if (!_reader->readPart(1, &vars))
|
||||
return false;
|
||||
|
||||
// Get all variables
|
||||
if (!vars.writeInto(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
if (!_spriteHandler->set(_reader, 4))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::GameHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if (size == 0) {
|
||||
// Indicator to save all variables
|
||||
dataVar = 0;
|
||||
size = varSize;
|
||||
}
|
||||
|
||||
if (((uint32) offset) < kPropsSize) {
|
||||
// Properties
|
||||
|
||||
if (((uint32) (offset + size)) > kPropsSize) {
|
||||
warning("Wrong index size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyTo(dataVar, _props + offset, size);
|
||||
|
||||
refreshProps();
|
||||
|
||||
// If that screen doesn't save any extra temp saves, write a dummy
|
||||
if (_writer && (size == 40) && (offset == 0)) {
|
||||
if (!_hasExtra) {
|
||||
SavePartMem mem(1);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
uint8 extraSaveNumber = 0;
|
||||
if (!mem.readFrom(&extraSaveNumber, 0, 1))
|
||||
return false;
|
||||
if (!vars.readFrom(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
if (!_writer->writePart(2, &mem))
|
||||
return false;
|
||||
if (!_writer->writePart(3, &vars))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (((uint32) offset) < kPropsSize + kIndexSize) {
|
||||
// Save index
|
||||
|
||||
if (((uint32) size) != kIndexSize) {
|
||||
warning("Wrong index size (%d, %d)", size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just copy the index into our buffer
|
||||
_vm->_inter->_variables->copyTo(dataVar, _index, kIndexSize);
|
||||
|
||||
} else {
|
||||
// Save slot, whole variable block
|
||||
|
||||
_hasExtra = false;
|
||||
|
||||
uint32 slot = _slotFile->getSlot(offset);
|
||||
int slotRem = _slotFile->getSlotRemainder(offset);
|
||||
|
||||
debugC(2, kDebugSaveLoad, "Saving to slot %d", slot);
|
||||
|
||||
if ((slot >= kSlotCount) || (slotRem != 0) ||
|
||||
(dataVar != 0) || (((uint32) size) != varSize)) {
|
||||
|
||||
warning("Invalid saving procedure (%d, %d, %d, %d, %d)",
|
||||
dataVar, size, offset, slot, slotRem);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!createWriter(slot))
|
||||
return false;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(), 0,
|
||||
_vm->getEndianness(), varSize);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
// Write the description
|
||||
info.setDesc(_index + (slot * kSlotNameLength), kSlotNameLength);
|
||||
// Write all variables
|
||||
if (!vars.readFrom(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
if (!_writer->writePart(0, &info))
|
||||
return false;
|
||||
if (!_writer->writePart(1, &vars))
|
||||
return false;
|
||||
|
||||
if (!_spriteHandler->get(_writer, 4))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 SaveLoad_v6::GameHandler::getExtraID(int slot) {
|
||||
if (!_reader || (_reader->getSlot() != (uint32)slot))
|
||||
return 0;
|
||||
|
||||
SavePartMem mem(1);
|
||||
if (!_reader->readPart(2, &mem))
|
||||
return 0;
|
||||
|
||||
uint8 extraSaveNumber;
|
||||
if (!mem.writeInto(&extraSaveNumber, 0, 1))
|
||||
return 0;
|
||||
|
||||
return extraSaveNumber;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::GameHandler::loadExtra(int slot, uint8 id,
|
||||
int16 dataVar, int32 size, int32 offset) {
|
||||
|
||||
if (!_reader || (_reader->getSlot() != (uint32)slot))
|
||||
return false;
|
||||
|
||||
SavePartMem mem(1);
|
||||
if (!_reader->readPart(2, &mem))
|
||||
return false;
|
||||
|
||||
uint8 extraSaveNumber;
|
||||
if (!mem.writeInto(&extraSaveNumber, 0, 1))
|
||||
return false;
|
||||
|
||||
if (extraSaveNumber != id)
|
||||
return false;
|
||||
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
SavePartVars vars(_vm, varSize);
|
||||
if (!_reader->readPart(3, &vars))
|
||||
return false;
|
||||
|
||||
if (!vars.writeInto(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::GameHandler::saveExtra(int slot, uint8 id,
|
||||
int16 dataVar, int32 size, int32 offset) {
|
||||
|
||||
if (!_writer || (_writer->getSlot() != (uint32)slot))
|
||||
return false;
|
||||
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
SavePartMem mem(1);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
if (!mem.readFrom(&id, 0, 1))
|
||||
return false;
|
||||
if (!vars.readFrom(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
if (!_writer->writePart(2, &mem))
|
||||
return false;
|
||||
if (!_writer->writePart(3, &vars))
|
||||
return false;
|
||||
|
||||
_hasExtra = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SaveLoad_v6::GameHandler::buildIndex(byte *buffer) const {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
|
||||
if (varSize == 0)
|
||||
return;
|
||||
|
||||
SavePartInfo info(kSlotNameLength, (uint32) _vm->getGameType(),
|
||||
0, _vm->getEndianness(), varSize);
|
||||
|
||||
_slotFile->buildIndex(buffer, info, nullptr, true);
|
||||
}
|
||||
|
||||
void SaveLoad_v6::GameHandler::refreshProps() {
|
||||
uint32 maxSlot = _slotFile->getSlotMax();
|
||||
|
||||
memset(_props + 40, 0xFF, 40); // Joker
|
||||
_props[159] = 0x03; // # of joker unused
|
||||
WRITE_LE_UINT32(_props + 160, maxSlot); // # of saves
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::GameHandler::createReader(int slot) {
|
||||
// If slot < 0, just check if a reader exists
|
||||
if (slot < 0)
|
||||
return (_reader != nullptr);
|
||||
|
||||
if (!_reader || (_reader->getSlot() != ((uint32) slot))) {
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
delete _reader;
|
||||
|
||||
_reader = new SaveReader(5, slot, slotFile);
|
||||
if (!_reader->load()) {
|
||||
delete _reader;
|
||||
_reader = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::GameHandler::createWriter(int slot) {
|
||||
// If slot < 0, just check if a writer exists
|
||||
if (slot < 0)
|
||||
return (_writer != nullptr);
|
||||
|
||||
if (!_writer || (_writer->getSlot() != ((uint32) slot))) {
|
||||
Common::String slotFile = _slotFile->build(slot);
|
||||
|
||||
if (slotFile.empty())
|
||||
return false;
|
||||
|
||||
delete _writer;
|
||||
_writer = new SaveWriter(5, slot, slotFile);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v6::AutoHandler::File::File(GobEngine *vm, const Common::String &base) :
|
||||
SlotFileStatic(vm, base, "aut") {
|
||||
}
|
||||
|
||||
SaveLoad_v6::AutoHandler::File::~File() {
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v6::AutoHandler::AutoHandler(GobEngine *vm, const Common::String &target) :
|
||||
SaveHandler(vm), _file(vm, target) {
|
||||
}
|
||||
|
||||
SaveLoad_v6::AutoHandler::~AutoHandler() {
|
||||
}
|
||||
|
||||
int32 SaveLoad_v6::AutoHandler::getSize() {
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return -1;
|
||||
|
||||
SaveReader reader(1, 0, fileName);
|
||||
SaveHeader header;
|
||||
|
||||
if (!reader.load())
|
||||
return -1;
|
||||
|
||||
if (!reader.readPartHeader(0, &header))
|
||||
return -1;
|
||||
|
||||
// Return the part's size
|
||||
return header.getSize() + 2900;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::AutoHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if ((size != 0) || (offset != 2900)) {
|
||||
warning("Invalid autoloading procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
SaveReader reader(1, 0, fileName);
|
||||
SaveHeader header;
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
if (!reader.load())
|
||||
return false;
|
||||
|
||||
if (!reader.readPartHeader(0, &header))
|
||||
return false;
|
||||
|
||||
if (header.getSize() != varSize) {
|
||||
warning("Autosave mismatch (%d, %d)", header.getSize(), varSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reader.readPart(0, &vars))
|
||||
return false;
|
||||
|
||||
if (!vars.writeInto(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::AutoHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
uint32 varSize = SaveHandler::getVarSize(_vm);
|
||||
if (varSize == 0)
|
||||
return false;
|
||||
|
||||
if ((size != 0) || (offset != 2900)) {
|
||||
warning("Invalid autosaving procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
SaveWriter writer(1, 0, fileName);
|
||||
SavePartVars vars(_vm, varSize);
|
||||
|
||||
if (!vars.readFrom(0, 0, varSize))
|
||||
return false;
|
||||
|
||||
return writer.writePart(0, &vars);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v6::AutoSpriteHandler::File::File(GobEngine *vm, const Common::String &base) :
|
||||
SlotFileStatic(vm, base, "asp") {
|
||||
}
|
||||
|
||||
SaveLoad_v6::AutoSpriteHandler::File::~File() {
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v6::AutoSpriteHandler::AutoSpriteHandler(GobEngine *vm,
|
||||
const Common::String &target) : TempSpriteHandler(vm), _file(vm, target) {
|
||||
|
||||
}
|
||||
|
||||
SaveLoad_v6::AutoSpriteHandler::~AutoSpriteHandler() {
|
||||
}
|
||||
|
||||
int32 SaveLoad_v6::AutoSpriteHandler::getSize() {
|
||||
Common::InSaveFile *file = _file.openRead();
|
||||
if (!file)
|
||||
return -1;
|
||||
|
||||
delete file;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::AutoSpriteHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (offset != 0) {
|
||||
warning("Invalid autosprite saving procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TempSpriteHandler::create(624, 272, true))
|
||||
return false;
|
||||
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
SaveReader reader(1, 0, fileName);
|
||||
if (!reader.load())
|
||||
return false;
|
||||
|
||||
if (!reader.readPart(0, _sprite))
|
||||
return false;
|
||||
|
||||
return TempSpriteHandler::load(dataVar, size, offset);
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::AutoSpriteHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if (!TempSpriteHandler::save(dataVar, size, offset))
|
||||
return false;
|
||||
|
||||
if (offset != 0) {
|
||||
warning("Invalid autosprite saving procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String fileName = _file.build();
|
||||
if (fileName.empty())
|
||||
return false;
|
||||
|
||||
SaveWriter writer(1, 0, fileName);
|
||||
|
||||
return writer.writePart(0, _sprite);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v6::TempHandler::TempHandler(GobEngine *vm) : SaveHandler(vm),
|
||||
_empty(true), _size(0), _data(nullptr) {
|
||||
}
|
||||
|
||||
SaveLoad_v6::TempHandler::~TempHandler() {
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
int32 SaveLoad_v6::TempHandler::getSize() {
|
||||
if (_empty)
|
||||
return -1;
|
||||
|
||||
return _size + 2900;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::TempHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
if (_empty || (_size == 0) || !_data)
|
||||
return false;
|
||||
|
||||
if ((size != 0) || (offset != 2900)) {
|
||||
warning("Invalid temp loading procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
_vm->_inter->_variables->copyFrom(0, _data, _size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::TempHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
if ((size != 0) || (offset != 2900)) {
|
||||
warning("Invalid temp saving procedure (%d, %d, %d)", dataVar, size, offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
delete[] _data;
|
||||
|
||||
_size = SaveHandler::getVarSize(_vm);
|
||||
_data = new byte[_size];
|
||||
|
||||
_vm->_inter->_variables->copyTo(0, _data, _size);
|
||||
|
||||
_empty = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::TempHandler::deleteFile() {
|
||||
delete[] _data;
|
||||
|
||||
_empty = true;
|
||||
_size = 0;
|
||||
_data = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v6::ExtraHandler::ExtraHandler(GobEngine *vm, GameHandler &game,
|
||||
uint8 id, int slot) : SaveHandler(vm), _game(&game), _id(id), _slot(slot) {
|
||||
|
||||
}
|
||||
|
||||
SaveLoad_v6::ExtraHandler::~ExtraHandler() {
|
||||
}
|
||||
|
||||
int32 SaveLoad_v6::ExtraHandler::getSize() {
|
||||
if (_game->getExtraID(_slot) != _id)
|
||||
return -1;
|
||||
|
||||
return SaveHandler::getVarSize(_vm) + 2900;
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::ExtraHandler::load(int16 dataVar, int32 size, int32 offset) {
|
||||
return _game->loadExtra(_slot, _id, dataVar, size, offset);
|
||||
}
|
||||
|
||||
bool SaveLoad_v6::ExtraHandler::save(int16 dataVar, int32 size, int32 offset) {
|
||||
return _game->saveExtra(_slot, _id, dataVar, size, offset);
|
||||
}
|
||||
|
||||
|
||||
SaveLoad_v6::SaveLoad_v6(GobEngine *vm, const char *targetName) :
|
||||
SaveLoad(vm) {
|
||||
|
||||
_spriteHandler = new SpriteHandler(vm);
|
||||
_gameHandler = new GameHandler(vm, targetName, *_spriteHandler);
|
||||
_autoHandler = new AutoHandler(vm, targetName);
|
||||
_autoSpriteHandler = new AutoSpriteHandler(vm, targetName);
|
||||
|
||||
_tmpHandler[0] = new TempHandler(vm);
|
||||
_tmpHandler[1] = new TempHandler(vm);
|
||||
|
||||
_saveFiles[0].handler = _gameHandler;
|
||||
_saveFiles[1].handler = _autoHandler;
|
||||
|
||||
_saveFiles[7].handler = _tmpHandler[0];
|
||||
_saveFiles[8].handler = _tmpHandler[1];
|
||||
|
||||
for (int i = 0; i < 60; i++)
|
||||
_saveFiles[ 9 + i].handler =
|
||||
_extraHandler[ i] = new ExtraHandler(_vm, *_gameHandler, 2, i);
|
||||
for (int i = 0; i < 60; i++)
|
||||
_saveFiles[69 + i].handler =
|
||||
_extraHandler[60 + i] = new ExtraHandler(_vm, *_gameHandler, 3, i);
|
||||
|
||||
_saveFiles[129].handler = _autoSpriteHandler;
|
||||
|
||||
for (int i = 0; i < 60; i++)
|
||||
_saveFiles[130 + i].handler = _spriteHandler;
|
||||
}
|
||||
|
||||
SaveLoad_v6::~SaveLoad_v6() {
|
||||
for (int i = 0; i < 120; i++)
|
||||
delete _extraHandler[i];
|
||||
|
||||
delete _tmpHandler[0];
|
||||
delete _tmpHandler[1];
|
||||
delete _autoSpriteHandler;
|
||||
delete _autoHandler;
|
||||
delete _gameHandler;
|
||||
delete _spriteHandler;
|
||||
}
|
||||
|
||||
const SaveLoad_v6::SaveFile *SaveLoad_v6::getSaveFile(const char *fileName) const {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad_v6::SaveFile *SaveLoad_v6::getSaveFile(const char *fileName) {
|
||||
fileName = stripPath(fileName);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_saveFiles); i++)
|
||||
if (!scumm_stricmp(fileName, _saveFiles[i].sourceName))
|
||||
return &_saveFiles[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveHandler *SaveLoad_v6::getHandler(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->handler;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *SaveLoad_v6::getDescription(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->description;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SaveLoad::SaveMode SaveLoad_v6::getSaveMode(const char *fileName) const {
|
||||
const SaveFile *saveFile = getSaveFile(fileName);
|
||||
|
||||
if (saveFile)
|
||||
return saveFile->mode;
|
||||
|
||||
return kSaveModeNone;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
2285
engines/gob/save/saveload_v7.cpp
Normal file
2285
engines/gob/save/saveload_v7.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user