From 2a90435e5dccc0085613e35cc7177d1766cea6d0 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 22 Jul 2008 10:15:58 +0000 Subject: Fix for bug #2019355 (FW: broken compatibility with 0.11.1 saves): - Changed savegame loading related functions to use SeekableReadStream rather than InSaveFile so MemoryReadStream can be used transparently. - Fixed loadResourcesFromSave to load multiframe animations correctly and to load 0.11.0/0.11.1 Future Wars savegames which used a slightly different format. - Added a savegame format detector that tries to detect between the old Future Wars savegame format, the new one and a broken revision of the new one. - Changed makeLoad to first load the savegame fully into memory and only then handle it (If the savegame's packed then it's unpacked first). If the packed savegame can't tell its unpacked size (i.e. it's using zlib format) then we'll try to load up to 256kB of the savegame data. Thanks to wjp for his help with nailing this release critical bug. svn-id: r33192 --- engines/cine/various.cpp | 276 +++++++++++++++++++++++++++-------------------- 1 file changed, 162 insertions(+), 114 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index ab2fa645c7..8e6f3fce76 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -246,21 +246,130 @@ bool CineEngine::loadSaveDirectory(void) { return true; } +/*! \brief Savegame format detector + * \param fHandle Savefile to check + * \return Savegame format on success, ANIMSIZE_UNKNOWN on failure + * + * This function seeks through the savefile and tries to determine the + * savegame format it uses. There's a miniscule chance that the detection + * algorithm could get confused and think that the file uses both the older + * and the newer format but that is such a remote possibility that I wouldn't + * worry about it at all. + */ +enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle) { + // The animDataTable begins at savefile position 0x2315. + // Each animDataTable entry takes 23 bytes in older saves (Revisions 21772-31443) + // and 30 bytes in the save format after that (Revision 31444 and onwards). + // There are 255 entries in the animDataTable in both of the savefile formats. + static const uint animDataTableStart = 0x2315; + static const uint animEntriesCount = 255; + static const uint oldAnimEntrySize = 23; + static const uint newAnimEntrySize = 30; + static const uint defaultAnimEntrySize = newAnimEntrySize; + static const uint animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize}; + Common::Array animEntrySizeMatches; + const uint32 prevStreamPos = fHandle.pos(); + + // Try to walk through the savefile using different animDataTable entry sizes + // and make a list of all the successful entry sizes. + for (uint i = 0; i < ARRAYSIZE(animEntrySizeChoices); i++) { + // 206 = 2 * 50 * 2 + 2 * 3 (Size of global and object script entries) + // 20 = 4 * 2 + 2 * 6 (Size of overlay and background incrust entries) + static const uint sizeofScreenParams = 2 * 6; + static const uint globalScriptEntrySize = 206; + static const uint objectScriptEntrySize = 206; + static const uint overlayEntrySize = 20; + static const uint bgIncrustEntrySize = 20; + static const uint chainEntrySizes[] = { + globalScriptEntrySize, + objectScriptEntrySize, + overlayEntrySize, + bgIncrustEntrySize + }; + + uint animEntrySize = animEntrySizeChoices[i]; + // Jump over the animDataTable entries and the screen parameters + uint32 newPos = animDataTableStart + animEntrySize * animEntriesCount + sizeofScreenParams; + // Check that there's data left after the point we're going to jump to + if (newPos >= fHandle.size()) { + continue; + } + fHandle.seek(newPos); + + // Jump over the remaining items in the savegame file + // (i.e. the global scripts, object scripts, overlays and background incrusts). + bool chainWalkSuccess = true; + for (uint chainIndex = 0; chainIndex < ARRAYSIZE(chainEntrySizes); chainIndex++) { + // Read entry count and jump over the entries + int entryCount = fHandle.readSint16BE(); + newPos = fHandle.pos() + chainEntrySizes[chainIndex] * entryCount; + // Check that we didn't go past the end of file. + // Note that getting exactly to the end of file is acceptable. + if (newPos > fHandle.size()) { + chainWalkSuccess = false; + break; + } + fHandle.seek(newPos); + } + + // If we could walk the chain successfully and + // got exactly to the end of file then we've got a match. + if (chainWalkSuccess && fHandle.pos() == fHandle.size()) { + // We found a match, let's save it + animEntrySizeMatches.push_back(animEntrySize); + } + } + + // Check that we got only one entry size match. + // If we didn't, then return an error. + enum CineSaveGameFormat result = ANIMSIZE_UNKNOWN; + if (animEntrySizeMatches.size() == 1) { + const uint animEntrySize = animEntrySizeMatches[0]; + assert(animEntrySize == oldAnimEntrySize || animEntrySize == newAnimEntrySize); + if (animEntrySize == oldAnimEntrySize) { + result = ANIMSIZE_23; + } else { // animEntrySize == newAnimEntrySize + // Check data and mask pointers in all of the animDataTable entries + // to see whether we've got the version with the broken data and mask pointers or not. + // In the broken format all data and mask pointers were always zero. + static const uint relativeDataPos = 2 * 4; + bool pointersIntact = false; + for (uint i = 0; i < animEntriesCount; i++) { + fHandle.seek(animDataTableStart + i * animEntrySize + relativeDataPos); + uint32 data = fHandle.readUint32BE(); + uint32 mask = fHandle.readUint32BE(); + if (data != NULL || mask != NULL) { + pointersIntact = true; + break; + } + } + result = (pointersIntact ? ANIMSIZE_30_PTRS_INTACT : ANIMSIZE_30_PTRS_BROKEN); + } + } else if (animEntrySizeMatches.size() > 1) { + warning("Savegame format detector got confused by input data. Detecting savegame to be using an unknown format"); + } else { // animEtrySizeMatches.size() == 0 + debug(3, "Savegame format detector was unable to detect savegame's format"); + } + + fHandle.seek(prevStreamPos); + return result; +} + /*! \brief Restore script list item from savefile - * \param fHandle Savefile handlem open for reading + * \param fHandle Savefile handle open for reading * \param isGlobal Restore object or global script? */ -void loadScriptFromSave(Common::InSaveFile *fHandle, bool isGlobal) { +void loadScriptFromSave(Common::SeekableReadStream &fHandle, bool isGlobal) { ScriptVars localVars, labels; uint16 compare, pos; int16 idx; - labels.load(*fHandle); - localVars.load(*fHandle); + labels.load(fHandle); + localVars.load(fHandle); - compare = fHandle->readUint16BE(); - pos = fHandle->readUint16BE(); - idx = fHandle->readUint16BE(); + compare = fHandle.readUint16BE(); + pos = fHandle.readUint16BE(); + idx = fHandle.readUint16BE(); // no way to reinitialize these if (idx < 0) { @@ -283,7 +392,7 @@ void loadScriptFromSave(Common::InSaveFile *fHandle, bool isGlobal) { /*! \brief Restore overlay sprites from savefile * \param fHandle Savefile open for reading */ -void loadOverlayFromSave(Common::InSaveFile &fHandle) { +void loadOverlayFromSave(Common::SeekableReadStream &fHandle) { overlay tmp; fHandle.readUint32BE(); @@ -299,115 +408,17 @@ void loadOverlayFromSave(Common::InSaveFile &fHandle) { overlayList.push_back(tmp); } -/*! \brief Savefile format tester - * \param fHandle Savefile to check - * - * This function seeks through savefile and tries to guess if it's the original - * savegame format or broken format from ScummVM 0.10/0.11 - * The test is incomplete but this should cover 99.99% of cases. - * If anyone makes a savefile which could confuse this test, assert will - * report it - */ -bool brokenSave(Common::InSaveFile &fHandle) { - // Backward seeking not supported in compressed savefiles - // if you really want it, finish it yourself - return false; - - // fixed size part: 14093 bytes (12308 bytes in broken save) - // animDataTable begins at byte 6431 - - int filesize = fHandle.size(); - int startpos = fHandle.pos(); - int pos, tmp; - bool correct = false, broken = false; - - // check for correct format - while (filesize > 14093) { - pos = 14093; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 206; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 206; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 20; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 20; - - if (pos == filesize) correct = true; - break; - } - debug(5, "brokenSave: correct format check %s: size=%d, pos=%d", - correct ? "passed" : "failed", filesize, pos); - - // check for broken format - while (filesize > 12308) { - pos = 12308; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 206; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 206; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 20; - if (pos >= filesize) break; - - fHandle.seek(pos); - tmp = fHandle.readUint16BE(); - pos += 2 + tmp * 20; - - if (pos == filesize) broken = true; - break; - } - debug(5, "brokenSave: broken format check %s: size=%d, pos=%d", - broken ? "passed" : "failed", filesize, pos); - - // there's a very small chance that both cases will match - // if anyone runs into it, you'll have to walk through - // the animDataTable and try to open part file for each entry - if (!correct && !broken) { - error("brokenSave: file format check failed"); - } else if (correct && broken) { - error("brokenSave: both file formats seem to apply"); - } - - fHandle.seek(startpos); - debug(5, "brokenSave: detected %s file format", - correct ? "correct" : "broken"); - - return broken; -} - /*! \todo Implement Operation Stealth loading, this is obviously Future Wars only * \todo Add support for loading the zoneQuery table (Operation Stealth specific) */ bool CineEngine::makeLoad(char *saveName) { int16 i; int16 size; - bool broken; - Common::InSaveFile *fHandle; char bgName[13]; - fHandle = g_saveFileMan->openForLoading(saveName); + Common::SharedPtr saveFile(g_saveFileMan->openForLoading(saveName)); - if (!fHandle) { + if (!saveFile) { drawString(otherMessages[0], 0); waitPlayerInput(); // restoreScreen(); @@ -415,6 +426,46 @@ bool CineEngine::makeLoad(char *saveName) { return false; } + uint32 saveSize = saveFile->size(); + if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it + // Can't get information about the savefile's size so let's try + // reading as much as we can from the file up to a predefined upper limit. + // + // Some estimates for maximum savefile sizes (All with 255 animDataTable entries of 30 bytes each): + // With 256 global scripts, object scripts, overlays and background incrusts: + // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 256 = ~129kB + // With 512 global scripts, object scripts, overlays and background incrusts: + // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 512 = ~242kB + // + // I think it extremely unlikely that there would be over 512 global scripts, object scripts, + // overlays and background incrusts so 256kB seems like quite a safe upper limit. + // NOTE: If the savegame format is changed then this value might have to be re-evaluated! + // Hopefully devices with more limited memory can also cope with this memory allocation. + saveSize = 256 * 1024; + } + Common::SharedPtr fHandle(saveFile->readStream(saveSize)); + + // Try to detect the used savegame format + enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*fHandle); + + // Handle problematic savegame formats + if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) { + // One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but + // that's not implemented here because it was never used in a stable + // release of ScummVM but only during development (From revision 31453, + // which introduced the problem, until revision 32073, which fixed it). + // Therefore be bail out if we detect this particular savegame format. + warning("Detected a known broken savegame format, not loading savegame"); + return false; + } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { + // If we can't detect the savegame format + // then let's try the default format and hope for the best. + warning("Couldn't detect the used savegame format, trying default savegame format. Things may break"); + saveGameFormat = ANIMSIZE_30_PTRS_INTACT; + } + // Now we should have either of these formats + assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); + g_sound->stopMusic(); freeAnimDataTable(); overlayList.clear(); @@ -464,7 +515,6 @@ bool CineEngine::makeLoad(char *saveName) { checkForPendingDataLoadSwitch = 0; - broken = brokenSave(*fHandle); // At savefile position 0x0000: currentDisk = fHandle->readUint16BE(); @@ -588,7 +638,7 @@ bool CineEngine::makeLoad(char *saveName) { fHandle->readUint16BE(); // At 0x2315: - loadResourcesFromSave(*fHandle, broken); + loadResourcesFromSave(*fHandle, saveGameFormat); // TODO: handle screen params (really required ?) fHandle->readUint16BE(); @@ -600,12 +650,12 @@ bool CineEngine::makeLoad(char *saveName) { size = fHandle->readSint16BE(); for (i = 0; i < size; i++) { - loadScriptFromSave(fHandle, true); + loadScriptFromSave(*fHandle, true); } size = fHandle->readSint16BE(); for (i = 0; i < size; i++) { - loadScriptFromSave(fHandle, false); + loadScriptFromSave(*fHandle, false); } size = fHandle->readSint16BE(); @@ -615,8 +665,6 @@ bool CineEngine::makeLoad(char *saveName) { loadBgIncrustFromSave(*fHandle); - delete fHandle; - if (strlen(currentMsgName)) { loadMsg(currentMsgName); } -- cgit v1.2.3 From c92f154b90ef5c09e500978d6e60f9d8f2db1868 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 22 Jul 2008 14:38:54 +0000 Subject: Fix warnings in CINE svn-id: r33202 --- engines/cine/various.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 8e6f3fce76..f3b8cc2582 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -265,7 +265,7 @@ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle static const uint animEntriesCount = 255; static const uint oldAnimEntrySize = 23; static const uint newAnimEntrySize = 30; - static const uint defaultAnimEntrySize = newAnimEntrySize; +// static const uint defaultAnimEntrySize = newAnimEntrySize; static const uint animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize}; Common::Array animEntrySizeMatches; const uint32 prevStreamPos = fHandle.pos(); @@ -338,7 +338,7 @@ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle fHandle.seek(animDataTableStart + i * animEntrySize + relativeDataPos); uint32 data = fHandle.readUint32BE(); uint32 mask = fHandle.readUint32BE(); - if (data != NULL || mask != NULL) { + if ((data != 0) || (mask != 0)) { pointersIntact = true; break; } -- cgit v1.2.3 From 955d0700f55b21e6e70668170869f72ad9746bd7 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Sun, 27 Jul 2008 14:33:37 +0000 Subject: Cut savegame loading into smaller functional parts (resetEngine, loadPlainSave etc). svn-id: r33338 --- engines/cine/various.cpp | 237 ++++++++++++++++++++++++----------------------- 1 file changed, 123 insertions(+), 114 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index f3b8cc2582..383cda1875 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -408,70 +408,13 @@ void loadOverlayFromSave(Common::SeekableReadStream &fHandle) { overlayList.push_back(tmp); } -/*! \todo Implement Operation Stealth loading, this is obviously Future Wars only - * \todo Add support for loading the zoneQuery table (Operation Stealth specific) - */ -bool CineEngine::makeLoad(char *saveName) { - int16 i; - int16 size; - char bgName[13]; - - Common::SharedPtr saveFile(g_saveFileMan->openForLoading(saveName)); - - if (!saveFile) { - drawString(otherMessages[0], 0); - waitPlayerInput(); - // restoreScreen(); - checkDataDisk(-1); - return false; - } - - uint32 saveSize = saveFile->size(); - if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it - // Can't get information about the savefile's size so let's try - // reading as much as we can from the file up to a predefined upper limit. - // - // Some estimates for maximum savefile sizes (All with 255 animDataTable entries of 30 bytes each): - // With 256 global scripts, object scripts, overlays and background incrusts: - // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 256 = ~129kB - // With 512 global scripts, object scripts, overlays and background incrusts: - // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 512 = ~242kB - // - // I think it extremely unlikely that there would be over 512 global scripts, object scripts, - // overlays and background incrusts so 256kB seems like quite a safe upper limit. - // NOTE: If the savegame format is changed then this value might have to be re-evaluated! - // Hopefully devices with more limited memory can also cope with this memory allocation. - saveSize = 256 * 1024; - } - Common::SharedPtr fHandle(saveFile->readStream(saveSize)); - - // Try to detect the used savegame format - enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*fHandle); - - // Handle problematic savegame formats - if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) { - // One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but - // that's not implemented here because it was never used in a stable - // release of ScummVM but only during development (From revision 31453, - // which introduced the problem, until revision 32073, which fixed it). - // Therefore be bail out if we detect this particular savegame format. - warning("Detected a known broken savegame format, not loading savegame"); - return false; - } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { - // If we can't detect the savegame format - // then let's try the default format and hope for the best. - warning("Couldn't detect the used savegame format, trying default savegame format. Things may break"); - saveGameFormat = ANIMSIZE_30_PTRS_INTACT; - } - // Now we should have either of these formats - assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); - +void CineEngine::resetEngine() { g_sound->stopMusic(); freeAnimDataTable(); overlayList.clear(); - // if (g_cine->getGameType() == Cine::GType_OS) { - // freeUnkList(); - // } + if (g_cine->getGameType() == Cine::GType_OS) { + seqList.clear(); + } bgIncrustList.clear(); closePart(); @@ -481,7 +424,7 @@ bool CineEngine::makeLoad(char *saveName) { scriptTable.clear(); messageTable.clear(); - for (i = 0; i < NUM_MAX_OBJECT; i++) { + for (int i = 0; i < NUM_MAX_OBJECT; i++) { objectTable[i].part = 0; objectTable[i].name[0] = 0; objectTable[i].frame = 0; @@ -514,29 +457,34 @@ bool CineEngine::makeLoad(char *saveName) { renderer->clear(); checkForPendingDataLoadSwitch = 0; +} +bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { + int16 i; + int16 size; + char bgName[13]; // At savefile position 0x0000: - currentDisk = fHandle->readUint16BE(); + currentDisk = in.readUint16BE(); // At 0x0002: - fHandle->read(currentPartName, 13); + in.read(currentPartName, 13); // At 0x000F: - fHandle->read(currentDatName, 13); + in.read(currentDatName, 13); // At 0x001C: - saveVar2 = fHandle->readSint16BE(); + saveVar2 = in.readSint16BE(); // At 0x001E: - fHandle->read(currentPrcName, 13); + in.read(currentPrcName, 13); // At 0x002B: - fHandle->read(currentRelName, 13); + in.read(currentRelName, 13); // At 0x0038: - fHandle->read(currentMsgName, 13); + in.read(currentMsgName, 13); // At 0x0045: - fHandle->read(bgName, 13); + in.read(bgName, 13); // At 0x0052: - fHandle->read(currentCtName, 13); + in.read(currentCtName, 13); checkDataDisk(currentDisk); @@ -561,109 +509,109 @@ bool CineEngine::makeLoad(char *saveName) { } // At 0x005F: - fHandle->readUint16BE(); + in.readUint16BE(); // At 0x0061: - fHandle->readUint16BE(); + in.readUint16BE(); // At 0x0063: for (i = 0; i < 255; i++) { // At 0x0063 + i * 32 + 0: - objectTable[i].x = fHandle->readSint16BE(); + objectTable[i].x = in.readSint16BE(); // At 0x0063 + i * 32 + 2: - objectTable[i].y = fHandle->readSint16BE(); + objectTable[i].y = in.readSint16BE(); // At 0x0063 + i * 32 + 4: - objectTable[i].mask = fHandle->readUint16BE(); + objectTable[i].mask = in.readUint16BE(); // At 0x0063 + i * 32 + 6: - objectTable[i].frame = fHandle->readSint16BE(); + objectTable[i].frame = in.readSint16BE(); // At 0x0063 + i * 32 + 8: - objectTable[i].costume = fHandle->readSint16BE(); + objectTable[i].costume = in.readSint16BE(); // At 0x0063 + i * 32 + 10: - fHandle->read(objectTable[i].name, 20); + in.read(objectTable[i].name, 20); // At 0x0063 + i * 32 + 30: - objectTable[i].part = fHandle->readUint16BE(); + objectTable[i].part = in.readUint16BE(); } // At 0x2043 (i.e. 0x0063 + 255 * 32): - renderer->restorePalette(*fHandle); + renderer->restorePalette(in); // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): - globalVars.load(*fHandle, NUM_MAX_VAR - 1); + globalVars.load(in, NUM_MAX_VAR - 1); // At 0x2281 (i.e. 0x2083 + 255 * 2): for (i = 0; i < 16; i++) { // At 0x2281 + i * 2: - zoneData[i] = fHandle->readUint16BE(); + zoneData[i] = in.readUint16BE(); } // At 0x22A1 (i.e. 0x2281 + 16 * 2): for (i = 0; i < 4; i++) { // At 0x22A1 + i * 2: - commandVar3[i] = fHandle->readUint16BE(); + commandVar3[i] = in.readUint16BE(); } // At 0x22A9 (i.e. 0x22A1 + 4 * 2): - fHandle->read(commandBuffer, 0x50); + in.read(commandBuffer, 0x50); renderer->setCommand(commandBuffer); // At 0x22F9 (i.e. 0x22A9 + 0x50): - renderer->_cmdY = fHandle->readUint16BE(); + renderer->_cmdY = in.readUint16BE(); // At 0x22FB: - bgVar0 = fHandle->readUint16BE(); + bgVar0 = in.readUint16BE(); // At 0x22FD: - allowPlayerInput = fHandle->readUint16BE(); + allowPlayerInput = in.readUint16BE(); // At 0x22FF: - playerCommand = fHandle->readSint16BE(); + playerCommand = in.readSint16BE(); // At 0x2301: - commandVar1 = fHandle->readSint16BE(); + commandVar1 = in.readSint16BE(); // At 0x2303: - isDrawCommandEnabled = fHandle->readUint16BE(); + isDrawCommandEnabled = in.readUint16BE(); // At 0x2305: - var5 = fHandle->readUint16BE(); + var5 = in.readUint16BE(); // At 0x2307: - var4 = fHandle->readUint16BE(); + var4 = in.readUint16BE(); // At 0x2309: - var3 = fHandle->readUint16BE(); + var3 = in.readUint16BE(); // At 0x230B: - var2 = fHandle->readUint16BE(); + var2 = in.readUint16BE(); // At 0x230D: - commandVar2 = fHandle->readSint16BE(); + commandVar2 = in.readSint16BE(); // At 0x230F: - renderer->_messageBg = fHandle->readUint16BE(); + renderer->_messageBg = in.readUint16BE(); // At 0x2311: - fHandle->readUint16BE(); + in.readUint16BE(); // At 0x2313: - fHandle->readUint16BE(); + in.readUint16BE(); // At 0x2315: - loadResourcesFromSave(*fHandle, saveGameFormat); + loadResourcesFromSave(in, saveGameFormat); // TODO: handle screen params (really required ?) - fHandle->readUint16BE(); - fHandle->readUint16BE(); - fHandle->readUint16BE(); - fHandle->readUint16BE(); - fHandle->readUint16BE(); - fHandle->readUint16BE(); - - size = fHandle->readSint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + + size = in.readSint16BE(); for (i = 0; i < size; i++) { - loadScriptFromSave(*fHandle, true); + loadScriptFromSave(in, true); } - size = fHandle->readSint16BE(); + size = in.readSint16BE(); for (i = 0; i < size; i++) { - loadScriptFromSave(*fHandle, false); + loadScriptFromSave(in, false); } - size = fHandle->readSint16BE(); + size = in.readSint16BE(); for (i = 0; i < size; i++) { - loadOverlayFromSave(*fHandle); + loadOverlayFromSave(in); } - loadBgIncrustFromSave(*fHandle); + loadBgIncrustFromSave(in); if (strlen(currentMsgName)) { loadMsg(currentMsgName); @@ -683,6 +631,67 @@ bool CineEngine::makeLoad(char *saveName) { return true; } +/*! \todo Implement Operation Stealth loading, this is obviously Future Wars only + * \todo Add support for loading the zoneQuery table (Operation Stealth specific) + */ +bool CineEngine::makeLoad(char *saveName) { + Common::SharedPtr saveFile(g_saveFileMan->openForLoading(saveName)); + + if (!saveFile) { + drawString(otherMessages[0], 0); + waitPlayerInput(); + // restoreScreen(); + checkDataDisk(-1); + return false; + } + + uint32 saveSize = saveFile->size(); + if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it + // Can't get information about the savefile's size so let's try + // reading as much as we can from the file up to a predefined upper limit. + // + // Some estimates for maximum savefile sizes (All with 255 animDataTable entries of 30 bytes each): + // With 256 global scripts, object scripts, overlays and background incrusts: + // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 256 = ~129kB + // With 512 global scripts, object scripts, overlays and background incrusts: + // 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 512 = ~242kB + // + // I think it extremely unlikely that there would be over 512 global scripts, object scripts, + // overlays and background incrusts so 256kB seems like quite a safe upper limit. + // NOTE: If the savegame format is changed then this value might have to be re-evaluated! + // Hopefully devices with more limited memory can also cope with this memory allocation. + saveSize = 256 * 1024; + } + Common::SharedPtr in(saveFile->readStream(saveSize)); + + // Try to detect the used savegame format + enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*in); + + // Handle problematic savegame formats + if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) { + // One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but + // that's not implemented here because it was never used in a stable + // release of ScummVM but only during development (From revision 31453, + // which introduced the problem, until revision 32073, which fixed it). + // Therefore be bail out if we detect this particular savegame format. + warning("Detected a known broken savegame format, not loading savegame"); + return false; + } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { + // If we can't detect the savegame format + // then let's try the default format and hope for the best. + warning("Couldn't detect the used savegame format, trying default savegame format. Things may break"); + saveGameFormat = ANIMSIZE_30_PTRS_INTACT; + } + // Now we should have either of these formats + assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); + + // Reset the engine's state + resetEngine(); + + // Load the plain Future Wars savegame format + return loadPlainSaveFW(*in, saveGameFormat); +} + /*! \todo Add support for saving the zoneQuery table (Operation Stealth specific) */ void makeSave(char *saveFileName) { -- cgit v1.2.3 From cedbb6b2b23ef5d55c26022b7535cf3d248c5df7 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Sun, 27 Jul 2008 14:36:53 +0000 Subject: Clear the confusing usage of NUM_MAX_VAR (It's 255 actually, not 256). svn-id: r33339 --- engines/cine/various.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 383cda1875..4ac4c4a590 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -535,7 +535,7 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor renderer->restorePalette(in); // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): - globalVars.load(in, NUM_MAX_VAR - 1); + globalVars.load(in, NUM_MAX_VAR); // At 0x2281 (i.e. 0x2083 + 255 * 2): for (i = 0; i < 16; i++) { @@ -733,7 +733,7 @@ void makeSave(char *saveFileName) { renderer->savePalette(*fHandle); - globalVars.save(*fHandle, NUM_MAX_VAR - 1); + globalVars.save(*fHandle, NUM_MAX_VAR); for (i = 0; i < 16; i++) { fHandle->writeUint16BE(zoneData[i]); -- cgit v1.2.3 From 06a45c49c79056ef6ae81cc9f846ebddf07d03bc Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Sun, 27 Jul 2008 22:50:36 +0000 Subject: Added a preliminary saving routine for Operation Stealth (Disabled by default, needs more work still. WIP!). Added backgrounds' name saving (8 names in Operation Stealth instead of just 1 like in Future Wars). Added 256 color palette saving and restoring (One of the palettes isn't properly handled yet though). svn-id: r33349 --- engines/cine/various.cpp | 371 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 253 insertions(+), 118 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 4ac4c4a590..b4bbcc2bb9 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -229,6 +229,129 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { return -1; } +void saveObjectTable(Common::OutSaveFile &out) { + out.writeUint16BE(NUM_MAX_OBJECT); // Entry count + out.writeUint16BE(0x20); // Entry size + + for (int i = 0; i < NUM_MAX_OBJECT; i++) { + out.writeUint16BE(objectTable[i].x); + out.writeUint16BE(objectTable[i].y); + out.writeUint16BE(objectTable[i].mask); + out.writeUint16BE(objectTable[i].frame); + out.writeUint16BE(objectTable[i].costume); + out.write(objectTable[i].name, 20); + out.writeUint16BE(objectTable[i].part); + } +} + +void saveZoneData(Common::OutSaveFile &out) { + for (int i = 0; i < 16; i++) { + out.writeUint16BE(zoneData[i]); + } +} + +void saveCommandVariables(Common::OutSaveFile &out) { + for (int i = 0; i < 4; i++) { + out.writeUint16BE(commandVar3[i]); + } +} + +void saveAnimDataTable(Common::OutSaveFile &out) { + out.writeUint16BE(NUM_MAX_ANIMDATA); // Entry count + out.writeUint16BE(0x1E); // Entry size + + for (int i = 0; i < NUM_MAX_ANIMDATA; i++) { + animDataTable[i].save(out); + } +} + +void saveScreenParams(Common::OutSaveFile &out) { + // Screen parameters, unhandled + out.writeUint16BE(0); + out.writeUint16BE(0); + out.writeUint16BE(0); + out.writeUint16BE(0); + out.writeUint16BE(0); + out.writeUint16BE(0); +} + +void saveGlobalScripts(Common::OutSaveFile &out) { + ScriptList::const_iterator it; + out.writeUint16BE(globalScripts.size()); + for (it = globalScripts.begin(); it != globalScripts.end(); ++it) { + (*it)->save(out); + } +} + +void saveObjectScripts(Common::OutSaveFile &out) { + ScriptList::const_iterator it; + out.writeUint16BE(objectScripts.size()); + for (it = objectScripts.begin(); it != objectScripts.end(); ++it) { + (*it)->save(out); + } +} + +void saveOverlayList(Common::OutSaveFile &out) { + Common::List::const_iterator it; + + out.writeUint16BE(overlayList.size()); + + for (it = overlayList.begin(); it != overlayList.end(); ++it) { + out.writeUint32BE(0); // next + out.writeUint32BE(0); // previous? + out.writeUint16BE(it->objIdx); + out.writeUint16BE(it->type); + out.writeSint16BE(it->x); + out.writeSint16BE(it->y); + out.writeSint16BE(it->width); + out.writeSint16BE(it->color); + } +} + +void saveBgIncrustList(Common::OutSaveFile &out) { + Common::List::const_iterator it; + out.writeUint16BE(bgIncrustList.size()); + + for (it = bgIncrustList.begin(); it != bgIncrustList.end(); ++it) { + out.writeUint32BE(0); // next + out.writeUint32BE(0); // previous? + out.writeUint16BE(it->objIdx); + out.writeUint16BE(it->param); + out.writeUint16BE(it->x); + out.writeUint16BE(it->y); + out.writeUint16BE(it->frame); + out.writeUint16BE(it->part); + } +} + +void saveZoneQuery(Common::OutSaveFile &out) { + for (int i = 0; i < 16; i++) { + out.writeUint16BE(zoneQuery[i]); + } +} + +void saveSeqList(Common::OutSaveFile &out) { + Common::List::const_iterator it; + out.writeUint16BE(seqList.size()); + + for (it = seqList.begin(); it != seqList.end(); ++it) { + out.writeSint16BE(it->var4); + out.writeUint16BE(it->objIdx); + out.writeSint16BE(it->var8); + out.writeSint16BE(it->frame); + out.writeSint16BE(it->varC); + out.writeSint16BE(it->varE); + out.writeSint16BE(it->var10); + out.writeSint16BE(it->var12); + out.writeSint16BE(it->var14); + out.writeSint16BE(it->var16); + out.writeSint16BE(it->var18); + out.writeSint16BE(it->var1A); + out.writeSint16BE(it->var1C); + out.writeSint16BE(it->var1E); + } +} + bool CineEngine::loadSaveDirectory(void) { Common::InSaveFile *fHandle; char tmp[80]; @@ -692,134 +815,64 @@ bool CineEngine::makeLoad(char *saveName) { return loadPlainSaveFW(*in, saveGameFormat); } -/*! \todo Add support for saving the zoneQuery table (Operation Stealth specific) - */ -void makeSave(char *saveFileName) { - int16 i; - Common::OutSaveFile *fHandle; +void CineEngine::makeSaveFW(Common::OutSaveFile &out) { + out.writeUint16BE(currentDisk); + out.write(currentPartName, 13); + out.write(currentDatName, 13); + out.writeUint16BE(saveVar2); + out.write(currentPrcName, 13); + out.write(currentRelName, 13); + out.write(currentMsgName, 13); + renderer->saveBgNames(out); + out.write(currentCtName, 13); + + saveObjectTable(out); + renderer->savePalette(out); + globalVars.save(out, NUM_MAX_VAR); + saveZoneData(out); + saveCommandVariables(out); + out.write(commandBuffer, 0x50); + + out.writeUint16BE(renderer->_cmdY); + out.writeUint16BE(bgVar0); + out.writeUint16BE(allowPlayerInput); + out.writeUint16BE(playerCommand); + out.writeUint16BE(commandVar1); + out.writeUint16BE(isDrawCommandEnabled); + out.writeUint16BE(var5); + out.writeUint16BE(var4); + out.writeUint16BE(var3); + out.writeUint16BE(var2); + out.writeUint16BE(commandVar2); + out.writeUint16BE(renderer->_messageBg); + + saveAnimDataTable(out); + saveScreenParams(out); + + saveGlobalScripts(out); + saveObjectScripts(out); + saveOverlayList(out); + saveBgIncrustList(out); +} - fHandle = g_saveFileMan->openForSaving(saveFileName); +void CineEngine::makeSave(char *saveFileName) { + Common::SharedPtr fHandle(g_saveFileMan->openForSaving(saveFileName)); + + setMouseCursor(MOUSE_CURSOR_DISK); if (!fHandle) { drawString(otherMessages[1], 0); waitPlayerInput(); // restoreScreen(); checkDataDisk(-1); - return; - } - - fHandle->writeUint16BE(currentDisk); - fHandle->write(currentPartName, 13); - fHandle->write(currentDatName, 13); - fHandle->writeUint16BE(saveVar2); - fHandle->write(currentPrcName, 13); - fHandle->write(currentRelName, 13); - fHandle->write(currentMsgName, 13); - renderer->saveBg(*fHandle); - fHandle->write(currentCtName, 13); - - fHandle->writeUint16BE(0xFF); - fHandle->writeUint16BE(0x20); - - for (i = 0; i < 255; i++) { - fHandle->writeUint16BE(objectTable[i].x); - fHandle->writeUint16BE(objectTable[i].y); - fHandle->writeUint16BE(objectTable[i].mask); - fHandle->writeUint16BE(objectTable[i].frame); - fHandle->writeUint16BE(objectTable[i].costume); - fHandle->write(objectTable[i].name, 20); - fHandle->writeUint16BE(objectTable[i].part); - } - - renderer->savePalette(*fHandle); - - globalVars.save(*fHandle, NUM_MAX_VAR); - - for (i = 0; i < 16; i++) { - fHandle->writeUint16BE(zoneData[i]); - } - - for (i = 0; i < 4; i++) { - fHandle->writeUint16BE(commandVar3[i]); - } - - fHandle->write(commandBuffer, 0x50); - - fHandle->writeUint16BE(renderer->_cmdY); - - fHandle->writeUint16BE(bgVar0); - fHandle->writeUint16BE(allowPlayerInput); - fHandle->writeUint16BE(playerCommand); - fHandle->writeUint16BE(commandVar1); - fHandle->writeUint16BE(isDrawCommandEnabled); - fHandle->writeUint16BE(var5); - fHandle->writeUint16BE(var4); - fHandle->writeUint16BE(var3); - fHandle->writeUint16BE(var2); - fHandle->writeUint16BE(commandVar2); - - fHandle->writeUint16BE(renderer->_messageBg); - - fHandle->writeUint16BE(0xFF); - fHandle->writeUint16BE(0x1E); - - for (i = 0; i < NUM_MAX_ANIMDATA; i++) { - animDataTable[i].save(*fHandle); - } - - fHandle->writeUint16BE(0); // Screen params, unhandled - fHandle->writeUint16BE(0); - fHandle->writeUint16BE(0); - fHandle->writeUint16BE(0); - fHandle->writeUint16BE(0); - fHandle->writeUint16BE(0); - - { - ScriptList::iterator it; - fHandle->writeUint16BE(globalScripts.size()); - for (it = globalScripts.begin(); it != globalScripts.end(); ++it) { - (*it)->save(*fHandle); - } - - fHandle->writeUint16BE(objectScripts.size()); - for (it = objectScripts.begin(); it != objectScripts.end(); ++it) { - (*it)->save(*fHandle); - } - } - - { - Common::List::iterator it; - - fHandle->writeUint16BE(overlayList.size()); - - for (it = overlayList.begin(); it != overlayList.end(); ++it) { - fHandle->writeUint32BE(0); - fHandle->writeUint32BE(0); - fHandle->writeUint16BE(it->objIdx); - fHandle->writeUint16BE(it->type); - fHandle->writeSint16BE(it->x); - fHandle->writeSint16BE(it->y); - fHandle->writeSint16BE(it->width); - fHandle->writeSint16BE(it->color); + } else { + if (g_cine->getGameType() == GType_FW) { + makeSaveFW(*fHandle); + } else { + makeSaveOS(*fHandle); } } - Common::List::iterator it; - fHandle->writeUint16BE(bgIncrustList.size()); - - for (it = bgIncrustList.begin(); it != bgIncrustList.end(); ++it) { - fHandle->writeUint32BE(0); // next - fHandle->writeUint32BE(0); // unkPtr - fHandle->writeUint16BE(it->objIdx); - fHandle->writeUint16BE(it->param); - fHandle->writeUint16BE(it->x); - fHandle->writeUint16BE(it->y); - fHandle->writeUint16BE(it->frame); - fHandle->writeUint16BE(it->part); - } - - delete fHandle; - setMouseCursor(MOUSE_CURSOR_NORMAL); } @@ -960,6 +1013,88 @@ void CineEngine::makeSystemMenu(void) { } } +/** + * Save an Operation Stealth type savegame. WIP! Not yet enabled by default! + * + * TODO: Add some kind of a header to the Operation Stealth's savegame file + * that differentiates it from any of the plain data savegame formats used by + * the already officially supported Future Wars. + * NOTE: This is going to be very much a work in progress so the Operation Stealth's + * savegame formats that are going to be tried are extremely probably not going + * to be supported at all after Operation Stealth becomes officially supported. + * This means that the savegame format will hopefully change to something nicer + * when official support for Operation Stealth begins. + */ +void CineEngine::makeSaveOS(Common::OutSaveFile &out) { + int i; + + // TODO: Enable saving in Operation Stealth after adding a header and possibly some testing + warning("makeSaveOS: Saving in Operation Stealth not yet enabled. Not saving game"); + return; + + out.writeUint16BE(currentDisk); + out.write(currentPartName, 13); + out.write(currentPrcName, 13); + out.write(currentRelName, 13); + out.write(currentMsgName, 13); + renderer->saveBgNames(out); + out.write(currentCtName, 13); + + saveObjectTable(out); + renderer->savePalette(out); + globalVars.save(out, NUM_MAX_VAR); + saveZoneData(out); + saveCommandVariables(out); + out.write(commandBuffer, 0x50); + saveZoneQuery(out); + + // FIXME: Save a proper name here, saving an empty string currently. + // 0x2925: Current music name (String, 13 bytes). + for (i = 0; i < 13; i++) { + out.writeByte(0); + } + // FIXME: Save proper value for this variable, currently writing zero + // 0x2932: Is music loaded? (Uint16BE, Boolean). + out.writeUint16BE(0); + // FIXME: Save proper value for this variable, currently writing zero + // 0x2934: Is music playing? (Uint16BE, Boolean). + out.writeUint16BE(0); + + out.writeUint16BE(renderer->_cmdY); + out.writeUint16BE(0); // Some unknown variable that seems to always be zero + out.writeUint16BE(allowPlayerInput); + out.writeUint16BE(playerCommand); + out.writeUint16BE(commandVar1); + out.writeUint16BE(isDrawCommandEnabled); + out.writeUint16BE(var5); + out.writeUint16BE(var4); + out.writeUint16BE(var3); + out.writeUint16BE(var2); + out.writeUint16BE(commandVar2); + out.writeUint16BE(renderer->_messageBg); + + // FIXME: Save proper value for this variable, currently writing zero. + // An unknown variable at 0x295E: adBgVar1 (Uint16BE). + out.writeUint16BE(0); + out.writeUint16BE(currentAdditionalBgIdx); + out.writeUint16BE(currentAdditionalBgIdx2); + // FIXME: Save proper value for this variable, currently writing zero. + // 0x2954: additionalBgVScroll (Uint16BE). This probably means renderer->_bgShift. + out.writeUint16BE(0); + // FIXME: Save proper value for this variable, currently writing zero. + // An unknown variable at 0x2956: adBgVar0 (Uint16BE). Maybe this means bgVar0? + out.writeUint16BE(0); + out.writeUint16BE(disableSystemMenu); + + saveAnimDataTable(out); + saveScreenParams(out); + saveGlobalScripts(out); + saveObjectScripts(out); + saveSeqList(out); + saveOverlayList(out); + saveBgIncrustList(out); +} + void drawMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 offset, int16 color, byte* page) { gfxDrawLine(x + offset, y + offset, x + width - offset, y + offset, color, page); // top gfxDrawLine(x + offset, currentY + 4 - offset, x + width - offset, currentY + 4 - offset, color, page); // bottom -- cgit v1.2.3 From 16fe053ab4535865b7f52a274cc886a682caf7d4 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 08:44:49 +0000 Subject: Made the savegame loading routine choose between loading a Future Wars or an Operation Stealth savegame format. Added a stub for loading the Operation Stealth's temporary savegame format (Not yet implemented). Made mouse cursor change to a disk icon when loading a savegame and back to normal after its done. svn-id: r33362 --- engines/cine/various.cpp | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index b4bbcc2bb9..6efb441049 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -582,6 +582,11 @@ void CineEngine::resetEngine() { checkForPendingDataLoadSwitch = 0; } +bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { + warning("loadTempSaveOS: This is a stub. Temporary Operation Stealth savegame loading not yet implemented"); + return false; +} + bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { int16 i; int16 size; @@ -740,8 +745,6 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor loadMsg(currentMsgName); } - setMouseCursor(MOUSE_CURSOR_NORMAL); - if (strlen(currentDatName)) { /* i = saveVar2; saveVar2 = 0; @@ -768,6 +771,8 @@ bool CineEngine::makeLoad(char *saveName) { return false; } + setMouseCursor(MOUSE_CURSOR_DISK); + uint32 saveSize = saveFile->size(); if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it // Can't get information about the savefile's size so let's try @@ -791,6 +796,8 @@ bool CineEngine::makeLoad(char *saveName) { enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*in); // Handle problematic savegame formats + bool load = true; // Should we try to load the savegame? + bool result = false; if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) { // One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but // that's not implemented here because it was never used in a stable @@ -798,21 +805,30 @@ bool CineEngine::makeLoad(char *saveName) { // which introduced the problem, until revision 32073, which fixed it). // Therefore be bail out if we detect this particular savegame format. warning("Detected a known broken savegame format, not loading savegame"); - return false; + load = false; // Don't load the savegame } else if (saveGameFormat == ANIMSIZE_UNKNOWN) { // If we can't detect the savegame format // then let's try the default format and hope for the best. warning("Couldn't detect the used savegame format, trying default savegame format. Things may break"); saveGameFormat = ANIMSIZE_30_PTRS_INTACT; } - // Now we should have either of these formats - assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT); - // Reset the engine's state - resetEngine(); + if (load) { + // Reset the engine's state + resetEngine(); + + if (saveGameFormat == TEMP_OS_FORMAT) { + // Load the temporary Operation Stealth savegame format + result = loadTempSaveOS(*in); + } else { + // Load the plain Future Wars savegame format + result = loadPlainSaveFW(*in, saveGameFormat); + } + } - // Load the plain Future Wars savegame format - return loadPlainSaveFW(*in, saveGameFormat); + setMouseCursor(MOUSE_CURSOR_NORMAL); + + return result; } void CineEngine::makeSaveFW(Common::OutSaveFile &out) { -- cgit v1.2.3 From 50088df80fb3fbc421e252f667faab88f73bc6f9 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 10:09:00 +0000 Subject: Now detects temporary Operation Stealth savegame format and saves it. No loading yet. svn-id: r33365 --- engines/cine/various.cpp | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 6efb441049..48155f7d90 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -229,6 +229,20 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { return -1; } +bool writeChunkHeader(Common::OutSaveFile &out, const ChunkHeader &header) { + out.writeUint32BE(header.id); + out.writeUint32BE(header.version); + out.writeUint32BE(header.size); + return !out.ioFailed(); +} + +bool loadChunkHeader(Common::SeekableReadStream &in, ChunkHeader &header) { + header.id = in.readUint32BE(); + header.version = in.readUint32BE(); + header.size = in.readUint32BE(); + return !in.ioFailed(); +} + void saveObjectTable(Common::OutSaveFile &out) { out.writeUint16BE(NUM_MAX_OBJECT); // Entry count out.writeUint16BE(0x20); // Entry size @@ -378,8 +392,23 @@ bool CineEngine::loadSaveDirectory(void) { * algorithm could get confused and think that the file uses both the older * and the newer format but that is such a remote possibility that I wouldn't * worry about it at all. + * + * Also detects the temporary Operation Stealth savegame format now. */ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle) { + const uint32 prevStreamPos = fHandle.pos(); + + // First check for the temporary Operation Stealth savegame format. + fHandle.seek(0); + ChunkHeader hdr; + loadChunkHeader(fHandle, hdr); + fHandle.seek(prevStreamPos); + if (hdr.id == TEMP_OS_FORMAT_ID) { + return TEMP_OS_FORMAT; + } + + // Ok, so the savegame isn't using the temporary Operation Stealth savegame format. + // Let's check for the plain Future Wars savegame format and its different versions then. // The animDataTable begins at savefile position 0x2315. // Each animDataTable entry takes 23 bytes in older saves (Revisions 21772-31443) // and 30 bytes in the save format after that (Revision 31444 and onwards). @@ -388,10 +417,8 @@ enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle static const uint animEntriesCount = 255; static const uint oldAnimEntrySize = 23; static const uint newAnimEntrySize = 30; -// static const uint defaultAnimEntrySize = newAnimEntrySize; static const uint animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize}; Common::Array animEntrySizeMatches; - const uint32 prevStreamPos = fHandle.pos(); // Try to walk through the savefile using different animDataTable entry sizes // and make a list of all the successful entry sizes. @@ -774,6 +801,7 @@ bool CineEngine::makeLoad(char *saveName) { setMouseCursor(MOUSE_CURSOR_DISK); uint32 saveSize = saveFile->size(); + // TODO: Evaluate the maximum savegame size for the temporary Operation Stealth savegame format. if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it // Can't get information about the savefile's size so let's try // reading as much as we can from the file up to a predefined upper limit. @@ -1044,10 +1072,14 @@ void CineEngine::makeSystemMenu(void) { void CineEngine::makeSaveOS(Common::OutSaveFile &out) { int i; - // TODO: Enable saving in Operation Stealth after adding a header and possibly some testing - warning("makeSaveOS: Saving in Operation Stealth not yet enabled. Not saving game"); - return; + // Make a temporary Operation Stealth savegame format chunk header and save it. + ChunkHeader header; + header.id = TEMP_OS_FORMAT_ID; + header.version = CURRENT_OS_SAVE_VER; + header.size = 0; // No data is currently put inside the chunk, all the plain data comes right after it. + writeChunkHeader(out, header); + // Start outputting the plain savegame data right after the chunk header. out.writeUint16BE(currentDisk); out.write(currentPartName, 13); out.write(currentPrcName, 13); -- cgit v1.2.3 From c23f805a7fb3870fcf2695d889a09954a010d959 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 10:44:54 +0000 Subject: Cut Future Wars savegame loading routine into parts that can be reused when loading the Operation Stealth savegame format. svn-id: r33366 --- engines/cine/various.cpp | 129 +++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 55 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 48155f7d90..6dbff06a58 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -609,14 +609,78 @@ void CineEngine::resetEngine() { checkForPendingDataLoadSwitch = 0; } +bool loadObjectTable(Common::SeekableReadStream &in) { + in.readUint16BE(); // Entry count + in.readUint16BE(); // Entry size + + for (int i = 0; i < NUM_MAX_OBJECT; i++) { + objectTable[i].x = in.readSint16BE(); + objectTable[i].y = in.readSint16BE(); + objectTable[i].mask = in.readUint16BE(); + objectTable[i].frame = in.readSint16BE(); + objectTable[i].costume = in.readSint16BE(); + in.read(objectTable[i].name, 20); + objectTable[i].part = in.readUint16BE(); + } + return !in.ioFailed(); +} + +bool loadZoneData(Common::SeekableReadStream &in) { + for (int i = 0; i < 16; i++) { + zoneData[i] = in.readUint16BE(); + } + return !in.ioFailed(); +} + +bool loadCommandVariables(Common::SeekableReadStream &in) { + for (int i = 0; i < 4; i++) { + commandVar3[i] = in.readUint16BE(); + } + return !in.ioFailed(); +} + +bool loadScreenParams(Common::SeekableReadStream &in) { + // TODO: handle screen params (really required ?) + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + in.readUint16BE(); + return !in.ioFailed(); +} + +bool loadGlobalScripts(Common::SeekableReadStream &in) { + int size = in.readSint16BE(); + for (int i = 0; i < size; i++) { + loadScriptFromSave(in, true); + } + return !in.ioFailed(); +} + +bool loadObjectScripts(Common::SeekableReadStream &in) { + int size = in.readSint16BE(); + for (int i = 0; i < size; i++) { + loadScriptFromSave(in, false); + } + return !in.ioFailed(); +} + +bool loadOverlayList(Common::SeekableReadStream &in) { + int size = in.readSint16BE(); + for (int i = 0; i < size; i++) { + loadOverlayFromSave(in); + } + return !in.ioFailed(); +} + +// TODO: Implement this function bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { warning("loadTempSaveOS: This is a stub. Temporary Operation Stealth savegame loading not yet implemented"); return false; } bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { - int16 i; - int16 size; char bgName[13]; // At savefile position 0x0000: @@ -664,45 +728,19 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor } // At 0x005F: - in.readUint16BE(); - // At 0x0061: - in.readUint16BE(); - - // At 0x0063: - for (i = 0; i < 255; i++) { - // At 0x0063 + i * 32 + 0: - objectTable[i].x = in.readSint16BE(); - // At 0x0063 + i * 32 + 2: - objectTable[i].y = in.readSint16BE(); - // At 0x0063 + i * 32 + 4: - objectTable[i].mask = in.readUint16BE(); - // At 0x0063 + i * 32 + 6: - objectTable[i].frame = in.readSint16BE(); - // At 0x0063 + i * 32 + 8: - objectTable[i].costume = in.readSint16BE(); - // At 0x0063 + i * 32 + 10: - in.read(objectTable[i].name, 20); - // At 0x0063 + i * 32 + 30: - objectTable[i].part = in.readUint16BE(); - } + loadObjectTable(in); - // At 0x2043 (i.e. 0x0063 + 255 * 32): + // At 0x2043 (i.e. 0x005F + 2 * 2 + 255 * 32): renderer->restorePalette(in); // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): globalVars.load(in, NUM_MAX_VAR); // At 0x2281 (i.e. 0x2083 + 255 * 2): - for (i = 0; i < 16; i++) { - // At 0x2281 + i * 2: - zoneData[i] = in.readUint16BE(); - } + loadZoneData(in); // At 0x22A1 (i.e. 0x2281 + 16 * 2): - for (i = 0; i < 4; i++) { - // At 0x22A1 + i * 2: - commandVar3[i] = in.readUint16BE(); - } + loadCommandVariables(in); // At 0x22A9 (i.e. 0x22A1 + 4 * 2): in.read(commandBuffer, 0x50); @@ -743,29 +781,10 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor // At 0x2315: loadResourcesFromSave(in, saveGameFormat); - // TODO: handle screen params (really required ?) - in.readUint16BE(); - in.readUint16BE(); - in.readUint16BE(); - in.readUint16BE(); - in.readUint16BE(); - in.readUint16BE(); - - size = in.readSint16BE(); - for (i = 0; i < size; i++) { - loadScriptFromSave(in, true); - } - - size = in.readSint16BE(); - for (i = 0; i < size; i++) { - loadScriptFromSave(in, false); - } - - size = in.readSint16BE(); - for (i = 0; i < size; i++) { - loadOverlayFromSave(in); - } - + loadScreenParams(in); + loadGlobalScripts(in); + loadObjectScripts(in); + loadOverlayList(in); loadBgIncrustFromSave(in); if (strlen(currentMsgName)) { -- cgit v1.2.3 From b08288c1cd816105636aa628526dba758e886236 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 10:54:53 +0000 Subject: Added remaining load functions needed for the Operation Stealth savegame format loading (loadSeqList and loadZoneQuery). Not used yet. svn-id: r33367 --- engines/cine/various.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 6dbff06a58..02e09be88a 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -674,6 +674,36 @@ bool loadOverlayList(Common::SeekableReadStream &in) { return !in.ioFailed(); } +bool loadSeqList(Common::SeekableReadStream &in) { + uint size = in.readUint16BE(); + SeqListElement tmp; + for (uint i = 0; i < size; i++) { + tmp.var4 = in.readSint16BE(); + tmp.objIdx = in.readUint16BE(); + tmp.var8 = in.readSint16BE(); + tmp.frame = in.readSint16BE(); + tmp.varC = in.readSint16BE(); + tmp.varE = in.readSint16BE(); + tmp.var10 = in.readSint16BE(); + tmp.var12 = in.readSint16BE(); + tmp.var14 = in.readSint16BE(); + tmp.var16 = in.readSint16BE(); + tmp.var18 = in.readSint16BE(); + tmp.var1A = in.readSint16BE(); + tmp.var1C = in.readSint16BE(); + tmp.var1E = in.readSint16BE(); + seqList.push_back(tmp); + } + return !in.ioFailed(); +} + +bool loadZoneQuery(Common::SeekableReadStream &in) { + for (int i = 0; i < 16; i++) { + zoneQuery[i] = in.readUint16BE(); + } + return !in.ioFailed(); +} + // TODO: Implement this function bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { warning("loadTempSaveOS: This is a stub. Temporary Operation Stealth savegame loading not yet implemented"); -- cgit v1.2.3 From add07fceaaa2cbbc9e286c420d4bc66c4d17dc36 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 28 Jul 2008 16:02:40 +0000 Subject: Added loading of temporary Operation Stealth savegames. Needs testing! - Music related settings and adBgVar0 & adBgVar1 aren't loaded currently. Modified resetEngine to also reset more of the Operation Stealth specific variables. Added getter for background scrolling value. Changed additional background indices 1 & 2 from byte to uint16. Made savegame loading functions return !in.ioFailed() as return value instead of true as previously. svn-id: r33379 --- engines/cine/various.cpp | 160 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 144 insertions(+), 16 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 02e09be88a..379b723d2c 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -562,9 +562,6 @@ void CineEngine::resetEngine() { g_sound->stopMusic(); freeAnimDataTable(); overlayList.clear(); - if (g_cine->getGameType() == Cine::GType_OS) { - seqList.clear(); - } bgIncrustList.clear(); closePart(); @@ -607,6 +604,16 @@ void CineEngine::resetEngine() { renderer->clear(); checkForPendingDataLoadSwitch = 0; + + if (g_cine->getGameType() == Cine::GType_OS) { + seqList.clear(); + currentAdditionalBgIdx = 0; + currentAdditionalBgIdx2 = 0; + // TODO: Add resetting of the following variables + // adBgVar1 = 0; + // adBgVar0 = 0; + // gfxFadeOutCompleted = 0; + } } bool loadObjectTable(Common::SeekableReadStream &in) { @@ -704,10 +711,137 @@ bool loadZoneQuery(Common::SeekableReadStream &in) { return !in.ioFailed(); } -// TODO: Implement this function bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { - warning("loadTempSaveOS: This is a stub. Temporary Operation Stealth savegame loading not yet implemented"); - return false; + char musicName[13]; + char bgNames[8][13]; + + // First check the temporary Operation Stealth savegame format header. + ChunkHeader hdr; + loadChunkHeader(in, hdr); + if (hdr.id != TEMP_OS_FORMAT_ID) { + warning("loadTempSaveOS: File has incorrect identifier. Not loading savegame"); + return false; + } else if (hdr.version > CURRENT_OS_SAVE_VER) { + warning("loadTempSaveOS: Detected newer format version. Not loading savegame"); + return false; + } else if (hdr.version < CURRENT_OS_SAVE_VER) { + warning("loadTempSaveOS: Detected older format version. Trying to load nonetheless. Things may break"); + } else { // hdr.id == TEMP_OS_FORMAT_ID && hdr.version == CURRENT_OS_SAVE_VER + debug(3, "loadTempSaveOS: Found correct header (Both the identifier and version number match)."); + } + + // There shouldn't be any data in the header's chunk currently so it's an error if there is. + if (hdr.size > 0) { + warning("loadTempSaveOS: Format header's chunk seems to contain data so format is incorrect. Not loading savegame"); + return false; + } + + // Ok, so we've got a correct header for a temporary Operation Stealth savegame. + // Let's start loading the plain savegame data then. + currentDisk = in.readUint16BE(); + in.read(currentPartName, 13); + in.read(currentPrcName, 13); + in.read(currentRelName, 13); + in.read(currentMsgName, 13); + + // Load the 8 background names. + for (uint i = 0; i < 8; i++) { + in.read(bgNames[i], 13); + } + + in.read(currentCtName, 13); + + loadObjectTable(in); + renderer->restorePalette(in); + globalVars.load(in, NUM_MAX_VAR); + loadZoneData(in); + loadCommandVariables(in); + in.read(commandBuffer, 0x50); + loadZoneQuery(in); + + // TODO: Use the loaded string (Current music name (String, 13 bytes)). + in.read(musicName, 13); + + // TODO: Use the loaded value (Is music loaded? (Uint16BE, Boolean)). + in.readUint16BE(); + + // TODO: Use the loaded value (Is music playing? (Uint16BE, Boolean)). + in.readUint16BE(); + + renderer->_cmdY = in.readUint16BE(); + in.readUint16BE(); // Some unknown variable that seems to always be zero + allowPlayerInput = in.readUint16BE(); + playerCommand = in.readUint16BE(); + commandVar1 = in.readUint16BE(); + isDrawCommandEnabled = in.readUint16BE(); + var5 = in.readUint16BE(); + var4 = in.readUint16BE(); + var3 = in.readUint16BE(); + var2 = in.readUint16BE(); + commandVar2 = in.readUint16BE(); + renderer->_messageBg = in.readUint16BE(); + + // TODO: Use the loaded value (adBgVar1 (Uint16BE)). + in.readUint16BE(); + + currentAdditionalBgIdx = in.readSint16BE(); + currentAdditionalBgIdx2 = in.readSint16BE(); + + // TODO: Check whether the scroll value really gets used correctly after this. + // Note that the backgrounds are loaded only later than this value is set. + renderer->setScroll(in.readUint16BE()); + + // TODO: Use the loaded value (adBgVar0 (Uint16BE). Maybe this means bgVar0?). + in.readUint16BE(); + + disableSystemMenu = in.readUint16BE(); + + // TODO: adBgVar1 = 1 here + + // Load the animDataTable entries + in.readUint16BE(); // Entry count (255 in the PC version of Operation Stealth). + in.readUint16BE(); // Entry size (36 in the PC version of Operation Stealth). + loadResourcesFromSave(in, ANIMSIZE_30_PTRS_INTACT); + + loadScreenParams(in); + loadGlobalScripts(in); + loadObjectScripts(in); + loadSeqList(in); + loadOverlayList(in); + loadBgIncrustFromSave(in); + + if (strlen(currentPrcName)) { + loadPrc(currentPrcName); + } + + if (strlen(currentRelName)) { + loadRel(currentRelName); + } + + if (strlen(currentMsgName)) { + loadMsg(currentMsgName); + } + + // Load first background (Uses loadBg) + if (strlen(bgNames[0])) { + loadBg(bgNames[0]); + } + + // Add backgrounds 1-7 (Uses addBackground) + for (int i = 1; i < 8; i++) { + if (strlen(bgNames[i])) { + addBackground(bgNames[i], i); + } + } + + if (strlen(currentCtName)) { + loadCtOS(currentCtName); + } + + // TODO: Add current music loading and playing here + // TODO: Palette handling? + + return !in.ioFailed(); } bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { @@ -830,12 +964,9 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor }*/ } - return true; + return !in.ioFailed(); } -/*! \todo Implement Operation Stealth loading, this is obviously Future Wars only - * \todo Add support for loading the zoneQuery table (Operation Stealth specific) - */ bool CineEngine::makeLoad(char *saveName) { Common::SharedPtr saveFile(g_saveFileMan->openForLoading(saveName)); @@ -1107,11 +1238,8 @@ void CineEngine::makeSystemMenu(void) { } /** - * Save an Operation Stealth type savegame. WIP! Not yet enabled by default! + * Save an Operation Stealth type savegame. WIP! * - * TODO: Add some kind of a header to the Operation Stealth's savegame file - * that differentiates it from any of the plain data savegame formats used by - * the already officially supported Future Wars. * NOTE: This is going to be very much a work in progress so the Operation Stealth's * savegame formats that are going to be tried are extremely probably not going * to be supported at all after Operation Stealth becomes officially supported. @@ -1173,8 +1301,8 @@ void CineEngine::makeSaveOS(Common::OutSaveFile &out) { // FIXME: Save proper value for this variable, currently writing zero. // An unknown variable at 0x295E: adBgVar1 (Uint16BE). out.writeUint16BE(0); - out.writeUint16BE(currentAdditionalBgIdx); - out.writeUint16BE(currentAdditionalBgIdx2); + out.writeSint16BE(currentAdditionalBgIdx); + out.writeSint16BE(currentAdditionalBgIdx2); // FIXME: Save proper value for this variable, currently writing zero. // 0x2954: additionalBgVScroll (Uint16BE). This probably means renderer->_bgShift. out.writeUint16BE(0); -- cgit v1.2.3 From 09f70b640897b4b36185acd7359e908eb0e3ae7b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 28 Jul 2008 22:21:11 +0000 Subject: Fixing 'warning: comparison of unsigned expression < 0 is always false' svn-id: r33383 --- engines/cine/various.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 379b723d2c..ab181743db 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -724,7 +724,7 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { } else if (hdr.version > CURRENT_OS_SAVE_VER) { warning("loadTempSaveOS: Detected newer format version. Not loading savegame"); return false; - } else if (hdr.version < CURRENT_OS_SAVE_VER) { + } else if ((int)hdr.version < (int)CURRENT_OS_SAVE_VER) { warning("loadTempSaveOS: Detected older format version. Trying to load nonetheless. Things may break"); } else { // hdr.id == TEMP_OS_FORMAT_ID && hdr.version == CURRENT_OS_SAVE_VER debug(3, "loadTempSaveOS: Found correct header (Both the identifier and version number match)."); -- cgit v1.2.3 From 0365c45b8c613eb9a84e656b5a4f0eb2be33e5e0 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 29 Jul 2008 10:13:53 +0000 Subject: Rearranged parts of the Operation Stealth savegame loading routine. - Emulating the Future Wars savegame loading routine and hoping for the best. - Fixes an array out of bounds access when loading the global scripts. Now the loading crashes in the mainloop in processSeqList! But at least we got a bit farther this time. More fixing to come... svn-id: r33404 --- engines/cine/various.cpp | 67 +++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 24 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index ab181743db..9a9393cc92 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -751,6 +751,45 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { in.read(currentCtName, 13); + // Moved the loading of current procedure, relation, + // backgrounds and Ct here because if they were at the + // end of this function then the global scripts loading + // made an array out of bounds access. In the original + // game's disassembly these aren't here but at the end. + // The difference is probably in how we handle loading + // the global scripts and some other things (i.e. the + // loading routines aren't exactly the same and subtle + // semantic differences result in having to do things + // in a different order). + { + // Not sure if this is needed with Operation Stealth... + checkDataDisk(currentDisk); + + if (strlen(currentPrcName)) { + loadPrc(currentPrcName); + } + + if (strlen(currentRelName)) { + loadRel(currentRelName); + } + + // Load first background (Uses loadBg) + if (strlen(bgNames[0])) { + loadBg(bgNames[0]); + } + + // Add backgrounds 1-7 (Uses addBackground) + for (int i = 1; i < 8; i++) { + if (strlen(bgNames[i])) { + addBackground(bgNames[i], i); + } + } + + if (strlen(currentCtName)) { + loadCtOS(currentCtName); + } + } + loadObjectTable(in); renderer->restorePalette(in); globalVars.load(in, NUM_MAX_VAR); @@ -810,34 +849,14 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { loadOverlayList(in); loadBgIncrustFromSave(in); - if (strlen(currentPrcName)) { - loadPrc(currentPrcName); - } - - if (strlen(currentRelName)) { - loadRel(currentRelName); - } - + // Left this here instead of moving it earlier in this function with + // the other current value loadings (e.g. loading of current procedure, + // current backgrounds etc). Mostly emulating the way we've handled + // Future Wars savegames and hoping that things work out. if (strlen(currentMsgName)) { loadMsg(currentMsgName); } - // Load first background (Uses loadBg) - if (strlen(bgNames[0])) { - loadBg(bgNames[0]); - } - - // Add backgrounds 1-7 (Uses addBackground) - for (int i = 1; i < 8; i++) { - if (strlen(bgNames[i])) { - addBackground(bgNames[i], i); - } - } - - if (strlen(currentCtName)) { - loadCtOS(currentCtName); - } - // TODO: Add current music loading and playing here // TODO: Palette handling? -- cgit v1.2.3 From 52700d59fdba83f549a23569c058e1cccac7f510 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 29 Jul 2008 12:56:32 +0000 Subject: Added a debug message to loadTempSaveOS's to check whether we loaded the whole savefile. Made objectStruct's clearing also clear x and y member variables in resetEngine. svn-id: r33407 --- engines/cine/various.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 9a9393cc92..9ff0d54f67 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -572,6 +572,8 @@ void CineEngine::resetEngine() { messageTable.clear(); for (int i = 0; i < NUM_MAX_OBJECT; i++) { + objectTable[i].x = 0; + objectTable[i].y = 0; objectTable[i].part = 0; objectTable[i].name[0] = 0; objectTable[i].frame = 0; @@ -860,6 +862,12 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { // TODO: Add current music loading and playing here // TODO: Palette handling? + if (in.pos() == in.size()) { + debug(3, "loadTempSaveOS: Loaded the whole savefile."); + } else { + warning("loadTempSaveOS: Loaded the savefile but didn't exhaust it completely. Something was left over"); + } + return !in.ioFailed(); } -- cgit v1.2.3 From d83c6d7d68027d3a174ad305720ed3c5de7cb0c7 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Tue, 29 Jul 2008 13:44:14 +0000 Subject: Added purgeSeqList function (Used in mainloop now). Let's see if this helps any... Renamed functions: * addScriptToList0 -> addScriptToGlobalScripts * executeList0 -> executeGlobalScripts * executeList1 -> executeObjectScripts * purgeList1 -> purgeObjectScripts (Also added a clarifying TODO to this function) * purgeList0 -> purgeGlobalScripts (Also added a clarifying TODO to this function) svn-id: r33409 --- engines/cine/various.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 9ff0d54f67..14f75efe29 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -2013,7 +2013,7 @@ void checkForPendingDataLoad(void) { // fixes a crash when failing copy protection in Amiga or Atari ST // versions of Future Wars. if (loadPrcOk) { - addScriptToList0(1); + addScriptToGlobalScripts(1); } else if (scumm_stricmp(currentPrcName, COPY_PROT_FAIL_PRC_NAME)) { // We only show an error here for other files than the file that // is loaded if copy protection fails (i.e. L201.ANI). -- cgit v1.2.3 From 4210defa2980092822bd8e931b7ca37bbae020ad Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 30 Jul 2008 11:03:52 +0000 Subject: Added some debug aids related to addAni and the processSeqList crashing. svn-id: r33444 --- engines/cine/various.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 14f75efe29..1af807c867 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -2186,6 +2186,8 @@ uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &ele const int8 *ptr2; int16 di; + debug(5, "addAni: param1 = %d, objIdx = %d, ptr = %p, param3 = %d", param1, objIdx, ptr, param3); + // In the original an error string is set and 0 is returned if the following doesn't hold assert(ptr); @@ -2291,6 +2293,19 @@ void processSeqListElement(SeqListElement &element) { int16 var_10; int16 var_4; int16 var_2; + + // Initial interpretations for variables addressed through ptr1 (8-bit addressing): + // These may be inaccurate! + // 0: ? + // 1: xRadius + // 2: yRadius + // 3: ? + // 4: xAdd + // 5: yAdd + // 6: ? + // 7: ? + // After this come (At least at positions 0, 1 and 3 in 16-bit addressing) + // 16-bit big-endian values used for addressing through ptr1. if (element.var12 < element.var10) { element.var12++; -- cgit v1.2.3 From 81cb4931582f5839cca2958a634525ffb81a1714 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Wed, 30 Jul 2008 11:36:14 +0000 Subject: Debug printing a couple more relevant variables in addAni. svn-id: r33446 --- engines/cine/various.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 1af807c867..2fcb015fcd 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -2186,7 +2186,8 @@ uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &ele const int8 *ptr2; int16 di; - debug(5, "addAni: param1 = %d, objIdx = %d, ptr = %p, param3 = %d", param1, objIdx, ptr, param3); + debug(5, "addAni: param1 = %d, objIdx = %d, ptr = %p, element.var8 = %d, element.var14 = %d param3 = %d", + param1, objIdx, ptr, element.var8, element.var14, param3); // In the original an error string is set and 0 is returned if the following doesn't hold assert(ptr); -- cgit v1.2.3 From 99addb709cb4982725c685447774021ad2917e59 Mon Sep 17 00:00:00 2001 From: Kari Salminen Date: Mon, 4 Aug 2008 19:32:52 +0000 Subject: Fix for misplaced objects in mouse object selection (Operation Stealth specific). - Implemented Operation Stealth specific part of getObjectUnderCursor which handles negative frame values. - Fixed a test case (Should test for ydif <= 0 although tested for ydif < 0). - Made part-value be anded with 0x0F in a test case to comply with disassembly. - Added comment about a test case which isn't present in the disassembly. Removing it makes things crash sometimes so letting it be. svn-id: r33620 --- engines/cine/various.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'engines/cine/various.cpp') diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 2fcb015fcd..58b0c9f269 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -189,6 +189,15 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { frame = ABS((int16)(objectTable[it->objIdx].frame)); part = objectTable[it->objIdx].part; + // Additional case for negative frame values in Operation Stealth + if (g_cine->getGameType() == Cine::GType_OS && objectTable[it->objIdx].frame < 0) { + if ((it->type == 1) && (x >= objX) && (objX + frame >= x) && (y >= objY) && (objY + part >= y)) { + return it->objIdx; + } else { + continue; + } + } + if (it->type == 0) { threshold = animDataTable[frame]._var1; } else { @@ -201,16 +210,19 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { xdif = x - objX; ydif = y - objY; - if ((xdif < 0) || ((threshold << 4) <= xdif) || (ydif < 0) || (ydif >= height) || !animDataTable[frame].data()) { + if ((xdif < 0) || ((threshold << 4) <= xdif) || (ydif <= 0) || (ydif >= height) || !animDataTable[frame].data()) { continue; } if (g_cine->getGameType() == Cine::GType_OS) { + // This test isn't present in Operation Stealth's PC version's disassembly + // but removing it makes things crash sometimes (e.g. when selecting a verb + // and moving the mouse cursor around the floor in the airport's bathroom). if (xdif >= width) { continue; } - if (it->type == 0 && animDataTable[frame].getColor(xdif, ydif) != part) { + if (it->type == 0 && animDataTable[frame].getColor(xdif, ydif) != (part & 0x0F)) { return it->objIdx; } else if (it->type == 1 && gfxGetBit(xdif, ydif, animDataTable[frame].data(), animDataTable[frame]._width * 4)) { return it->objIdx; -- cgit v1.2.3