[Scummvm-cvs-logs] SF.net SVN: scummvm: [31268] scummvm/trunk/engines/kyra

lordhoto at users.sourceforge.net lordhoto at users.sourceforge.net
Thu Mar 27 19:03:01 CET 2008


Revision: 31268
          http://scummvm.svn.sourceforge.net/scummvm/?rev=31268&view=rev
Author:   lordhoto
Date:     2008-03-27 11:03:00 -0700 (Thu, 27 Mar 2008)

Log Message:
-----------
- Implemented support for --list-saves in Kyra engine
- Added support for variable length savegame name field
- Changed savegame identifier
- Increased savegame file version

Modified Paths:
--------------
    scummvm/trunk/engines/kyra/detection.cpp
    scummvm/trunk/engines/kyra/kyra.h
    scummvm/trunk/engines/kyra/kyra_v1.h
    scummvm/trunk/engines/kyra/kyra_v2.h
    scummvm/trunk/engines/kyra/saveload.cpp
    scummvm/trunk/engines/kyra/saveload_v1.cpp
    scummvm/trunk/engines/kyra/saveload_v2.cpp

Modified: scummvm/trunk/engines/kyra/detection.cpp
===================================================================
--- scummvm/trunk/engines/kyra/detection.cpp	2008-03-27 16:12:48 UTC (rev 31267)
+++ scummvm/trunk/engines/kyra/detection.cpp	2008-03-27 18:03:00 UTC (rev 31268)
@@ -29,6 +29,7 @@
 
 #include "common/config-manager.h"
 #include "common/advancedDetector.h"
+#include "common/savefile.h"
 
 #include "base/plugins.h"
 
@@ -445,15 +446,17 @@
 public:
 	KyraMetaEngine() : Common::AdvancedMetaEngine(detectionParams) {}
 
-	virtual const char *getName() const {
+	const char *getName() const {
 		return "Legend of Kyrandia Engine";
 	}
 
-	virtual const char *getCopyright() const {
+	const char *getCopyright() const {
 		return "The Legend of Kyrandia (C) Westwood Studios";
 	}
 
-	virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+	bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+
+	SaveStateList listSaves(const char *target) const;
 };
 
 bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
@@ -489,10 +492,38 @@
 		break;
 	default:
 		res = false;
-		error("Kyra engine: unknown gameID");
+		warning("Kyra engine: unknown gameID");
 	}
 
 	return res;
 }
 
+SaveStateList KyraMetaEngine::listSaves(const char *target) const {
+	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+	Kyra::KyraEngine::SaveHeader header;
+	Common::String pattern = target;
+	pattern += ".???";
+
+	Common::StringList filenames;
+	filenames = saveFileMan->listSavefiles(pattern.c_str());
+	sort(filenames.begin(), filenames.end());	// Sort (hopefully ensuring we are sorted numerically..)
+
+	SaveStateList saveList;
+	for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++) {
+		// Obtain the last 3 digits of the filename, since they correspond to the save slot
+		int slotNum = atoi(file->c_str() + file->size() - 3);
+		
+		if (slotNum >= 0 && slotNum <= 999) {
+			Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+			if (in) {
+				if (Kyra::KyraEngine::readSaveHeader(in, header) == Kyra::KyraEngine::kRSHENoError)
+					saveList.push_back(SaveStateDescriptor(slotNum, header.description, *file));
+				delete in;
+			}
+		}
+	}
+
+	return saveList;
+}
+
 REGISTER_PLUGIN(KYRA, PLUGIN_TYPE_ENGINE, KyraMetaEngine);

Modified: scummvm/trunk/engines/kyra/kyra.h
===================================================================
--- scummvm/trunk/engines/kyra/kyra.h	2008-03-27 16:12:48 UTC (rev 31267)
+++ scummvm/trunk/engines/kyra/kyra.h	2008-03-27 18:03:00 UTC (rev 31268)
@@ -38,6 +38,8 @@
 class OutSaveFile;
 } // end of namespace Common
 
+class KyraMetaEngine;
+
 namespace Kyra {
 
 struct GameFlags {
@@ -101,6 +103,7 @@
 
 class KyraEngine : public Engine {
 friend class Debugger;
+friend class ::KyraMetaEngine;
 public:
 	KyraEngine(OSystem *system, const GameFlags &flags);
 	virtual ~KyraEngine();
@@ -225,10 +228,27 @@
 	static const int8 _addYPosTable[];
 
 	// save/load
-	virtual uint32 saveGameID() const = 0;
+	const char *getSavegameFilename(int num);
 
-	const char *getSavegameFilename(int num);
-	Common::InSaveFile *openSaveForReading(const char *filename, uint32 &version, char *saveName);
+	struct SaveHeader {
+		Common::String description;
+		uint32 version;
+		byte gameID;
+		uint32 flags;
+
+		bool originalSave;	// savegame from original interpreter
+		bool oldHeader;		// old scummvm save header
+	};
+
+	enum kReadSaveHeaderError {
+		kRSHENoError = 0,
+		kRSHEInvalidType = 1,
+		kRSHEInvalidVersion = 2,
+		kRSHEIoError = 3
+	};
+	static kReadSaveHeaderError readSaveHeader(Common::InSaveFile *file, SaveHeader &header);
+
+	Common::InSaveFile *openSaveForReading(const char *filename, SaveHeader &header);
 	Common::OutSaveFile *openSaveForWriting(const char *filename, const char *saveName) const;
 };
 

Modified: scummvm/trunk/engines/kyra/kyra_v1.h
===================================================================
--- scummvm/trunk/engines/kyra/kyra_v1.h	2008-03-27 16:12:48 UTC (rev 31267)
+++ scummvm/trunk/engines/kyra/kyra_v1.h	2008-03-27 18:03:00 UTC (rev 31268)
@@ -281,8 +281,6 @@
 	void snd_voiceWaitForFinish(bool ingame = true);
 
 protected:
-	uint32 saveGameID() const { return 'KYRA'; }
-
 	void saveGame(const char *fileName, const char *saveName);
 	void loadGame(const char *fileName);
 

Modified: scummvm/trunk/engines/kyra/kyra_v2.h
===================================================================
--- scummvm/trunk/engines/kyra/kyra_v2.h	2008-03-27 16:12:48 UTC (rev 31267)
+++ scummvm/trunk/engines/kyra/kyra_v2.h	2008-03-27 18:03:00 UTC (rev 31268)
@@ -1201,8 +1201,6 @@
 	int _dbgPass;
 
 	// save/load specific
-	uint32 saveGameID() const { return 'HOFS'; }
-
 	void saveGame(const char *fileName, const char *saveName);
 	void loadGame(const char *fileName);
 };

Modified: scummvm/trunk/engines/kyra/saveload.cpp
===================================================================
--- scummvm/trunk/engines/kyra/saveload.cpp	2008-03-27 16:12:48 UTC (rev 31267)
+++ scummvm/trunk/engines/kyra/saveload.cpp	2008-03-27 18:03:00 UTC (rev 31268)
@@ -29,71 +29,130 @@
 
 #include "kyra/kyra.h"
 
-#define CURRENT_SAVE_VERSION 8
+#define CURRENT_SAVE_VERSION 9
 
-#define GF_FLOPPY (1 <<  0)
-#define GF_TALKIE (1 <<  1)
+#define GF_FLOPPY  (1 <<  0)
+#define GF_TALKIE  (1 <<  1)
 #define GF_FMTOWNS (1 <<  2)
 
 namespace Kyra {
 
-Common::InSaveFile *KyraEngine::openSaveForReading(const char *filename, uint32 &version, char *saveName) {
-	debugC(9, kDebugLevelMain, "KyraEngine::openSaveForReading('%s', %p, %p)", filename, (const void*)&version, saveName);
+KyraEngine::kReadSaveHeaderError KyraEngine::readSaveHeader(Common::InSaveFile *in, SaveHeader &header) {
+	uint32 type = in->readUint32BE();
+	header.originalSave = false;
+	header.oldHeader = false;
+	header.flags = 0;
 
+	if (type == MKID_BE('KYRA') || type == MKID_BE('ARYK')) { // old Kyra1 header ID
+		header.gameID = GI_KYRA1;
+		header.oldHeader = true;
+	} else if (type == MKID_BE('HOFS')) { // old Kyra2 header ID
+		header.gameID = GI_KYRA2;
+		header.oldHeader = true;
+	} else if (type == MKID_BE('WWSV')) {
+		header.gameID = in->readByte();
+	} else {
+		// try checking for original save header
+		const int descriptionSize[2] = { 30, 80 };
+		char descriptionBuffer[81];
+
+		bool saveOk = false;
+
+		for (uint i = 0; i < ARRAYSIZE(descriptionSize) && !saveOk; ++i) {
+			in->seek(0, SEEK_SET);
+			in->read(descriptionBuffer, descriptionSize[i]);
+			descriptionBuffer[descriptionSize[i]] = 0;
+			
+			type = in->readUint32BE();
+			header.version = in->readUint16LE();
+			if (type == MKID_BE('MBL3') && header.version == 100) {
+				saveOk = true;
+				header.description = descriptionBuffer;
+				header.gameID = GI_KYRA2;
+				break;
+			}
+		}
+
+		if (saveOk) {
+			header.originalSave = true;
+			header.description = descriptionBuffer;
+			return kRSHENoError;
+		} else {
+			return kRSHEInvalidType;
+		}
+	}
+
+	header.version = in->readUint32BE();
+	if (header.version > CURRENT_SAVE_VERSION || (header.oldHeader && header.version > 8) || (type == MKID_BE('ARYK') && header.version > 3))
+		return kRSHEInvalidVersion;
+
+	// Versions prior to 9 are using a fixed length description field
+	if (header.version <= 8) {
+		char buffer[31];
+		in->read(buffer, 31);
+		header.description = buffer;
+	} else {
+		header.description = "";
+		for (char c = 0; (c = in->readByte()) != 0;)
+			header.description += c;
+	}
+
+	if (header.version >= 2)
+		header.flags = in->readUint32BE();
+
+	return (in->ioFailed() ? kRSHEIoError : kRSHENoError);
+}
+
+Common::InSaveFile *KyraEngine::openSaveForReading(const char *filename, SaveHeader &header) {
+	debugC(9, kDebugLevelMain, "KyraEngine::openSaveForReading('%s', -)", filename);
+
 	Common::InSaveFile *in = 0;
 	if (!(in = _saveFileMan->openForLoading(filename))) {
 		warning("Can't open file '%s', game not loaded", filename);
 		return 0;
 	}
 
-	uint32 type = in->readUint32BE();
+	kReadSaveHeaderError errorCode = KyraEngine::readSaveHeader(in, header);
+	if (errorCode != kRSHENoError) {
+		if (errorCode == kRSHEInvalidType)
+			warning("No ScummVM Kyra engine savefile header.");
+		else if (errorCode == kRSHEInvalidVersion)
+			warning("Savegame is not the right version (%u, '%s')", header.version, header.oldHeader ? "true" : "false");
+		else if (errorCode == kRSHEIoError)
+			warning("Load failed ('%s').", filename);
 
-	// FIXME: The kyra savegame code used to be endian unsafe. Uncomment the
-	// following line to graciously handle old savegames from LE machines.
-	// if (type != MKID_BE('KYRA') && type != MKID_BE('ARYK')) {
-	if (type != MKID_BE(saveGameID())) {
-		warning("No ScummVM Kyra engine savefile header.");
 		delete in;
 		return 0;
 	}
 
-	version = in->readUint32BE();
-	if (version > CURRENT_SAVE_VERSION) {
-		warning("Savegame is not the right version (%u)", version);
-		delete in;
-		return 0;
-	}
+	if (!header.originalSave) {
+		if (!header.oldHeader) {
+			if (header.gameID != _flags.gameID) {
+				warning("Trying to load game state from other game (save game: %u, running game: %u)", header.gameID, _flags.gameID);
+				delete in;
+				return 0;
+			}
+		}
 
-	char saveNameBuffer[31];
-	if (!saveName)
-		saveName = saveNameBuffer;
-	in->read(saveName, 31);
-
-	if (_flags.gameID == GI_KYRA1 && version < 2) {
-		warning("Make sure your savefile was from this version! (too old savefile version to detect that)");
-	} else {
-		uint32 flags = in->readUint32BE();
-		if ((flags & GF_FLOPPY) && (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
-			warning("Can not load DOS Floppy savefile for this (non DOS Floppy) gameversion");
-			delete in;
-			return 0;
-		} else if ((flags & GF_TALKIE) && !(_flags.isTalkie)) {
-			warning("Can not load DOS CD-ROM savefile for this (non DOS CD-ROM) gameversion");
-			delete in;
-			return 0;
-		} else if ((flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
-			warning("Can not load FM-Towns/PC98 savefile for this (non FM-Towns/PC98) gameversion");
-			delete in;
-			return 0;
+		if (header.version < 2) {
+			warning("Make sure your savefile was from this version! (too old savefile version to detect that)");
+		} else {
+			if ((header.flags & GF_FLOPPY) && (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
+				warning("Can not load DOS Floppy savefile for this (non DOS Floppy) gameversion");
+				delete in;
+				return 0;
+			} else if ((header.flags & GF_TALKIE) && !(_flags.isTalkie)) {
+				warning("Can not load DOS CD-ROM savefile for this (non DOS CD-ROM) gameversion");
+				delete in;
+				return 0;
+			} else if ((header.flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
+				warning("Can not load FM-Towns/PC98 savefile for this (non FM-Towns/PC98) gameversion");
+				delete in;
+				return 0;
+			}
 		}
 	}
 
-	if (in->ioFailed()) {
-		error("Load failed ('%s', '%s').", filename, saveName);
-		delete in;
-		return 0;
-	}
-
 	return in;
 }
 
@@ -109,9 +168,10 @@
 	}
 
 	// Savegame version
-	out->writeUint32BE(saveGameID());
+	out->writeUint32BE(MKID_BE('WWSV'));
+	out->writeByte(_flags.gameID);
 	out->writeUint32BE(CURRENT_SAVE_VERSION);
-	out->write(saveName, 31);
+	out->write(saveName, strlen(saveName)+1);
 	if (_flags.isTalkie)
 		out->writeUint32BE(GF_TALKIE);
 	else if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)

Modified: scummvm/trunk/engines/kyra/saveload_v1.cpp
===================================================================
--- scummvm/trunk/engines/kyra/saveload_v1.cpp	2008-03-27 16:12:48 UTC (rev 31267)
+++ scummvm/trunk/engines/kyra/saveload_v1.cpp	2008-03-27 18:03:00 UTC (rev 31268)
@@ -38,12 +38,17 @@
 void KyraEngine_v1::loadGame(const char *fileName) {
 	debugC(9, kDebugLevelMain, "KyraEngine_v1::loadGame('%s')", fileName);
 
-	uint32 version = 0;
-	char saveName[31];
-	Common::InSaveFile *in = openSaveForReading(fileName, version, saveName);
+	SaveHeader header;
+	Common::InSaveFile *in = openSaveForReading(fileName, header);
 	if (!in)
 		return;
 
+	if (header.originalSave) {
+		// no support for original savefile in Kyrandia 1 (yet)
+		delete in;
+		return;
+	}
+
 	snd_playSoundEffect(0x0A);
 	snd_playWanderScoreViaMap(0, 1);
 
@@ -99,7 +104,7 @@
 	_poisonDeathCounter = in->readByte();
 	_animator->_brandonDrawFrame = in->readUint16BE();
 
-	_timer->loadDataFromFile(in, version);
+	_timer->loadDataFromFile(in, header.version);
 
 	memset(_flagsTable, 0, sizeof(_flagsTable));
 	uint32 flagsSize = in->readUint32BE();
@@ -131,7 +136,7 @@
 			_roomTable[sceneId].needInit[i] = in->readByte();
 		}
 	}
-	if (version >= 3) {
+	if (header.version >= 3) {
 		_lastMusicCommand = in->readSint16BE();
 		if (_lastMusicCommand != -1)
 			snd_playWanderScoreViaMap(_lastMusicCommand, 1);
@@ -140,7 +145,7 @@
 	// Version 4 stored settings in the savegame. As of version 5, they are
 	// handled by the config manager.
 
-	if (version == 4) {
+	if (header.version == 4) {
 		in->readByte(); // Text speed
 		in->readByte(); // Walk speed
 		in->readByte(); // Music
@@ -148,7 +153,7 @@
 		in->readByte(); // Voice
 	}
 
-	if (version >= 7) {
+	if (header.version >= 7) {
 		_curSfxFile = in->readByte();
 
 		// In the first version when this entry was introduced,
@@ -200,9 +205,9 @@
 	setMousePos(brandonX, brandonY);
 	
 	if (in->ioFailed())
-		error("Load failed ('%s', '%s').", fileName, saveName);
+		error("Load failed ('%s', '%s').", fileName, header.description.c_str());
 	else
-		debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", saveName);
+		debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", header.description.c_str());
 
 	// We didn't explicitly set the walk speed, but it's saved as part of
 	// the _timers array, so we need to re-sync it with _configWalkspeed.

Modified: scummvm/trunk/engines/kyra/saveload_v2.cpp
===================================================================
--- scummvm/trunk/engines/kyra/saveload_v2.cpp	2008-03-27 16:12:48 UTC (rev 31267)
+++ scummvm/trunk/engines/kyra/saveload_v2.cpp	2008-03-27 18:03:00 UTC (rev 31268)
@@ -131,47 +131,11 @@
 void KyraEngine_v2::loadGame(const char *fileName) {
 	debugC(9, kDebugLevelMain, "KyraEngine_v2::loadGame('%s')", fileName);
 
-	uint32 version = 0;
-	char saveName[31];
-	Common::InSaveFile *in = openSaveForReading(fileName, version, saveName);
+	SaveHeader header;
+	Common::InSaveFile *in = openSaveForReading(fileName, header);
 	if (!in) {
-		// check for original savefile
-		if ((in = _saveFileMan->openForLoading(fileName))) {
-			in->seek(0x50, SEEK_CUR);
-
-			uint8 type[4];
-			uint8 acceptedType[4] = { 0x4D, 0x42, 0x4C, 0x33 }; // 'MBL3'
-			in->read(type, sizeof(type));
-			uint16 origVersion = in->readUint16LE();
-			
-			debug(1, "Savegame type: '%c%c%c%c' version: %d", type[0], type[1], type[2], type[3], version);
-
-			if (!memcmp(type, acceptedType, 4) && origVersion == 100) {
-				warning("Trying to load savegame from original interpreter, while this is possible, it is not officially supported.");
-
-				in->seek(0, SEEK_SET);
-
-				// read first 31 bytes of original description
-				in->read(saveName, 30);
-				saveName[30] = 0;
-				// skip last part of original description
-				in->seek(0x50-30, SEEK_CUR);
-				version = 0xF000 + origVersion;
-				// skip type
-				in->seek(4, SEEK_CUR);
-				// skip version
-				in->seek(2, SEEK_CUR);
-			} else {
-				delete in;
-				in = 0;
-			}
-		}
-
-		if (!in) {
-			showMessageFromCCode(0x35, 0x84, 0);
-			snd_playSoundEffect(0x0D);
-			return;
-		}
+		showMessageFromCCode(0x35, 0x84, 0);
+		snd_playSoundEffect(0x0D);
 	}
 
 	bool setFlag1EE = (queryGameFlag(0x1EE) != 0);
@@ -187,8 +151,8 @@
 
 	_screen->hideMouse();
 
-	if (version < 0xF000) {
-		_timer->loadDataFromFile(in, version);
+	if (!header.originalSave) {
+		_timer->loadDataFromFile(in, header.version);
 
 		uint32 flagsSize = in->readUint32BE();
 		assert(flagsSize <= sizeof(_flagsTable));
@@ -264,8 +228,6 @@
 		_sceneExit3 = in->readUint16BE();
 		_sceneExit4 = in->readUint16BE();
 	} else {
-		version -= 0xF000;
-
 		/*word_2AB05 = */in->readUint16LE();
 		_lastMusicCommand = in->readSint16LE();
 		_newChapterFile = in->readByte();
@@ -363,9 +325,9 @@
 	}
 
 	if (in->ioFailed())
-		error("Load failed ('%s', '%s').", fileName, saveName);
+		error("Load failed ('%s', '%s').", fileName, header.description.c_str());
 	else
-		debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", saveName);
+		debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", header.description.c_str());
 
 	delete in;
 


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