[Scummvm-cvs-logs] SF.net SVN: scummvm:[35033] scummvm/trunk/engines/cine

thebluegr at users.sourceforge.net thebluegr at users.sourceforge.net
Thu Nov 13 09:59:17 CET 2008


Revision: 35033
          http://scummvm.svn.sourceforge.net/scummvm/?rev=35033&view=rev
Author:   thebluegr
Date:     2008-11-13 08:59:17 +0000 (Thu, 13 Nov 2008)

Log Message:
-----------
Started moving Save/Load code to saveload.cpp/.h

Modified Paths:
--------------
    scummvm/trunk/engines/cine/anim.cpp
    scummvm/trunk/engines/cine/anim.h
    scummvm/trunk/engines/cine/bg_list.h
    scummvm/trunk/engines/cine/module.mk
    scummvm/trunk/engines/cine/various.cpp
    scummvm/trunk/engines/cine/various.h

Added Paths:
-----------
    scummvm/trunk/engines/cine/saveload.cpp
    scummvm/trunk/engines/cine/saveload.h

Modified: scummvm/trunk/engines/cine/anim.cpp
===================================================================
--- scummvm/trunk/engines/cine/anim.cpp	2008-11-12 23:39:38 UTC (rev 35032)
+++ scummvm/trunk/engines/cine/anim.cpp	2008-11-13 08:59:17 UTC (rev 35033)
@@ -776,75 +776,4 @@
 	return result;
 }
 
-/*! \brief Load animDataTable from save
- * \param fHandle Savefile open for reading
- * \param saveGameFormat The used savegame format
- * \todo Add Operation Stealth savefile support
- *
- * Unlike the old code, this one actually rebuilds the table one frame
- * at a time.
- */
-void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) {
-	int16 currentAnim, foundFileIdx, frame;
-	char *animName, part[256], name[10];
-	uint16 width, height, bpp, var1;
-
-	strcpy(part, currentPartName);
-
-	// We only support these variations of the savegame format at the moment.
-	assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT);
-
-	const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30);
-	const int fileStartPos = fHandle.pos();
-	currentAnim = 0;
-	while (currentAnim < NUM_MAX_ANIMDATA) {
-		// Seek to the start of the current animation's entry
-		fHandle.seek(fileStartPos + currentAnim * entrySize);
-		// Read in the current animation entry
-		width = fHandle.readUint16BE();
-		var1 = fHandle.readUint16BE();
-		bpp = fHandle.readUint16BE();
-		height = fHandle.readUint16BE();
-
-		bool validPtr = false;
-		// Handle variables only present in animation entries of size 30
-		if (entrySize == 30) {
-			validPtr = (fHandle.readUint32BE() != 0); // Read data pointer
-			fHandle.readUint32BE(); // Discard mask pointer
-		}
-
-		foundFileIdx = fHandle.readSint16BE();
-		frame = fHandle.readSint16BE();
-		fHandle.read(name, 10);
-
-		// Handle variables only present in animation entries of size 23
-		if (entrySize == 23) {
-			validPtr = (fHandle.readByte() != 0);
-		}
-
-		// Don't try to load invalid entries.
-		if (foundFileIdx < 0 || !validPtr) {
-			currentAnim++; // Jump over the invalid entry
-			continue;
-		}
-
-		// Alright, the animation entry looks to be valid so let's start handling it...
-		if (strcmp(currentPartName, name)) {
-			closePart();
-			loadPart(name);
-		}
-
-		animName = partBuffer[foundFileIdx].partName;
-		loadRelatedPalette(animName); // Is this for Future Wars only?
-		const int16 prevAnim = currentAnim;
-		currentAnim = loadResource(animName, currentAnim);
-		assert(currentAnim > prevAnim); // Make sure we advance forward
-	}
-
-	loadPart(part);
-
-	// Make sure we jump over all the animation entries
-	fHandle.seek(fileStartPos + NUM_MAX_ANIMDATA * entrySize);
-}
-
 } // End of namespace Cine

Modified: scummvm/trunk/engines/cine/anim.h
===================================================================
--- scummvm/trunk/engines/cine/anim.h	2008-11-12 23:39:38 UTC (rev 35032)
+++ scummvm/trunk/engines/cine/anim.h	2008-11-13 08:59:17 UTC (rev 35033)
@@ -30,59 +30,6 @@
 
 namespace Cine {
 
-/**
- * Cine engine's save game formats.
- * Enumeration entries (Excluding the one used as an error)
- * are sorted according to age (i.e. top one is oldest, last one newest etc).
- *
- * ANIMSIZE_UNKNOWN:
- * - Animation data entry size is unknown (Used as an error).
- *
- * ANIMSIZE_23:
- * - Animation data entry size is 23 bytes.
- * - Used at least by 0.11.0 and 0.11.1 releases of ScummVM.
- * - Introduced in revision 21772, stopped using in revision 31444.
- *
- * ANIMSIZE_30_PTRS_BROKEN:
- * - Animation data entry size is 30 bytes.
- * - Data and mask pointers in the saved structs are always NULL.
- * - Introduced in revision 31453, stopped using in revision 32073.
- *
- * ANIMSIZE_30_PTRS_INTACT:
- * - Animation data entry size is 30 bytes.
- * - Data and mask pointers in the saved structs are intact,
- *   so you can test them for equality or inequality with NULL
- *   but don't try using them for anything else, it won't work.
- * - Introduced in revision 31444, got broken in revision 31453,
- *   got fixed in revision 32073 and used after that.
- *
- * TEMP_OS_FORMAT:
- * - Temporary Operation Stealth savegame format.
- * - NOT backward compatible and NOT to be supported in the future.
- *   This format should ONLY be used during development and abandoned
- *   later in favor of a better format!
- */
-enum CineSaveGameFormat {
-	ANIMSIZE_UNKNOWN,
-	ANIMSIZE_23,
-	ANIMSIZE_30_PTRS_BROKEN,
-	ANIMSIZE_30_PTRS_INTACT,
-	TEMP_OS_FORMAT
-};
-
-/** Identifier for the temporary Operation Stealth savegame format. */
-static const uint32 TEMP_OS_FORMAT_ID = MKID_BE('TEMP');
-
-/** The current version number of Operation Stealth's savegame format. */
-static const uint32 CURRENT_OS_SAVE_VER = 0;
-
-/** Chunk header used by the temporary Operation Stealth savegame format. */
-struct ChunkHeader {
-	uint32 id;      ///< Identifier (e.g. MKID_BE('TEMP'))
-	uint32 version; ///< Version number
-	uint32 size;    ///< Size of the chunk after this header in bytes
-};
-
 struct AnimHeaderStruct {
 	byte field_0;
 	byte field_1;

Modified: scummvm/trunk/engines/cine/bg_list.h
===================================================================
--- scummvm/trunk/engines/cine/bg_list.h	2008-11-12 23:39:38 UTC (rev 35032)
+++ scummvm/trunk/engines/cine/bg_list.h	2008-11-13 08:59:17 UTC (rev 35033)
@@ -28,7 +28,6 @@
 
 
 #include "common/scummsys.h"
-#include "common/savefile.h"
 #include "common/list.h"
 
 namespace Cine {

Modified: scummvm/trunk/engines/cine/module.mk
===================================================================
--- scummvm/trunk/engines/cine/module.mk	2008-11-12 23:39:38 UTC (rev 35032)
+++ scummvm/trunk/engines/cine/module.mk	2008-11-13 08:59:17 UTC (rev 35033)
@@ -14,6 +14,7 @@
 	part.o \
 	prc.o \
 	rel.o \
+	saveload.o \
 	script_fw.o \
 	script_os.o \
 	sound.o \

Added: scummvm/trunk/engines/cine/saveload.cpp
===================================================================
--- scummvm/trunk/engines/cine/saveload.cpp	                        (rev 0)
+++ scummvm/trunk/engines/cine/saveload.cpp	2008-11-13 08:59:17 UTC (rev 35033)
@@ -0,0 +1,1048 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/savefile.h"
+
+#include "cine/cine.h"
+#include "cine/bg_list.h"
+#include "cine/saveload.h"
+#include "cine/various.h"
+
+namespace Cine {
+
+int16 currentDisk;
+int16 saveVar2;
+
+
+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();
+}
+
+/*! \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);
+}
+
+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();
+}
+
+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;
+}
+
+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);
+}
+
+/**
+ * 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 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);
+}
+
+/*! \brief Load animDataTable from save
+ * \param fHandle Savefile open for reading
+ * \param saveGameFormat The used savegame format
+ * \todo Add Operation Stealth savefile support
+ *
+ * Unlike the old code, this one actually rebuilds the table one frame
+ * at a time.
+ */
+void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) {
+	int16 currentAnim, foundFileIdx, frame;
+	char *animName, part[256], name[10];
+	uint16 width, height, bpp, var1;
+
+	strcpy(part, currentPartName);
+
+	// We only support these variations of the savegame format at the moment.
+	assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT);
+
+	const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30);
+	const int fileStartPos = fHandle.pos();
+	currentAnim = 0;
+	while (currentAnim < NUM_MAX_ANIMDATA) {
+		// Seek to the start of the current animation's entry
+		fHandle.seek(fileStartPos + currentAnim * entrySize);
+		// Read in the current animation entry
+		width = fHandle.readUint16BE();
+		var1 = fHandle.readUint16BE();
+		bpp = fHandle.readUint16BE();
+		height = fHandle.readUint16BE();
+
+		bool validPtr = false;
+		// Handle variables only present in animation entries of size 30
+		if (entrySize == 30) {
+			validPtr = (fHandle.readUint32BE() != 0); // Read data pointer
+			fHandle.readUint32BE(); // Discard mask pointer
+		}
+
+		foundFileIdx = fHandle.readSint16BE();
+		frame = fHandle.readSint16BE();
+		fHandle.read(name, 10);
+
+		// Handle variables only present in animation entries of size 23
+		if (entrySize == 23) {
+			validPtr = (fHandle.readByte() != 0);
+		}
+
+		// Don't try to load invalid entries.
+		if (foundFileIdx < 0 || !validPtr) {
+			currentAnim++; // Jump over the invalid entry
+			continue;
+		}
+
+		// Alright, the animation entry looks to be valid so let's start handling it...
+		if (strcmp(currentPartName, name)) {
+			closePart();
+			loadPart(name);
+		}
+
+		animName = partBuffer[foundFileIdx].partName;
+		loadRelatedPalette(animName); // Is this for Future Wars only?
+		const int16 prevAnim = currentAnim;
+		currentAnim = loadResource(animName, currentAnim);
+		assert(currentAnim > prevAnim); // Make sure we advance forward
+	}
+
+	loadPart(part);
+
+	// Make sure we jump over all the animation entries
+	fHandle.seek(fileStartPos + NUM_MAX_ANIMDATA * entrySize);
+}
+
+} // End of namespace Cine


Property changes on: scummvm/trunk/engines/cine/saveload.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/cine/saveload.h
===================================================================
--- scummvm/trunk/engines/cine/saveload.h	                        (rev 0)
+++ scummvm/trunk/engines/cine/saveload.h	2008-11-13 08:59:17 UTC (rev 35033)
@@ -0,0 +1,89 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef CINE_SAVELOAD_H
+#define CINE_SAVELOAD_H
+
+#include "common/endian.h"
+
+namespace Cine {
+
+/**
+ * Cine engine's save game formats.
+ * Enumeration entries (Excluding the one used as an error)
+ * are sorted according to age (i.e. top one is oldest, last one newest etc).
+ *
+ * ANIMSIZE_UNKNOWN:
+ * - Animation data entry size is unknown (Used as an error).
+ *
+ * ANIMSIZE_23:
+ * - Animation data entry size is 23 bytes.
+ * - Used at least by 0.11.0 and 0.11.1 releases of ScummVM.
+ * - Introduced in revision 21772, stopped using in revision 31444.
+ *
+ * ANIMSIZE_30_PTRS_BROKEN:
+ * - Animation data entry size is 30 bytes.
+ * - Data and mask pointers in the saved structs are always NULL.
+ * - Introduced in revision 31453, stopped using in revision 32073.
+ *
+ * ANIMSIZE_30_PTRS_INTACT:
+ * - Animation data entry size is 30 bytes.
+ * - Data and mask pointers in the saved structs are intact,
+ *   so you can test them for equality or inequality with NULL
+ *   but don't try using them for anything else, it won't work.
+ * - Introduced in revision 31444, got broken in revision 31453,
+ *   got fixed in revision 32073 and used after that.
+ *
+ * TEMP_OS_FORMAT:
+ * - Temporary Operation Stealth savegame format.
+ * - NOT backward compatible and NOT to be supported in the future.
+ *   This format should ONLY be used during development and abandoned
+ *   later in favor of a better format!
+ */
+enum CineSaveGameFormat {
+	ANIMSIZE_UNKNOWN,
+	ANIMSIZE_23,
+	ANIMSIZE_30_PTRS_BROKEN,
+	ANIMSIZE_30_PTRS_INTACT,
+	TEMP_OS_FORMAT
+};
+
+/** Identifier for the temporary Operation Stealth savegame format. */
+static const uint32 TEMP_OS_FORMAT_ID = MKID_BE('TEMP');
+
+/** The current version number of Operation Stealth's savegame format. */
+static const uint32 CURRENT_OS_SAVE_VER = 0;
+
+/** Chunk header used by the temporary Operation Stealth savegame format. */
+struct ChunkHeader {
+	uint32 id;      ///< Identifier (e.g. MKID_BE('TEMP'))
+	uint32 version; ///< Version number
+	uint32 size;    ///< Size of the chunk after this header in bytes
+};
+
+
+} // End of namespace Cine
+
+#endif


Property changes on: scummvm/trunk/engines/cine/saveload.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/cine/various.cpp
===================================================================
--- scummvm/trunk/engines/cine/various.cpp	2008-11-12 23:39:38 UTC (rev 35032)
+++ scummvm/trunk/engines/cine/various.cpp	2008-11-13 08:59:17 UTC (rev 35033)
@@ -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 currentPartName[15];
 char currentDatName[30];
 
-int16 saveVar2;
-
 byte isInPause = 0;
 
 /*! \brief Values used by the xMoveKeyb variable */
@@ -116,7 +113,6 @@
 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 @@
 	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 @@
 	}
 }
 
-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 @@
 	}
 }
 
-/**
- * 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

Modified: scummvm/trunk/engines/cine/various.h
===================================================================
--- scummvm/trunk/engines/cine/various.h	2008-11-12 23:39:38 UTC (rev 35032)
+++ scummvm/trunk/engines/cine/various.h	2008-11-13 08:59:17 UTC (rev 35033)
@@ -41,6 +41,9 @@
 int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y, uint16 width, bool recheckValue = false);
 void makeCommandLine(void);
 void makeActionMenu(void);
+void drawString(const char *string, byte param);
+void waitPlayerInput(void);
+void setTextWindow(uint16 param1, uint16 param2, uint16 param3, uint16 param4);
 
 extern bool disableSystemMenu;
 extern bool inMenu;
@@ -70,7 +73,12 @@
 extern uint16 var3;
 extern uint16 var4;
 extern uint16 var5;
+extern int16 commandVar1;
+extern int16 commandVar2;
+extern int16 commandVar3[4];
 
+extern char currentDatName[30];
+
 void setTextWindow(uint16 param1, uint16 param2, uint16 param3, uint16 param4);
 
 extern uint16 errorVar;


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list