diff options
Diffstat (limited to 'engines/cine/various.cpp')
-rw-r--r-- | engines/cine/various.cpp | 942 |
1 files changed, 0 insertions, 942 deletions
diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 4d928456d4..3a826fab97 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -26,7 +26,6 @@ #include "common/endian.h" #include "common/events.h" -#include "common/savefile.h" #include "cine/cine.h" #include "cine/main_loop.h" @@ -91,8 +90,6 @@ char currentCtName[15]; char currentPartName[15]; char currentDatName[30]; -int16 saveVar2; - byte isInPause = 0; /*! \brief Values used by the xMoveKeyb variable */ @@ -116,7 +113,6 @@ uint16 yMoveKeyb = kKeybMoveCenterY; SelectedObjStruct currentSelectedObject; CommandeType currentSaveName[10]; -int16 currentDisk; static const int16 choiceResultTable[] = { 1, 1, 1, 2, 1, 1, 1 }; static const int16 subObjectUseTable[] = { 3, 3, 3, 3, 3, 0, 0 }; @@ -276,347 +272,6 @@ 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 - - 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]); - } -} - -/*! \brief Save the 80 bytes long command buffer padded to that length with zeroes. */ -void saveCommandBuffer(Common::OutSaveFile &out) { - // Let's make sure there's space for the trailing zero - // (That's why we subtract one from the maximum command buffer size here). - uint32 size = MIN<uint32>(commandBuffer.size(), kMaxCommandBufferSize - 1); - out.write(commandBuffer.c_str(), size); - // Write the rest as zeroes (Here we also write the string's trailing zero) - for (uint i = 0; i < kMaxCommandBufferSize - size; i++) { - out.writeByte(0); - } -} - -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<overlay>::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<BGIncrust>::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<SeqListElement>::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]; - - snprintf(tmp, 80, "%s.dir", _targetName.c_str()); - fHandle = g_saveFileMan->openForLoading(tmp); - - if (!fHandle) { - return false; - } - - fHandle->read(currentSaveName, 10 * 20); - delete fHandle; - - 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. - * - * 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). - // 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 animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize}; - Common::Array<uint> animEntrySizeMatches; - - // 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 - int32 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 != 0) || (mask != 0)) { - 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 handle open for reading - * \param isGlobal Restore object or global script? - */ -void loadScriptFromSave(Common::SeekableReadStream &fHandle, bool isGlobal) { - ScriptVars localVars, labels; - uint16 compare, pos; - int16 idx; - - labels.load(fHandle); - localVars.load(fHandle); - - compare = fHandle.readUint16BE(); - pos = fHandle.readUint16BE(); - idx = fHandle.readUint16BE(); - - // no way to reinitialize these - if (idx < 0) { - return; - } - - // original code loaded everything into globalScripts, this should be - // the correct behavior - if (isGlobal) { - ScriptPtr tmp(scriptInfo->create(*scriptTable[idx], idx, labels, localVars, compare, pos)); - assert(tmp); - globalScripts.push_back(tmp); - } else { - ScriptPtr tmp(scriptInfo->create(*relTable[idx], idx, labels, localVars, compare, pos)); - assert(tmp); - objectScripts.push_back(tmp); - } -} - -/*! \brief Restore overlay sprites from savefile - * \param fHandle Savefile open for reading - */ -void loadOverlayFromSave(Common::SeekableReadStream &fHandle) { - overlay tmp; - - fHandle.readUint32BE(); - fHandle.readUint32BE(); - - tmp.objIdx = fHandle.readUint16BE(); - tmp.type = fHandle.readUint16BE(); - tmp.x = fHandle.readSint16BE(); - tmp.y = fHandle.readSint16BE(); - tmp.width = fHandle.readSint16BE(); - tmp.color = fHandle.readSint16BE(); - - overlayList.push_back(tmp); -} - void CineEngine::resetEngine() { g_sound->stopMusic(); freeAnimDataTable(); @@ -668,520 +323,6 @@ void CineEngine::resetEngine() { } } -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(); -} - -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(); -} - -bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { - 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 ((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)."); - } - - // 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); - - // 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); - loadZoneData(in); - loadCommandVariables(in); - char tempCommandBuffer[kMaxCommandBufferSize]; - in.read(tempCommandBuffer, kMaxCommandBufferSize); - commandBuffer = tempCommandBuffer; - renderer->setCommand(commandBuffer); - 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); - - // 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); - } - - // 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(); -} - -bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) { - char bgName[13]; - - // At savefile position 0x0000: - currentDisk = in.readUint16BE(); - - // At 0x0002: - in.read(currentPartName, 13); - // At 0x000F: - in.read(currentDatName, 13); - - // At 0x001C: - saveVar2 = in.readSint16BE(); - - // At 0x001E: - in.read(currentPrcName, 13); - // At 0x002B: - in.read(currentRelName, 13); - // At 0x0038: - in.read(currentMsgName, 13); - // At 0x0045: - in.read(bgName, 13); - // At 0x0052: - in.read(currentCtName, 13); - - checkDataDisk(currentDisk); - - if (strlen(currentPartName)) { - loadPart(currentPartName); - } - - if (strlen(currentPrcName)) { - loadPrc(currentPrcName); - } - - if (strlen(currentRelName)) { - loadRel(currentRelName); - } - - if (strlen(bgName)) { - loadBg(bgName); - } - - if (strlen(currentCtName)) { - loadCtFW(currentCtName); - } - - // At 0x005F: - loadObjectTable(in); - - // 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): - loadZoneData(in); - - // At 0x22A1 (i.e. 0x2281 + 16 * 2): - loadCommandVariables(in); - - // At 0x22A9 (i.e. 0x22A1 + 4 * 2): - char tempCommandBuffer[kMaxCommandBufferSize]; - in.read(tempCommandBuffer, kMaxCommandBufferSize); - commandBuffer = tempCommandBuffer; - renderer->setCommand(commandBuffer); - - // At 0x22F9 (i.e. 0x22A9 + 0x50): - renderer->_cmdY = in.readUint16BE(); - - // At 0x22FB: - bgVar0 = in.readUint16BE(); - // At 0x22FD: - allowPlayerInput = in.readUint16BE(); - // At 0x22FF: - playerCommand = in.readSint16BE(); - // At 0x2301: - commandVar1 = in.readSint16BE(); - // At 0x2303: - isDrawCommandEnabled = in.readUint16BE(); - // At 0x2305: - var5 = in.readUint16BE(); - // At 0x2307: - var4 = in.readUint16BE(); - // At 0x2309: - var3 = in.readUint16BE(); - // At 0x230B: - var2 = in.readUint16BE(); - // At 0x230D: - commandVar2 = in.readSint16BE(); - - // At 0x230F: - renderer->_messageBg = in.readUint16BE(); - - // At 0x2311: - in.readUint16BE(); - // At 0x2313: - in.readUint16BE(); - - // At 0x2315: - loadResourcesFromSave(in, saveGameFormat); - - loadScreenParams(in); - loadGlobalScripts(in); - loadObjectScripts(in); - loadOverlayList(in); - loadBgIncrustFromSave(in); - - if (strlen(currentMsgName)) { - loadMsg(currentMsgName); - } - - if (strlen(currentDatName)) { -/* i = saveVar2; - saveVar2 = 0; - loadMusic(); - if (i) { - playMusic(); - }*/ - } - - return !in.ioFailed(); -} - -bool CineEngine::makeLoad(char *saveName) { - Common::SharedPtr<Common::InSaveFile> saveFile(g_saveFileMan->openForLoading(saveName)); - - if (!saveFile) { - drawString(otherMessages[0], 0); - waitPlayerInput(); - // restoreScreen(); - checkDataDisk(-1); - return false; - } - - 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. - // - // 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<Common::MemoryReadStream> in(saveFile->readStream(saveSize)); - - // Try to detect the used savegame format - 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 - // release of ScummVM but only during development (From revision 31453, - // which introduced the problem, until revision 32073, which fixed it). - // Therefore we bail out if we detect this particular savegame format. - warning("Detected a known broken savegame format, not loading savegame"); - 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; - } - - 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); - } - } - - setMouseCursor(MOUSE_CURSOR_NORMAL); - - return result; -} - -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); - saveCommandBuffer(out); - - 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); -} - -void CineEngine::makeSave(char *saveFileName) { - Common::SharedPtr<Common::OutSaveFile> fHandle(g_saveFileMan->openForSaving(saveFileName)); - - setMouseCursor(MOUSE_CURSOR_DISK); - - if (!fHandle) { - drawString(otherMessages[1], 0); - waitPlayerInput(); - // restoreScreen(); - checkDataDisk(-1); - } else { - if (g_cine->getGameType() == GType_FW) { - makeSaveFW(*fHandle); - } else { - makeSaveOS(*fHandle); - } - } - - setMouseCursor(MOUSE_CURSOR_NORMAL); -} - void CineEngine::makeSystemMenu(void) { int16 numEntry, systemCommand; int16 mouseX, mouseY, mouseButton; @@ -1319,89 +460,6 @@ void CineEngine::makeSystemMenu(void) { } } -/** - * Save an Operation Stealth type savegame. WIP! - * - * 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; - - // 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); - 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); - saveCommandBuffer(out); - 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.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); - // 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 |