From 4ceecdb25fde5e82f4e96774ebfb28d5d319820c Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Thu, 18 Dec 2008 02:48:15 +0000 Subject: Preliminary save/load support for Urban Runner svn-id: r35418 --- engines/gob/inter.cpp | 6 +- engines/gob/inter.h | 10 +- engines/gob/inter_bargon.cpp | 4 +- engines/gob/inter_v2.cpp | 40 +++---- engines/gob/inter_v3.cpp | 4 +- engines/gob/inter_v4.cpp | 4 +- engines/gob/inter_v5.cpp | 4 +- engines/gob/inter_v6.cpp | 4 +- engines/gob/saveload.h | 27 +++++ engines/gob/saveload_v6.cpp | 244 ++++++++++++++++++++++++++++++++++++++++++- engines/gob/variables.cpp | 4 + engines/gob/variables.h | 2 + 12 files changed, 314 insertions(+), 39 deletions(-) diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index fef4c8453d..85eb69e7cf 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -55,9 +55,9 @@ Inter::Inter(GobEngine *vm) : _vm(vm) { _soundEndTimeKey = 0; _soundStopVal = 0; - memset(_pasteBuf, 0, 300); - memset(_pasteSizeBuf, 0, 300); - _pastePos = 0; + memset(_varStack, 0, 300); + memset(_varSizesStack, 0, 300); + _varStackPos = 0; _noBusyWait = false; diff --git a/engines/gob/inter.h b/engines/gob/inter.h index 7026ed5ab6..5d82700457 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -89,9 +89,9 @@ protected: int16 _animPalHighIndex[8]; int16 _animPalDir[8]; - byte _pasteBuf[300]; - byte _pasteSizeBuf[300]; - int16 _pastePos; + byte _varStack[300]; + byte _varSizesStack[300]; + int16 _varStackPos; // The busy-wait detection in o1_keyFunc breaks fast scrolling in Ween bool _noBusyWait; @@ -364,8 +364,8 @@ protected: void o2_loadFontToSprite(); void o2_totSub(); void o2_switchTotSub(); - void o2_copyVars(); - void o2_pasteVars(); + void o2_pushVars(); + void o2_popVars(); void o2_loadMapObjects(); void o2_freeGoblins(); void o2_moveGoblin(); diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp index 154dbee603..aa6e1fa7d9 100644 --- a/engines/gob/inter_bargon.cpp +++ b/engines/gob/inter_bargon.cpp @@ -204,8 +204,8 @@ void Inter_Bargon::setupOpcodes() { /* 40 */ OPCODE(o2_totSub), OPCODE(o2_switchTotSub), - OPCODE(o2_copyVars), - OPCODE(o2_pasteVars), + OPCODE(o2_pushVars), + OPCODE(o2_popVars), /* 44 */ {NULL, ""}, {NULL, ""}, diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index 2b780f96b1..7aa17b33ab 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -212,8 +212,8 @@ void Inter_v2::setupOpcodes() { /* 40 */ OPCODE(o2_totSub), OPCODE(o2_switchTotSub), - OPCODE(o2_copyVars), - OPCODE(o2_pasteVars), + OPCODE(o2_pushVars), + OPCODE(o2_popVars), /* 44 */ {NULL, ""}, {NULL, ""}, @@ -1178,39 +1178,40 @@ void Inter_v2::o2_switchTotSub() { _vm->_game->switchTotSub(index, skipPlay); } -void Inter_v2::o2_copyVars() { +void Inter_v2::o2_pushVars() { byte count; int16 varOff; count = *_vm->_global->_inter_execPtr++; - for (int i = 0; i < count; i++, _pastePos++) { + for (int i = 0; i < count; i++, _varStackPos++) { if ((*_vm->_global->_inter_execPtr == 25) || (*_vm->_global->_inter_execPtr == 28)) { varOff = _vm->_parse->parseVarIndex(); _vm->_global->_inter_execPtr++; - _variables->copyTo(varOff, _pasteBuf + _pastePos, _pasteSizeBuf + _pastePos, + _variables->copyTo(varOff, _varStack + _varStackPos, + _varSizesStack + _varStackPos, _vm->_global->_inter_animDataSize * 4); - _pastePos += _vm->_global->_inter_animDataSize * 4; - _pasteBuf[_pastePos] = _vm->_global->_inter_animDataSize * 4; - _pasteSizeBuf[_pastePos] = _vm->_global->_inter_animDataSize * 4; + _varStackPos += _vm->_global->_inter_animDataSize * 4; + _varStack[_varStackPos] = _vm->_global->_inter_animDataSize * 4; + _varSizesStack[_varStackPos] = _vm->_global->_inter_animDataSize * 4; } else { - if (evalExpr(&varOff) == 20) + if (!evalExpr(&varOff) == 20) _vm->_global->_inter_resVal = 0; - memcpy(_pasteBuf + _pastePos, &_vm->_global->_inter_resVal, 4); - memcpy(_pasteSizeBuf + _pastePos, &_vm->_global->_inter_resVal, 4); - _pastePos += 4; - _pasteBuf[_pastePos] = 4; - _pasteSizeBuf[_pastePos] = 4; + memcpy(_varStack + _varStackPos, &_vm->_global->_inter_resVal, 4); + memcpy(_varSizesStack + _varStackPos, &_vm->_global->_inter_resVal, 4); + _varStackPos += 4; + _varStack[_varStackPos] = 4; + _varSizesStack[_varStackPos] = 4; } } } -void Inter_v2::o2_pasteVars() { +void Inter_v2::o2_popVars() { byte count; int16 varOff; int16 sizeV; @@ -1219,12 +1220,13 @@ void Inter_v2::o2_pasteVars() { count = *_vm->_global->_inter_execPtr++; for (int i = 0; i < count; i++) { varOff = _vm->_parse->parseVarIndex(); - sizeV = _pasteBuf[--_pastePos]; - sizeS = _pasteSizeBuf[_pastePos]; + sizeV = _varStack[--_varStackPos]; + sizeS = _varSizesStack[_varStackPos]; assert(sizeV == sizeS); - _pastePos -= sizeV; - _variables->copyFrom(varOff, _pasteBuf + _pastePos, _pasteSizeBuf + _pastePos, sizeV); + _varStackPos -= sizeV; + _variables->copyFrom(varOff, _varStack + _varStackPos, + _varSizesStack + _varStackPos, sizeV); } } diff --git a/engines/gob/inter_v3.cpp b/engines/gob/inter_v3.cpp index 131b15fc37..fee8358ec0 100644 --- a/engines/gob/inter_v3.cpp +++ b/engines/gob/inter_v3.cpp @@ -201,8 +201,8 @@ void Inter_v3::setupOpcodes() { /* 40 */ OPCODE(o2_totSub), OPCODE(o2_switchTotSub), - OPCODE(o2_copyVars), - OPCODE(o2_pasteVars), + OPCODE(o2_pushVars), + OPCODE(o2_popVars), /* 44 */ {NULL, ""}, {NULL, ""}, diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp index 03b5e902e9..77cd490323 100644 --- a/engines/gob/inter_v4.cpp +++ b/engines/gob/inter_v4.cpp @@ -202,8 +202,8 @@ void Inter_v4::setupOpcodes() { /* 40 */ OPCODE(o2_totSub), OPCODE(o2_switchTotSub), - OPCODE(o2_copyVars), - OPCODE(o2_pasteVars), + OPCODE(o2_pushVars), + OPCODE(o2_popVars), /* 44 */ {NULL, ""}, {NULL, ""}, diff --git a/engines/gob/inter_v5.cpp b/engines/gob/inter_v5.cpp index c1bef2a85d..dbdeb6f533 100644 --- a/engines/gob/inter_v5.cpp +++ b/engines/gob/inter_v5.cpp @@ -156,8 +156,8 @@ void Inter_v5::setupOpcodes() { /* 40 */ OPCODE(o2_totSub), OPCODE(o2_switchTotSub), - OPCODE(o2_copyVars), - OPCODE(o2_pasteVars), + OPCODE(o2_pushVars), + OPCODE(o2_popVars), /* 44 */ {NULL, ""}, {NULL, ""}, diff --git a/engines/gob/inter_v6.cpp b/engines/gob/inter_v6.cpp index e61e78cbbb..8e16337827 100644 --- a/engines/gob/inter_v6.cpp +++ b/engines/gob/inter_v6.cpp @@ -135,8 +135,8 @@ void Inter_v6::setupOpcodes() { /* 40 */ OPCODE(o6_totSub), OPCODE(o2_switchTotSub), - OPCODE(o2_copyVars), - OPCODE(o2_pasteVars), + OPCODE(o2_pushVars), + OPCODE(o2_popVars), /* 44 */ {NULL, ""}, {NULL, ""}, diff --git a/engines/gob/saveload.h b/engines/gob/saveload.h index 467403bdb8..dbfa80b67a 100644 --- a/engines/gob/saveload.h +++ b/engines/gob/saveload.h @@ -414,6 +414,7 @@ class SaveLoad_v6 : public SaveLoad { public: enum SaveType { kSaveNone, + kSaveGame, kSaveNoCD }; @@ -431,6 +432,32 @@ protected: }; static SaveFile _saveFiles[]; + + int32 _varSize; + + StagedSave *_save; + + byte _indexBuffer[2900]; + bool _hasIndex; + + virtual int getSaveType(const char *fileName); + + virtual int32 getSizeVersioned(int type); + virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset); + virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + + int32 getSizeGame(SaveFile &saveFile); + + bool loadGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + + bool saveGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + + void assertInited(); + + void refreshIndex(); }; } // End of namespace Gob diff --git a/engines/gob/saveload_v6.cpp b/engines/gob/saveload_v6.cpp index cc233a36ba..b3e9eec2c1 100644 --- a/engines/gob/saveload_v6.cpp +++ b/engines/gob/saveload_v6.cpp @@ -28,19 +28,35 @@ #include "gob/gob.h" #include "gob/saveload.h" #include "gob/game.h" +#include "gob/inter.h" namespace Gob { SaveLoad_v6::SaveFile SaveLoad_v6::_saveFiles[] = { - {"mdo.def", 0, kSaveModeExists, kSaveNone}, - {"NO_CD.TXT", 0, kSaveModeExists, kSaveNoCD} + { "cat.inf", 0, kSaveModeSave, kSaveGame}, + { "mdo.def", 0, kSaveModeExists, kSaveNone}, + {"no_cd.txt", 0, kSaveModeExists, kSaveNoCD}, }; SaveLoad_v6::SaveLoad_v6(GobEngine *vm, const char *targetName) : SaveLoad(vm, targetName) { + + _save = new StagedSave(_vm->getEndianness()); + + _saveFiles[0].destName = new char[strlen(targetName) + 5]; + _saveFiles[1].destName = 0; + _saveFiles[2].destName = 0; + + sprintf(_saveFiles[0].destName, "%s.s00", targetName); + + _varSize = 0; + _hasIndex = false; } SaveLoad_v6::~SaveLoad_v6() { + delete _save; + + delete[] _saveFiles[0].destName; } SaveLoad::SaveMode SaveLoad_v6::getSaveMode(const char *fileName) { @@ -63,4 +79,228 @@ SaveLoad::SaveMode SaveLoad_v6::getSaveMode(const char *fileName) { return kSaveModeNone; } +int SaveLoad_v6::getSaveType(const char *fileName) { + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return i; + + return -1; +} + +int32 SaveLoad_v6::getSizeVersioned(int type) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveGame: + return getSizeGame(_saveFiles[type]); + default: + return -1; + } + + return -1; +} + +bool SaveLoad_v6::loadVersioned(int type, int16 dataVar, int32 size, int32 offset) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveGame: + if (loadGame(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading from slot %d", getSlot(offset)); + break; + + default: + return -1; + } + + return false; +} + +bool SaveLoad_v6::saveVersioned(int type, int16 dataVar, int32 size, int32 offset) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveGame: + if (saveGame(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving to slot %d", getSlot(offset)); + break; + + default: + return -1; + } + + return false; +} + +int SaveLoad_v6::getSlot(int32 offset) const { + return ((offset - 2900) / _varSize); +} + +int SaveLoad_v6::getSlotRemainder(int32 offset) const { + return ((offset - 2900) % _varSize); +} + +int32 SaveLoad_v6::getSizeGame(SaveFile &saveFile) { + if (!_hasIndex) + return -1; + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in; + + for (int i = 60; i >= 0; i--) { + in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); + if (in) { + delete in; + return (i + 1) * _varSize + 2900; + } + } + + return -1; +} + +bool SaveLoad_v6::loadGame(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + if (size == 0) { + dataVar = 0; + size = _varSize; + } + + if (offset < 2900) { + debugC(3, kDebugSaveLoad, "Saving save index"); + + if ((offset + size) > 2900) { + warning("Wrong index size (%d, %d)", size, offset); + return false; + } + + if (!_hasIndex) { + warning("No index written yet"); + return false; + } + + refreshIndex(); + + byte *sizes = new byte[size]; + memset(sizes, 0, size); + + _vm->_inter->_variables->copyFrom(dataVar, _indexBuffer + offset, sizes, size); + + delete[] sizes; + + + } else { + int slot = getSlot(offset); + int slotRem = getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); + + if ((slot >= 60) || (slotRem != 0)) { + warning("Invalid loading procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + refreshIndex(); + SaveLoad::setCurrentSlot(saveFile.destName, slot); + + if (!_save->load(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) + return false; + + refreshIndex(); + } + + return true; +} + +bool SaveLoad_v6::saveGame(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + if (size == 0) { + dataVar = 0; + size = _varSize; + } + + if (offset < 2900) { + debugC(3, kDebugSaveLoad, "Saving save index"); + + if ((offset + size) > 2900) { + warning("Wrong index size (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyTo(dataVar, _indexBuffer + offset, 0, size); + _hasIndex = true; + + } else { + int slot = getSlot(offset); + int slotRem = getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); + + if ((slot >= 60) || (slotRem != 0)) { + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + if (!_hasIndex) { + warning("No index written yet"); + return false; + } + + SaveLoad::setCurrentSlot(saveFile.destName, slot); + + byte sizes[40]; + memset(sizes, 0, 40); + if(!_save->save(0, 40, 0, saveFile.destName, _indexBuffer + 500 + (slot * 40), sizes)) + return false; + + if (!_save->save(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) + return false; + + refreshIndex(); + } + + return true; +} + +void SaveLoad_v6::assertInited() { + if (_varSize > 0) + return; + + _varSize = _vm->_inter->_variables->getSize(); + + _save->addStage(40); + _save->addStage(_varSize); +} + +void SaveLoad_v6::refreshIndex() { + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in; + + int32 max = -1; + byte *names = _indexBuffer + 500; + for (int i = 0; i < 60; i++, names += 40) { + in = saveMan->openForLoading(setCurrentSlot(_saveFiles[0].destName, i)); + if (in) { + max = i; + in->read(names, 40); + delete in; + } else + memset(names, 0, 40); + } + + WRITE_LE_UINT32(_indexBuffer + 160, max + 1); + + Common::OutSaveFile *out = saveMan->openForSaving("Foobar"); + out->write(_indexBuffer, 2900); + out->flush(); + delete out; +} + } // End of namespace Gob diff --git a/engines/gob/variables.cpp b/engines/gob/variables.cpp index 805aaeb839..7b1390abe8 100644 --- a/engines/gob/variables.cpp +++ b/engines/gob/variables.cpp @@ -44,6 +44,10 @@ Variables::~Variables() { delete[] _sizes; } +uint32 Variables::getSize() const { + return _size; +} + void Variables::clear() { memset(_vars, 0, _size); diff --git a/engines/gob/variables.h b/engines/gob/variables.h index 32f160a6bd..c2f2285b80 100644 --- a/engines/gob/variables.h +++ b/engines/gob/variables.h @@ -39,6 +39,8 @@ public: Variables(uint32 size); virtual ~Variables(); + uint32 getSize() const; + void writeVar8(uint32 var, uint8 value); void writeVar16(uint32 var, uint16 value); void writeVar32(uint32 var, uint32 value); -- cgit v1.2.3