From dee8a04168fb0d0ccc58b73dd9fb8d0be9499b17 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Sun, 8 Apr 2007 00:08:26 +0000 Subject: Restructured saving/loading. Should work for Gob3 now, too... svn-id: r26414 --- engines/gob/global.cpp | 3 - engines/gob/global.h | 7 - engines/gob/gob.cpp | 439 +------------------------------------ engines/gob/gob.h | 22 +- engines/gob/inter_v2.cpp | 55 +++-- engines/gob/inter_v3.cpp | 133 +----------- engines/gob/module.mk | 3 + engines/gob/saveload.cpp | 511 ++++++++++++++++++++++++++++++++++++++++++++ engines/gob/saveload.h | 162 ++++++++++++++ engines/gob/saveload_v2.cpp | 286 +++++++++++++++++++++++++ engines/gob/saveload_v3.cpp | 428 +++++++++++++++++++++++++++++++++++++ 11 files changed, 1427 insertions(+), 622 deletions(-) create mode 100644 engines/gob/saveload.cpp create mode 100644 engines/gob/saveload.h create mode 100644 engines/gob/saveload_v2.cpp create mode 100644 engines/gob/saveload_v3.cpp 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 ¶ms) { 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 ¶ms) { 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 ¶ms) { int16 dataVar; int16 handle; byte *buf; + SaveType type; evalExpr(0); dataVar = _vm->_parse->parseVarIndex(); @@ -1825,17 +1827,11 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { 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 ¶ms) { int32 offset; int32 size; int16 dataVar; + SaveType type; evalExpr(0); dataVar = _vm->_parse->parseVarIndex(); @@ -1898,15 +1895,13 @@ bool Inter_v2::o2_writeData(OpFuncParams ¶ms) { 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 ¶ms) { return false; } -bool Inter_v3::o3_checkData(OpFuncParams ¶ms) { - 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 ¶ms) { - 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 ¶ms) { - 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 -- cgit v1.2.3