aboutsummaryrefslogtreecommitdiff
path: root/engines/gob
diff options
context:
space:
mode:
authorSven Hesse2007-04-08 00:08:26 +0000
committerSven Hesse2007-04-08 00:08:26 +0000
commitdee8a04168fb0d0ccc58b73dd9fb8d0be9499b17 (patch)
treef4e97855cff99a56b6ae703f7734242969f4785c /engines/gob
parent614ae1c08cae7d5c9b6f4ecddfa6050c41aa433f (diff)
downloadscummvm-rg350-dee8a04168fb0d0ccc58b73dd9fb8d0be9499b17.tar.gz
scummvm-rg350-dee8a04168fb0d0ccc58b73dd9fb8d0be9499b17.tar.bz2
scummvm-rg350-dee8a04168fb0d0ccc58b73dd9fb8d0be9499b17.zip
Restructured saving/loading. Should work for Gob3 now, too...
svn-id: r26414
Diffstat (limited to 'engines/gob')
-rw-r--r--engines/gob/global.cpp3
-rw-r--r--engines/gob/global.h7
-rw-r--r--engines/gob/gob.cpp439
-rw-r--r--engines/gob/gob.h22
-rw-r--r--engines/gob/inter_v2.cpp55
-rw-r--r--engines/gob/inter_v3.cpp133
-rw-r--r--engines/gob/module.mk3
-rw-r--r--engines/gob/saveload.cpp511
-rw-r--r--engines/gob/saveload.h162
-rw-r--r--engines/gob/saveload_v2.cpp286
-rw-r--r--engines/gob/saveload_v3.cpp428
11 files changed, 1427 insertions, 622 deletions
diff --git a/engines/gob/global.cpp b/engines/gob/global.cpp
index 9cbc4480b0..73e08112e8 100644
--- a/engines/gob/global.cpp
+++ b/engines/gob/global.cpp
@@ -125,9 +125,6 @@ Global::Global(GobEngine *vm) : _vm(vm) {
_inter_mouseX = 0;
_inter_mouseY = 0;
-
- _savedBack = 0;
- _savedBackSize = -1;
}
Global::~Global() {
diff --git a/engines/gob/global.h b/engines/gob/global.h
index 2180acb82f..68defd41e8 100644
--- a/engines/gob/global.h
+++ b/engines/gob/global.h
@@ -125,13 +125,6 @@ public:
int16 _inter_mouseX;
int16 _inter_mouseY;
- // While using the notepad or changing the font, the original executable
- // temporarily dumps Draw::_backSurface to a file. Since that's not really
- // a nice thing to do, we work around it.
- SurfaceDesc::Ptr _savedBack;
- Video::Color _savedPal[256];
- int32 _savedBackSize;
-
void clearVars(uint32 count) {
uint32 size = count * 4;
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index c80c8daab3..e7ff850da1 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -47,10 +47,7 @@
#include "gob/scenery.h"
#include "gob/music.h"
#include "gob/imd.h"
-
-// Use the original saves. Just for testing purposes, will be removed later
-// The new method is more convenient, and, more importantly, endian-safe
-//#define GOB_ORIGSAVES
+#include "gob/saveload.h"
namespace Gob {
@@ -80,18 +77,6 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) {
_copyProtection = ConfMan.getBool("copy_protection");
_quitRequested = false;
- int i;
- _saveFiles = new char*[3];
- for (i = 0; i < 3; i++)
- _saveFiles[i] = new char[_targetName.size() + 5];
- sprintf(_saveFiles[0], "%s.cat", _targetName.c_str());
- sprintf(_saveFiles[1], "%s.sav", _targetName.c_str());
- sprintf(_saveFiles[2], "%s.blo", _targetName.c_str());
- _saveSlotFile = new char[_targetName.size() + 5];
- sprintf(_saveSlotFile, "%s.s00", _targetName.c_str());
- memset(_saveIndex, 0, 600);
- memset(_saveIndexSizes, 0, 600);
-
Common::addSpecialDebugLevel(kDebugFuncOp, "FuncOpcodes", "Script FuncOpcodes debug level");
Common::addSpecialDebugLevel(kDebugDrawOp, "DrawOpcodes", "Script DrawOpcodes debug level");
Common::addSpecialDebugLevel(kDebugGobOp, "GoblinOpcodes", "Script GoblinOpcodes debug level");
@@ -125,13 +110,9 @@ GobEngine::~GobEngine() {
delete _draw;
delete _util;
delete _video;
+ delete _saveLoad;
delete[] _startTot;
delete[] _startTot0;
-
- for (int i = 0; i < 3; i++)
- delete[] _saveFiles[i];
- delete[] _saveFiles;
- delete[] _saveSlotFile;
}
int GobEngine::go() {
@@ -144,418 +125,6 @@ void GobEngine::shutdown() {
_quitRequested = true;
}
-int32 GobEngine::getSaveSize(enum SaveFiles sFile) {
- int32 size;
- Common::InSaveFile *in;
-
- size = -1;
-#ifndef GOB_ORIGSAVES
- int i;
- if (sFile == SAVE_CAT) {
- for (i = 14; i >= 0; i--)
- if ((in = _saveFileMan->openForLoading(getSaveSlotFile(i)))) {
- size = (i + 1) * READ_LE_UINT32(_game->_totFileData + 0x2C) * 4 + 600;
- delete in;
- break;
- }
- debugC(1, kDebugFileIO, "Requested save games size: %d", size);
- return size;
- }
-#endif // GOB_ORIGSAVES
-
- if (sFile == SAVE_SAV)
- size = _global->_savedBack == 0 ? -1 : _global->_savedBackSize;
- else if ((in = _saveFileMan->openForLoading(_saveFiles[(int) sFile]))) {
- size = in->size();
- delete in;
- }
-
- debugC(1, kDebugFileIO, "Requested size of file \"%s\": %d", _saveFiles[(int) sFile], size);
-
- return size;
-}
-
-const char *GobEngine::getSaveSlotFile(int slot) {
- static char *slotBase = _saveSlotFile + strlen(_targetName.c_str()) + 2;
-
- snprintf(slotBase, 3, "%02d", slot);
- return _saveSlotFile;
-}
-
-void GobEngine::saveGameData(enum SaveFiles sFile, int16 dataVar, int32 size, int32 offset) {
- int16 index;
- bool writePal;
- char *sName;
- byte *buf;
- byte *oBuf;
- int32 retSize;
- int32 iSize;
- int32 oSize;
- int32 oOff;
- SurfaceDesc *srcDesc;
- Common::InSaveFile *in;
- Common::OutSaveFile *out;
-
- retSize = 0;
- index = 0;
- oBuf = 0;
- in = 0;
- writePal = false;
- sName = _saveFiles[(int) sFile];
-
- WRITE_VAR(1, 1);
-
- if (sFile == SAVE_SAV) {
- _global->_savedBackSize = -1;
- if (size >= 0) {
- warning("Invalid attempt at saving a sprite");
- return;
- }
- if (size < -1000) {
- size += 1000;
- writePal = true;
- memcpy((char *) _global->_savedPal, (char *) _global->_pPaletteDesc->vgaPal, 768);
- }
- index = -size - 1;
- if ((index < 0) || (index >= 50)) {
- warning("Invalid attempt at saving a sprite");
- return;
- }
- srcDesc = _draw->_spritesArray[index];
-
- _global->_savedBack =
- _video->initSurfDesc(_vm->_global->_videoMode, srcDesc->getWidth(), srcDesc->getHeight(), 0);
- _vm->_video->drawSprite(srcDesc, _global->_savedBack, 0, 0,
- srcDesc->getWidth() - 1, srcDesc->getHeight() - 1, 0, 0, 0);
-
- _global->_savedBackSize = _draw->getSpriteRectSize(index);
- if (writePal)
- _global->_savedBackSize += 768;
-
- WRITE_VAR(1, 0);
- return;
- }
-
- if (size < 0) {
- warning("Invalid saving procedure");
- return;
- }
-
- int32 varSize = READ_LE_UINT32(_game->_totFileData + 0x2C) * 4;
-
- if (size == 0) {
- dataVar = 0;
- size = varSize;
- }
- buf = _global->_inter_variables + dataVar;
-#ifndef GOB_ORIGSAVES
- if (sFile == SAVE_CAT) {
- if (saveGame((offset - 600) / varSize, dataVar, size, offset))
- WRITE_VAR(1, 0);
- return;
- } else if (offset != 0) {
- warning("Can't write file \"%s\": Can't correctly enfore endianness with offset", sName);
- return;
- }
-#endif // GOB_ORIGSAVES
-
- if ((in = _saveFileMan->openForLoading(sName)))
- iSize = in->size();
- else
- iSize = 0;
-
- oOff = offset < 0 ? MAX((int32) 0, iSize - (-offset - 1)) : offset;
- oSize = MAX(iSize, oOff + size);
- oBuf = new byte[oSize];
- memset(oBuf, 0, oSize);
-
- if (in) {
- in->read(oBuf, iSize);
- delete in;
- }
-
- if (!(out = _saveFileMan->openForSaving(sName))) {
- warning("Can't open file \"%s\" for writing", sName);
- delete[] oBuf;
- return;
- }
-
- retSize = writeDataEndian(*out, buf, _global->_inter_variablesSizes + dataVar, size);
-
- out->finalize();
-
- if (out->ioFailed() || (retSize != size))
- warning("Can't write file \"%s\"", sName);
- else {
- debugC(1, kDebugFileIO, "Saved file \"%s\" (%d, %d bytes at %d)",
- sName, dataVar, size, offset);
- WRITE_VAR(1, 0);
- }
-
- delete out;
- delete[] oBuf;
-}
-
-bool GobEngine::saveGame(int saveSlot, int16 dataVar, int32 size, int32 offset) {
- int32 varSize;
- byte *varBuf;
- byte *sizeBuf;
- Common::OutSaveFile *out;
-
- varBuf = _global->_inter_variables + dataVar;
- sizeBuf = _global->_inter_variablesSizes + dataVar;
- varSize = READ_LE_UINT32(_game->_totFileData + 0x2C) * 4;
- if ((offset == 0) && (size == 600)) {
- memcpy(_saveIndex, varBuf, size);
- memcpy(_saveIndexSizes, sizeBuf, size);
- return true;
- } else if ((((offset - 600) % varSize) == 0) && (size == varSize)) {
- if (!(out = _saveFileMan->openForSaving(getSaveSlotFile(saveSlot)))) {
- warning("Can't open file \"%s\" for writing", getSaveSlotFile(saveSlot));
- return false;
- }
- writeDataEndian(*out, _saveIndex + saveSlot * 40, _saveIndexSizes + saveSlot * 40, 40);
- writeDataEndian(*out, varBuf, sizeBuf, size);
- out->finalize();
- if (out->ioFailed()) {
- warning("Can't save to slot %d", saveSlot);
- return false;
- }
- debugC(1, kDebugFileIO, "Saved to slot %d", saveSlot);
- delete out;
- return true;
- } else {
- warning("Invalid saving procedure");
- return false;
- }
-}
-
-uint32 GobEngine::writeDataEndian(Common::OutSaveFile &out, byte *varBuf, byte *sizeBuf,
- int32 size) {
-
-#ifndef GOB_ORIGSAVES
-
- int i;
- byte tmp[4];
- uint32 written;
-
- written = 0;
- for (i = 0; i < size; i++, varBuf++) {
- if (sizeBuf[i] == 3)
- WRITE_LE_UINT32(tmp, *((uint32 *) varBuf));
- else if (sizeBuf[i] == 1)
- WRITE_LE_UINT16(tmp, *((uint16 *) varBuf));
- else if (sizeBuf[i] == 0)
- *tmp = *varBuf;
- else {
- warning("Can't write data, corrupted variables sizes");
- return 0;
- }
- written += out.write(tmp, sizeBuf[i] + 1);
- varBuf += sizeBuf[i];
- i += sizeBuf[i];
- }
-
- out.write(sizeBuf, size);
-
- return written;
-
-#else // GOB_ORIGSAVES
-
- return out.write(varBuf, size);
-
-#endif // GOB_ORIGSAVES
-
-}
-
-void GobEngine::loadGameData(enum SaveFiles sFile, int16 dataVar, int32 size, int32 offset) {
- int32 sSize;
- int32 retSize;
- int16 index;
- byte *buf;
- char *sName;
- bool readPal;
- SurfaceDesc *destDesc;
- Common::InSaveFile *in;
-
- index = 0;
- readPal = false;
- sName = _saveFiles[(int) sFile];
-
- WRITE_VAR(1, 1);
-
- if (sFile == SAVE_SAV) {
- if (size >= 0) {
- warning("Invalid attempt at loading a sprite");
- return;
- }
- if (size < -1000) {
- size += 1000;
- readPal = true;
- memcpy((char *) _global->_pPaletteDesc->vgaPal, (char *) _global->_savedPal, 768);
- }
- index = -size - 1;
- if ((index < 0) || (index >= 50)) {
- warning("Invalid attempt at loading a sprite");
- return;
- }
- destDesc = _draw->_spritesArray[index];
-
- if ((destDesc->getWidth() != _global->_savedBack->getWidth()) ||
- (destDesc->getHeight() != _global->_savedBack->getHeight())) {
- warning("Resolution doesn't match while loading a sprite");
- return;
- }
-
- _vm->_video->drawSprite(_global->_savedBack, destDesc, 0, 0,
- destDesc->getWidth() - 1, destDesc->getHeight() - 1, 0, 0, 0);
- if (index == 21) {
- _vm->_draw->forceBlit();
- _video->waitRetrace();
- }
-
- WRITE_VAR(1, 0);
- return;
- }
-
- if (size < 0) {
- warning("Invalid loading procedure");
- return;
- }
-
- int32 varSize;
- varSize = READ_LE_UINT32(_game->_totFileData + 0x2C) * 4;
- if (size == 0) {
- dataVar = 0;
- size = varSize;
- }
- buf = _global->_inter_variables + dataVar;
-#ifndef GOB_ORIGSAVES
- if (sFile == SAVE_CAT) {
- if (loadGame((offset - 600) / varSize, dataVar, size, offset))
- WRITE_VAR(1, 0);
- return;
- } else if (offset != 0) {
- warning("Can't read file \"%s\": Can't correctly enfore endianness with offset", sName);
- return;
- }
-#endif // GOB_ORIGSAVES
-
- if (_global->_inter_resStr[0] == 0) {
- WRITE_VAR(1, size);
- return;
- }
-
- if (!(in = _saveFileMan->openForLoading(sName))) {
- warning("Can't open file \"%s\" for reading", sName);
- return;
- }
-
- debugC(1, kDebugFileIO, "Loading file \"%s\" (%d, %d bytes at %d)",
- sName, dataVar, size, offset);
-
- sSize = in->size();
- _draw->animateCursor(4);
- if (offset < 0)
- in->seek(sSize - (-offset - 1), 0);
- else
- in->seek(offset, 0);
-
- retSize = readDataEndian(*in, buf, _global->_inter_variablesSizes + dataVar, size);
-
- if (retSize == size)
- WRITE_VAR(1, 0);
-
- delete in;
- return;
-}
-
-bool GobEngine::loadGame(int saveSlot, int16 dataVar, int32 size, int32 offset) {
- int i;
- int32 varSize;
- byte *varBuf;
- byte *sizeBuf;
- Common::InSaveFile *in;
-
- varBuf = _global->_inter_variables + dataVar;
- sizeBuf = _global->_inter_variablesSizes + dataVar;
- varSize = READ_LE_UINT32(_game->_totFileData + 0x2C) * 4;
- if ((offset == 0) && (size == 600)) {
- for (i = 0; i < 15; i++, varBuf += 40) {
- if ((in = _saveFileMan->openForLoading(getSaveSlotFile(i)))) {
- in->read(varBuf, 40);
- delete in;
- } else
- memset(varBuf, 0, 40);
- }
- return true;
- } else if ((((offset - 600) % varSize) == 0) && (size == varSize)) {
- if (!(in = _saveFileMan->openForLoading(getSaveSlotFile(saveSlot)))) {
- warning("Can't load from slot %d", saveSlot);
- return false;
- }
- if (((in->size() / 2) - 40) != (uint32) varSize) {
- warning("Can't load from slot %d: Wrong size", saveSlot);
- return false;
- }
- in->seek(80);
- readDataEndian(*in, varBuf, sizeBuf, size);
- delete in;
- debugC(1, kDebugFileIO, "Loading from slot %d", saveSlot);
- return true;
- } else {
- warning("Invalid loading procedure");
- return false;
- }
-}
-
-uint32 GobEngine::readDataEndian(Common::InSaveFile &in, byte *varBuf, byte *sizeBuf,
- int32 size) {
-
-#ifndef GOB_ORIGSAVES
-
- uint32 read;
- byte *vars;
- byte *sizes;
- int i;
-
- vars = new byte[size];
- sizes = new byte[size];
-
- read = in.read(vars, size);
- if (in.read(sizes, size) != read) {
- warning("Can't read data: Corrupted variables sizes");
- delete[] vars;
- delete[] sizes;
- return 0;
- }
-
- for (i = 0; i < size; i++) {
- if (sizes[i] == 3)
- *((uint32 *) (vars + i)) = READ_LE_UINT32(vars + i);
- else if (sizes[i] == 1)
- *((uint16 *) (vars + i)) = READ_LE_UINT16(vars + i);
- else if (sizes[i] != 0) {
- warning("Can't read data: Corrupted variables sizes");
- return 0;
- }
- i += sizes[i];
- }
-
- memcpy(varBuf, vars, size);
- memcpy(sizeBuf, sizes, size);
- delete[] vars;
- delete[] sizes;
-
- return read;
-
-#else // GOB_ORIGSAVES
-
- return in.read(varBuf, size);
-
-#endif // GOB_ORIGSAVES
-}
-
void GobEngine::validateLanguage() {
if (_vm->_global->_languageWanted != _vm->_global->_language) {
warning("Your game version doesn't support the requested language");
@@ -578,6 +147,7 @@ int GobEngine::init() {
}
_adlib = 0;
+ _saveLoad = 0;
_global = new Global(this);
_util = new Util(this);
_dataIO = new DataIO(this);
@@ -607,6 +177,7 @@ int GobEngine::init() {
_map = new Map_v2(this);
_goblin = new Goblin_v2(this);
_scenery = new Scenery_v2(this);
+ _saveLoad = new SaveLoad_v2(this, _targetName.c_str());
} else if (_features & Gob::GF_BARGON) {
_init = new Init_v2(this);
_video = new Video_v2(this);
@@ -618,6 +189,7 @@ int GobEngine::init() {
_map = new Map_v2(this);
_goblin = new Goblin_v2(this);
_scenery = new Scenery_v2(this);
+ _saveLoad = new SaveLoad_v2(this, _targetName.c_str());
} else if (_features & Gob::GF_GOB3) {
_init = new Init_v2(this);
_video = new Video_v2(this);
@@ -629,6 +201,7 @@ int GobEngine::init() {
_map = new Map_v2(this);
_goblin = new Goblin_v3(this);
_scenery = new Scenery_v2(this);
+ _saveLoad = new SaveLoad_v3(this, _targetName.c_str());
} else
error("GobEngine::init(): Unknown version of game engine");
diff --git a/engines/gob/gob.h b/engines/gob/gob.h
index c74b7632ef..c3151b9e7e 100644
--- a/engines/gob/gob.h
+++ b/engines/gob/gob.h
@@ -48,6 +48,7 @@ class PalAnim;
class Parse;
class Scenery;
class Util;
+class SaveLoad;
class Adlib;
#define VARP(offs) (_vm->_global->_inter_variables + (offs))
@@ -96,13 +97,6 @@ enum {
kDebugCollisions = 1 << 8
};
-enum SaveFiles {
- SAVE_CAT = 0, // Saves
- SAVE_SAV, // Holds a sprite, normally a cache for Draw::_backBuffer
- // (see Global::_savedBack)
- SAVE_BLO // Notes
-};
-
inline char *strncpy0(char *dest, const char *src, size_t n) {
strncpy(dest, src, n);
dest[n] = 0;
@@ -163,21 +157,11 @@ private:
class GobEngine : public Engine {
protected:
- char **_saveFiles;
- char *_saveSlotFile;
- byte _saveIndex[600];
- byte _saveIndexSizes[600];
GobEngine *_vm;
int go();
int init();
- const char *getSaveSlotFile(int slot);
- bool saveGame(int saveSlot, int16 dataVar, int32 size, int32 offset);
- bool loadGame(int saveSlot, int16 dataVar, int32 size, int32 offset);
- uint32 writeDataEndian(Common::OutSaveFile &out, byte *varBuf, byte *sizeBuf, int32 size);
- uint32 readDataEndian(Common::InSaveFile &in, byte *varBuf, byte *sizeBuf, int32 size);
-
bool detectGame();
public:
@@ -210,14 +194,12 @@ public:
Parse *_parse;
Scenery *_scenery;
Inter *_inter;
+ SaveLoad *_saveLoad;
Adlib *_adlib;
ImdPlayer *_imdPlayer;
void shutdown();
- int32 getSaveSize(enum SaveFiles sFile);
- void saveGameData(enum SaveFiles sFile, int16 dataVar, int32 size, int32 offset);
- void loadGameData(enum SaveFiles sFile, int16 dataVar, int32 size, int32 offset);
const char *getLangDesc(int16 language) {
if ((language < 0) || (language > 8))
language = 2;
diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp
index 688f52a155..819ba6df11 100644
--- a/engines/gob/inter_v2.cpp
+++ b/engines/gob/inter_v2.cpp
@@ -43,6 +43,7 @@
#include "gob/scenery.h"
#include "gob/sound.h"
#include "gob/video.h"
+#include "gob/saveload.h"
namespace Gob {
@@ -1776,21 +1777,16 @@ bool Inter_v2::o2_checkData(OpFuncParams &params) {
int16 handle;
int16 varOff;
int32 size;
+ SaveType type;
evalExpr(0);
varOff = _vm->_parse->parseVarIndex();
size = -1;
handle = 1;
- if (!scumm_stricmp(_vm->_global->_inter_resStr, "cat.inf"))
- size = _vm->getSaveSize(SAVE_CAT);
- else if (!scumm_stricmp(_vm->_global->_inter_resStr, "cat.cat"))
- size = _vm->getSaveSize(SAVE_CAT);
- else if (!scumm_stricmp(_vm->_global->_inter_resStr, "save.inf"))
- size = _vm->getSaveSize(SAVE_SAV);
- else if (!scumm_stricmp(_vm->_global->_inter_resStr, "bloc.inf"))
- size = _vm->getSaveSize(SAVE_BLO);
- else {
+
+ type = _vm->_saveLoad->getSaveType(_vm->_global->_inter_resStr);
+ if (type == kSaveNone) {
handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr);
if (handle >= 0) {
@@ -1798,10 +1794,15 @@ bool Inter_v2::o2_checkData(OpFuncParams &params) {
size = _vm->_dataIO->getDataSize(_vm->_global->_inter_resStr);
} else
warning("File \"%s\" not found", _vm->_global->_inter_resStr);
- }
+ } else
+ size = _vm->_saveLoad->getSize(type);
+
if (size == -1)
handle = -1;
+ debugC(2, kDebugFileIO, "Requested size of file \"%s\": %d",
+ _vm->_global->_inter_resStr, size);
+
WRITE_VAR_OFFSET(varOff, handle);
WRITE_VAR(16, (uint32) size);
@@ -1815,6 +1816,7 @@ bool Inter_v2::o2_readData(OpFuncParams &params) {
int16 dataVar;
int16 handle;
byte *buf;
+ SaveType type;
evalExpr(0);
dataVar = _vm->_parse->parseVarIndex();
@@ -1825,17 +1827,11 @@ bool Inter_v2::o2_readData(OpFuncParams &params) {
debugC(2, kDebugFileIO, "Read from file \"%s\" (%d, %d bytes at %d)",
_vm->_global->_inter_resStr, dataVar, size, offset);
- if (!scumm_stricmp(_vm->_global->_inter_resStr, "cat.inf")) {
- _vm->loadGameData(SAVE_CAT, dataVar, size, offset);
- return false;
- } else if (!scumm_stricmp(_vm->_global->_inter_resStr, "cat.cat")) {
- _vm->loadGameData(SAVE_CAT, dataVar, size, offset);
- return false;
- } else if (!scumm_stricmp(_vm->_global->_inter_resStr, "save.inf")) {
- _vm->loadGameData(SAVE_SAV, dataVar, size, offset);
- return false;
- } else if (!scumm_stricmp(_vm->_global->_inter_resStr, "bloc.inf")) {
- _vm->loadGameData(SAVE_BLO, dataVar, size, offset);
+ type = _vm->_saveLoad->getSaveType(_vm->_global->_inter_resStr);
+ if (type != kSaveNone) {
+ WRITE_VAR(1, 1);
+ if (_vm->_saveLoad->load(type, dataVar, size, offset))
+ WRITE_VAR(1, 0);
return false;
}
@@ -1888,6 +1884,7 @@ bool Inter_v2::o2_writeData(OpFuncParams &params) {
int32 offset;
int32 size;
int16 dataVar;
+ SaveType type;
evalExpr(0);
dataVar = _vm->_parse->parseVarIndex();
@@ -1898,15 +1895,13 @@ bool Inter_v2::o2_writeData(OpFuncParams &params) {
debugC(2, kDebugFileIO, "Write to file \"%s\" (%d, %d bytes at %d)",
_vm->_global->_inter_resStr, dataVar, size, offset);
- if (!scumm_stricmp(_vm->_global->_inter_resStr, "cat.inf"))
- _vm->saveGameData(SAVE_CAT, dataVar, size, offset);
- else if (!scumm_stricmp(_vm->_global->_inter_resStr, "cat.cat"))
- _vm->saveGameData(SAVE_CAT, dataVar, size, offset);
- else if (!scumm_stricmp(_vm->_global->_inter_resStr, "save.inf"))
- _vm->saveGameData(SAVE_SAV, dataVar, size, offset);
- else if (!scumm_stricmp(_vm->_global->_inter_resStr, "bloc.inf"))
- _vm->saveGameData(SAVE_BLO, dataVar, size, offset);
- else
+ WRITE_VAR(1, 1);
+
+ type = _vm->_saveLoad->getSaveType(_vm->_global->_inter_resStr);
+ if (type != kSaveNone) {
+ if (_vm->_saveLoad->save(type, dataVar, size, offset))
+ WRITE_VAR(1, 0);
+ } else
warning("Attempted to write to file \"%s\"", _vm->_global->_inter_resStr);
return false;
diff --git a/engines/gob/inter_v3.cpp b/engines/gob/inter_v3.cpp
index 0917423441..0fb270891b 100644
--- a/engines/gob/inter_v3.cpp
+++ b/engines/gob/inter_v3.cpp
@@ -23,6 +23,7 @@
#include "common/stdafx.h"
#include "common/endian.h"
+#include "common/file.h"
#include "gob/gob.h"
#include "gob/inter.h"
@@ -518,7 +519,7 @@ void Inter_v3::setupOpcodes() {
OPCODE(o1_waitEndPlay),
OPCODE(o1_playComposition),
OPCODE(o2_getFreeMem),
- OPCODE(o3_checkData),
+ OPCODE(o2_checkData),
/* 40 */
{NULL, ""},
OPCODE(o1_prepareStr),
@@ -536,8 +537,8 @@ void Inter_v3::setupOpcodes() {
OPCODE(o1_loadFont),
/* 4C */
OPCODE(o1_freeFont),
- OPCODE(o3_readData),
- OPCODE(o3_writeData),
+ OPCODE(o2_readData),
+ OPCODE(o2_writeData),
OPCODE(o1_manageDataFile),
};
@@ -891,130 +892,4 @@ bool Inter_v3::o3_copySprite(OpFuncParams &params) {
return false;
}
-bool Inter_v3::o3_checkData(OpFuncParams &params) {
- int16 handle;
- int16 varOff;
- int32 size;
-
- evalExpr(0);
- varOff = _vm->_parse->parseVarIndex();
-
- size = -1;
- handle = 1;
- if (!scumm_stricmp(_vm->_global->_inter_resStr, "intro.$$$"))
- size = _vm->getSaveSize(SAVE_SAV);
- else if (!scumm_stricmp(_vm->_global->_inter_resStr, "cat.inf"))
- warning("Gob3 Stub: Requested save file size");
- else {
- handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr);
-
- if (handle >= 0) {
- _vm->_dataIO->closeData(handle);
- size = _vm->_dataIO->getDataSize(_vm->_global->_inter_resStr);
- } else
- warning("File \"%s\" not found", _vm->_global->_inter_resStr);
- }
- if (size == -1)
- handle = -1;
-
- WRITE_VAR_OFFSET(varOff, handle);
- WRITE_VAR(16, (uint32) size);
-
- return false;
-}
-
-bool Inter_v3::o3_readData(OpFuncParams &params) {
- int32 retSize;
- int32 size;
- int32 offset;
- int16 dataVar;
- int16 handle;
- byte *buf;
-
- evalExpr(0);
- dataVar = _vm->_parse->parseVarIndex();
- size = _vm->_parse->parseValExpr();
- evalExpr(0);
- offset = _vm->_global->_inter_resVal;
-
- debugC(2, kDebugFileIO, "Read from file \"%s\" (%d, %d bytes at %d)",
- _vm->_global->_inter_resStr, dataVar, size, offset);
-
- if (!scumm_stricmp(_vm->_global->_inter_resStr, "intro.$$$")) {
- _vm->loadGameData(SAVE_SAV, dataVar, size, offset);
- return false;
- } else if (!scumm_stricmp(_vm->_global->_inter_resStr, "cat.inf")) {
- warning("Gob3 Stub: Game state loading");
- return false;
- }
-
- if (size < 0) {
- warning("Attempted to read a raw sprite from file \"%s\"",
- _vm->_global->_inter_resStr);
- return false ;
- } else if (size == 0) {
- dataVar = 0;
- size = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4;
- }
-
- buf = _vm->_global->_inter_variables + dataVar;
- memset(_vm->_global->_inter_variablesSizes + dataVar, 0, size);
-
- if (_vm->_global->_inter_resStr[0] == 0) {
- WRITE_VAR(1, size);
- return false;
- }
-
- WRITE_VAR(1, 1);
- handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr);
-
- if (handle < 0)
- return false;
-
- _vm->_draw->animateCursor(4);
- if (offset < 0)
- _vm->_dataIO->seekData(handle, -offset - 1, SEEK_END);
- else
- _vm->_dataIO->seekData(handle, offset, SEEK_SET);
-
- if (((dataVar >> 2) == 59) && (size == 4)) {
- WRITE_VAR(59, _vm->_dataIO->readUint32(handle));
- // The scripts in some versions divide through 256^3 then,
- // effectively doing a LE->BE conversion
- if ((_vm->_platform != Common::kPlatformPC) && (VAR(59) < 256))
- WRITE_VAR(59, SWAP_BYTES_32(VAR(59)));
- } else
- retSize = _vm->_dataIO->readData(handle, buf, size);
-
- if (retSize == size)
- WRITE_VAR(1, 0);
-
- _vm->_dataIO->closeData(handle);
- return false;
-}
-
-bool Inter_v3::o3_writeData(OpFuncParams &params) {
- int32 offset;
- int32 size;
- int16 dataVar;
-
- evalExpr(0);
- dataVar = _vm->_parse->parseVarIndex();
- size = _vm->_parse->parseValExpr();
- evalExpr(0);
- offset = _vm->_global->_inter_resVal;
-
- debugC(2, kDebugFileIO, "Write to file \"%s\" (%d, %d bytes at %d)",
- _vm->_global->_inter_resStr, dataVar, size, offset);
-
- if (!scumm_stricmp(_vm->_global->_inter_resStr, "intro.$$$"))
- _vm->saveGameData(SAVE_SAV, dataVar, size, offset);
- else if (!scumm_stricmp(_vm->_global->_inter_resStr, "cat.inf"))
- warning("Gob3 Stub: Game state saving");
- else
- warning("Attempted to write to file \"%s\"", _vm->_global->_inter_resStr);
-
- return false;
-}
-
} // End of namespace Gob
diff --git a/engines/gob/module.mk b/engines/gob/module.mk
index 0a182faaf0..63aea49a29 100644
--- a/engines/gob/module.mk
+++ b/engines/gob/module.mk
@@ -38,6 +38,9 @@ MODULE_OBJS := \
parse.o \
parse_v1.o \
parse_v2.o \
+ saveload.o \
+ saveload_v2.o \
+ saveload_v3.o \
scenery.o \
scenery_v1.o \
scenery_v2.o \
diff --git a/engines/gob/saveload.cpp b/engines/gob/saveload.cpp
new file mode 100644
index 0000000000..e4b14639b1
--- /dev/null
+++ b/engines/gob/saveload.cpp
@@ -0,0 +1,511 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/endian.h"
+#include "common/file.h"
+
+#include "gob/gob.h"
+#include "gob/saveload.h"
+#include "gob/global.h"
+#include "gob/draw.h"
+#include "gob/video.h"
+
+namespace Gob {
+
+SaveLoad::SaveLoad(GobEngine *vm, const char *targetName) : _vm(vm) {
+ _curSlot = -1;
+
+ _stagesCount = 0;
+ _buffer = 0;
+
+ _tempSprite = 0;
+ memset(_tempPal, 0, 768);
+ _tempSpriteSize = -1;
+
+ _saveFiles = new char*[5];
+
+ assert(_saveFiles);
+
+ _saveFiles[0] = new char[strlen(targetName) + 5];
+ _saveFiles[1] = 0;
+ _saveFiles[2] = new char[strlen(targetName) + 5];
+ _saveFiles[3] = _saveFiles[0];
+ _saveFiles[4] = 0;
+
+ assert(_saveFiles[0] && _saveFiles[2]);
+
+ sprintf(_saveFiles[0], "%s.s00", targetName);
+ sprintf(_saveFiles[2], "%s.blo", targetName);
+}
+
+SaveLoad::~SaveLoad() {
+ for (int i = 0; i < _stagesCount; i++)
+ delete[] _buffer[i];
+ delete[] _buffer;
+
+ delete _tempSprite;
+
+ delete[] _saveFiles[0];
+ delete[] _saveFiles[2];
+ delete[] _saveFiles;
+}
+
+const char *SaveLoad::setCurSlot(int slot) {
+ static char *slotBase = _saveFiles[0] + strlen(_saveFiles[0]) - 2;
+
+ if (_curSlot != slot) {
+ _curSlot = slot;
+
+ if (_curSlot >= 0)
+ snprintf(slotBase, 3, "%02d", slot);
+ }
+
+ return _saveFiles[0];
+}
+
+uint32 SaveLoad::read(Common::ReadStream &in, byte *buf,
+ byte *sizes, uint32 count) {
+ uint32 nRead;
+
+ nRead = in.read(buf, count);
+ if (nRead != count) {
+ warning("Can't read data: requested %d, got %d", count, nRead);
+ return 0;
+ }
+
+ nRead = in.read(sizes, count);
+ if (nRead != count) {
+ warning("Can't read data sizes: requested %d, got %d", count, nRead);
+ return 0;
+ }
+
+ return count;
+}
+
+uint32 SaveLoad::write(Common::WriteStream &out, byte *buf,
+ byte *sizes, uint32 count) {
+ uint32 written;
+
+ written = out.write(buf, count);
+ if (written != count) {
+ warning("Can't write data: requested %d, wrote %d", count, written);
+ return 0;
+ }
+
+ written = out.write(sizes, count);
+ if (written != count) {
+ warning("Can't write data: requested %d, wrote %d", count, written);
+ return 0;
+ }
+
+ return count;
+}
+
+bool SaveLoad::loadDataEndian(Common::ReadStream &in,
+ int16 dataVar, uint32 size) {
+
+ bool retVal = false;
+
+ byte *varBuf = new byte[size];
+ byte *sizeBuf = new byte[size];
+
+ assert(varBuf && sizeBuf);
+
+ if (read(in, varBuf, sizeBuf, size) == size) {
+ if (fromEndian(varBuf, sizeBuf, size)) {
+ memcpy(_vm->_global->_inter_variables + dataVar, varBuf, size);
+ memcpy(_vm->_global->_inter_variablesSizes + dataVar, sizeBuf, size);
+ retVal = true;
+ }
+ }
+
+ delete[] varBuf;
+ delete[] sizeBuf;
+
+ return retVal;
+}
+
+bool SaveLoad::saveDataEndian(Common::WriteStream &out,
+ int16 dataVar, uint32 size) {
+
+ bool retVal = false;
+
+ byte *varBuf = new byte[size];
+ byte *sizeBuf = new byte[size];
+
+ assert(varBuf && sizeBuf);
+
+ memcpy(varBuf, _vm->_global->_inter_variables + dataVar, size);
+ memcpy(sizeBuf, _vm->_global->_inter_variablesSizes + dataVar, size);
+
+ if (toEndian(varBuf, sizeBuf, size))
+ if (write(out, varBuf, sizeBuf, size) == size)
+ retVal = true;
+
+ delete[] varBuf;
+ delete[] sizeBuf;
+
+ return retVal;
+}
+
+int32 SaveLoad::getSize(SaveType type) {
+ switch(type) {
+ case kSaveNone:
+ return -1;
+ break;
+
+ case kSaveGame:
+ return getSizeGame();
+ break;
+
+ case kSaveTempSprite:
+ return getSizeTempSprite();
+ break;
+
+ case kSaveNotes:
+ return getSizeNotes();
+ break;
+
+ case kSaveScreenshot:
+ return getSizeScreenshot();
+ break;
+
+ case kSaveIgnore:
+ return -1;
+ break;
+ }
+
+ return -1;
+}
+
+bool SaveLoad::load(SaveType type, int16 dataVar, int32 size, int32 offset) {
+ switch(type) {
+ case kSaveNone:
+ return false;
+ break;
+
+ case kSaveGame:
+ return loadGame(dataVar, size, offset);
+ break;
+
+ case kSaveTempSprite:
+ return loadTempSprite(dataVar, size, offset);
+ break;
+
+ case kSaveNotes:
+ return loadNotes(dataVar, size, offset);
+ break;
+
+ case kSaveScreenshot:
+ return loadScreenshot(dataVar, size, offset);
+ break;
+
+ case kSaveIgnore:
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+bool SaveLoad::save(SaveType type, int16 dataVar, int32 size, int32 offset) {
+ switch(type) {
+ case kSaveNone:
+ return false;
+ break;
+
+ case kSaveGame:
+ return saveGame(dataVar, size, offset);
+ break;
+
+ case kSaveTempSprite:
+ return saveTempSprite(dataVar, size, offset);
+ break;
+
+ case kSaveNotes:
+ return saveNotes(dataVar, size, offset);
+ break;
+
+ case kSaveScreenshot:
+ return saveScreenshot(dataVar, size, offset);
+ break;
+
+ case kSaveIgnore:
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+int32 SaveLoad::getSizeTempSprite() {
+ return _tempSpriteSize;
+}
+
+bool SaveLoad::loadTempSprite(int16 dataVar, int32 size, int32 offset) {
+ int index;
+ bool readPal;
+
+ if (size >= 0) {
+ warning("Invalid attempt at loading from the temporary sprite");
+ return false;
+ }
+
+ index = getSpriteIndex(size);
+ readPal = getSpritePalette(size);
+
+ if ((index < 0) || (index >= SPRITES_COUNT)) {
+ warning("Index out of range while loading from the temporary "
+ "sprite (%d)", index);
+ return false;
+ }
+
+ return loadTempSprite(index, readPal);
+}
+
+bool SaveLoad::saveTempSprite(int16 dataVar, int32 size, int32 offset) {
+ int index;
+ bool readPal;
+
+ if (size >= 0) {
+ warning("Invalid attempt at saving to the temporary sprite");
+ return false;
+ }
+
+ index = getSpriteIndex(size);
+ readPal = getSpritePalette(size);
+
+ if ((index < 0) || (index >= SPRITES_COUNT)) {
+ warning("Index out of range while saving to the temporary sprite (%d)",
+ index);
+ return false;
+ }
+
+ return saveTempSprite(index, readPal);
+}
+
+bool SaveLoad::loadTempSprite(uint32 index, bool palette) {
+ SurfaceDesc *sprite;
+
+ if (palette)
+ memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal,
+ (char *) _tempPal, 768);
+
+ sprite = _vm->_draw->_spritesArray[index];
+
+ if (!sprite) {
+ warning("Couldn't load from the temporary sprite: "
+ "No such sprite %d", index);
+ return false;
+ }
+
+ if ((sprite->getWidth() != _tempSprite->getWidth()) ||
+ (sprite->getHeight() != _tempSprite->getHeight())) {
+ warning("Resolution doesn't match while loading from the "
+ "temporary sprite (%d: %dx%d vs. %dx%d)", index,
+ sprite->getWidth(), sprite->getHeight(),
+ _tempSprite->getWidth(), _tempSprite->getHeight());
+ return false;
+ }
+
+ _vm->_video->drawSprite(_tempSprite, sprite, 0, 0,
+ sprite->getWidth() - 1, sprite->getHeight() - 1, 0, 0, 0);
+
+ if (index == 21) {
+ _vm->_draw->forceBlit();
+ _vm->_video->retrace();
+ }
+
+ return true;
+}
+
+bool SaveLoad::saveTempSprite(uint32 index, bool palette) {
+ SurfaceDesc *sprite = _vm->_draw->_spritesArray[index];
+
+ if (!sprite) {
+ warning("Couldn't save to the temporary sprite: "
+ "No such sprite %d", index);
+ return false;
+ }
+
+ delete _tempSprite;
+ _tempSprite = _vm->_video->initSurfDesc(_vm->_global->_videoMode,
+ sprite->getWidth(), sprite->getHeight(), 0);
+
+ _vm->_video->drawSprite(sprite, _tempSprite, 0, 0,
+ sprite->getWidth() - 1, sprite->getHeight() - 1, 0, 0, 0);
+
+ _tempSpriteSize = _vm->_draw->getSpriteRectSize(index);
+
+ if (palette) {
+ memcpy((char *) _tempPal,
+ (char *) _vm->_global->_pPaletteDesc->vgaPal, 768);
+ _tempSpriteSize += 768;
+ }
+
+ return true;
+}
+
+bool SaveLoad::loadSprite(Common::ReadStream &in, int32 size) {
+ SurfaceDesc *sprite;
+ byte *buf;
+ int nRead;
+ int index;
+ bool readPal;
+
+ if (size >= 0) {
+ warning("Invalid attempt at loading a sprite");
+ return false;
+ }
+
+ index = getSpriteIndex(size);
+ readPal = getSpritePalette(size);
+
+ if ((index < 0) || (index >= SPRITES_COUNT)) {
+ warning("Index out of range while loading a sprite (%d)",
+ index);
+ return false;
+ }
+
+ size = _vm->_draw->getSpriteRectSize(index);
+ sprite = _vm->_draw->_spritesArray[index];
+
+ if (!sprite) {
+ warning("Couldn't load sprite: No such sprite %d", index);
+ return false;
+ }
+
+ buf = new byte[MAX(768, size)];
+ assert(buf);
+
+ if (readPal) {
+ nRead = in.read(buf, 768);
+ if (nRead != 768) {
+ warning("Couldn't read a palette: requested 768, got %d", nRead);
+ delete[] buf;
+ return false;
+ }
+
+ memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal,
+ (char *) buf, 768);
+ }
+
+ nRead = in.read(buf, size);
+ if (nRead != size) {
+ warning("Couldn't read sprite data: requested %d, got %d", size, nRead);
+ delete[] buf;
+ return false;
+ }
+
+ memcpy((char *) sprite->getVidMem(), buf, size);
+
+ delete[] buf;
+ return true;
+}
+
+bool SaveLoad::saveSprite(Common::WriteStream &out, int32 size) {
+ SurfaceDesc *sprite;
+ int written;
+ int index;
+ bool readPal;
+
+ if (size >= 0) {
+ warning("Invalid attempt at saving a sprite");
+ return false;
+ }
+
+ index = getSpriteIndex(size);
+ readPal = getSpritePalette(size);
+
+ if ((index < 0) || (index >= SPRITES_COUNT)) {
+ warning("Index out of range while saving a sprite (%d)",
+ index);
+ return false;
+ }
+
+ size = _vm->_draw->getSpriteRectSize(index);
+ sprite = _vm->_draw->_spritesArray[index];
+
+ if (!sprite) {
+ warning("Couldn't save sprite: No such sprite %d", index);
+ return false;
+ }
+
+ if (readPal) {
+ written = out.write((char *) _vm->_global->_pPaletteDesc->vgaPal, 768);
+ if (written != 768) {
+ warning("Couldn't write a palette: requested 768, wrote %d", written);
+ return false;
+ }
+ }
+
+ written = out.write((char *) sprite->getVidMem(), size);
+ if (written != size) {
+ warning("Couldn't write a sprite: requested %d, wrote %d",
+ size, written);
+ return false;
+ }
+
+ return true;
+}
+
+bool SaveLoad::fromEndian(byte *buf, const byte *sizes, uint32 count) {
+ while (count-- > 0) {
+ if (*sizes == 3)
+ *((uint32 *) buf) = READ_LE_UINT32(buf);
+ else if (*sizes == 1)
+ *((uint16 *) buf) = READ_LE_UINT16(buf);
+ else if (*sizes != 0) {
+ warning("SaveLoad::fromEndian(): Corrupted variables sizes");
+ return false;
+ }
+
+ count -= *sizes;
+ buf += *sizes + 1;
+ sizes += *sizes + 1;
+ }
+
+ return true;
+}
+
+bool SaveLoad::toEndian(byte *buf, const byte *sizes, uint32 count) {
+ while (count-- > 0) {
+ if (*sizes == 3)
+ WRITE_LE_UINT32(buf, *((uint32 *) buf));
+ else if (*sizes == 1)
+ WRITE_LE_UINT16(buf, *((uint16 *) buf));
+ else if (*sizes != 0) {
+ warning("SaveLoad::toEndian(): Corrupted variables sizes");
+ return false;
+ }
+
+ count -= *sizes;
+ buf += *sizes + 1;
+ sizes += *sizes + 1;
+ }
+
+ return true;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/saveload.h b/engines/gob/saveload.h
new file mode 100644
index 0000000000..905ec6965d
--- /dev/null
+++ b/engines/gob/saveload.h
@@ -0,0 +1,162 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GOB_SAVELOAD_H
+#define GOB_SAVELOAD_H
+
+#include "common/stream.h"
+
+#include "gob/video.h"
+
+namespace Gob {
+
+enum SaveType {
+ kSaveNone = -1,
+ kSaveGame,
+ kSaveTempSprite,
+ kSaveNotes,
+ kSaveScreenshot,
+ kSaveIgnore
+};
+
+class SaveLoad {
+public:
+ int32 getSize(SaveType type);
+ bool load(SaveType type, int16 dataVar, int32 size, int32 offset);
+ bool save(SaveType type, int16 dataVar, int32 size, int32 offset);
+
+ virtual SaveType getSaveType(const char *fileName) = 0;
+
+ SaveLoad(GobEngine *vm, const char *targetName);
+ virtual ~SaveLoad();
+
+protected:
+ int _curSlot;
+ char **_saveFiles;
+
+ int _stagesCount;
+ byte **_buffer;
+
+ // While using the notepad or changing the font, the original executable
+ // temporarily dumps Draw::_backSurface to a file. Since that's not really
+ // a nice thing to do, we work around it.
+ SurfaceDesc *_tempSprite;
+ Video::Color _tempPal[256];
+ int32 _tempSpriteSize;
+
+ GobEngine *_vm;
+
+ int getSpriteIndex(int32 size) {
+ if (size < -1000)
+ size += 1000;
+
+ return -size - 1;
+ }
+ bool getSpritePalette(int32 size) {
+ return size < -1000;
+ }
+
+ const char *setCurSlot(int slot);
+ bool fromEndian(byte *buf, const byte *sizes, uint32 count);
+ bool toEndian(byte *buf, const byte *sizes, uint32 count);
+ uint32 read(Common::ReadStream &in, byte *buf,
+ byte *sizes, uint32 count);
+ uint32 write(Common::WriteStream &out, byte *buf,
+ byte *sizes, uint32 count);
+
+ bool loadDataEndian(Common::ReadStream &in, int16 dataVar, uint32 size);
+ bool saveDataEndian(Common::WriteStream &out, int16 dataVar, uint32 size);
+
+ bool loadTempSprite(uint32 index, bool palette);
+ bool saveTempSprite(uint32 index, bool palette);
+ bool loadSprite(Common::ReadStream &in, int32 size);
+ bool saveSprite(Common::WriteStream &out, int32 size);
+
+ int32 getSizeTempSprite();
+ bool loadTempSprite(int16 dataVar, int32 size, int32 offset);
+ bool saveTempSprite(int16 dataVar, int32 size, int32 offset);
+
+ virtual uint32 getSaveGameSize() = 0;
+
+ virtual int32 getSizeGame() = 0;
+ virtual int32 getSizeNotes() = 0;
+ virtual int32 getSizeScreenshot() = 0;
+ virtual bool loadGame(int16 dataVar, int32 size, int32 offset) = 0;
+ virtual bool loadNotes(int16 dataVar, int32 size, int32 offset) = 0;
+ virtual bool loadScreenshot(int16 dataVar, int32 size, int32 offset) = 0;
+ virtual bool saveGame(int16 dataVar, int32 size, int32 offset) = 0;
+ virtual bool saveNotes(int16 dataVar, int32 size, int32 offset) = 0;
+ virtual bool saveScreenshot(int16 dataVar, int32 size, int32 offset) = 0;
+};
+
+class SaveLoad_v2 : public SaveLoad {
+public:
+ virtual SaveType getSaveType(const char *fileName);
+
+ SaveLoad_v2(GobEngine *vm, const char *targetName);
+ virtual ~SaveLoad_v2() {};
+
+protected:
+ virtual uint32 getSaveGameSize();
+
+ virtual int32 getSizeGame();
+ virtual int32 getSizeNotes();
+ virtual int32 getSizeScreenshot();
+ virtual bool loadGame(int16 dataVar, int32 size, int32 offset);
+ virtual bool loadNotes(int16 dataVar, int32 size, int32 offset);
+ virtual bool loadScreenshot(int16 dataVar, int32 size, int32 offset);
+ virtual bool saveGame(int16 dataVar, int32 size, int32 offset);
+ virtual bool saveNotes(int16 dataVar, int32 size, int32 offset);
+ virtual bool saveScreenshot(int16 dataVar, int32 size, int32 offset);
+};
+
+class SaveLoad_v3 : public SaveLoad_v2 {
+public:
+ virtual SaveType getSaveType(const char *fileName);
+
+ SaveLoad_v3(GobEngine *vm, const char *targetName);
+ virtual ~SaveLoad_v3() {};
+
+protected:
+ bool _useScreenshots;
+ bool _firstSizeGame;
+ int8 _saveSlot;
+
+ virtual uint32 getSaveGameSize();
+
+ virtual int32 getSizeGame();
+ virtual int32 getSizeNotes();
+ virtual int32 getSizeScreenshot();
+ virtual bool loadGame(int16 dataVar, int32 size, int32 offset);
+ virtual bool loadNotes(int16 dataVar, int32 size, int32 offset);
+ virtual bool loadScreenshot(int16 dataVar, int32 size, int32 offset);
+ virtual bool saveGame(int16 dataVar, int32 size, int32 offset);
+ virtual bool saveNotes(int16 dataVar, int32 size, int32 offset);
+ virtual bool saveScreenshot(int16 dataVar, int32 size, int32 offset);
+
+ bool saveGame(int32 screenshotSize);
+};
+
+} // End of namespace Gob
+
+#endif // GOB_SAVELOAD_H
diff --git a/engines/gob/saveload_v2.cpp b/engines/gob/saveload_v2.cpp
new file mode 100644
index 0000000000..b8aa0ec804
--- /dev/null
+++ b/engines/gob/saveload_v2.cpp
@@ -0,0 +1,286 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/endian.h"
+#include "common/file.h"
+
+#include "gob/gob.h"
+#include "gob/saveload.h"
+#include "gob/global.h"
+#include "gob/game.h"
+
+namespace Gob {
+
+SaveLoad_v2::SaveLoad_v2(GobEngine *vm, const char *targetName) :
+ SaveLoad(vm, targetName) {
+
+ _stagesCount = 1;
+
+ _buffer = new byte*[_stagesCount];
+
+ assert(_buffer);
+
+ _buffer[0] = 0;
+}
+
+SaveType SaveLoad_v2::getSaveType(const char *fileName) {
+ if (!scumm_stricmp(fileName, "cat.inf"))
+ return kSaveGame;
+ if (!scumm_stricmp(fileName, "cat.cat"))
+ return kSaveGame;
+ if (!scumm_stricmp(fileName, "save.inf"))
+ return kSaveTempSprite;
+ if (!scumm_stricmp(fileName, "bloc.inf"))
+ return kSaveNotes;
+
+ return kSaveNone;
+}
+
+uint32 SaveLoad_v2::getSaveGameSize() {
+ return 80 + (READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4) * 2;
+}
+
+int32 SaveLoad_v2::getSizeNotes() {
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::InSaveFile *in;
+ int32 size = -1;
+
+ in = saveMan->openForLoading(_saveFiles[(int) kSaveNotes]);
+ if (in) {
+ size = in->size();
+ delete in;
+ }
+
+ return size;
+}
+
+int32 SaveLoad_v2::getSizeGame() {
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::InSaveFile *in;
+
+ for (int i = 14; i >= 0; i--) {
+ in = saveMan->openForLoading(setCurSlot(i));
+ if (in) {
+ delete in;
+ return (i + 1) * READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) *
+ 4 + 600;
+ }
+ }
+
+ return -1;
+}
+
+int32 SaveLoad_v2::getSizeScreenshot() {
+ return -1;
+}
+
+bool SaveLoad_v2::loadGame(int16 dataVar, int32 size, int32 offset) {
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::InSaveFile *in;
+ int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4;
+
+ if (size == 0) {
+ dataVar = 0;
+ size = varSize;
+ }
+
+ int slot = (offset - 600) / varSize;
+ int slotR = (offset - 600) % varSize;
+
+ if ((offset == 0) && (size == 600)) {
+
+ byte *varBuf = _vm->_global->_inter_variables + dataVar;
+ for (int i = 0; i < 15; i++, varBuf += 40) {
+ in = saveMan->openForLoading(setCurSlot(i));
+ if (in) {
+ in->read(varBuf, 40);
+ delete in;
+ } else
+ memset(varBuf, 0, 40);
+ }
+ memset(_vm->_global->_inter_variablesSizes + dataVar, 0, 600);
+ return true;
+
+ } else if ((offset > 0) && (slot < 15) &&
+ (slotR == 0) && (size == varSize)) {
+
+ in = saveMan->openForLoading(setCurSlot(slot));
+ if (!in) {
+ warning("Can't open file for slot %d", slot);
+ return false;
+ }
+
+ uint32 sGameSize = getSaveGameSize();
+ uint32 fSize = in->size();
+ if (fSize != sGameSize) {
+ warning("Can't load from slot %d: Wrong size (%d, %d)", slot,
+ fSize, sGameSize);
+ delete in;
+ return false;
+ }
+
+ in->seek(80);
+ if (loadDataEndian(*in, dataVar, size)) {
+ delete in;
+ debugC(1, kDebugFileIO, "Loading from slot %d", slot);
+ return true;
+ }
+ delete in;
+
+ } else
+ warning("Invalid loading procedure (%d, %d, %d, %d)",
+ offset, size, slot, slotR);
+
+ return false;
+}
+
+bool SaveLoad_v2::loadNotes(int16 dataVar, int32 size, int32 offset) {
+ bool retVal;
+
+ if ((size <= 0) || (offset != 0)) {
+ warning("Invalid attempt at loading the notes (%d, %d)", size, offset);
+ return false;
+ }
+
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ char *sName = _saveFiles[(int) kSaveNotes];
+
+ Common::InSaveFile *in = saveMan->openForLoading(sName);
+ if (!in) {
+ warning("Can't open file \"%s\" for reading", sName);
+ return false;
+ }
+
+ retVal = loadDataEndian(*in, dataVar, size);
+ delete in;
+ return retVal;
+}
+
+bool SaveLoad_v2::loadScreenshot(int16 dataVar, int32 size, int32 offset) {
+ return false;
+}
+
+bool SaveLoad_v2::saveGame(int16 dataVar, int32 size, int32 offset) {
+ int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4;
+
+ if (size == 0) {
+ dataVar = 0;
+ size = varSize;
+ }
+
+ int slot = (offset - 600) / varSize;
+ int slotR = (offset - 600) % varSize;
+
+ if ((offset == 0) && (size == 600)) {
+
+ delete[] _buffer[0];
+ _buffer[0] = new byte[1200];
+ assert(_buffer[0]);
+
+ memcpy(_buffer[0], _vm->_global->_inter_variables + dataVar, 600);
+ memset(_buffer[0] + 600, 0, 600);
+
+ return true;
+
+ } else if ((offset > 0) && (slot < 15) &&
+ (slotR == 0) && (size == varSize)) {
+
+ if (!_buffer[0]) {
+ warning("Tried to save without writing the index first");
+ return false;
+ }
+
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::OutSaveFile *out;
+
+ out = saveMan->openForSaving(setCurSlot(slot));
+ if (!out) {
+ warning("Can't open file for slot %d for writing", slot);
+ delete[] _buffer[0];
+ _buffer[0] = 0;
+ return false;
+ }
+
+ bool retVal = false;
+
+ if (out->write(_buffer[0] + slot * 40, 40) == 40)
+ if (out->write(_buffer[0] + 600 + slot * 40, 40) == 40)
+ if (saveDataEndian(*out, dataVar, size)) {
+ out->finalize();
+ if (!out->ioFailed())
+ retVal = true;
+ }
+
+ if (!retVal)
+ warning("Can't save to slot %d", slot);
+ else
+ debugC(1, kDebugFileIO, "Saved to slot %d", slot);
+
+ delete[] _buffer[0];
+ _buffer[0] = 0;
+ delete out;
+
+ return retVal;
+
+ } else
+ warning("Invalid saving procedure (%d, %d, %d, %d)",
+ offset, size, slot, slotR);
+
+ return false;
+}
+
+bool SaveLoad_v2::saveNotes(int16 dataVar, int32 size, int32 offset) {
+ bool retVal;
+
+ if ((size <= 0) || (offset != 0)) {
+ warning("Invalid attempt at saving the notes (%d, %d)", size, offset);
+ return false;
+ }
+
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ char *sName = _saveFiles[(int) kSaveNotes];
+
+ Common::OutSaveFile *out = saveMan->openForSaving(sName);
+ if (!out) {
+ warning("Can't open file \"%s\" for writing", sName);
+ return false;
+ }
+
+ retVal = saveDataEndian(*out, dataVar, size);
+
+ out->finalize();
+ if (out->ioFailed()) {
+ warning("Can't save notes");
+ retVal = false;
+ }
+
+ delete out;
+ return retVal;
+}
+
+bool SaveLoad_v2::saveScreenshot(int16 dataVar, int32 size, int32 offset) {
+ return false;
+}
+
+} // End of namespace Gob
diff --git a/engines/gob/saveload_v3.cpp b/engines/gob/saveload_v3.cpp
new file mode 100644
index 0000000000..fdd31f2d37
--- /dev/null
+++ b/engines/gob/saveload_v3.cpp
@@ -0,0 +1,428 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 Ivan Dubrov
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/endian.h"
+#include "common/file.h"
+
+#include "gob/gob.h"
+#include "gob/saveload.h"
+#include "gob/global.h"
+#include "gob/game.h"
+
+namespace Gob {
+
+SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName) :
+ SaveLoad_v2(vm, targetName) {
+
+ _saveSlot = -1;
+ _stagesCount = 3;
+
+ _buffer = new byte*[_stagesCount];
+
+ assert(_buffer);
+
+ _buffer[0] = new byte[1000];
+ _buffer[1] = new byte[1200];
+ _buffer[2] = 0;
+
+ assert(_buffer[0] && _buffer[1]);
+
+ memset(_buffer[0], 0, 1000);
+ memset(_buffer[1], 0, 1200);
+
+ _useScreenshots = false;
+ _firstSizeGame = true;
+}
+
+SaveType SaveLoad_v3::getSaveType(const char *fileName) {
+ if (!scumm_stricmp(fileName, "cat.inf"))
+ return kSaveGame;
+ if (!scumm_stricmp(fileName, "ima.inf"))
+ return kSaveScreenshot;
+ if (!scumm_stricmp(fileName, "intro.$$$"))
+ return kSaveTempSprite;
+ if (!scumm_stricmp(fileName, "prot"))
+ return kSaveIgnore;
+ if (!scumm_stricmp(fileName, "config"))
+ return kSaveIgnore;
+
+ return kSaveNone;
+}
+
+uint32 SaveLoad_v3::getSaveGameSize() {
+ uint32 size;
+
+ size = 1040 + (READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4) * 2;
+ if (_useScreenshots)
+ size += 19968;
+
+ return size;
+}
+
+int32 SaveLoad_v3::getSizeNotes() {
+ return -1;
+}
+
+int32 SaveLoad_v3::getSizeGame() {
+ if (_firstSizeGame) {
+ _firstSizeGame = false;
+ return -1;
+ }
+
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::InSaveFile *in;
+ int32 size = -1;
+
+ int slot = _curSlot;
+ for (int i = 29; i >= 0; i--) {
+ in = saveMan->openForLoading(setCurSlot(i));
+ if (in) {
+ delete in;
+ size = (i + 1) * READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) *
+ 4 + 1700;
+ break;
+ }
+ }
+ setCurSlot(slot);
+
+ return size;
+}
+
+int32 SaveLoad_v3::getSizeScreenshot() {
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::InSaveFile *in;
+ int32 size = -1;
+
+ _useScreenshots = true;
+ int slot = _curSlot;
+ for (int i = 29; i >= 0; i--) {
+ in = saveMan->openForLoading(setCurSlot(i));
+ if (in) {
+ delete in;
+ size = (i + 1) * 19968 + 80;
+ break;
+ }
+ }
+ setCurSlot(slot);
+
+ return size;
+}
+
+bool SaveLoad_v3::loadGame(int16 dataVar, int32 size, int32 offset) {
+ int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4;
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::InSaveFile *in;
+
+ int slot = (offset - 1700) / varSize;
+ int slotR = (offset - 1700) % varSize;
+
+ if ((size > 0) && (offset < 500) && ((size + offset) <= 500)) {
+
+ memcpy(_vm->_global->_inter_variables + dataVar,
+ _buffer[0] + offset, size);
+ memcpy(_vm->_global->_inter_variablesSizes + dataVar,
+ _buffer[0] + offset + 500, size);
+ return true;
+
+ } else if ((size == 1200) && (offset == 500)) {
+
+ memset(_buffer[1], 0, 1200);
+
+ slot = _curSlot;
+ for (int i = 0; i < 30; i++) {
+ in = saveMan->openForLoading(setCurSlot(i));
+ if (in) {
+ in->seek(1000);
+ in->read(_buffer[1] + i * 40, 40);
+ delete in;
+ }
+ }
+ setCurSlot(slot);
+
+ memcpy(_vm->_global->_inter_variables + dataVar, _buffer[1], 1200);
+ memset(_vm->_global->_inter_variablesSizes + dataVar, 0, 1200);
+ return true;
+
+ } else if ((offset > 0) && (slot < 30) &&
+ (slotR == 0) && (size == 0)) {
+
+ in = saveMan->openForLoading(setCurSlot(slot));
+ if (!in) {
+ warning("Can't open file for slot %d", slot);
+ return false;
+ }
+
+ uint32 sGameSize = getSaveGameSize();
+ uint32 fSize = in->size();
+ if (fSize != sGameSize) {
+ warning("Can't load from slot %d: Wrong size (%d, %d)", slot,
+ fSize, sGameSize);
+ delete in;
+ return false;
+ }
+
+ byte varBuf[500], sizeBuf[500];
+ if (read(*in, varBuf, sizeBuf, 500) == 500) {
+ if (fromEndian(varBuf, sizeBuf, 500)) {
+ memcpy(_buffer[0], varBuf, 500);
+ memcpy(_buffer[0] + 500, sizeBuf, 500);
+ in->seek(1040);
+ if (loadDataEndian(*in, 0, varSize)) {
+ delete in;
+ debugC(1, kDebugFileIO, "Loading from slot %d", slot);
+ return true;
+ }
+ }
+ }
+ delete in;
+
+ } else
+ warning("Invalid loading procedure (%d, %d, %d, %d)",
+ offset, size, slot, slotR);
+
+ return false;
+}
+
+bool SaveLoad_v3::loadNotes(int16 dataVar, int32 size, int32 offset) {
+ return false;
+}
+
+bool SaveLoad_v3::loadScreenshot(int16 dataVar, int32 size, int32 offset) {
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::InSaveFile *in;
+
+ int slot = (offset - 80) / 19968;
+ int slotR = (offset - 80) % 19968;
+
+ _useScreenshots = true;
+ if ((size == 40) && (offset == 40)) {
+ char buf[40];
+
+ memset(buf, 0, 40);
+
+ slot = _curSlot;
+ for (int i = 0; i < 30; i++) {
+ in = saveMan->openForLoading(setCurSlot(i));
+ if (in) {
+ delete in;
+ buf[i] = 1;
+ }
+ }
+ setCurSlot(slot);
+
+ memcpy(_vm->_global->_inter_variables + dataVar, buf, 40);
+ memset(_vm->_global->_inter_variablesSizes + dataVar, 0, 40);
+ return true;
+
+ } else if ((offset > 0) && (slot < 30) &&
+ (slotR == 0) && (size < 0)) {
+
+ int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4;
+
+ in = saveMan->openForLoading(setCurSlot(slot));
+ if (!in) {
+ warning("Can't open file for slot %d", slot);
+ return false;
+ }
+
+ uint32 sGameSize = getSaveGameSize();
+ uint32 fSize = in->size();
+ if (fSize != sGameSize) {
+ warning("Can't load screenshot from slot %d: Wrong size (%d, %d)",
+ slot, fSize, sGameSize);
+ delete in;
+ return false;
+ }
+
+ in->seek(1040 + varSize * 2);
+ return loadSprite(*in, size);
+
+ } else
+ warning("Invalid attempt at loading a screenshot (%d, %d, %d, %d)",
+ offset, size, slot, slotR);
+
+ return false;
+}
+
+bool SaveLoad_v3::saveGame(int16 dataVar, int32 size, int32 offset) {
+ int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4;
+
+ int slot = (offset - 1700) / varSize;
+ int slotR = (offset - 1700) % varSize;
+
+ if ((size > 0) && (offset < 500) && ((size + offset) <= 500)) {
+
+ memcpy(_buffer[0] + offset,
+ _vm->_global->_inter_variables + dataVar, size);
+ memcpy(_buffer[0] + offset + 500,
+ _vm->_global->_inter_variablesSizes + dataVar, size);
+
+ return true;
+
+ } else if ((size > 0) && (offset >= 500) && (offset < 1700) &&
+ ((size + offset) <= 1700)) {
+
+ memcpy(_buffer[1] + offset - 500,
+ _vm->_global->_inter_variables + dataVar, size);
+
+ return true;
+
+ } else if ((offset > 0) && (slot < 30) &&
+ (slotR == 0) && (size == 0)) {
+
+ _saveSlot = -1;
+
+ delete _buffer[2];
+ _buffer[2] = new byte[varSize * 2];
+ assert(_buffer[2]);
+
+ memcpy(_buffer[2], _vm->_global->_inter_variables, varSize);
+ memcpy(_buffer[2] + varSize,
+ _vm->_global->_inter_variablesSizes, varSize);
+
+ if (!toEndian(_buffer[2], _buffer[2] + varSize, varSize)) {
+ delete _buffer[2];
+ _buffer[2] = 0;
+ return false;
+ }
+
+ _saveSlot = slot;
+
+ if (!_useScreenshots)
+ return saveGame(0);
+
+ return true;
+
+ } else
+ warning("Invalid saving procedure (%d, %d, %d, %d)",
+ offset, size, slot, slotR);
+
+ return false;
+}
+
+bool SaveLoad_v3::saveNotes(int16 dataVar, int32 size, int32 offset) {
+ return false;
+}
+
+bool SaveLoad_v3::saveScreenshot(int16 dataVar, int32 size, int32 offset) {
+ int slot = (offset - 80) / 19968;
+ int slotR = (offset - 80) % 19968;
+
+ _useScreenshots = true;
+
+ if ((offset < 80) && (size > 0)) {
+
+ return true;
+
+ } else if ((offset > 0) && (slot < 30) &&
+ (slotR == 0) && (size < 0)) {
+
+ return saveGame(size);
+
+ } else
+ warning("Invalid attempt at saving a screenshot (%d, %d, %d, %d)",
+ offset, size, slot, slotR);
+
+ return false;
+}
+
+bool SaveLoad_v3::saveGame(int32 screenshotSize) {
+ int8 slot = _saveSlot;
+
+ _saveSlot = -1;
+
+ if ((slot < 0) || (slot > 29)) {
+ warning("Can't save to slot %d: Out of range", slot);
+ delete[] _buffer[2];
+ _buffer[2] = 0;
+ return false;
+ }
+
+ if (!_buffer[2]) {
+ warning("Can't save to slot %d: No data", slot);
+ return false;
+ }
+
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::OutSaveFile *out;
+
+ out = saveMan->openForSaving(setCurSlot(slot));
+ if (!out) {
+ warning("Can't open file for slot %d for writing", slot);
+ delete[] _buffer[2];
+ _buffer[2] = 0;
+ return false;
+ }
+
+ int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4;
+ byte varBuf[500], sizeBuf[500];
+
+ memcpy(varBuf, _buffer[0], 500);
+ memcpy(sizeBuf, _buffer[0] + 500, 500);
+
+ bool retVal = false;
+ if (toEndian(varBuf, sizeBuf, 500))
+ if (write(*out, varBuf, sizeBuf, 500) == 500)
+ if (out->write(_buffer[1] + slot * 40, 40) == 40)
+ if (out->write(_buffer[2], varSize * 2) == ((uint32) (varSize * 2))) {
+ out->flush();
+ if (!out->ioFailed())
+ retVal = true;
+ }
+
+ delete[] _buffer[2];
+ _buffer[2] = 0;
+
+ if (!retVal) {
+ warning("Can't save to slot %d", slot);
+ delete out;
+ return false;
+ }
+
+ if (_useScreenshots) {
+ if (screenshotSize >= 0) {
+ warning("Can't save to slot %d: Screenshot expected", slot);
+ delete out;
+ return false;
+ }
+
+ if (!saveSprite(*out, screenshotSize)) {
+ delete out;
+ return false;
+ }
+ }
+
+ out->finalize();
+ if (out->ioFailed()) {
+ warning("Can't save to slot %d", slot);
+ delete out;
+ return false;
+ }
+
+ debugC(1, kDebugFileIO, "Saved to slot %d", slot);
+ delete out;
+ return true;
+}
+
+} // End of namespace Gob