diff options
Diffstat (limited to 'engines/dreamweb/saveload.cpp')
-rw-r--r-- | engines/dreamweb/saveload.cpp | 729 |
1 files changed, 531 insertions, 198 deletions
diff --git a/engines/dreamweb/saveload.cpp b/engines/dreamweb/saveload.cpp index f0fd477ec1..a526c8a3bc 100644 --- a/engines/dreamweb/saveload.cpp +++ b/engines/dreamweb/saveload.cpp @@ -22,44 +22,116 @@ #include "dreamweb/dreamweb.h" #include "engines/metaengine.h" +#include "graphics/thumbnail.h" #include "gui/saveload.h" #include "common/config-manager.h" #include "common/translation.h" +#include "common/serializer.h" -namespace DreamGen { +namespace DreamWeb { // Temporary storage for loading the room from a savegame Room g_madeUpRoomDat; -void DreamGenContext::loadGame() { - if (data.byte(kCommandtype) != 246) { - data.byte(kCommandtype) = 246; - commandOnly(41); - } - if (data.word(kMousebutton) == data.word(kOldbutton)) + +void syncReelRoutine(Common::Serializer &s, ReelRoutine *reel) { + s.syncAsByte(reel->reallocation); + s.syncAsByte(reel->mapX); + s.syncAsByte(reel->mapY); + s.syncAsUint16LE(reel->_reelPointer); + s.syncAsByte(reel->period); + s.syncAsByte(reel->counter); + s.syncAsByte(reel->b7); +} + +void syncGameVars(Common::Serializer &s, GameVars &vars) { + s.syncAsByte(vars._startVars); + s.syncAsByte(vars._progressPoints); + s.syncAsByte(vars._watchOn); + s.syncAsByte(vars._shadesOn); + s.syncAsByte(vars._secondCount); + s.syncAsByte(vars._minuteCount); + s.syncAsByte(vars._hourCount); + s.syncAsByte(vars._zoomOn); + s.syncAsByte(vars._location); + s.syncAsByte(vars._exPos); + s.syncAsUint16LE(vars._exFramePos); + s.syncAsUint16LE(vars._exTextPos); + s.syncAsUint16LE(vars._card1Money); + s.syncAsUint16LE(vars._listPos); + s.syncAsByte(vars._ryanPage); + s.syncAsUint16LE(vars._watchingTime); + s.syncAsUint16LE(vars._reelToWatch); + s.syncAsUint16LE(vars._endWatchReel); + s.syncAsByte(vars._speedCount); + s.syncAsByte(vars._watchSpeed); + s.syncAsUint16LE(vars._reelToHold); + s.syncAsUint16LE(vars._endOfHoldReel); + s.syncAsByte(vars._watchMode); + s.syncAsByte(vars._destAfterHold); + s.syncAsByte(vars._newsItem); + s.syncAsByte(vars._liftFlag); + s.syncAsByte(vars._liftPath); + s.syncAsByte(vars._lockStatus); + s.syncAsByte(vars._doorPath); + s.syncAsByte(vars._countToOpen); + s.syncAsByte(vars._countToClose); + s.syncAsByte(vars._rockstarDead); + s.syncAsByte(vars._generalDead); + s.syncAsByte(vars._sartainDead); + s.syncAsByte(vars._aideDead); + s.syncAsByte(vars._beenMugged); + s.syncAsByte(vars._gunPassFlag); + s.syncAsByte(vars._canMoveAltar); + s.syncAsByte(vars._talkedToAttendant); + s.syncAsByte(vars._talkedToSparky); + s.syncAsByte(vars._talkedToBoss); + s.syncAsByte(vars._talkedToRecep); + s.syncAsByte(vars._cardPassFlag); + s.syncAsByte(vars._madmanFlag); + s.syncAsByte(vars._keeperFlag); + s.syncAsByte(vars._lastTrigger); + s.syncAsByte(vars._manDead); + s.syncAsByte(vars._seed1); + s.syncAsByte(vars._seed2); + s.syncAsByte(vars._seed3); + s.syncAsByte(vars._needToTravel); + s.syncAsByte(vars._throughDoor); + s.syncAsByte(vars._newObs); + s.syncAsByte(vars._ryanOn); + s.syncAsByte(vars._combatCount); + s.syncAsByte(vars._lastWeapon); + s.syncAsByte(vars._dreamNumber); + s.syncAsByte(vars._roomAfterDream); + s.syncAsByte(vars._shakeCounter); +} + +void DreamWebEngine::loadGame() { + commandOnlyCond(41, 246); + if (_mouseButton == _oldButton) return; // "noload" - if (data.word(kMousebutton) == 1) + if (_mouseButton == 1) doLoad(-1); } // if -1, open menu to ask for slot to load // if >= 0, directly load from that slot -void DreamGenContext::doLoad(int savegameId) { - data.byte(kLoadingorsave) = 1; +void DreamWebEngine::doLoad(int savegameId) { + _loadingOrSave = 1; if (ConfMan.getBool("dreamweb_originalsaveload") && savegameId == -1) { showOpBox(); showLoadOps(); - data.byte(kCurrentslot) = 0; + _currentSlot = 0; showSlots(); showNames(); - data.byte(kPointerframe) = 0; + _pointerFrame = 0; workToScreenM(); namesToOld(); - data.byte(kGetback) = 0; + _getBack = 0; - while (data.byte(kGetback) == 0) { - if (quitRequested()) + while (_getBack == 0) { + if (_quitRequested) return; delPointer(); readMouse(); @@ -68,14 +140,15 @@ void DreamGenContext::doLoad(int savegameId) { dumpPointer(); dumpTextLine(); RectWithCallback loadlist[] = { - { kOpsx+176,kOpsx+192,kOpsy+60,kOpsy+76,&DreamGenContext::getBackToOps }, - { kOpsx+128,kOpsx+190,kOpsy+12,kOpsy+100,&DreamGenContext::actualLoad }, - { kOpsx+2,kOpsx+92,kOpsy+4,kOpsy+81,&DreamGenContext::selectSlot }, - { 0,320,0,200,&DreamGenContext::blank }, + { kOpsx+176,kOpsx+192,kOpsy+60,kOpsy+76,&DreamWebEngine::getBackToOps }, + { kOpsx+128,kOpsx+190,kOpsy+12,kOpsy+100,&DreamWebEngine::actualLoad }, + { kOpsx+2,kOpsx+92,kOpsy+4,kOpsy+81,&DreamWebEngine::selectSlot }, + { kOpsx+158,kOpsx+158+(18*3),kOpsy-17,kOpsy-1,&DreamWebEngine::selectSaveLoadPage }, + { 0,320,0,200,&DreamWebEngine::blank }, { 0xFFFF,0,0,0,0 } }; checkCoords(loadlist); - if (data.byte(kGetback) == 2) + if (_getBack == 2) return; // "quitloaded" } } else { @@ -93,67 +166,62 @@ void DreamGenContext::doLoad(int savegameId) { } if (savegameId < 0) { - data.byte(kGetback) = 0; + _getBack = 0; return; } loadPosition(savegameId); - data.byte(kGetback) = 1; + _getBack = 1; } // If we reach this point, loadPosition() has just been called. // Among other things, it will have filled g_MadeUpRoomDat. - // kTempgraphics might not have been allocated if we bypassed all menus - if (data.word(kTempgraphics) != 0xFFFF) - getRidOfTemp(); + _saveGraphics.clear(); startLoading(g_madeUpRoomDat); loadRoomsSample(); - data.byte(kRoomloaded) = 1; - data.byte(kNewlocation) = 255; + _roomLoaded = 1; + _newLocation = 255; clearSprites(); initMan(); initRain(); - data.word(kTextaddressx) = 13; - data.word(kTextaddressy) = 182; - data.byte(kTextlen) = 240; + _textAddressX = 13; + _textAddressY = 182; + _textLen = 240; startup(); - workToScreenCPP(); - data.byte(kGetback) = 4; + workToScreen(); + _getBack = 4; } -void DreamGenContext::saveGame() { - if (data.byte(kMandead) == 2) { +void DreamWebEngine::saveGame() { + if (_vars._manDead == 2) { blank(); return; } - if (data.byte(kCommandtype) != 247) { - data.byte(kCommandtype) = 247; - commandOnly(44); - } - if (data.word(kMousebutton) != 1) + commandOnlyCond(44, 247); + if (_mouseButton != 1) return; - data.byte(kLoadingorsave) = 2; + _loadingOrSave = 2; if (ConfMan.getBool("dreamweb_originalsaveload")) { showOpBox(); showSaveOps(); - data.byte(kCurrentslot) = 0; + _currentSlot = 0; showSlots(); showNames(); workToScreenM(); namesToOld(); - data.word(kBufferin) = 0; - data.word(kBufferout) = 0; - data.byte(kGetback) = 0; + _bufferIn = 0; + _bufferOut = 0; + _getBack = 0; - while (data.byte(kGetback) == 0) { - if (quitRequested()) + while (_getBack == 0) { + if (_quitRequested) return; delPointer(); checkInput(); @@ -164,10 +232,11 @@ void DreamGenContext::saveGame() { dumpTextLine(); RectWithCallback savelist[] = { - { kOpsx+176,kOpsx+192,kOpsy+60,kOpsy+76,&DreamGenContext::getBackToOps }, - { kOpsx+128,kOpsx+190,kOpsy+12,kOpsy+100,&DreamGenContext::actualSave }, - { kOpsx+2,kOpsx+92,kOpsy+4,kOpsy+81,&DreamGenContext::selectSlot }, - { 0,320,0,200,&DreamGenContext::blank }, + { kOpsx+176,kOpsx+192,kOpsy+60,kOpsy+76,&DreamWebEngine::getBackToOps }, + { kOpsx+128,kOpsx+190,kOpsy+12,kOpsy+100,&DreamWebEngine::actualSave }, + { kOpsx+2,kOpsx+92,kOpsy+4,kOpsy+81,&DreamWebEngine::selectSlot }, + { kOpsx+158,kOpsx+158+(18*3),kOpsy-17,kOpsy-1,&DreamWebEngine::selectSaveLoadPage }, + { 0,320,0,200,&DreamWebEngine::blank }, { 0xFFFF,0,0,0,0 } }; checkCoords(savelist); @@ -186,80 +255,194 @@ void DreamGenContext::saveGame() { delete dialog; if (savegameId < 0) { - data.byte(kGetback) = 0; + _getBack = 0; return; } char descbuf[17] = { 2, 0 }; - strncpy((char*)descbuf+1, game_description.c_str(), 16); + Common::strlcpy((char *)descbuf + 1, game_description.c_str(), 16); unsigned int desclen = game_description.size(); if (desclen > 15) desclen = 15; // zero terminate, and pad with ones descbuf[++desclen] = 0; - while (desclen < 17) + while (desclen < 16) descbuf[++desclen] = 1; - if (savegameId < 7) - memcpy(&_saveNames[17*savegameId], descbuf, 17); - - savePosition(savegameId, descbuf); // TODO: The below is copied from actualsave - getRidOfTemp(); + _saveGraphics.clear(); restoreAll(); // reels - data.word(kTextaddressx) = 13; - data.word(kTextaddressy) = 182; - data.byte(kTextlen) = 240; + _textAddressX = 13; + _textAddressY = 182; + _textLen = 240; redrawMainScrn(); + workToScreen(); // show the main screen without the mouse pointer + + // We need to save after the scene has been redrawn, to capture the + // correct screen thumbnail + savePosition(savegameId, descbuf); + workToScreenM(); - data.byte(kGetback) = 4; + _getBack = 4; } } -void DreamGenContext::namesToOld() { - memcpy(_saveNamesOld, _saveNames, 17*7); +void DreamWebEngine::namesToOld() { + memcpy(_saveNamesOld, _saveNames, 17*21); } -void DreamGenContext::oldToNames() { - memcpy(_saveNames, _saveNamesOld, 17*7); +void DreamWebEngine::oldToNames() { + memcpy(_saveNames, _saveNamesOld, 17*21); } -void DreamGenContext::saveLoad() { - if (data.word(kWatchingtime) || (data.byte(kPointermode) == 2)) { +void DreamWebEngine::saveLoad() { + if (_vars._watchingTime || (_pointerMode == 2)) { blank(); return; } - if (data.byte(kCommandtype) != 253) { - data.byte(kCommandtype) = 253; - commandOnly(43); - } - if ((data.word(kMousebutton) != data.word(kOldbutton)) && (data.word(kMousebutton) & 1)) + commandOnlyCond(43, 253); + if ((_mouseButton != _oldButton) && (_mouseButton & 1)) doSaveLoad(); } -void DreamGenContext::showMainOps() { - showFrame(tempGraphics(), kOpsx+10, kOpsy+10, 8, 0); - showFrame(tempGraphics(), kOpsx+59, kOpsy+30, 7, 0); - showFrame(tempGraphics(), kOpsx+128+4, kOpsy+12, 1, 0); +void DreamWebEngine::doSaveLoad() { + _pointerFrame = 0; + _textAddressX = 70; + _textAddressY = 182-8; + _textLen = 181; + _manIsOffScreen = 1; + clearWork(); + createPanel2(); + underTextLine(); + getRidOfAll(); + loadSaveBox(); + showOpBox(); + showMainOps(); + workToScreen(); + + RectWithCallback opsList[] = { + { kOpsx+59,kOpsx+114,kOpsy+30,kOpsy+76,&DreamWebEngine::getBackFromOps }, + { kOpsx+10,kOpsx+77,kOpsy+10,kOpsy+59,&DreamWebEngine::DOSReturn }, + { kOpsx+128,kOpsx+190,kOpsy+16,kOpsy+100,&DreamWebEngine::discOps }, + { 0,320,0,200,&DreamWebEngine::blank }, + { 0xFFFF,0,0,0,0 } + }; + + bool firstOps = true; + + do { // restart ops + if (firstOps) { + firstOps = false; + } else { + showOpBox(); + showMainOps(); + workToScreenM(); + } + _getBack = 0; + + do { // wait ops + if (_quitRequested) { + _manIsOffScreen = 0; + return; + } + + readMouse(); + showPointer(); + vSync(); + dumpPointer(); + dumpTextLine(); + delPointer(); + checkCoords(opsList); + } while (!_getBack); + } while (_getBack == 2); + + _textAddressX = 13; + _textAddressY = 182; + _textLen = 240; + if (_getBack != 4) { + _saveGraphics.clear(); + restoreAll(); + redrawMainScrn(); + workToScreenM(); + _commandType = 200; + } + _manIsOffScreen = 0; } -void DreamGenContext::showDiscOps() { - showFrame(tempGraphics(), kOpsx+128+4, kOpsy+12, 1, 0); - showFrame(tempGraphics(), kOpsx+10, kOpsy+10, 9, 0); - showFrame(tempGraphics(), kOpsx+59, kOpsy+30, 10, 0); - showFrame(tempGraphics(), kOpsx+176+2, kOpsy+60-4, 5, 0); +void DreamWebEngine::getBackFromOps() { + if (_vars._manDead == 2) + blank(); + else + getBack1(); } -void DreamGenContext::actualSave() { - if (data.byte(kCommandtype) != 222) { - data.byte(kCommandtype) = 222; - commandOnly(44); +void DreamWebEngine::getBackToOps() { + commandOnlyCond(42, 201); + + if (_mouseButton != _oldButton) { + if (_mouseButton & 1) { + oldToNames(); + _getBack = 2; + } } +} + +void DreamWebEngine::showMainOps() { + showFrame(_saveGraphics, kOpsx+10, kOpsy+10, 8, 0); + showFrame(_saveGraphics, kOpsx+59, kOpsy+30, 7, 0); + showFrame(_saveGraphics, kOpsx+128+4, kOpsy+12, 1, 0); +} + +void DreamWebEngine::showDiscOps() { + showFrame(_saveGraphics, kOpsx+128+4, kOpsy+12, 1, 0); + showFrame(_saveGraphics, kOpsx+10, kOpsy+10, 9, 0); + showFrame(_saveGraphics, kOpsx+59, kOpsy+30, 10, 0); + showFrame(_saveGraphics, kOpsx+176+2, kOpsy+60-4, 5, 0); +} - if (!(data.word(kMousebutton) & 1)) +void DreamWebEngine::discOps() { + commandOnlyCond(43, 249); + + if (_mouseButton == _oldButton || !(_mouseButton & 1)) return; - unsigned int slot = data.byte(kCurrentslot); + scanForNames(); + _loadingOrSave = 2; + showOpBox(); + showDiscOps(); + _currentSlot = 0; + workToScreenM(); + _getBack = 0; + + RectWithCallback discOpsList[] = { + { kOpsx+59,kOpsx+114,kOpsy+30,kOpsy+76,&DreamWebEngine::loadGame }, + { kOpsx+10,kOpsx+79,kOpsy+10,kOpsy+59,&DreamWebEngine::saveGame }, + { kOpsx+176,kOpsx+192,kOpsy+60,kOpsy+76,&DreamWebEngine::getBackToOps }, + { 0,320,0,200,&DreamWebEngine::blank }, + { 0xFFFF,0,0,0,0 } + }; + + do { + if (_quitRequested) + return; // quitdiscops + + delPointer(); + readMouse(); + showPointer(); + vSync(); + dumpPointer(); + dumpTextLine(); + checkCoords(discOpsList); + } while (!_getBack); +} + +void DreamWebEngine::actualSave() { + commandOnlyCond(44, 222); + + if (!(_mouseButton & 1)) + return; + + unsigned int slot = _currentSlot + 7 * _saveLoadPage; const char *desc = &_saveNames[17*slot]; if (desc[1] == 0) // The actual description string starts at desc[1] @@ -267,54 +450,48 @@ void DreamGenContext::actualSave() { savePosition(slot, desc); - getRidOfTemp(); + _saveGraphics.clear(); restoreAll(); // reels - data.word(kTextaddressx) = 13; - data.word(kTextaddressy) = 182; - data.byte(kTextlen) = 240; + _textAddressX = 13; + _textAddressY = 182; + _textLen = 240; redrawMainScrn(); workToScreenM(); - data.byte(kGetback) = 4; + _getBack = 4; } -void DreamGenContext::actualLoad() { - if (data.byte(kCommandtype) != 221) { - data.byte(kCommandtype) = 221; - commandOnly(41); - } +void DreamWebEngine::actualLoad() { + commandOnlyCond(41, 221); - if (data.word(kMousebutton) == data.word(kOldbutton) || data.word(kMousebutton) != 1) + if (_mouseButton == _oldButton || _mouseButton != 1) return; - unsigned int slot = data.byte(kCurrentslot); + unsigned int slot = _currentSlot + 7 * _saveLoadPage; const char *desc = &_saveNames[17*slot]; if (desc[1] == 0) // The actual description string starts at desc[1] return; - loadPosition(data.byte(kCurrentslot)); - data.byte(kGetback) = 1; + loadPosition(slot); + _getBack = 1; } -void DreamGenContext::savePosition(unsigned int slot, const char *descbuf) { +void DreamWebEngine::savePosition(unsigned int slot, const char *descbuf) { - const Room ¤tRoom = g_roomData[data.byte(kLocation)]; + const Room ¤tRoom = g_roomData[_vars._location]; Room madeUpRoom = currentRoom; - madeUpRoom.roomsSample = data.byte(kRoomssample); - madeUpRoom.mapX = data.byte(kMapx); - madeUpRoom.mapY = data.byte(kMapy); - madeUpRoom.liftFlag = data.byte(kLiftflag); - madeUpRoom.b21 = data.byte(kManspath); - madeUpRoom.facing = data.byte(kFacing); + madeUpRoom.roomsSample = _roomsSample; + madeUpRoom.mapX = _mapX; + madeUpRoom.mapY = _mapY; + madeUpRoom.liftFlag = _vars._liftFlag; + madeUpRoom.b21 = _mansPath; + madeUpRoom.facing = _facing; madeUpRoom.b27 = 255; - - engine->processEvents(); // TODO: Is this necessary? - - Common::String filename = engine->getSavegameFilename(slot); + Common::String filename = getSavegameFilename(slot); debug(1, "savePosition: slot %d filename %s", slot, filename.c_str()); - Common::OutSaveFile *outSaveFile = engine->getSaveFileManager()->openForSaving(filename); + Common::OutSaveFile *outSaveFile = getSaveFileManager()->openForSaving(filename); if (!outSaveFile) // TODO: Do proper error handling! error("save could not be opened for writing"); @@ -330,21 +507,52 @@ void DreamGenContext::savePosition(unsigned int slot, const char *descbuf) { // fill length fields in savegame file header uint16 len[6] = { 17, kLengthofvars, kLengthofextra, - 4*kNumchanges, 48, kLenofreelrouts }; + 4*kNumChanges, 48, kNumReelRoutines*8+1 }; for (int i = 0; i < 6; ++i) header.setLen(i, len[i]); + // Write a new section with data that we need for ScummVM (version, + // thumbnail, played time etc). We don't really care for its size, + // so we just set it to a magic number. + header.setLen(6, SCUMMVM_BLOCK_MAGIC_SIZE); + outSaveFile->write((const uint8 *)&header, sizeof(FileHeader)); outSaveFile->write(descbuf, len[0]); - outSaveFile->write(data.ptr(kStartvars, len[1]), len[1]); - outSaveFile->write(getSegment(data.word(kExtras)).ptr(kExframedata, len[2]), len[2]); - outSaveFile->write(getSegment(data.word(kBuffers)).ptr(kListofchanges, len[3]), len[3]); + // TODO: Convert more to serializer? + Common::Serializer s(0, outSaveFile); + syncGameVars(s, _vars); + + // the Extras segment: + outSaveFile->write((const uint8 *)_exFrames._frames, kFrameBlocksize); + outSaveFile->write((const uint8 *)_exFrames._data, kExframeslen); + outSaveFile->write((const uint8 *)_exData, sizeof(DynObject)*kNumexobjects); + outSaveFile->write((const uint8 *)_exText._offsetsLE, 2*(kNumExObjects+2)); + outSaveFile->write((const uint8 *)_exText._text, kExtextlen); + + outSaveFile->write(_listOfChanges, len[3]); // len[4] == 48, which is sizeof(Room) plus 16 for 'Roomscango' outSaveFile->write((const uint8 *)&madeUpRoom, sizeof(Room)); - outSaveFile->write(data.ptr(kRoomscango, 16), 16); + outSaveFile->write(_roomsCanGo, 16); - outSaveFile->write(data.ptr(kReelroutines, len[5]), len[5]); + for (unsigned int i = 0; i < kNumReelRoutines; ++i) { + syncReelRoutine(s, &_reelRoutines[i]); + } + // Terminator + s.syncAsByte(_reelRoutines[kNumReelRoutines].reallocation); + + // ScummVM data block + outSaveFile->writeUint32BE(SCUMMVM_HEADER); + outSaveFile->writeByte(SAVEGAME_VERSION); + TimeDate curTime; + g_system->getTimeAndDate(curTime); + uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF); + uint32 saveTime = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF); + uint32 playTime = g_engine->getTotalPlayTime() / 1000; + outSaveFile->writeUint32LE(saveDate); + outSaveFile->writeUint32LE(saveTime); + outSaveFile->writeUint32LE(playTime); + Graphics::saveThumbnail(*outSaveFile); outSaveFile->finalize(); if (outSaveFile->err()) { @@ -355,13 +563,13 @@ void DreamGenContext::savePosition(unsigned int slot, const char *descbuf) { delete outSaveFile; } -void DreamGenContext::loadPosition(unsigned int slot) { - data.word(kTimecount) = 0; +void DreamWebEngine::loadPosition(unsigned int slot) { + _timeCount = 0; clearChanges(); - Common::String filename = engine->getSavegameFilename(slot); + Common::String filename = getSavegameFilename(slot); debug(1, "loadPosition: slot %d filename %s", slot, filename.c_str()); - Common::InSaveFile *inSaveFile = engine->getSaveFileManager()->openForLoading(filename); + Common::InSaveFile *inSaveFile = getSaveFileManager()->openForLoading(filename); if (!inSaveFile) // TODO: Do proper error handling! error("save could not be opened for reading"); @@ -376,143 +584,188 @@ void DreamGenContext::loadPosition(unsigned int slot) { if (len[0] != 17) ::error("Error loading save: description buffer isn't 17 bytes"); - if (slot < 7) { + if (slot < 21) { inSaveFile->read(&_saveNames[17*slot], len[0]); } else { - // The savenames buffer only has room for 7 descriptions + // The savenames buffer only has room for 21 descriptions uint8 namebuf[17]; inSaveFile->read(namebuf, 17); } - inSaveFile->read(data.ptr(kStartvars, len[1]), len[1]); - inSaveFile->read(getSegment(data.word(kExtras)).ptr(kExframedata, len[2]), len[2]); - inSaveFile->read(getSegment(data.word(kBuffers)).ptr(kListofchanges, len[3]), len[3]); + + // TODO: Use serializer for more? + Common::Serializer s(inSaveFile, 0); + syncGameVars(s, _vars); + + // the Extras segment: + inSaveFile->read((uint8 *)_exFrames._frames, kFrameBlocksize); + inSaveFile->read((uint8 *)_exFrames._data, kExframeslen); + inSaveFile->read((uint8 *)_exData, sizeof(DynObject)*kNumexobjects); + inSaveFile->read((uint8 *)_exText._offsetsLE, 2*(kNumExObjects+2)); + inSaveFile->read((uint8 *)_exText._text, kExtextlen); + + inSaveFile->read(_listOfChanges, len[3]); // len[4] == 48, which is sizeof(Room) plus 16 for 'Roomscango' // Note: the values read into g_madeUpRoomDat are only used in actualLoad, // which is (almost) immediately called after this function inSaveFile->read((uint8 *)&g_madeUpRoomDat, sizeof(Room)); - inSaveFile->read(data.ptr(kRoomscango, 16), 16); + inSaveFile->read(_roomsCanGo, 16); - inSaveFile->read(data.ptr(kReelroutines, len[5]), len[5]); + for (unsigned int i = 0; i < kNumReelRoutines; ++i) { + syncReelRoutine(s, &_reelRoutines[i]); + } + // Terminator + s.syncAsByte(_reelRoutines[kNumReelRoutines].reallocation); + + // Check if there's a ScummVM data block + if (header.len(6) == SCUMMVM_BLOCK_MAGIC_SIZE) { + uint32 tag = inSaveFile->readUint32BE(); + if (tag != SCUMMVM_HEADER) { + warning("ScummVM data block found, but the block header is incorrect - skipping"); + delete inSaveFile; + return; + } + + byte version = inSaveFile->readByte(); + if (version > SAVEGAME_VERSION) { + warning("ScummVM data block found, but it has been saved with a newer version of ScummVM - skipping"); + delete inSaveFile; + return; + } + + inSaveFile->skip(4); // saveDate + inSaveFile->skip(4); // saveTime + uint32 playTime = inSaveFile->readUint32LE(); + g_engine->setTotalPlayTime(playTime * 1000); + + // The thumbnail data follows, but we don't need it here + } delete inSaveFile; } // Count number of save files, and load their descriptions into _saveNames -unsigned int DreamGenContext::scanForNames() { - unsigned int count = 0; - - FileHeader header; - - // TODO: Change this to use SaveFileManager::listSavefiles() - for (unsigned int slot = 0; slot < 7; ++slot) { - _saveNames[17*slot+0] = 2; - _saveNames[17*slot+1] = 0; +uint DreamWebEngine::scanForNames() { + // There are 21 save slots, each of which are 17 bytes. The first byte + // doesn't seem to be used. The name starts at the second byte. All the + // slots are initialized to be empty. + for (unsigned int slot = 0; slot < 21; ++slot) { + _saveNames[17 * slot + 0] = 2; + _saveNames[17 * slot + 1] = 0; for (int i = 2; i < 17; ++i) - _saveNames[17*slot+i] = 1; - - // Try opening savegame with the given slot id - Common::String filename = engine->getSavegameFilename(slot); - Common::InSaveFile *inSaveFile = engine->getSaveFileManager()->openForLoading(filename); - if (!inSaveFile) - continue; - - ++count; - - inSaveFile->read((uint8 *)&header, sizeof(FileHeader)); - - if (header.len(0) != 17) { - ::warning("Error loading save: description buffer isn't 17 bytes"); - delete inSaveFile; - continue; - } - - // NB: Only possible if slot < 7 - inSaveFile->read(&_saveNames[17*slot], 17); + _saveNames[17 * slot + i] = 1; // initialize with 1'sdrea + } - delete inSaveFile; + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray files = saveFileMan->listSavefiles("DREAMWEB.D??"); + Common::sort(files.begin(), files.end()); + + SaveStateList saveList; + for (uint i = 0; i < files.size(); ++i) { + const Common::String &file = files[i]; + Common::InSaveFile *stream = saveFileMan->openForLoading(file); + if (!stream) + error("cannot open save file %s", file.c_str()); + char name[17] = {}; + stream->seek(0x61); + stream->read(name, sizeof(name) - 1); + delete stream; + + int slotNum = atoi(file.c_str() + file.size() - 2); + SaveStateDescriptor sd(slotNum, name); + saveList.push_back(sd); + if (slotNum < 21) + Common::strlcpy(&_saveNames[17 * slotNum + 1], name, 16); // the first character is unused } - al = (uint8)count; + // FIXME: Can the following be safely removed? +// al = saveList.size() <= 7 ? (uint8)saveList.size() : 7; - return count; + return saveList.size(); } -void DreamGenContext::loadOld() { - if (data.byte(kCommandtype) != 252) { - data.byte(kCommandtype) = 252; - commandOnly(48); - } +void DreamWebEngine::loadOld() { + commandOnlyCond(48, 252); - if (!(data.word(kMousebutton) & 1)) + if (!(_mouseButton & 1)) return; doLoad(-1); - if (data.byte(kGetback) == 4 || quitRequested()) + if (_getBack == 4 || _quitRequested) return; showDecisions(); workToScreenM(); - data.byte(kGetback) = 0; + _getBack = 0; +} + +void DreamWebEngine::showDecisions() { + createPanel2(); + showOpBox(); + showFrame(_saveGraphics, kOpsx + 17, kOpsy + 13, 6, 0); + underTextLine(); } -void DreamGenContext::loadSaveBox() { - loadIntoTemp("DREAMWEB.G08"); +void DreamWebEngine::loadSaveBox() { + loadGraphicsFile(_saveGraphics, "G08"); } // show savegame names (original interface), and set kCursorpos -void DreamBase::showNames() { +void DreamWebEngine::showNames() { + unsigned int offset = 7 * _saveLoadPage; for (int slot = 0; slot < 7; ++slot) { // The first character of the savegame name is unused - Common::String name(&_saveNames[17*slot + 1]); + Common::String name(&_saveNames[17 * (slot + offset) + 1]); - if (slot != data.byte(kCurrentslot)) { + if (slot != _currentSlot) { printDirect((const uint8 *)name.c_str(), kOpsx + 21, kOpsy + 10*slot + 10, 200, false); continue; } - if (data.byte(kLoadingorsave) != 2) { - data.word(kCharshift) = 91; + if (_loadingOrSave != 2) { + _charShift = 91; printDirect((const uint8 *)name.c_str(), kOpsx + 21, kOpsy + 10*slot + 10, 200, false); - data.word(kCharshift) = 0; + _charShift = 0; continue; } int pos = name.size(); - data.byte(kCursorpos) = pos; + _cursorPos = pos; name += '/'; // cursor character printDirect((const uint8 *)name.c_str(), kOpsx + 21, kOpsy + 10*slot + 10, 200, false); } } -void DreamGenContext::checkInput() { - if (data.byte(kLoadingorsave) == 3) +void DreamWebEngine::checkInput() { + if (_loadingOrSave == 3) return; readKey(); + unsigned int slot = _currentSlot + 7 * _saveLoadPage; + // The first character of the savegame name is unused - char *name = &_saveNames[17*data.byte(kCurrentslot) + 1]; + char *name = &_saveNames[17*slot + 1]; - if (data.byte(kCurrentkey) == 0) { + if (_currentKey == 0) { return; - } else if (data.byte(kCurrentkey) == 13) { - data.byte(kLoadingorsave) = 3; - } else if (data.byte(kCurrentkey) == 8) { - if (data.byte(kCursorpos) == 0) + } else if (_currentKey == 13) { + _loadingOrSave = 3; + } else if (_currentKey == 8) { + if (_cursorPos == 0) return; - --data.byte(kCursorpos); - name[data.byte(kCursorpos)] = 0; - name[data.byte(kCursorpos)+1] = 1; + --_cursorPos; + name[_cursorPos] = 0; + name[_cursorPos+1] = 1; } else { - if (data.byte(kCursorpos) == 14) + if (_cursorPos == 14) return; - name[data.byte(kCursorpos)] = data.byte(kCurrentkey); - name[data.byte(kCursorpos)+1] = 0; - name[data.byte(kCursorpos)+2] = 1; - ++data.byte(kCursorpos); + name[_cursorPos] = _currentKey; + name[_cursorPos+1] = 0; + name[_cursorPos+2] = 1; + ++_cursorPos; } showOpBox(); @@ -522,5 +775,85 @@ void DreamGenContext::checkInput() { workToScreenM(); } +void DreamWebEngine::selectSaveLoadPage() { + commandOnlyCond(31, 254); + + if (_mouseButton != 1 || _mouseButton == _oldButton) + return; + uint saveLoadPage = (_mouseX - (kOpsx + 158)) / 18; + if (saveLoadPage != _saveLoadPage) { + _saveLoadPage = saveLoadPage; + // This will also make the first slot the selected one, based + // on the mouse Y position. I can't decide if this is a feature + // or not. + selectSlot(); + } +} + +void DreamWebEngine::selectSlot() { + commandOnlyCond(45, 244); + + if (_mouseButton != 1 || _mouseButton == _oldButton) + return; // noselslot + if (_loadingOrSave == 3) + _loadingOrSave--; + + oldToNames(); + int y = _mouseY - (kOpsy + 4); + if (y < 11) + _currentSlot = 0; + else + _currentSlot = y / 11; + + delPointer(); + showOpBox(); + showSlots(); + showNames(); + if (_loadingOrSave == 1) + showLoadOps(); + else + showSaveOps(); + readMouse(); + showPointer(); + workToScreen(); + delPointer(); +} + +void DreamWebEngine::showSlots() { + showFrame(_icons1, kOpsx + 158, kOpsy - 11, 12, 0); + showFrame(_icons1, kOpsx + 158 + 18 * _saveLoadPage, kOpsy - 11, 13 + _saveLoadPage, 0); + showFrame(_saveGraphics, kOpsx + 7, kOpsy + 8, 2, 0); + + uint16 y = kOpsy + 11; + + for (int slot = 0; slot < 7; slot++) { + if (slot == _currentSlot) + showFrame(_saveGraphics, kOpsx + 10, y, 3, 0); + + y += 10; + } +} + +void DreamWebEngine::showOpBox() { + showFrame(_saveGraphics, kOpsx, kOpsy, 0, 0); + + // This call displays half of the ops dialog in the CD version. It's not + // in the floppy version, and if it's called, a stray red dot is shown in + // the game dialogs. + if (isCD()) + showFrame(_saveGraphics, kOpsx, kOpsy + 55, 4, 0); +} + +void DreamWebEngine::showLoadOps() { + showFrame(_saveGraphics, kOpsx + 128 + 4, kOpsy + 12, 1, 0); + showFrame(_saveGraphics, kOpsx + 176 + 2, kOpsy + 60 - 4, 5, 0); + printMessage(kOpsx + 104, kOpsy + 14, 55, 101, (101 & 1)); +} + +void DreamWebEngine::showSaveOps() { + showFrame(_saveGraphics, kOpsx + 128 + 4, kOpsy + 12, 1, 0); + showFrame(_saveGraphics, kOpsx + 176 + 2, kOpsy + 60 - 4, 5, 0); + printMessage(kOpsx + 104, kOpsy + 14, 54, 101, (101 & 1)); +} -} // End of namespace DreamGen +} // End of namespace DreamWeb |