[Scummvm-cvs-logs] SF.net SVN: scummvm: [22040] scummvm/trunk/engines/scumm/plugin.cpp

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Wed Apr 19 13:39:51 CEST 2006


Revision: 22040
Author:   fingolfin
Date:     2006-04-19 13:26:27 -0700 (Wed, 19 Apr 2006)
ViewCVS:  http://svn.sourceforge.net/scummvm/?rev=22040&view=rev

Log Message:
-----------
Some more tweaks to the (still disabled) new detection / filename generation code

Modified Paths:
--------------
    scummvm/trunk/engines/scumm/plugin.cpp
Modified: scummvm/trunk/engines/scumm/plugin.cpp
===================================================================
--- scummvm/trunk/engines/scumm/plugin.cpp	2006-04-19 20:04:53 UTC (rev 22039)
+++ scummvm/trunk/engines/scumm/plugin.cpp	2006-04-19 20:26:27 UTC (rev 22040)
@@ -28,6 +28,7 @@
 #include "base/plugins.h"
 
 #include "common/config-manager.h"
+#include "common/list.h"
 #include "common/md5.h"
 #include "common/system.h"	// Only needed for g_system
 
@@ -1002,38 +1003,12 @@
 }
 
 #if 0
-Common::String generateFilenameForDetection(const GameFilenamePattern &gfp) {
+Common::String ScummEngine::generateFilename(const int room) const {
+	// HACK to drive test compiles; of course _substEntry would be a member var of ScummEngine
+	const GameFilenamePattern _substEntry = { "maniac", "%.2d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 };
+	const int diskNumber = room ? res.roomno[rtRoom][room] : 0;
 	char buf[128];
 
-	switch (gfp.genMethod) {
-	case kGenDiskNum:
-	case kGenRoomNum:
-		snprintf(buf, sizeof(buf), gfp.pattern, 0);
-		break;
-
-	case kGenHEPC:
-		snprintf(buf, sizeof(buf), "%s.he0", gfp.pattern);
-		break;
-
-	case kGenHEMac:
-		snprintf(buf, sizeof(buf), "%s (0)", gfp.pattern);
-		break;
-
-	case kGenHEMacNoParens:
-		snprintf(buf, sizeof(buf), "%s 0", gfp.pattern);
-		break;
-
-	default:
-		error("generateFilenameForDetection: Unhandled genMethod");
-	}
-
-	return buf;
-}
-
-#if 0
-Common::String ScummEngine::generateFilename(int room, int diskNumber) {
-	char buf[128];
-
 	if (_game.version == 4) {
 		if (room == 0 || room >= 900) {
 			snprintf(buf, sizeof(buf), "%.3d.lfl", room);
@@ -1064,15 +1039,15 @@
 				switch(disk) {
 				case 2:
 					id = 'b';
-					snprintf(buf, sizeof(buf), "%s.(b)", pattern);
+					snprintf(buf, sizeof(buf), "%s.(b)", _substEntry.pattern);
 					break;
 				case 1:
 					id = 'a';
-					snprintf(buf, sizeof(buf), "%s.(a)", pattern);
+					snprintf(buf, sizeof(buf), "%s.(a)", _substEntry.pattern);
 					break;
 				default:
 					id = '0';
-					snprintf(buf, sizeof(buf), "%s.he0", pattern);
+					snprintf(buf, sizeof(buf), "%s.he0", _substEntry.pattern);
 				}
 			} else if (_game.heversion >= 70) {
 				id = (room == 0) ? '0' : '1';
@@ -1083,13 +1058,13 @@
 			if (_substEntry.genMethod == kGenHEPC) {
 				// For HE >= 98, we already called snprintf above.
 				if (_game.heversion < 98)
-					snprintf(buf, sizeof(buf), "%s.he%c", pattern, id);
+					snprintf(buf, sizeof(buf), "%s.he%c", _substEntry.pattern, id);
 			} else {
 				if (id == '3') { // special case for cursors
 					// For mac they're stored in game binary
-					strncpy(buf, _substEntry.pattern, bufsize);
+					strncpy(buf, _substEntry.pattern, sizeof(buf));
 				} else {
-					if (subst.genMethod == kGenMac)
+					if (_substEntry.genMethod == kGenHEMac)
 						snprintf(buf, sizeof(buf), "%s (%c)", _substEntry.pattern, id);
 					else
 						snprintf(buf, sizeof(buf), "%s %c", _substEntry.pattern, id);
@@ -1099,7 +1074,7 @@
 			break;
 
 		default:
-			error("FOO");
+			error("generateFilename: Unsupported genMethod");
 		}
 	}
 
@@ -1107,16 +1082,51 @@
 }
 #endif
 
+#if 0
+Common::String generateFilenameForDetection(const GameFilenamePattern &gfp) {
+	char buf[128];
+
+	switch (gfp.genMethod) {
+	case kGenDiskNum:
+	case kGenRoomNum:
+		snprintf(buf, sizeof(buf), gfp.pattern, 0);
+		break;
+
+	case kGenHEPC:
+		snprintf(buf, sizeof(buf), "%s.he0", gfp.pattern);
+		break;
+
+	case kGenHEMac:
+		snprintf(buf, sizeof(buf), "%s (0)", gfp.pattern);
+		break;
+
+	case kGenHEMacNoParens:
+		snprintf(buf, sizeof(buf), "%s 0", gfp.pattern);
+		break;
+
+	default:
+		error("generateFilenameForDetection: Unsupported genMethod");
+	}
+
+	return buf;
+}
+
 struct DetectorDesc {
 	Common::String path;
 	Common::String md5;
 	const MD5Table *md5Entry;	// Entry of the md5 table corresponding to this file, if any.
-	//GameSettings game;
 };
 
-void detectGames(const FSList &fslist) {
+
+struct DetectorResult {
+	const GameFilenamePattern *gfp;
+	GameSettings game;
+};
+
+void detectGames(const char *gameid_XXX, const FSList &fslist, Common::List<DetectorResult> &results) {
 	typedef Common::HashMap<Common::String, DetectorDesc> DescMap;
 	DescMap fileMD5Map;
+	const GameSettings *g;
 	
 	for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
 		if (!file->isDirectory()) {
@@ -1129,7 +1139,14 @@
 
 	// Iterate over all filename patterns.
 	for (const GameFilenamePattern *gfp = gameFilenamesTable; gfp->gameid; ++gfp) {
-		// Generate the detectname corresponding to the gfp.
+		// If gameid_XXX was specified, we only try to detect that specific game,
+		// so we can just skip over everything with a differing gameid.
+		if (gameid_XXX && scumm_stricmp(gameid_XXX, gfp->gameid))
+			continue;
+	
+		// Generate the detectname corresponding to the gfp. If the file doesn't
+		// exist in the directory we are looking at, we can skip to the next
+		// one immediately.
 		Common::String file(generateFilenameForDetection(*gfp));
 		if (!fileMD5Map.contains(file))
 			continue;
@@ -1148,9 +1165,43 @@
 				d.md5Entry = findInMD5Table(md5str);
 
 				if (d.md5Entry) {
-/*
-					TODO: Exact match found, handle this
-*/
+					// Exact match found
+
+					// Sanity check: Make sure the gameids match!
+					if (scumm_stricmp(d.md5Entry->gameid, gfp->gameid)) {
+						error("SCUMM detectGames: MD5 %s implies gameid '%s', but gameid '%s' was expected",
+								md5str, d.md5Entry->gameid, gfp->gameid);
+					}
+
+					DetectorResult dr;
+					dr.game.gameid = 0;
+					dr.gfp = gfp;
+
+					// Compute the precise game settings using gameVariantsTable.
+					for (g = gameVariantsTable; g->gameid; ++g) {
+						if (g->gameid[0] == 0 || !scumm_stricmp(d.md5Entry->gameid, g->gameid)) {
+							// The gameid either matches, or is empty (the latter indicates
+							// a generic entry, used currently for generic HE specifies.
+			
+							if (g->variant == 0 || !scumm_stricmp(d.md5Entry->variant, g->variant)) {
+								// Perfect match found, use it and stop the loop
+								dr.game = *g;
+								dr.game.gameid = gfp->gameid;
+								if (d.md5Entry->platform != Common::kPlatformUnknown) {
+									if (dr.game.platform != Common::kPlatformUnknown && dr.game.platform != d.md5Entry->platform)
+										warning("SCUMM detectGames: Platform values differ for MD5 '%s': %d vs %d (please report to Fingolfin)",
+													md5str, dr.game.platform, d.md5Entry->platform);
+									dr.game.platform = d.md5Entry->platform;
+								}
+								results.push_back(dr);
+								break;
+							}
+						}
+					}
+
+					// Sanity check: We *should* have found a matching gameid / variant at this point.
+					// If not, then there's a bug in our data tables...
+					assert(dr.game.gameid != 0);
 				}
 			}
 		}
@@ -1160,17 +1211,158 @@
 		if (d.md5Entry != 0)
 			continue;
 
-		// At this point, the MD5 sum has been computed but is not known.
-/*
-		TODO: Look at the file (like in Engine_SCUMM_detectGames) to further
-		narrow down the possibilities... For names that are unique, we don't
-		have to do much more. For non-unique names, we could at least try
-		to determine the SCUMM version to somewhat reduce the list of
-		possible candidates.
+		// At this point, the MD5 sum has been computed but is not known. We
+		// still do our best to identify the game & variant correctly.
 		
-		How to determine whether a detection filename is unique? Well the only
-		names which are *not* unique are 00.LFL and 000.LFL anyway!
-*/	
+		// First step is to determine the correct gameid. Luckily, in most
+		// cases the filename alone implies the gameid. Currently the only
+		// exceptions are 00.LFL and 000.LFL, for which we add special cases
+		// below.
+		
+		// After that, we may take a peek at the file contents to further
+		// narrow down the list of variants.
+		
+		// TODO: Should we do some sort of caching on the data we read? Like,
+		// keep a copy of the first N bytes ?
+
+		Common::File tmp;
+		if (!tmp.open(d.path.c_str())) {
+			warning("SCUMM detectGames: failed to open '%s' for read access", d.path.c_str());
+			continue;
+		}
+		byte buf[6];
+		tmp.read(buf, 6);
+		
+		if (file == "00.LFL") {
+			// Used in V1, V2, V3 games.
+			
+			if (buf[0] == 0xbc && buf[1] == 0xb9) {
+				// The NES version of MM
+				// TODO
+			} else if (buf[0] == 0xCE && buf[1] == 0xF5) {
+				// Looks like V1.
+
+				// Candidates: maniac classic, zak classic
+
+				// TODO: Maybe we can use the filesize to distinguish these two?
+				// English V1 Zak: 1896 bytes
+				// English V1 MM:  1972 bytes
+
+				// Since it seems unlikely that there are other (official)
+				// variants of these two games around, it should be safe to use
+				// the filesize for detection. In case of an unknown size,
+				// we just generate a warning and skip the file.
+			} else if (buf[0] == 0xFF && buf[1] == 0xFE) {
+				// GF_OLD_BUNDLE: could be V2 or old V3.
+				// Candidates: maniac enhanced, zak enhanced, indy3ega, loom
+				/*
+				TODO: Might be possible to distinguish those by the script count.
+				Specifically, my versions of these games have this in their headers:
+	
+				Loom (en; de; en demo; en MAC):
+				_numGlobalObjects 1000
+				_numRooms 100
+				_numCostumes 200
+				_numScripts 200
+				_numSounds 80
+	
+				Indy3EGA (en PC; en Mac; en demo):
+				_numGlobalObjects 1000
+				_numRooms 99
+				_numCostumes 129
+				_numScripts 139
+				_numSounds 84
+	
+				MM (en; de):
+				_numGlobalObjects 780
+				_numRooms 61
+				_numCostumes 40
+				_numScripts 179
+				_numSounds 120
+	
+				Zak (de; en demo):
+				_numGlobalObjects 780
+				_numRooms 61
+				_numCostumes 40
+				_numScripts 155
+				_numSounds 120
+	
+				So, they all have a different number of scripts.
+				*/
+			} else if (buf[4] == '0' && buf[5] == 'R') {
+				// newer V3 game
+				// Candidates: indy3, indy3Towns, zakTowns, loomTowns
+				/*
+				Considering that we know about *all* TOWNS versions,
+				and know their MD5s, we could simply rely on this and
+				if we find something which has an unknown MD5, assume
+				that it is an (so far unknown) version of Indy3.
+	
+				We can combine this with a look at the resource headers:
+	
+				Indy3:
+				_numGlobalObjects 1000
+				_numRooms 99
+				_numCostumes 129
+				_numScripts 139
+				_numSounds 84
+	
+				Indy3Towns, ZakTowns, ZakLoom demo:
+				_numGlobalObjects 1000
+				_numRooms 99
+				_numCostumes 199
+				_numScripts 199
+				_numSounds 199
+	
+				Assuming that all the town variants look like the latter, we can
+				do the check like this:
+				  if (numScripts == 139)
+					assume Indy3
+				  else if (numScripts == 199)
+					assume towns game
+				  else
+					unknown, do not accept it
+				*/
+			} else {
+				// TODO: Unknown file header, deal with it. Maybe an unencrypted
+				// variant...
+				// Anyway, we don't know to deal with the file, so we
+				// just skip it.
+			}
+		} else if (file == "000.LFL") {
+			// Used in V4
+			// Candidates: monkeyEGA, pass, monkeyVGA, loomcd
+			/*
+			For all of them, we have:
+			_numGlobalObjects 1000
+			_numRooms 99
+			_numCostumes 199
+			_numScripts 199
+			_numSounds 199
+			
+			Any good ideas to distinguish those? Maybe by the presence / absence
+			of some files?
+			At least PASS and the monkeyEGA demo differ by 903.LFL missing...
+			And the count of DISK??.LEC files differs depending on what version
+			you have (4 or 8 floppy versions). 
+			loomcd of course shipped on only one "disc".
+			
+			pass: 000.LFL, 901.LFL, 902.LFL, 904.LFL, disk01.lec
+			monkeyEGA:  000.LFL, 901-904.LFL, DISK01-09.LEC
+			monkeyEGA DEMO: 000.LFL, 901.LFL, 902.LFL, 904.LFL, disk01.lec
+			monkeyVGA: 000.LFL, 901-904.LFL, DISK01-04.LEC
+			loomcd: 000.LFL, 901-904.LFL, DISK01.LEC
+			*/
+		} else {
+			// So at this point the gameid is determined, but not necessarily
+			// the variant!
+			
+			// TODO: Add code that does this, at least for the non-HE games.
+			// Note sure how realistic it is to correctly detect HE-game
+			// variants, would require me to look at a sufficiently large
+			// sample collection of HE games (assuming I had the time :).
+			
+		}
 	}
 }
 
@@ -1772,7 +1964,7 @@
 					md5, elem->gameid, gameid);
 		}
 	
-		// Compute the precise game settings using 'gameVariantsTable'.
+		// Compute the precise game settings using gameVariantsTable.
 		for (g = gameVariantsTable; g->gameid; ++g) {
 			if (g->gameid[0] == 0 || !scumm_stricmp(elem->gameid, g->gameid)) {
 				// The gameid either matches, or is empty (the latter indicates


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