diff options
| author | Max Horn | 2006-04-23 17:33:16 +0000 | 
|---|---|---|
| committer | Max Horn | 2006-04-23 17:33:16 +0000 | 
| commit | 0d67640a58b044ade0605319e091df9b2f666e4a (patch) | |
| tree | fcec3906ad2abb5ea28072663193a7cce9282e83 | |
| parent | d11f5724f96107a07d462be2410d93f55bd1fba2 (diff) | |
| download | scummvm-rg350-0d67640a58b044ade0605319e091df9b2f666e4a.tar.gz scummvm-rg350-0d67640a58b044ade0605319e091df9b2f666e4a.tar.bz2 scummvm-rg350-0d67640a58b044ade0605319e091df9b2f666e4a.zip  | |
Behold, the new SCUMM detector finally has arrived. Unified detection & engine instantiation, reduced code duplication, more powerful detection in case MD5 is not known / can't be computed, and many other nifty improvements.
svn-id: r22110
| -rw-r--r-- | README | 1 | ||||
| -rw-r--r-- | engines/scumm/cursor.cpp | 4 | ||||
| -rw-r--r-- | engines/scumm/debugger.cpp | 2 | ||||
| -rw-r--r-- | engines/scumm/he/intern_he.h | 16 | ||||
| -rw-r--r-- | engines/scumm/he/resource_he.cpp | 45 | ||||
| -rw-r--r-- | engines/scumm/he/resource_he.h | 2 | ||||
| -rw-r--r-- | engines/scumm/he/sound_he.cpp | 18 | ||||
| -rw-r--r-- | engines/scumm/intern.h | 18 | ||||
| -rw-r--r-- | engines/scumm/plugin.cpp | 1484 | ||||
| -rw-r--r-- | engines/scumm/plugin.h | 37 | ||||
| -rw-r--r-- | engines/scumm/resource.cpp | 111 | ||||
| -rw-r--r-- | engines/scumm/scumm-md5.h | 78 | ||||
| -rw-r--r-- | engines/scumm/scumm.cpp | 145 | ||||
| -rw-r--r-- | engines/scumm/scumm.h | 16 | ||||
| -rw-r--r-- | engines/scumm/sound.cpp | 30 | ||||
| -rw-r--r-- | tools/scumm-md5.txt | 78 | 
16 files changed, 691 insertions, 1394 deletions
@@ -1224,7 +1224,6 @@ An example config file looks as follows:  The following keywords are recognized: -        basename        string          path            string   The path to where a game's data files are          read_only       bool     If true, ScummVM will never try to overwrite                                   the configuration file. diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp index 6e86ad5644..fd0d2a90f4 100644 --- a/engines/scumm/cursor.cpp +++ b/engines/scumm/cursor.cpp @@ -93,8 +93,8 @@ static const byte default_v6_cursor[] = {  	0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0x00,0x0F,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,  }; -ScummEngine_v5::ScummEngine_v5(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) - : ScummEngine(syst, gs, md5sum, subst) { +ScummEngine_v5::ScummEngine_v5(OSystem *syst, const DetectorResult &dr) + : ScummEngine(syst, dr) {  	for (int i = 0; i < 4; i++) {  		memcpy(_cursorImages[i], default_cursor_images[i], 32); diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp index 0f37947467..c064405b15 100644 --- a/engines/scumm/debugger.cpp +++ b/engines/scumm/debugger.cpp @@ -83,7 +83,7 @@ ScummDebugger::ScummDebugger(ScummEngine *s)  	DVar_Register("scumm_vars", &_vm->_scummVars, DVAR_INTARRAY, _vm->_numVariables);  //	DVar_Register("scumm_gamename", &_vm->_targetName, DVAR_STRING, 0); -	DVar_Register("scumm_exename", &_vm->_baseName, DVAR_STRING, 0); +//	DVar_Register("scumm_exename", &_vm->_baseName, DVAR_STRING, 0);  	DVar_Register("scumm_gameid", &_vm->_game.id, DVAR_BYTE, 0);  	// Register commands diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index 5524b2a21e..dc906a654c 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -51,7 +51,7 @@ protected:  	Common::File _hFileTable[17];  public: -	ScummEngine_v60he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) : ScummEngine_v6(syst, gs, md5sum, subst) {} +	ScummEngine_v60he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v6(syst, dr) {}  	virtual void scummInit(); @@ -116,7 +116,7 @@ protected:  	bool _skipProcessActors;  public: -	ScummEngine_v70he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v70he(OSystem *syst, const DetectorResult &dr);  	~ScummEngine_v70he();  	Wiz *_wiz; @@ -181,7 +181,7 @@ protected:  class ScummEngine_v71he : public ScummEngine_v70he {  public: -	ScummEngine_v71he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v71he(OSystem *syst, const DetectorResult &dr);  protected:  	virtual void saveOrLoad(Serializer *s); @@ -236,7 +236,7 @@ protected:  	WizParameters _wizParams;  public: -	ScummEngine_v72he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v72he(OSystem *syst, const DetectorResult &dr);  	virtual void scummInit(); @@ -347,7 +347,7 @@ protected:  	int32 _heSndResId, _curSndId, _sndPtrOffs, _sndTmrOffs;  public: -	ScummEngine_v80he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v80he(OSystem *syst, const DetectorResult &dr);  protected:  	virtual void setupOpcodes(); @@ -420,7 +420,7 @@ protected:  	int32 _curSpriteGroupId;  public: -	ScummEngine_v90he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v90he(OSystem *syst, const DetectorResult &dr);  	~ScummEngine_v90he();  	virtual void scummInit(); @@ -517,7 +517,7 @@ protected:  class ScummEngine_v99he : public ScummEngine_v90he {  public: -	ScummEngine_v99he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) : ScummEngine_v90he(syst, gs, md5sum, subst) {} +	ScummEngine_v99he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v90he(syst, dr) {}  	virtual void scummInit(); @@ -548,7 +548,7 @@ protected:  	const OpcodeEntryV100he *_opcodesV100he;  public: -	ScummEngine_v100he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) : ScummEngine_v99he(syst, gs, md5sum, subst) {} +	ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {}  protected:  	virtual void setupOpcodes(); diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp index c4b81f8516..13d78c5517 100644 --- a/engines/scumm/he/resource_he.cpp +++ b/engines/scumm/he/resource_he.cpp @@ -42,7 +42,6 @@ namespace Scumm {  ResExtractor::ResExtractor(ScummEngine_v70he *scumm)  	: _vm(scumm) { -	_fileName[0] = 0;  	memset(_cursorCache, 0, sizeof(_cursorCache));  } @@ -159,21 +158,15 @@ int Win32ResExtractor::extractResource_(const char *resType, char *resName, byte  	fi.memory = NULL;  	fi.file = new Common::File; -	if (!_fileName[0]) { // We are running for the first time -		snprintf(_fileName, 256, "%s.he3", _vm->getBaseName()); - -		if (_vm->_substResFileName.almostGameID != 0) { -			char buf1[128]; -			_vm->generateSubstResFileName(_fileName, buf1, sizeof(buf1)); -			strcpy(_fileName, buf1); -		} +	if (_fileName.empty()) { // We are running for the first time +		_fileName = _vm->generateFilename(3);  	}  	/* get file size */  	fi.file->open(_fileName);  	if (!fi.file->isOpen()) { -		error("Cannot open file %s", _fileName); +		error("Cannot open file %s", _fileName.c_str());  	}  	fi.total_size = fi.file->size(); @@ -1288,38 +1281,36 @@ int MacResExtractor::extractResource(int id, byte **buf) {  	Common::File in;  	int size; -	if (!_fileName[0]) // We are running for the first time -		if (_vm->_substResFileName.almostGameID != 0) { -			char buf1[128]; +	if (_fileName.empty()) { // We are running for the first time +		_fileName = _vm->generateFilename(3); -			snprintf(buf1, 128, "%s.he3", _vm->getBaseName()); -			_vm->generateSubstResFileName(buf1, _fileName, sizeof(buf1)); +		// Some programs write it as .bin. Try that too +		if (!in.exists(_fileName)) { +			Common::String tmp(_fileName); +			 +			_fileName += ".bin"; -			// Some programs write it as .bin. Try that too  			if (!in.exists(_fileName)) { -				strcpy(buf1, _fileName); -				snprintf(_fileName, 128, "%s.bin", buf1); - +				// And finally check if we have dumped resource fork +				_fileName = tmp; +				_fileName += ".bin";  				if (!in.exists(_fileName)) { -					// And finally check if we have dumped resource fork -					snprintf(_fileName, 128, "%s.rsrc", buf1); -					if (!in.exists(_fileName)) { -						error("Cannot open file any of files '%s', '%s.bin', '%s.rsrc", -							  buf1, buf1, buf1); -					} +					error("Cannot open file any of files '%s', '%s.bin', '%s.rsrc", +						  tmp.c_str(), tmp.c_str(), tmp.c_str());  				}  			}  		} +	}  	in.open(_fileName);  	if (!in.isOpen()) { -		error("Cannot open file %s", _fileName); +		error("Cannot open file %s", _fileName.c_str());  	}  	// we haven't calculated it  	if (_resOffset == -1) {  		if (!init(in)) -			error("Resource fork is missing in file '%s'", _fileName); +			error("Resource fork is missing in file '%s'", _fileName.c_str());  		in.close();  		in.open(_fileName);  	} diff --git a/engines/scumm/he/resource_he.h b/engines/scumm/he/resource_he.h index 20ad0a1110..976511a974 100644 --- a/engines/scumm/he/resource_he.h +++ b/engines/scumm/he/resource_he.h @@ -150,7 +150,7 @@ public:  	ResExtractor::CachedCursor *getCachedCursorSlot();  	bool _arg_raw; -	char _fileName[256]; +	Common::String _fileName;  	CachedCursor _cursorCache[MAX_CACHED_CURSORS];  	typedef Common::MemoryReadStream MemoryReadStream; diff --git a/engines/scumm/he/sound_he.cpp b/engines/scumm/he/sound_he.cpp index 57a03ed129..86221aea88 100644 --- a/engines/scumm/he/sound_he.cpp +++ b/engines/scumm/he/sound_he.cpp @@ -161,15 +161,9 @@ void Sound::setOverrideFreq(int freq) {  void Sound::setupHEMusicFile() {  	int i, total_size; -	char buf[32], buf1[128];  	Common::File musicFile; +	Common::String buf(_vm->generateFilename(4)); -	sprintf(buf, "%s.he4", _vm->getBaseName()); - -	if (_vm->_substResFileName.almostGameID != 0) { -		_vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); -		strcpy(buf, buf1); -	}  	if (musicFile.open(buf) == true) {  		musicFile.seek(4, SEEK_SET);  		total_size = musicFile.readUint32BE(); @@ -360,17 +354,11 @@ void Sound::playHESound(int soundID, int heOffset, int heChannel, int heFlags) {  	if (soundID > _vm->_numSounds) {  		int music_offs; -		char buf[32], buf1[128];  		Common::File musicFile; +		Common::String buf(_vm->generateFilename(4)); -		sprintf(buf, "%s.he4", _vm->getBaseName()); - -		if (_vm->_substResFileName.almostGameID != 0) { -			_vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); -			strcpy(buf, buf1); -		}  		if (musicFile.open(buf) == false) { -			warning("playHESound: Can't open music file %s", buf); +			warning("playHESound: Can't open music file %s", buf.c_str());  			return;  		}  		if (!getHEMusicDetails(soundID, music_offs, size)) { diff --git a/engines/scumm/intern.h b/engines/scumm/intern.h index 530f3a36ed..58bca67183 100644 --- a/engines/scumm/intern.h +++ b/engines/scumm/intern.h @@ -50,7 +50,7 @@ protected:  	byte _cursorHotspots[2 * 4];  public: -	ScummEngine_v5(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v5(OSystem *syst, const DetectorResult &dr);  protected:  	virtual void setupOpcodes(); @@ -193,7 +193,7 @@ protected:   */  class ScummEngine_v4 : public ScummEngine_v5 {  public: -	ScummEngine_v4(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v4(OSystem *syst, const DetectorResult &dr);  	virtual void scummInit(); @@ -212,7 +212,7 @@ protected:   */  class ScummEngine_v3 : public ScummEngine_v4 {  public: -	ScummEngine_v3(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v3(OSystem *syst, const DetectorResult &dr);  protected:  	virtual void readRoomsOffsets(); @@ -224,7 +224,7 @@ protected:   */  class ScummEngine_v3old : public ScummEngine_v3 {  public: -	ScummEngine_v3old(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v3old(OSystem *syst, const DetectorResult &dr);  protected:  	virtual void readResTypeList(int id, const char *name); @@ -257,7 +257,7 @@ protected:  	int8 _mouseOverBoxV2;  public: -	ScummEngine_v2(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v2(OSystem *syst, const DetectorResult &dr);  	virtual void scummInit(); @@ -403,7 +403,7 @@ protected:  	int _currentMode;  public: -	ScummEngine_c64(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_c64(OSystem *syst, const DetectorResult &dr);  	virtual void scummInit(); @@ -555,7 +555,7 @@ protected:  public: -	ScummEngine_v6(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v6(OSystem *syst, const DetectorResult &dr);  	virtual void scummInit(); @@ -784,7 +784,7 @@ protected:  #ifndef DISABLE_SCUMM_7_8  class ScummEngine_v7 : public ScummEngine_v6 {  public: -	ScummEngine_v7(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v7(OSystem *syst, const DetectorResult &dr);  	~ScummEngine_v7();  	struct LangIndexNode { @@ -865,7 +865,7 @@ protected:  	ObjectNameId *_objectIDMap;  public: -	ScummEngine_v8(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine_v8(OSystem *syst, const DetectorResult &dr);  	~ScummEngine_v8();  protected: diff --git a/engines/scumm/plugin.cpp b/engines/scumm/plugin.cpp index 69fcf553ba..c92b908846 100644 --- a/engines/scumm/plugin.cpp +++ b/engines/scumm/plugin.cpp @@ -186,25 +186,34 @@ static const ObsoleteGameID obsoleteGameIDsTable[] = {  	{NULL, NULL, UNK}  }; -// The following table contains information about variants of our various games. -// We index into it with help of md5table (from scumm-md5.h), to find the correct -// GameSettings for a given game variant. +// The following table contains information about variants of our various +// games. We index into it with help of md5table (from scumm-md5.h), to find +// the correct GameSettings for a given game variant.  //  // The first listed variant is assumed to be the 'default' variant -- i.e. the  // variant that gets used when no explicit variant code has been specified.  // -// Note: Only set 'platform' to a value different from UNK if that game variant -// really *only* exists for that given platform. In all other cases, the correct -// platform will be determined via the MD5 table or derived from the filename. +// Note #1: Only set 'platform' to a value different from UNK if that game +// variant really *only* exists for that given platform. In all other cases, +// the correct platform will be determined via the MD5 table or derived from +// the filename. +// +// Note #2: Make sure that all variants for a given gameid are in sequence with +// no gaps. Some code may rely on this and stop searching the table early as +// soon as the gameid changes. +// +// Note #3: Use 0 (zero) for the variant field *if and only if* the game has +// only a single unique variant. This is used to help the detector quickly +// decide whether it has to worry about distinguishing multiple variants or not.  static const GameSettings gameVariantsTable[] = { -	// The C64 version of MM is detected via the platform field and hence has no seperate entry in this list -	{"maniac", "V2",  GID_MANIAC, 2, 0, MDT_PCSPK, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, UNK}, -	{"maniac", "NES", GID_MANIAC, 1, 0, MDT_NONE,  GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, Common::kPlatformNES}, -	{"maniac", "V1",  GID_MANIAC, 1, 0, MDT_PCSPK, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, Common::kPlatformPC}, +	{"maniac", "C64",  GID_MANIAC, 0, 0, MDT_PCSPK, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, Common::kPlatformC64}, +	{"maniac", "V1",   GID_MANIAC, 1, 0, MDT_PCSPK, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, Common::kPlatformPC}, +	{"maniac", "NES",  GID_MANIAC, 1, 0, MDT_NONE,  GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, Common::kPlatformNES}, +	{"maniac", "V2",   GID_MANIAC, 2, 0, MDT_PCSPK, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, UNK}, +	{"maniac", "Demo", GID_MANIAC, 2, 0, MDT_PCSPK, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE | GF_DEMO, Common::kPlatformPC}, -	// The C64 version of Zak is detected via the platform field and hence has no seperate entry in this list +	{"zak", "V1",       GID_ZAK, 1, 0, MDT_PCSPK, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, UNK},  	{"zak", "V2",       GID_ZAK, 2, 0, MDT_PCSPK, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, UNK}, -	{"zak", "V1",       GID_ZAK, 1, 0, MDT_PCSPK, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, Common::kPlatformPC},  	{"zak", "FM-TOWNS", GID_ZAK, 3, 0, MDT_TOWNS, GF_SMALL_HEADER | GF_NO_SCALING | GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns},  	{"indy3", "EGA",      GID_INDY3, 3, 0, MDT_PCSPK | MDT_ADLIB, GF_SMALL_HEADER | GF_NO_SCALING | GF_16COLOR | GF_USE_KEY | GF_OLD_BUNDLE, UNK}, @@ -259,58 +268,58 @@ static const GameSettings gameVariantsTable[] = {  	{"fbear", "HE 70", GID_FBEAR, 6, 70, MDT_NONE,             GF_USE_KEY | GF_NEW_COSTUMES, Common::kPlatformWindows},  #ifndef DISABLE_HE -	{"activity", "", GID_HEGAME, 6, 70, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"activity", 0, GID_HEGAME, 6, 70, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	// Humongous Entertainment Scumm Version 7.1  	// The first version to use 640x480 resolution  	// There are also 7.1 versions of freddemo, airdemo and farmdemo -	{"catalog", "", GID_HEGAME, 6, 71, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"freddi", "", GID_HEGAME, 6, 71, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"catalog", 0, GID_HEGAME, 6, 71, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"freddi", 0, GID_HEGAME, 6, 71, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	// Humongous Entertainment Scumm Version 7.2 -	{"airport", "", GID_HEGAME, 6, 72, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"puttzoo", "", GID_HEGAME, 6, 72, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"airport", 0, GID_HEGAME, 6, 72, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"puttzoo", 0, GID_HEGAME, 6, 72, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	// Changed o_getResourceSize to cover all resource types -	{"farm", "", GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"jungle", "", GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"farm", 0, GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"jungle", 0, GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	// Humongous Entertainment Scumm Version 8.0 ?  Scummsrc.80 -	{"freddi2", "", GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"pajama", "", GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"putttime", "", GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"freddi2", 0, GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"pajama", 0, GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"putttime", 0, GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"balloon", "", GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"dog", "", GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"maze", "", GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"socks", "", GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"balloon", 0, GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"dog", 0, GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"maze", 0, GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"socks", 0, GID_HEGAME, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	{"water", "",      GID_WATER, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	{"water", "HE 80", GID_WATER, 6, 80, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	{"water", "HE 99", GID_WATER, 6, 99, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	// Humongous Entertainment Scumm Version 9.0 ?  Scummsys.90 -	{"baseball", "", GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"thinkerk", "", GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"thinker1", "", GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"freddi3", "", GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"spyfox", "", GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"baseball", 0, GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"thinkerk", 0, GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"thinker1", 0, GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"freddi3", 0, GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"spyfox", 0, GID_HEGAME, 6, 90, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	// Humongous Entertainment Scumm Version 9.5 ?  Scummsys.95 -	{"pajama2", "", GID_HEGAME, 6, 95, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"chase", "", GID_HEGAME, 6, 95, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"pajama2", 0, GID_HEGAME, 6, 95, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"chase", 0, GID_HEGAME, 6, 95, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	// Humongous Entertainment Scumm Version 9.8 ?  Scummsys.98  	// these and later games can easily be identified by the .(a) file instead of a .he1  	// and INIB chunk in the .he0 -	{"lost", "", GID_HEGAME, 6, 98, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"lost", 0, GID_HEGAME, 6, 98, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	{"puttrace", "HE 98",   GID_PUTTRACE, 6, 98, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	{"puttrace", "HE 98.5", GID_PUTTRACE, 6, 98, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES | GF_HE_985, UNK},  	{"puttrace", "HE 99",   GID_PUTTRACE, 6, 99, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"bluesabctime", "", GID_HEGAME, 6, 98, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, -	{"soccer", "", GID_SOCCER, 6, 98, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"bluesabctime", 0, GID_HEGAME, 6, 98, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK}, +	{"soccer", 0, GID_SOCCER, 6, 98, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES, UNK},  	// Global scripts increased to 2048  	{"freddi4", "",       GID_HEGAME, 6, 98, MDT_NONE, GF_USE_KEY | GF_NEW_COSTUMES | GF_HE_985, UNK}, @@ -369,256 +378,6 @@ static const GameSettings gameVariantsTable[] = {  	{NULL, NULL, 0, 0, MDT_NONE, 0, 0, UNK}  }; -static const SubstResFileNames substResFileNameTable[] = { -	// The first few entries for 00.LFL/01.LFL files are here for two reasons: -	// 1) For the detector to detect these games -	// 2) Because the ScummEngine constructor distinguishes between extracted -	//    and non-extracted variants of these C64/NES games by the presence -	//    or absence of a SubstResFileNames record. -	// Use 1 will go away with the new detector code. Use 2 needs some more -	// attention, but most likely should be solved by passing the name of the -	// "detect file" to the contructor. -	{ "00.LFL", "Maniac Mansion (E).prg", kGenAsIs }, -	{ "00.LFL", "Maniac Mansion (F).prg", kGenAsIs }, -	{ "00.LFL", "Maniac Mansion (SW).prg", kGenAsIs }, -	{ "00.LFL", "Maniac Mansion (U).prg", kGenAsIs }, -	{ "00.LFL", "Maniac Mansion (G).prg", kGenAsIs }, -	{ "00.LFL", "maniac1.d64", kGenAsIs }, // Do not -	{ "01.LFL", "maniac2.d64", kGenAsIs }, // swap -	{ "00.LFL", "zak1.d64", kGenAsIs },    // these -	{ "01.LFL", "zak2.d64", kGenAsIs },    // lines - -	{ "atlantis", "Fate of Atlantis Data", kGenAsIs }, -	{ "atlantis", "fate", kGenPC }, -	{ "atlantis", "playfate", kGenPC }, -	{ "atlantis", "indy4", kGenPC }, -	{ "atlantis", "indydemo", kGenPC }, -	{ "tentacle", "Day of the Tentacle Data", kGenAsIs }, -	{ "tentacle", "dottdemo", kGenPC }, -	{ "tentacle", "Day of the Tentacle Demo Data", kGenAsIs }, -	{ "monkey", "monkey1", kGenPC }, -	{ "monkey", "monkeyk", kGenPC }, // FM-TOWNS Jap -	{ "monkey", "game", kGenPC }, // SegaCD -	{ "monkey2", "mi2demo", kGenPC }, -	{ "samnmax", "Sam & Max Data", kGenAsIs }, -	{ "samnmax", "Sam & Max Demo Data", kGenAsIs }, -	{ "samnmax", "ramnmax", kGenPC }, // Used in some releases of Russian Sam'n'Max -	{ "samnmax", "samdemo", kGenPC }, -	{ "samnmax", "snmdemo", kGenPC }, -	{ "samnmax", "snmidemo", kGenPC }, -	{ "samnmax", "sdemo", kGenPC }, -#ifndef DISABLE_SCUMM_7_8 -	{ "dig", "The Dig Data", kGenAsIs }, -	{ "dig", "The Dig Demo Data", kGenAsIs }, -	{ "ft", "Full Throttle Data", kGenAsIs }, -	{ "ft", "Full Throttle Demo Data", kGenAsIs }, -	{ "ft", "Vollgas Data", kGenAsIs }, -	{ "ft", "Vollgas Demo Data", kGenAsIs }, -	{ "ft", "ftdemo", kGenPC }, -#endif -	{ "fbear", "fbdemo", kGenPC }, -	{ "fbear", "Fatty Bear Demo", kGenMacNoParens }, -	{ "fbear", "Fatty Bear", kGenMacNoParens }, -	{ "puttmoon", "moondemo", kGenPC }, -	{ "puttmoon", "Putt-Putt Moon Demo", kGenMacNoParens }, -	{ "puttmoon", "Putt-Putt Moon", kGenMacNoParens }, -	{ "puttputt", "puttdemo", kGenPC }, -	{ "puttputt", "Putt-Putt's Demo", kGenMacNoParens }, -	{ "puttputt", "Putt-Putt Parade", kGenMacNoParens }, -#ifndef DISABLE_HE -	{ "airport", "airdemo", kGenPC }, -	{ "airport", "Airport Demo", kGenMac }, -	{ "airport", "The AirPort", kGenMac }, -	{ "balloon", "Balloon-O-Rama", kGenMac }, -	{ "baseball", "BaseBall", kGenMac }, -	{ "baseball2001", "bb2demo", kGenPC }, -	{ "baseball2001", "Baseball 2001 Demo", kGenMac }, -	{ "baseball2001", "Baseball 2001", kGenMac }, -	{ "baseball2001", "baseball 2001", kGenPC }, -	{ "Baseball2003", "Baseball 2003", kGenMac }, -	{ "basketball", "Basketball", kGenMac }, -	{ "bluesabctime", "BluesABCTimeDemo", kGenPC }, -	{ "bluesabctime", "BluesABCTimeDemo", kGenMac }, -	{ "catalog", "catalog2", kGenPC }, -	{ "chase", "Cheese Chase", kGenMac }, -	{ "dog", "Dog on a Stick", kGenMac }, -	{ "farm", "farmdemo", kGenPC }, -	{ "farm", "Farm Demo", kGenMac }, -	{ "football", "FootBall", kGenMac }, -	{ "football", "FootBall Demo", kGenMac }, -	{ "football", "FootBall2002", kGenPC }, -	{ "football", "footdemo", kGenPC }, -	{ "freddi", "freddemo", kGenPC }, -	{ "freddi", "Freddi Demo", kGenMac }, -	{ "freddi", "Freddi Fish", kGenMac }, -	{ "freddi", "FreddiD", kGenPC }, -	{ "freddi2", "ff2-demo", kGenPC }, -	{ "freddi2", "FFHSDemo", kGenMac }, -	{ "freddi2", "FFHSDemo", kGenPC }, -	{ "freddi2", "Freddi Fish 2 Demo", kGenMac }, -	{ "freddi2", "Freddi Fish 2", kGenMac }, -	{ "freddi2", "FreddiCHSH", kGenPC }, -	{ "freddi2", "Fritzi Fisch 2", kGenMac }, -	{ "freddi3", "F3-mdemo", kGenMac }, -	{ "freddi3", "F3-Mdemo", kGenMac }, -	{ "freddi3", "f3-mdemo", kGenPC }, -	{ "freddi3", "FF3-DEMO", kGenPC }, -	{ "freddi3", "Freddi Fish 3", kGenMac }, -	{ "freddi3", "FreddiFGT", kGenPC }, -	{ "freddi3", "FreddiFGT", kGenMac }, -	{ "freddi3", "FreddiSCS", kGenPC }, -	{ "freddi3", "Fritzi3demo", kGenMac }, -	{ "freddi3", "Fritzi3demo", kGenPC }, -	{ "freddi3", "MM3-DEMO", kGenPC }, -	{ "freddi3", "MM3-Demo", kGenMac }, // FR Mac demo -	{ "freddi4", "f4-demo", kGenPC }, -	{ "freddi4", "ff4demo", kGenPC }, -	{ "freddi4", "Ff4demo", kGenMac }, -	{ "freddi4", "Freddi 4", kGenMac }, -	{ "freddi4", "Freddi 4 Demo", kGenMac }, -	{ "freddi4", "FreddiGS", kGenPC }, -	{ "freddi4", "FreddiGS", kGenMac }, -	{ "freddi4", "FreddiHRBG", kGenPC }, -	{ "freddicove", "FreddiCCC", kGenPC }, -	{ "freddicove", "FreddiCove", kGenMac }, -	{ "freddicove", "FreddiDZZ", kGenPC }, -	{ "freddicove", "ff5demo", kGenPC }, -	{ "freddicove", "FFCoveDemo", kGenPC }, -	{ "freddicove", "FreddiCoveDemo", kGenMac }, -	{ "freddicove", "FF5Demo", kGenMac }, // NL Mac demo -	{ "FreddisFunShop", "Freddi's FunShop", kGenMac }, -	{ "jungle", "The Jungle", kGenMac }, -	{ "lost", "Lost and Found", kGenMac }, -	{ "lost", "smaller", kGenPC }, -	{ "maze", "Maze Madness", kGenMac}, -	{ "mustard", "Mustard", kGenMac }, -	{ "pajama", "Pyjama Pit", kGenMac }, -	{ "pajama", "Pajama Sam", kGenMac }, -	{ "pajama", "PajamaNHD", kGenPC }, -	{ "pajama", "PJS-DEMO", kGenPC }, -	{ "pajama", "PYJAMA", kGenPC }, -	{ "pajama", "SAMDEMO", kGenPC }, -	{ "pajama", "SAMDEMO", kGenMac }, // FR Mac demo -	{ "pajama2", "Pajama Sam 2", kGenMac }, -	{ "pajama2", "PajamaTAL", kGenPC }, -	{ "pajama2", "PyjamaDBMN", kGenPC }, -	{ "pajama2", "PyjamaDBMN", kGenMac }, -	{ "pajama2", "Pyjama Pit 2 Demo", kGenMac }, -	{ "pajama2", "PJP2DEMO", kGenPC }, -	{ "pajama2", "PJ2Demo", kGenMac }, -	{ "pajama2", "pj2demo", kGenPC }, -	{ "pajama2", "Pjs2demo", kGenPC }, -	{ "pajama2", "PJ2 Demo", kGenMac }, // NL Mac demo -	{ "pajama3", "GPJ3Demo", kGenPC }, -	{ "pajama3", "Pajama Sam 3", kGenMac }, -	{ "pajama3", "Pajama Sam 3-Demo", kGenMac }, -	{ "pajama3", "pj3-demo", kGenPC }, -	{ "pajama3", "pj3demo", kGenPC }, -	{ "pajama3", "PJ3Demo", kGenMac }, -	{ "pajama3", "Pajama Sam Demo", kGenMac }, -	{ "pajama3", "PjSamDemo", kGenMac }, -	{ "pajama3", "PjSamDemo", kGenPC }, -	{ "pajama3", "PyjamaSKS", kGenPC }, -	{ "pajama3", "PyjamaSKS", kGenMac }, -	{ "pajama3", "UKPajamaEAT", kGenPC }, // Russian -	{ "pjgames", "PJGames", kGenMac }, -	{ "puttcircus", "circdemo", kGenPC }, -	{ "puttcircus", "Putt Circus Demo", kGenMac }, -	{ "puttcircus", "Putt Circus", kGenMac }, -	{ "puttrace", "500demo", kGenPC }, -	{ "puttrace", "racedemo", kGenPC }, -	{ "puttrace", "RaceDemo", kGenMac }, -	{ "puttrace", "Rennen", kGenPC }, -	{ "puttrace", "Putt500 demo", kGenMac }, // NL Mac demo -	{ "puttrace", "Putt Race", kGenMac }, -	{ "puttrace", "ToffRennen", kGenPC }, -	{ "puttrace", "ToffRennen", kGenMac }, -	{ "puttrace", "UKPuttRace", kGenPC }, // Russian -	{ "PuttsFunShop", "Putt's FunShop", kGenMac }, -	{ "putttime", "PuttPuttTTT", kGenPC }, -	{ "putttime", "PuttPuttTTT", kGenMac }, -	{ "putttime", "PuttTijd", kGenPC }, -	{ "putttime", "Putt Time", kGenMac }, -	{ "putttime", "PuttTTT", kGenMac }, -	{ "putttime", "PuttTTT", kGenPC }, -	{ "putttime", "TIJDDEMO", kGenPC }, -	{ "putttime", "timedemo", kGenPC }, -	{ "putttime", "TimeDemo", kGenMac }, -	{ "putttime", "TEMPDEMO", kGenPC }, -	{ "putttime", "Tempdemo", kGenMac }, // FR Mac demo -	{ "putttime", "toffzeit", kGenPC }, // German Toeff-Toeff: Reist durch die Zeit -	{ "putttime", "toffzeit", kGenMac }, // German Toeff-Toeff: Reist durch die Zeit -	{ "putttime", "ZeitDemo", kGenMac }, -	{ "putttime", "ZEITDEMO", kGenPC }, -	{ "puttzoo", "Puttzoo Demo", kGenMac }, -	{ "puttzoo", "PuttZoo", kGenMac },  - -	{ "puttzoo", "T\xC3\xB6""ff-T\xC3\xB6""ff\xE2\x84\xA2 Zoo Demo", kGenMac },	// German Toeff-Toeff, UTF-8 encoding -	{ "puttzoo", "T\xF6""ff-T""\xF6""ff\x99 Zoo Demo", kGenMac },	// German Toeff-Toeff, Windows encoding - -	{ "puttzoo", "zoodemo", kGenPC }, -	{ "puttzoo", "Zoo Demo", kGenMac }, -	{ "SamsFunShop", "Sam's FunShop", kGenMac }, -	{ "soccer", "Soccer", kGenMac }, -	{ "Soccer2004", "Soccer 2004", kGenMac }, -	{ "socks", "SockWorks", kGenMac }, -	{ "spyfox", "Fuchsdem", kGenMac }, -	{ "spyfox", "FUCHSDEM", kGenPC}, -	{ "spyfox", "FoxDemo", kGenMac }, -	{ "spyfox", "foxdemo", kGenPC}, -	{ "spyfox", "JAMESDEM", kGenPC }, -	{ "spyfox", "Spydemo", kGenMac}, -	{ "spyfox", "Spydemo", kGenPC}, -	{ "spyfox", "SPYFox", kGenMac }, -	{ "spyfox", "SPYFoxDC", kGenPC }, -	{ "spyfox", "SPYFoxDC", kGenMac }, -	{ "spyfox", "SpyFoxDMK", kGenPC }, -	{ "spyfox", "SpyFoxDMK", kGenMac }, -	{ "spyfox", "Spy Fox Demo", kGenMac }, // NL Mac demo -	{ "spyfox", "JR-Demo", kGenMac }, // FR Mac demo -	{ "spyfox2", "sf2-demo", kGenPC }, -	{ "spyfox2", "sf2demo", kGenPC }, -	{ "spyfox2", "Sf2demo", kGenMac }, -	{ "spyfox2", "Spy Fox 2 - Demo", kGenMac }, -	{ "spyfox2", "Spy Fox 2", kGenMac }, -	{ "spyfox2", "SpyFoxOR", kGenPC }, -	{ "spyfox2", "SpyFoxOR", kGenMac }, -	{ "spyfox2", "spyfoxsr", kGenPC }, -	{ "spyozon", "sf3-demo", kGenPC }, -	{ "spyozon", "Spy Ozone Demo", kGenMac }, -	{ "spyozon", "SPYFoxOZU", kGenPC }, -	{ "spyozon", "SpyOzon", kGenMac }, -	{ "thinker1", "1grademo", kGenPC }, -	{ "thinker1", "Thinker1", kGenMac }, -	{ "thinkerk", "kinddemo", kGenPC }, -	{ "thinkerk", "KindDemo", kGenMac }, -	{ "thinkerk", "ThinkerK", kGenMac }, -	{ "water", "Water Worries", kGenMac }, -#endif -	{ NULL, NULL, kGenAsIs } -}; - - -#if 0 - -enum FilenameGenMethod { -	kGenDiskNum, -	kGenRoomNum, -	kGenHEMac, -	kGenHEMacNoParens, -	kGenHEPC, -	kGenUnchanged -}; - -struct GameFilenamePattern { -	const char *gameid; -	const char *pattern; -	FilenameGenMethod genMethod; -	Common::Language language; -	Common::Platform platform; -	const char *variant; -}; -  using Common::UNK_LANG;  // The following describes how Fingolfin thinks this table might be used one day; @@ -635,68 +394,68 @@ using Common::UNK_LANG;  // Note: Setting variant to 0 means "don't care", while setting it to ""  // (i.e. an empty string) means "use the default variant".  static const GameFilenamePattern gameFilenamesTable[] = { -	{ "maniac", "%.2d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "maniac", "%.2d.MAN", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "maniac", "maniac1.d64", kGenUnchanged, UNK_LANG, Common::kPlatformC64, 0 },   // ... and maniac2.d64 +	{ "maniac", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "maniac", "%02d.MAN", kGenRoomNum, UNK_LANG, UNK, "Demo" }, +	{ "maniac", "maniac1.d64", kGenUnchanged, UNK_LANG, Common::kPlatformC64, "C64" },   // ... and maniac2.d64  	{ "maniac", "Maniac Mansion (E).prg", kGenUnchanged, Common::EN_GRB, Common::kPlatformNES, "NES" },  	{ "maniac", "Maniac Mansion (F).prg", kGenUnchanged, Common::FR_FRA, Common::kPlatformNES, "NES" },  	{ "maniac", "Maniac Mansion (SW).prg", kGenUnchanged, Common::SE_SWE, Common::kPlatformNES, "NES" },  	{ "maniac", "Maniac Mansion (U).prg", kGenUnchanged, Common::EN_USA, Common::kPlatformNES, "NES" },  	{ "maniac", "Maniac Mansion (G).prg", kGenUnchanged, Common::DE_DEU, Common::kPlatformNES, "NES" }, -	{ "zak", "%.2d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "zak", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },  	{ "zak", "zak1.d64", kGenUnchanged, UNK_LANG, Common::kPlatformC64, 0 },         // ... and zak2.d64 -	{ "indy3", "%.2d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "indy3", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "loom", "%.2d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "loom", "%.3d.LFL", kGenRoomNum, UNK_LANG, UNK, "VGA" },	// Loom CD +	{ "loom", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "loom", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, "VGA" },	// Loom CD -	{ "pass", "%.3d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "pass", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "monkey", "%.3d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },		// EGA & VGA versions -	{ "monkey", "monkey.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "monkey", "monkey1.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "monkey", "monkeyk.%.3d", kGenRoomNum, Common::JA_JPN, Common::kPlatformFMTowns, "FM-TOWNS" }, // FM-TOWNS Jap -	{ "monkey", "game.%.3d", kGenRoomNum, UNK_LANG, Common::kPlatformSegaCD, "SEGA" }, // SegaCD +	{ "monkey", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 },		// EGA & VGA versions +	{ "monkey", "monkey.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "monkey", "monkey1.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "monkey", "monkeyk.%03d", kGenDiskNum, Common::JA_JPN, Common::kPlatformFMTowns, "FM-TOWNS" }, // FM-TOWNS Jap +	{ "monkey", "game.%03d", kGenDiskNum, UNK_LANG, Common::kPlatformSegaCD, "SEGA" }, // SegaCD -	{ "monkey2", "monkey2.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "monkey2", "mi2demo.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "monkey2", "monkey2.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "monkey2", "mi2demo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, -	{ "atlantis", "atlantis.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "atlantis", "fate.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "atlantis", "playfate.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "atlantis", "indy4.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "atlantis", "indydemo.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "atlantis", "atlantis.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "atlantis", "fate.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "atlantis", "playfate.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "atlantis", "indy4.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "atlantis", "indydemo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },  	{ "atlantis", "Fate of Atlantis Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, -	{ "tentacle", "tentacle.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "tentacle", "dottdemo.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "tentacle", "tentacle.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "tentacle", "dottdemo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 },  	{ "tentacle", "Day of the Tentacle Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 },  	{ "tentacle", "Day of the Tentacle Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, -	{ "samnmax", "samnmax.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "samnmax", "samnmax.sm%d", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "samnmax", "samnmax.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "samnmax", "samnmax.sm%d", kGenDiskNum, UNK_LANG, UNK, 0 },  	{ "samnmax", "Sam & Max Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 },  	{ "samnmax", "Sam & Max Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, -	{ "samnmax", "ramnmax.%.3d", kGenRoomNum, Common::RU_RUS, UNK, 0 }, // Used in some releases of Russian Sam'n'Max -	{ "samnmax", "samdemo.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "samnmax", "snmdemo.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "samnmax", "snmidemo.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, -	{ "samnmax", "sdemo.%.3d", kGenRoomNum, UNK_LANG, UNK, 0 }, +	{ "samnmax", "ramnmax.%03d", kGenDiskNum, Common::RU_RUS, UNK, 0 }, // Used in some releases of Russian Sam'n'Max +	{ "samnmax", "samdemo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "samnmax", "snmdemo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "samnmax", "snmidemo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "samnmax", "sdemo.sm%d", kGenDiskNum, UNK_LANG, UNK, 0 },  #ifndef DISABLE_SCUMM_7_8  	{ "dig", "dig.la%d", kGenDiskNum, UNK_LANG, UNK, 0 },  	{ "dig", "The Dig Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, -	{ "dig", "The Dig Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, +	{ "dig", "The Dig Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, "Demo" },  	{ "ft", "ft.la%d", kGenDiskNum, UNK_LANG, UNK, 0 }, -	{ "ft", "ft.%.3d", kGenDiskNum, UNK_LANG, UNK, 0 },    // Used by PC version of Full Throttle demo -	{ "ft", "ftdemo.la%d", kGenDiskNum, UNK_LANG, UNK, 0 }, +	{ "ft", "ft.%03d", kGenDiskNum, UNK_LANG, UNK, "Demo" },    // Used by PC version of Full Throttle demo +	{ "ft", "ftdemo.la%d", kGenDiskNum, UNK_LANG, UNK, "Demo" },  	{ "ft", "Full Throttle Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, -	{ "ft", "Full Throttle Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, +	{ "ft", "Full Throttle Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, "Demo" },  	{ "ft", "Vollgas Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, -	{ "ft", "Vollgas Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, +	{ "ft", "Vollgas Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, "Demo" },  	{ "comi", "comi.la%d", kGenDiskNum, UNK_LANG, UNK, 0 },  #endif @@ -968,8 +727,6 @@ static const GameFilenamePattern gameFilenamesTable[] = {  	{ NULL, NULL, kGenUnchanged, UNK_LANG, UNK, 0 }  }; -#endif -  #pragma mark -  #pragma mark --- Miscellaneous --- @@ -1002,29 +759,26 @@ const MD5Table *findInMD5Table(const char *md5) {  	return (const MD5Table *)bsearch(md5, md5table, arraySize, sizeof(MD5Table), compareMD5Table);  } -#if 0  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];  	if (_game.version == 4) {  		if (room == 0 || room >= 900) { -			snprintf(buf, sizeof(buf), "%.3d.lfl", room); +			snprintf(buf, sizeof(buf), "%03d.lfl", room);  		} else { -			snprintf(buf, sizeof(buf), "disk%.2d.lec", diskNumber); +			snprintf(buf, sizeof(buf), "disk%02d.lec", diskNumber);  		}  	} else {  		char id = 0; -		switch (_substEntry.genMethod) { +		switch (_filenamePattern.genMethod) {  		case kGenDiskNum: -			snprintf(buf, sizeof(buf), _substEntry.pattern, diskNumber); +			snprintf(buf, sizeof(buf), _filenamePattern.pattern, diskNumber);  			break;  		case kGenRoomNum: -			snprintf(buf, sizeof(buf), _substEntry.pattern, room); +			snprintf(buf, sizeof(buf), _filenamePattern.pattern, room);  			break;  		case kGenHEMac: @@ -1039,15 +793,15 @@ Common::String ScummEngine::generateFilename(const int room) const {  				switch(disk) {  				case 2:  					id = 'b'; -					snprintf(buf, sizeof(buf), "%s.(b)", _substEntry.pattern); +					snprintf(buf, sizeof(buf), "%s.(b)", _filenamePattern.pattern);  					break;  				case 1:  					id = 'a'; -					snprintf(buf, sizeof(buf), "%s.(a)", _substEntry.pattern); +					snprintf(buf, sizeof(buf), "%s.(a)", _filenamePattern.pattern);  					break;  				default:  					id = '0'; -					snprintf(buf, sizeof(buf), "%s.he0", _substEntry.pattern); +					snprintf(buf, sizeof(buf), "%s.he0", _filenamePattern.pattern);  				}  			} else if (_game.heversion >= 70) {  				id = (room == 0) ? '0' : '1'; @@ -1055,24 +809,28 @@ Common::String ScummEngine::generateFilename(const int room) const {  				id = diskNumber + '0';  			} -			if (_substEntry.genMethod == kGenHEPC) { +			if (_filenamePattern.genMethod == kGenHEPC) {  				// For HE >= 98, we already called snprintf above.  				if (_game.heversion < 98) -					snprintf(buf, sizeof(buf), "%s.he%c", _substEntry.pattern, id); +					snprintf(buf, sizeof(buf), "%s.he%c", _filenamePattern.pattern, id);  			} else {  				if (id == '3') { // special case for cursors  					// For mac they're stored in game binary -					strncpy(buf, _substEntry.pattern, sizeof(buf)); +					strncpy(buf, _filenamePattern.pattern, sizeof(buf));  				} else { -					if (_substEntry.genMethod == kGenHEMac) -						snprintf(buf, sizeof(buf), "%s (%c)", _substEntry.pattern, id); +					if (_filenamePattern.genMethod == kGenHEMac) +						snprintf(buf, sizeof(buf), "%s (%c)", _filenamePattern.pattern, id);  					else -						snprintf(buf, sizeof(buf), "%s %c", _substEntry.pattern, id); +						snprintf(buf, sizeof(buf), "%s %c", _filenamePattern.pattern, id);  				}  			}  			break; +		case kGenUnchanged: +			strncpy(buf, _filenamePattern.pattern, sizeof(buf)); +			break; +  		default:  			error("generateFilename: Unsupported genMethod");  		} @@ -1080,9 +838,7 @@ Common::String ScummEngine::generateFilename(const int room) const {  	return buf;  } -#endif -#if 0  Common::String generateFilenameForDetection(const GameFilenamePattern &gfp) {  	char buf[128]; @@ -1104,6 +860,10 @@ Common::String generateFilenameForDetection(const GameFilenamePattern &gfp) {  		snprintf(buf, sizeof(buf), "%s 0", gfp.pattern);  		break; +	case kGenUnchanged: +		strncpy(buf, gfp.pattern, sizeof(buf)); +		break; +  	default:  		error("generateFilenameForDetection: Unsupported genMethod");  	} @@ -1114,19 +874,15 @@ Common::String generateFilenameForDetection(const GameFilenamePattern &gfp) {  struct DetectorDesc {  	Common::String path;  	Common::String md5; +	uint8 md5sum[16];  	const MD5Table *md5Entry;	// Entry of the md5 table corresponding to this file, if any.  }; - -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; +void detectGames(const FSList &fslist, Common::List<DetectorResult> &results, const char *gameid_XXX) { +	typedef Common::HashMap<Common::String, DetectorDesc, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> DescMap;  	DescMap fileMD5Map;  	const GameSettings *g; +	DetectorResult dr;  	for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {  		if (!file->isDirectory()) { @@ -1150,8 +906,32 @@ void detectGames(const char *gameid_XXX, const FSList &fslist, Common::List<Dete  		Common::String file(generateFilenameForDetection(*gfp));  		if (!fileMD5Map.contains(file))  			continue; + +		// Reset the DetectorResult variable +		dr.fp.pattern = gfp->pattern; +		dr.fp.genMethod = gfp->genMethod; +		dr.game.gameid = 0; +		dr.language = gfp->language; +		dr.md5.clear(); +		memset(dr.md5sum, 0, 16); +		dr.extra = 0; -		// OK, the file is present. Compute the MD5, if it hasn't been done yet. +		//  ____            _     _  +		// |  _ \ __ _ _ __| |_  / | +		// | |_) / _` | '__| __| | | +		// |  __/ (_| | |  | |_  | | +		// |_|   \__,_|_|   \__| |_| +		// +		// PART 1: Trying to find an exact match using MD5. +		// +		// +		// Background: We found a valid detection file. Check if its MD5 +		// checksum occurs in our MD5 table. If it does, try to use that +		// to find an exact match. +		// +		// We only do that if the MD5 hadn't already been computed (since +		// we may look at some detection files multiple times). +		//  		DetectorDesc &d = fileMD5Map[file];  		if (d.md5.empty()) {  			uint8 md5sum[16]; @@ -1162,37 +942,33 @@ void detectGames(const char *gameid_XXX, const FSList &fslist, Common::List<Dete  				}  				d.md5 = md5str; +				memcpy(d.md5sum, md5sum, 16);  				d.md5Entry = findInMD5Table(md5str); +				dr.md5 = d.md5; +				memcpy(dr.md5sum, d.md5sum, 16); +  				if (d.md5Entry) {  					// 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; +					dr.language = d.md5Entry->language; +					dr.extra = d.md5Entry->extra;  					// 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. -			 +							// a generic entry, currently used for some generic HE settings.  							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)", +								dr.game.gameid = d.md5Entry->gameid; + +								// Sanity check +								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; -								} +								dr.game.platform = d.md5Entry->platform; +								  								results.push_back(dr);  								break;  							} @@ -1208,255 +984,242 @@ void detectGames(const char *gameid_XXX, const FSList &fslist, Common::List<Dete  		// If an exact match for this file has already been found, don't bother   		// looking at it anymore. -		if (d.md5Entry != 0) +		if (d.md5Entry)  			continue; -		// At this point, the MD5 sum has been computed but is not known. We -		// still do our best to identify the game & variant correctly. -		 -		// 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. + + +		//  ____            _     ____   +		// |  _ \ __ _ _ __| |_  |___ \ * +		// | |_) / _` | '__| __|   __) | +		// |  __/ (_| | |  | |_   / __/  +		// |_|   \__,_|_|   \__| |_____| +		// +		// PART 2: Fuzzy matching for files with unknown MD5. +		// -		// 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 ? +		// We loop over the game variants matching the gameid associated to +		// the gfp record. We then try to decide for each whether it could be +		// appropriate or not. +		dr.md5 = d.md5; +		memcpy(dr.md5sum, d.md5sum, 16); +		for (g = gameVariantsTable; g->gameid; ++g) { +			// Skip over entries with a different gameid. +			if (g->gameid[0] == 0 || scumm_stricmp(gfp->gameid, g->gameid)) +				continue; -		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. +			dr.game = *g; +			dr.extra = g->variant; // FIXME: We (ab)use 'variant' for the 'extra' description for now. +			if (gfp->platform != Common::kPlatformUnknown) +				dr.game.platform = gfp->platform; + + +			// If a variant has been specified, use that! +			if (gfp->variant) { +				if (!scumm_stricmp(gfp->variant, g->variant)) { +					// perfect match found +					results.push_back(dr); +					break; +				} +				continue; +			} -			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 +			// Next possibility: There exists only a single variant of this +			// gameid anyway (we know this is the case if g->variant is 0). +			// Then of course we have no further work to do. +			if (g->variant == 0) { +				results.push_back(dr); +				break; +			} +			 +			// At this point, we know that the gameid matches, but no variant +			// was specified, yet there are multiple ones. So we try our best +			// to distinguish between the variants. +			// To do this, we take a close look at the detection file and +			// try to filter out some cases. + +			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; +			} +			 +			if (file == "00.LFL") { +				// Used in V1, V2, V3 games. +				if (g->version > 3) +					continue; + +				// Read a few bytes to narrow down the game.				 +				byte buf[6]; +				tmp.read(buf, 6); +				 +				if (buf[0] == 0xbc && buf[1] == 0xb9) { +					// The NES version of MM +					if (g->id == GID_MANIAC && g->platform == Common::kPlatformNES) { +						// perfect match +						results.push_back(dr); +						break; +					} +				} else if (buf[0] == 0xCE && buf[1] == 0xF5) { +					// Looks like V1. +					// Candidates: maniac classic, zak classic +					 +					if (g->version != 1) +						continue; + +					// TODO: Maybe we can use the filesize to distinguish these two? +					// English V1 Zak: 1896 bytes +					// English V1 MM:  1972 bytes -				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 +					// 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 + +					if (g->version != 2 && g->version != 3  || !(g->features & GF_OLD_BUNDLE)) +						continue; + +					/* +					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. +					*/ +					 +					/* Alternate approach: Distinguish by the presence/absence +					   of certain files. In the following, '+' means the file +					   present, '-' means the file is absent. + +					   maniac: -58.LFL, -85.LFL, -86.LFL +					   zak:    +58.LFL, -85.LFL, -86.LFL +					   indy3:  +58.LFL, +85.LFL, +86.LFL +					   loom:   +58.LFL, -85.LFL, +86.LFL +					*/ +					   +				} else if (buf[4] == '0' && buf[5] == 'R') { +					// newer V3 game +					// Candidates: indy3, indy3Towns, zakTowns, loomTowns + +					if (g->version != 3 || (g->features & GF_OLD_BUNDLE)) +						continue; + +					/* +					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 + +				if (g->version != 4) +					continue; +  				/* -				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: +				For all of them, we have:  				_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 +				 +				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 { -				// 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. +				// So at this point the gameid is determined, but not necessarily +				// the variant! +				 +				// TODO: Add code that handles 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 :). +				 +				 +				// TODO: For Mac versions in container file, we can sometimes +				// distinguish the demo from the regular version by looking +				// at the content of the container file and then looking for +				// the *.000 file in there.  			} -		} 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 :). -			 -		} -	} -} - -#endif - - -#pragma mark - -#pragma mark --- Filename substitution --- -#pragma mark - - - -static void applySubstResFileName(const SubstResFileNames &subst, char *buf, int bufsize, const char *ext, char num) { -	switch (subst.genMethod) { -	case kGenMac: -	case kGenMacNoParens: -		if (num == '3') { // special case for cursors -			// For mac they're stored in game binary -			strncpy(buf, subst.expandedName, bufsize); -		} else { -			if (subst.genMethod == kGenMac) -				snprintf(buf, bufsize, "%s (%c)", subst.expandedName, num); -			else -				snprintf(buf, bufsize, "%s %c", subst.expandedName, num); -		} -		break; - -	case kGenPC: -		if (ext) -			snprintf(buf, bufsize, "%s%s", subst.expandedName, ext); -		else -			strncpy(buf, subst.expandedName, bufsize); -		break; - -	case kGenAsIs: -		strncpy(buf, subst.expandedName, bufsize); -		break; - -	default: -		*buf = 0; -		break; -	} -} - -bool applySubstResFileName(const SubstResFileNames &subst, const char *filename, char *buf, int bufsize) { -	if (subst.almostGameID == 0) -		return false; - -	size_t len = strlen(filename); -	assert(len > 0); - -	char num = filename[len - 1]; - -	// In some cases we have .(a) and .(b) extensions -	if (num == ')') -		num = filename[len - 2]; - -	const char *ext = strrchr(filename, '.'); -	if (ext) -		len = ext - filename; - -	if (!scumm_strnicmp(filename, subst.almostGameID, len)) { -		applySubstResFileName(subst, buf, bufsize, ext, num); -		return true; -	} - -	return false; -} - -int findSubstResFileName(SubstResFileNames &subst, const char *filename, int index) { -	if (index < 0) -		return -1; - -	size_t len = strlen(filename); -	assert(len > 0); - -	char num = filename[len - 1]; - -	// In some cases we have .(a) and .(b) extensions -	if (num == ')') -		num = filename[len - 2]; - -	const char *ext = strrchr(filename, '.'); -	if (ext) -		len = ext - filename; - -	int i; -	for (i = index; substResFileNameTable[i].almostGameID; i++) { -		if (!scumm_strnicmp(filename, substResFileNameTable[i].almostGameID, len)) { -			subst = substResFileNameTable[i]; -			return i+1; +			// Add the file to the candidate list +			results.push_back(dr);  		}  	} -	subst = substResFileNameTable[i]; -	return -1;  }  } // End of namespace Scumm @@ -1504,308 +1267,18 @@ GameDescriptor Engine_SCUMM_findGameID(const char *gameid) {  } -enum { -	kDetectNameMethodsCount = 8 -}; - -static bool generateDetectName(const GameSettings &g, int method, char *detectName) { -	detectName[0] = '\0'; - -	switch (method) { -	case 0: -		if (g.version <= 3) -			strcpy(detectName, "00.LFL"); -		break; -	case 1: -		// FIXME: The following would normally only allow for V4 games. But  -		// for loom, there is both a v3 and a v4 version, but due to the way -		// the detector works at this time, we'll only ever see the v3 variant -		// here. -		if (g.version == 3 || g.version == 4) -			strcpy(detectName, "000.LFL"); -		break; -	case 2: -		if (g.version < 4 || g.version > 7) -			return false; -		strcpy(detectName, g.gameid); -		strcat(detectName, ".000"); -		break; -	case 3: -		if (g.version >= 7) { -			strcpy(detectName, g.gameid); -			strcat(detectName, ".la0"); -		} -		break; -	case 4: -		if (g.heversion != 0) { -			strcpy(detectName, g.gameid); -			strcat(detectName, ".he0"); -		} -		break; -	case 5: -		// FIXME: Fingolfin asks: For which games is this case used?  -		// Please document this. Also: Why was this case missing in -		// Engine_SCUMM_create ? -		strcpy(detectName, g.gameid); -		break; -	case 6: -		if (g.id == GID_SAMNMAX) { -			strcpy(detectName, g.gameid); -			strcat(detectName, ".sm0"); -		} -		break; -	case 7: -		if (g.id == GID_MANIAC) -			strcpy(detectName, "00.MAN"); -		break; -	default: -		return false; -	} - -	if (!detectName[0]) -		return false; - -	return true; -} -  DetectedGameList Engine_SCUMM_detectGames(const FSList &fslist) {  	DetectedGameList detectedGames; -	const GameSettings *g; -	char detectName[128]; -	char tempName[128]; -	SubstResFileNames subst = { 0, 0, kGenAsIs }; - -	typedef Common::HashMap<Common::String, bool> StringSet; -	StringSet fileSet; +	Common::List<DetectorResult> results; -	const char *lastGameid = ""; - -	for (g = gameVariantsTable; g->gameid; ++g) { -		// HACK: For now we only consider the first ("default") variant for -		// gameids that have multiple variants. In a future version of the -		// detector code, this may change. -		if (0 == strcmp(lastGameid, g->gameid) || *(g->gameid) == 0) -			continue; -		lastGameid = g->gameid; +	detectGames(fslist, results, 0); -		// Determine the 'detectname' for this game, that is, the name of a -		// file that *must* be presented if the directory contains the data -		// for this game. For example, FOA requires atlantis.000 - -		// TODO: we need to add cache here -		for (int method = 0; method < kDetectNameMethodsCount; method++) { -			if (!generateDetectName(*g, method, detectName)) -				continue; - -			strcpy(tempName, detectName); - -			int substLastIndex = 0; - -			do { -				// Iterate over all files in the given directory -				for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { -					if (!file->isDirectory()) { -						const char *name = file->displayName().c_str(); - -						if (0 == scumm_stricmp(detectName, name)) { -							byte buf[6]; - -							if (g->version < 4) { -								// We take a look at the file now, to narrow -								// down the list of possible candidates a bit further. -								// E.g. it's trivial to distinguish V1 from V3 games. -								Common::File tmp; -								if (!tmp.open(file->path().c_str())) -									break; -								tmp.read(buf, 6); - -								if (buf[0] == 0xCE && buf[1] == 0xF5) { -									// Looks like V1. However, we currently do not distinguish between V1 and V2 -									// in the scumm_settings list. -									if (g->version != 1 && g->version != 2) -										break; - -									// Candidates: maniac clasic, zak classic - -									// TODO: Maybe we can use the filesize to distinguish these two? -									// English V1 Zak: 1896 bytes -									// English V1 MM:  1972 bytes -									// It would be interesting if those sizes are the same for other language -									// variants of these games, or for demos? -								} else if (buf[0] == 0xFF && buf[1] == 0xFE) { -									// GF_OLD_BUNDLE: could be V2 or old V3. -									if (!(g->features & GF_OLD_BUNDLE) || (g->version != 2 && g->version != 3)) -										break; -									// 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 -									if (g->version != 3) -										break; -									// 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 if (buf[4] == 'R' && buf[5] == 'N') { -									// V4 game -									if (g->version != 4) -										break; -									// Candidates: monkeyEGA, pass, monkeyVGA, loomcd -								/* -								For all of them, we have: -								_numGlobalObjects 1000 -								_numRooms 99 -								_numCostumes 199 -								_numScripts 199 -								_numSounds 199 -								*/ -								} else if (buf[0] == 0xa0 && buf[1] == 0x07 && buf[2] == 0xa5 && -										   buf[3] == 0xbc) { -									// MM NES .prg -									if (g->id != GID_MANIAC) -										break; -								} else if (buf[0] == 0xbc && buf[1] == 0xb9) { -									// MM NES 00.LFL -									if (g->id != GID_MANIAC) -										break; -								} else if (buf[0] == 0x31 && buf[1] == 0x0a) { -									// C64 MM & Zak disk1 -									if (g->version != 2) -										break; -								} else if (buf[0] == 0xcd && buf[1] == 0xfe) { -									// C64 MM & Zak 00.LFL -									if (g->version != 2) -										break; -								} else { -									// This is not a V1-V4 game -									break; -								} -							} - -							// Match found, add to list of candidates, then abort inner loop. -							DetectedGame dg(g->gameid, findDescriptionFromGameID(g->gameid)); -							if (substLastIndex > 0 && // HE Mac versions. -								(subst.genMethod == kGenMac || -								 subst.genMethod == kGenMacNoParens)) { -								dg.platform = Common::kPlatformMacintosh; -								fileSet[file->path()] = true; -							} else if (substLastIndex == 0 && g->id == GID_MANIAC && -									   (buf[0] == 0xbc || buf[0] == 0xa0)) { -								dg.platform = Common::kPlatformNES; -							} else if ((g->id == GID_MANIAC || g->id == GID_ZAK) && -									   ((buf[0] == 0x31 && buf[1] == 0x0a) || -										(buf[0] == 0xcd && buf[1] == 0xfe))) { -								dg.platform = Common::kPlatformC64; -							} else { -								fileSet[file->path()] = false; -							} -							 -							dg.updateDesc();	// Append the platform, if set, to the description. - -							detectedGames.push_back(dg); -							break; -						} -					} -				} - -				substLastIndex = findSubstResFileName(subst, tempName, substLastIndex); -				applySubstResFileName(subst, tempName, detectName, sizeof(detectName)); -			} while (subst.almostGameID != 0); -		} -	} - -	// Now, we check the MD5 sums of the 'candidate' files. If we have an exact match, -	// only return that. -	bool exactMatch = false; -	for (StringSet::const_iterator iter = fileSet.begin(); iter != fileSet.end(); ++iter) { -		uint8 md5sum[16]; -		const char *name = iter->_key.c_str(); - -		if (Common::md5_file(name, md5sum, kMD5FileSizeLimit)) { -			char md5str[32+1]; -			for (int j = 0; j < 16; j++) { -				sprintf(md5str + j*2, "%02x", (int)md5sum[j]); -			} - -			const MD5Table *elem = findInMD5Table(md5str); -			if (elem) { -				if (!exactMatch) -					detectedGames.clear();	// Clear all the non-exact candidates - -				DetectedGame dg(elem->gameid, findDescriptionFromGameID(elem->gameid), elem->language); -				if (iter->_value == true) // This was HE Mac game -					dg.platform = Common::kPlatformMacintosh; -				else -					dg.platform = elem->platform; -				dg.updateDesc(elem->extra);	// Append extra information to the description. -				 -				// Insert the 'enhanced' game data into the candidate list -				detectedGames.push_back(dg); - -				exactMatch = true; -			} -		} +	 +	for (Common::List<DetectorResult>::iterator x = results.begin(); x != results.end(); ++x) { +		DetectedGame dg(x->game.gameid, findDescriptionFromGameID(x->game.gameid), +				x->language, x->game.platform); +		dg.updateDesc(x->extra);	// Append additional information, if set, to the description. +		detectedGames.push_back(dg);  	}  	return detectedGames; @@ -1838,236 +1311,131 @@ Engine *Engine_SCUMM_create(OSystem *syst) {  		}  	} -	// Lookup the game ID in our database. If this lookup fails, then -	// the game ID is unknown, and we have to abort. -	const GameSettings *g = gameVariantsTable; -	while (g->gameid) { -		if (!scumm_stricmp(gameid, g->gameid)) -			break; -		g++; -	} -	if (!g->gameid) { -		return 0; -	} - -	// We now want to calculate the MD5 of the games detection file, so that we -	// can store it in savegames etc.. -	gameid = g->gameid; -	char detectName[256], tempName[256]; -	uint8 md5sum[16]; -	SubstResFileNames subst = { 0, 0, kGenAsIs }; -	bool found = false; - -	GameSettings game = *g; - -	// To this end, we first have to figure out what the proper detection file -	// is (00.LFL, 000.LFL, ...). So we iterate over all possible names, -	// and once we find a matching file, we assume that's it. -	for (int method = 0; method < kDetectNameMethodsCount && !found; method++) { -		if (!generateDetectName(game, method, detectName)) -			continue; -		strcpy(tempName, detectName); -		int substLastIndex = 0; -		do { -			// FIXME: Repeatedly calling File::exists like this is a bad idea. -			// Instead, use the fs.h code to get a list of all files in that  -			// directory and simply check whether that filename is contained  -			// in it.  -			if (Common::File::exists(detectName)) { -				found = true; -				break; -			} +	FilesystemNode dir; +	if (ConfMan.hasKey("path") ) +		dir = FilesystemNode(ConfMan.get("path")); +	FSList fslist = dir.listDir(FilesystemNode::kListFilesOnly); +	Common::List<DetectorResult> results; -			substLastIndex = findSubstResFileName(subst, tempName, substLastIndex); -			applySubstResFileName(subst, tempName, detectName, sizeof(detectName)); -		} while (subst.almostGameID != 0); - -		if (found) { -			if (subst.almostGameID != 0) -				debug(5, "Generated filename substitute: %s -> %s", tempName, detectName); -			break; -		} -	} +	// Invoke the detector, but fixed to the specified gameid. +	detectGames(fslist, results, gameid);  	// Unable to locate game data -	if (!found) { +	if (results.empty())  		return 0; -	} -	// Force game to have Mac platform if needed -	if (subst.almostGameID) { -		if (subst.genMethod == kGenMac || -			subst.genMethod == kGenMacNoParens) -			game.platform = Common::kPlatformMacintosh; -	} - -	// Determine a MD5 checksum which then is used to narrow down the choice -	// of game variants.  -	const char *md5 = NULL; -	char md5buf[33]; +	DetectorResult res(*(results.begin())); -	// First, check if the MD5 was overridden with a config file entry. -	if (ConfMan.hasKey("target_md5")) { -		assert(ConfMan.get("target_md5").size() == 32); -		md5 = ConfMan.get("target_md5").c_str(); -	} else { -		// Next, check if the MD5 was overridden via a target_md5.txt file. -		Common::File target_md5F; -		target_md5F.open("target_md5.txt"); -	 -		if (target_md5F.isOpen()) { -			bool valid = true; -	 -			target_md5F.readLine(md5buf, 33); -			for (int j = 0; j < 32 && valid; ++j) -				if (!((md5buf[j] >= '0' && md5buf[j] <= '9') ||  -					  (md5buf[j] >= 'A' && md5buf[j] <= 'F') || -					  (md5buf[j] >= 'a' && md5buf[j] <= 'f'))) -					valid = false; -	 -			if (valid) -				md5 = md5buf; -		} -	} -	 -	// Finally, if no MD5 value has been determined so far, compute it from the -	// detect file. -	if (!md5) { -		// Compute the MD5 of the file, and (if we succeeded) store a hex version -		// of it in gameMD5 (useful to print it to the user in messages). -		if (Common::md5_file(detectName, md5sum, kMD5FileSizeLimit)) { -			for (int j = 0; j < 16; j++) { -				sprintf(md5buf + j*2, "%02x", (int)md5sum[j]); -			} +/* +	// No unique match found. If a platform override is present, try to +	// narrow down the list a bit more. +	if (results.size() > 1 && ConfMan.hasKey("platform")) { +		Common::Platform platform = Common::parsePlatform(ConfMan.get("platform")); +		for (Common::List<DetectorResult>::iterator x = results.begin(); x != results.end(); ) { +			if (x->game.platform != platform) +				x = results.erase(x);  +			else +				++x;  		} -		md5 = md5buf;  	} +*/ - - -	// Now look up the MD5 in our lookup table (md5table). -	const MD5Table *elem = findInMD5Table(md5); - - -	// If a match was found, we use the information obtained from the md5table -	// to walk through the gameVariantsTable array and find a match there. -	// Otherwise, we print a warning about the MD5 being unknwon. -	if (elem) { -		// The MD5 is known and was found in our md5table. -		debug(5, "Using MD5 '%s'", md5); -		 -		// Sanity check: Make sure the gameids match! -		if (scumm_stricmp(elem->gameid, gameid)) { -			error("MD5 %s implies gameid '%s', but gameid '%s' was used", -					md5, elem->gameid, gameid); -		} -	 -		// 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 -				// a generic entry, used currently for generic HE specifies. - -				if (g->variant == 0 || !scumm_stricmp(elem->variant, g->variant)) { -					// Perfect match found, use it and stop the loop -					game = *g; -					game.gameid = gameid; -					if (elem->platform != Common::kPlatformUnknown) { -						if (game.platform != Common::kPlatformUnknown && game.platform != elem->platform) -							warning("Platform values differ for MD5 '%s': %d vs %d (please report to Fingolfin)", -										md5, game.platform, elem->platform); -						game.platform = elem->platform; -					} -					break; -				} -			} -		} -	} else { -		printf("Unknown MD5 (%s)! Please report the details (language, platform, etc.) of this game to the ScummVM team\n", md5); +	// Still no unique match found -> we just use the first one +	if (results.size() > 1) { +		warning("Engine_SCUMM_create: No unique game candidate found, using first one");  	} +	 + +	// TODO: Do we really still need / want the platform override ?  	// Check for a user override of the platform. We allow the user to override  	// the platform, to make it possible to add games which are not yet in   	// our MD5 database but require a specific platform setting.  	if (ConfMan.hasKey("platform")) -		game.platform = Common::parsePlatform(ConfMan.get("platform")); +		res.game.platform = Common::parsePlatform(ConfMan.get("platform")); + + +	// Language override +	if (ConfMan.hasKey("language")) +		res.language = Common::parseLanguage(ConfMan.get("language"));  	// V3 FM-TOWNS games *always* should use the corresponding music driver,  	// anything else makes no sense for them. -	if (game.platform == Common::kPlatformFMTowns && game.version == 3) { -		game.midi = MDT_TOWNS; +	// TODO: Maybe allow the null driver, too? +	if (res.game.platform == Common::kPlatformFMTowns && res.game.version == 3) { +		res.game.midi = MDT_TOWNS;  	}  	// Finally, we have massaged the GameDescriptor to our satisfaction, and can  	// instantiate the appropriate game engine. Hooray! -	switch (game.version) { +	switch (res.game.version) { +	case 0: +		engine = new ScummEngine_c64(syst, res); +		break;  	case 1:  	case 2: -		if (game.id == GID_MANIAC && game.platform == Common::kPlatformC64) -			engine = new ScummEngine_c64(syst, game, md5sum, subst); -		else -			engine = new ScummEngine_v2(syst, game, md5sum, subst); +		engine = new ScummEngine_v2(syst, res);  		break;  	case 3: -		if (game.features & GF_OLD_BUNDLE) -			engine = new ScummEngine_v3old(syst, game, md5sum, subst); +		if (res.game.features & GF_OLD_BUNDLE) +			engine = new ScummEngine_v3old(syst, res);  		else -			engine = new ScummEngine_v3(syst, game, md5sum, subst); +			engine = new ScummEngine_v3(syst, res);  		break;  	case 4: -		engine = new ScummEngine_v4(syst, game, md5sum, subst); +		engine = new ScummEngine_v4(syst, res);  		break;  	case 5: -		engine = new ScummEngine_v5(syst, game, md5sum, subst); +		engine = new ScummEngine_v5(syst, res);  		break;  	case 6: -		switch (game.heversion) { +		switch (res.game.heversion) {  #ifndef DISABLE_HE  		case 100: -			engine = new ScummEngine_v100he(syst, game, md5sum, subst); +			engine = new ScummEngine_v100he(syst, res);  			break;  		case 99: -			engine = new ScummEngine_v99he(syst, game, md5sum, subst); +			engine = new ScummEngine_v99he(syst, res);  			break;  		case 98:  		case 95:  		case 90: -			engine = new ScummEngine_v90he(syst, game, md5sum, subst); +			engine = new ScummEngine_v90he(syst, res);  			break;  		case 80: -			engine = new ScummEngine_v80he(syst, game, md5sum, subst); +			engine = new ScummEngine_v80he(syst, res);  			break;  		case 73:  		case 72: -			engine = new ScummEngine_v72he(syst, game, md5sum, subst); +			engine = new ScummEngine_v72he(syst, res);  			break;  		case 71: -			engine = new ScummEngine_v71he(syst, game, md5sum, subst); +			engine = new ScummEngine_v71he(syst, res);  			break;  		case 70: -			engine = new ScummEngine_v70he(syst, game, md5sum, subst); +			engine = new ScummEngine_v70he(syst, res);  			break;  #endif  #ifndef PALMOS_68K  		case 61: -			engine = new ScummEngine_v60he(syst, game, md5sum, subst); +			engine = new ScummEngine_v60he(syst, res);  			break;  #endif  		default: -			engine = new ScummEngine_v6(syst, game, md5sum, subst); +			engine = new ScummEngine_v6(syst, res);  		}  		break;  #ifndef DISABLE_SCUMM_7_8  	case 7: -		engine = new ScummEngine_v7(syst, game, md5sum, subst); +		engine = new ScummEngine_v7(syst, res);  		break;  	case 8: -		engine = new ScummEngine_v8(syst, game, md5sum, subst); +		engine = new ScummEngine_v8(syst, res);  		break;  #endif  	default: diff --git a/engines/scumm/plugin.h b/engines/scumm/plugin.h index a302cde6c6..e0d8f32afe 100644 --- a/engines/scumm/plugin.h +++ b/engines/scumm/plugin.h @@ -42,22 +42,37 @@ struct GameSettings {  }; -enum GenMethods { -	kGenMac, -	kGenMacNoParens, -	kGenPC, -	kGenAsIs +enum FilenameGenMethod { +	kGenDiskNum, +	kGenRoomNum, +	kGenHEMac, +	kGenHEMacNoParens, +	kGenHEPC, +	kGenUnchanged  }; -struct SubstResFileNames { -	const char *almostGameID; -	const char *expandedName; -	GenMethods genMethod; +struct FilenamePattern { +	const char *pattern; +	FilenameGenMethod genMethod;  }; +struct GameFilenamePattern { +	const char *gameid; +	const char *pattern; +	FilenameGenMethod genMethod; +	Common::Language language; +	Common::Platform platform; +	const char *variant; +}; -bool applySubstResFileName(const SubstResFileNames &subst, const char *filename, char *buf, int bufsize); -int findSubstResFileName(SubstResFileNames &subst, const char *filename, int index); +struct DetectorResult { +	FilenamePattern fp; +	GameSettings game; +	Common::Language language; +	Common::String md5; +	uint8 md5sum[16]; +	const char *extra; +};  } // End of namespace Scumm diff --git a/engines/scumm/resource.cpp b/engines/scumm/resource.cpp index b5fb6fb8e7..6ee4820f07 100644 --- a/engines/scumm/resource.cpp +++ b/engines/scumm/resource.cpp @@ -65,8 +65,6 @@ static bool checkTryMedia(BaseScummFile *handle);  /* Open a room */  void ScummEngine::openRoom(const int room) {  	bool result; -	char buf[128]; -	char buf2[128] = "";  	byte encByte = 0;  	debugC(DEBUG_GENERAL, "openRoom(%d)", room); @@ -90,57 +88,19 @@ void ScummEngine::openRoom(const int room) {  	const int diskNumber = room ? res.roomno[rtRoom][room] : 0;  	const int room_offs = room ? res.roomoffs[rtRoom][room] : 0; +	// FIXME: Since room_offs is const, clearly the following loop either +	// is never entered, or loops forever (if it wasn't for the return/error +	// statements in it, that is). -> This should be cleaned up!  	while (room_offs != -1) {  		if (room_offs != 0 && room != 0 && _game.heversion < 98) {  			_fileOffset = res.roomoffs[rtRoom][room];  			return;  		} - -		/* Either xxx.lfl or monkey.xxx file name */ -		if (_game.version <= 3) { -			sprintf(buf, "%.2d.lfl", room); -			// Maniac Mansion demo has .man instead of .lfl -			if (_game.id == GID_MANIAC) -				sprintf(buf2, "%.2d.man", room); -		} else if (_game.version == 4) { -			if (room == 0 || room >= 900) { -				sprintf(buf, "%.3d.lfl", room); -			} else { -				sprintf(buf, "disk%.2d.lec", diskNumber); -			} -		} else if (_game.heversion >= 98) { -			int disk = 0; -			if (_heV7DiskOffsets) -				disk = _heV7DiskOffsets[room]; - -			switch(disk) { -			case 2: -				sprintf(buf, "%s.(b)", _baseName.c_str()); -				break; -			case 1: -				sprintf(buf, "%s.(a)", _baseName.c_str()); -				break; -			default: -				sprintf(buf, "%s.he0", _baseName.c_str()); -			} -		} else if (_game.heversion >= 70) { -			sprintf(buf, "%s.he%d", _baseName.c_str(), room == 0 ? 0 : 1); -		} else if (_game.heversion >= 60) { -			sprintf(buf, "%s.he%d", _baseName.c_str(), diskNumber); - -		} else if (_game.version >= 7) { -			sprintf(buf, "%s.la%d", _baseName.c_str(), diskNumber); - -			// Used by PC version of Full Throttle demo -			if (_game.id == GID_FT && (_game.features & GF_DEMO) && _game.platform == Common::kPlatformPC) -				sprintf(buf2, "%s.%.3d", _baseName.c_str(), diskNumber); -		} else { -			sprintf(buf, "%s.%.3d", _baseName.c_str(), diskNumber); -			if (_game.id == GID_SAMNMAX) -				sprintf(buf2, "%s.sm%d", _baseName.c_str(), diskNumber); -		} +		Common::String filename(generateFilename(room)); + +		// Determine the encryption, if any.  		if (_game.features & GF_USE_KEY) {  			if (_game.version <= 3)  				encByte = 0xFF; @@ -154,26 +114,8 @@ void ScummEngine::openRoom(const int room) {  		if (room > 0 && (_game.version == 8))  			VAR(VAR_CURRENTDISK) = diskNumber; -		// If we have substitute -		if (_substResFileName.almostGameID != 0 && !(_game.platform == Common::kPlatformNES || _game.platform == Common::kPlatformC64)) { -			char tmpBuf[128]; -			generateSubstResFileName(buf, tmpBuf, sizeof(tmpBuf)); -			strcpy(buf, tmpBuf); -			if (buf2[0]) { -				generateSubstResFileName(buf2, tmpBuf, sizeof(tmpBuf)); -				strcpy(buf2, tmpBuf); -			} -		} - -		// Try to open the file with name 'buf'. If that fails, try buf2 (if -		// specified). -		result = openResourceFile(buf, encByte); -		if (!result && buf2[0]) { -			result = openResourceFile(buf2, encByte); -			// We have .man files so set demo mode -			if (_game.id == GID_MANIAC) -				_game.features |= GF_DEMO; -		} +		// Try to open the file +		result = openResourceFile(filename.c_str(), encByte);  		if (result) {  			if (room == 0) @@ -185,14 +127,15 @@ void ScummEngine::openRoom(const int room) {  			if (_fileOffset != 8)  				return; -			error("Room %d not in %s", room, buf); +			error("Room %d not in %s", room, filename.c_str());  			return;  		} -		askForDisk(buf, diskNumber); +		askForDisk(filename.c_str(), diskNumber);  	}  	do { -		sprintf(buf, "%.3d.lfl", room); +		char buf[16]; +		snprintf(buf, sizeof(buf), "%.3d.lfl", room);  		encByte = 0;  		if (openResourceFile(buf, encByte))  			break; @@ -246,39 +189,11 @@ bool ScummEngine::openFile(BaseScummFile &file, const char *filename, bool resou  	bool result = false;  	if (!_containerFile.empty()) { -		char name[128]; -  		file.close();  		file.open(_containerFile);  		assert(file.isOpen()); -		strncpy(name, filename, 128); - -		// Some Mac demos (i.e. DOTT) have bundled file names different -		// from target name. dottdemo.000 vs tentacle.000. So we should -		// substitute those names too -		if (resourceFile == true) { -			if (_substResFileNameBundle.almostGameID == 0) { -				int substLastIndex = 0; - -				do { -					if (file.openSubFile(name)) -						break; - -					substLastIndex = findSubstResFileName(_substResFileNameBundle, filename, substLastIndex); -					applySubstResFileName(_substResFileNameBundle, filename, name, sizeof(name)); -				} while (_substResFileNameBundle.almostGameID != 0); - -				if (_substResFileNameBundle.almostGameID != 0) { -					debug(5, "Generated substitute in Mac bundle: [%s -> %s]", filename, _substResFileNameBundle.almostGameID); -				} -			} - -			if (_substResFileNameBundle.almostGameID != 0) -				applySubstResFileName(_substResFileNameBundle, filename, name, sizeof(name)); -		} - -		result = file.openSubFile(name); +		result = file.openSubFile(filename);  	}  	if (!result) { diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index d605bb51c5..cef4f2fd72 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@  /* -  This file was generated by the md5table tool on Sun Apr 23 13:24:24 2006 +  This file was generated by the md5table tool on Sun Apr 23 13:52:04 2006    DO NOT EDIT MANUALLY!   */ @@ -36,7 +36,7 @@ static const MD5Table md5table[] = {  	{ "0b3222aaa7efcf283eb621e0cefd26cc", "puttputt", "HE 60", "", Common::RU_RUS, Common::kPlatformPC },  	{ "0c45eb4baff0c12c3d9dfa889c8070ab", "pajama3", "", "Demo", Common::DE_DEU, Common::kPlatformUnknown },  	{ "0cccfa5223099a60e76cfcca57a1a141", "freddi3", "", "", Common::NL_NLD, Common::kPlatformWindows }, -	{ "0d1b69471605201ef2fa9cec1f5f02d2", "maniac", "", "V2", Common::ES_ESP, Common::kPlatformPC }, +	{ "0d1b69471605201ef2fa9cec1f5f02d2", "maniac", "V2", "V2", Common::ES_ESP, Common::kPlatformPC },  	{ "0e4c5d54a0ad4b26132e78b5ea76642a", "samnmax", "", "Demo", Common::EN_ANY, Common::kPlatformPC },  	{ "0e9b01430e31d9fcd94071d433bbc6bf", "loom", "No Adlib", "EGA", Common::FR_FRA, Common::kPlatformAtariST },  	{ "0f5935bd5e88ba6f09e558d64459746d", "thinker1", "", "Demo", Common::EN_ANY, Common::kPlatformWindows }, @@ -44,14 +44,14 @@ static const MD5Table md5table[] = {  	{ "0f9c7a76657f0840b8f7ccb5bffeb9f4", "indy3", "No Adlib", "EGA", Common::FR_FRA, Common::kPlatformAtariST },  	{ "0fb73eddfcf584c02ba097984df131ba", "samnmax", "", "CD", Common::DE_DEU, Common::kPlatformUnknown },  	{ "1005456bfe351c1b679e1ff2dc2849e9", "puttzoo", "", "", Common::UNK_LANG, Common::kPlatformWindows }, -	{ "114acdc2659a273c220f86ee9edb24c1", "maniac", "", "V2", Common::FR_FRA, Common::kPlatformPC }, +	{ "114acdc2659a273c220f86ee9edb24c1", "maniac", "V2", "V2", Common::FR_FRA, Common::kPlatformPC },  	{ "11ddf1fde76e3156eb3a38da213f484e", "monkey2", "", "", Common::IT_ITA, Common::kPlatformAmiga },  	{ "11e6e244078ff09b0f3832e35420e0a7", "catalog", "", "Demo", Common::EN_ANY, Common::kPlatformWindows },  	{ "132bff65e6367c09cc69318ce1b59333", "monkey2", "", "", Common::EN_ANY, Common::kPlatformAmiga },  	{ "145bd3373574feb668cc2eea2ec6cf86", "balloon", "HE 80", "", Common::RU_RUS, Common::kPlatformWindows },  	{ "14d48c95b43ddeb983254cf6c43851f1", "freddi4", "", "", Common::NL_NLD, Common::kPlatformWindows },  	{ "151071053a1d0021198216713939521d", "freddi2", "HE 80", "", Common::EN_ANY, Common::kPlatformWindows }, -	{ "15240c59d3681ed53f714f8d925cb2d6", "maniac", "", "V2", Common::ES_ESP, Common::kPlatformAtariST }, +	{ "15240c59d3681ed53f714f8d925cb2d6", "maniac", "V2", "V2", Common::ES_ESP, Common::kPlatformAtariST },  	{ "157367c3c21e0d03a0cba44361b4cf65", "indy3", "No Adlib", "EGA", Common::EN_ANY, Common::kPlatformAtariST },  	{ "15e03ffbfeddb9c2aebc13dcb2a4a8f4", "monkey", "VGA", "VGA", Common::EN_ANY, Common::kPlatformPC },  	{ "15f588e887e857e8c56fe6ade4956168", "atlantis", "", "Floppy", Common::ES_ESP, Common::kPlatformAmiga }, @@ -63,10 +63,10 @@ static const MD5Table md5table[] = {  	{ "17f7296f63c78642724f057fd8e736a7", "maniac", "NES", "extracted", Common::EN_USA, Common::kPlatformNES },  	{ "17fa250eb72dae2dad511ba79c0b6b0a", "tentacle", "", "Demo", Common::FR_FRA, Common::kPlatformPC },  	{ "182344899c2e2998fca0bebcd82aa81a", "atlantis", "", "CD", Common::EN_ANY, Common::kPlatformPC }, -	{ "183d7464902d40d00800e8ee1f04117c", "maniac", "", "V2", Common::DE_DEU, Common::kPlatformPC }, +	{ "183d7464902d40d00800e8ee1f04117c", "maniac", "V2", "V2", Common::DE_DEU, Common::kPlatformPC },  	{ "1875b90fade138c9253a8e967007031a", "indy3", "VGA", "VGA", Common::EN_ANY, Common::kPlatformPC },  	{ "187d315f6b5168f68680dfe8c3d76a3e", "loom", "EGA", "EGA", Common::HB_ISR, Common::kPlatformPC }, -	{ "1900e501a52fbf55bde6e4196f6d2aa6", "zak", "", "V2", Common::IT_ITA, Common::kPlatformPC }, +	{ "1900e501a52fbf55bde6e4196f6d2aa6", "zak", "V2", "V2", Common::IT_ITA, Common::kPlatformPC },  	{ "19263586f749a560c1adf8b3393a9593", "socks", "HE 80", "", Common::RU_RUS, Common::kPlatformWindows },  	{ "19bf6938a94698296bcb0c99c31c91a7", "spyfox2", "", "Demo", Common::EN_GRB, Common::kPlatformWindows },  	{ "1a6e5ae2777a6a33f06ffc0226210934", "atlantis", "", "CD", Common::EN_ANY, Common::kPlatformMacintosh }, @@ -90,7 +90,7 @@ static const MD5Table md5table[] = {  	{ "22f4ea88a09da12df9308ba30bcb7d0f", "loom", "EGA", "EGA", Common::EN_ANY, Common::kPlatformPC },  	{ "257f8c14d8c584f7ddd601bcb00920c7", "maniac", "NES", "", Common::DE_DEU, Common::kPlatformNES },  	{ "2723fea3dae0cb47768c424b145ae0e7", "tentacle", "", "Floppy", Common::EN_ANY, Common::kPlatformPC }, -	{ "27b3a4224ad63d5b04627595c1c1a025", "zak", "", "V2", Common::IT_ITA, Common::kPlatformAmiga }, +	{ "27b3a4224ad63d5b04627595c1c1a025", "zak", "V2", "V2", Common::IT_ITA, Common::kPlatformAmiga },  	{ "28d24a33448fab6795850bc9f159a4a2", "atlantis", "", "Demo", Common::JA_JPN, Common::kPlatformFMTowns },  	{ "28ef68ee3ed76d7e2ee8ee13c15fbd5b", "loom", "EGA", "EGA", Common::EN_ANY, Common::kPlatformPC },  	{ "2a208ffbcd0e83e86f4356e6f64aa6e1", "loom", "EGA", "EGA", Common::ES_ESP, Common::kPlatformPC }, @@ -138,7 +138,7 @@ static const MD5Table md5table[] = {  	{ "3de99ef0523f8ca7958faa3afccd035a", "spyfox", "HE 100", "", Common::EN_ANY, Common::kPlatformUnknown },  	{ "3df6ead57930488bc61e6e41901d0e97", "fbear", "HE 61", "", Common::EN_ANY, Common::kPlatformMacintosh },  	{ "3e48298920fab9b7aec5a971e1bd1fab", "pajama3", "", "Demo", Common::EN_GRB, Common::kPlatformWindows }, -	{ "40564ec47da48a67787d1f9bd043902a", "maniac", "", "Demo", Common::EN_ANY, Common::kPlatformPC }, +	{ "40564ec47da48a67787d1f9bd043902a", "maniac", "Demo", "Demo", Common::EN_ANY, Common::kPlatformPC },  	{ "4167a92a1d46baa4f4127d918d561f88", "tentacle", "", "CD", Common::EN_ANY, Common::kPlatformUnknown },  	{ "425205754fa749f4f0b0dd9d09fa45fd", "football", "", "Demo", Common::EN_ANY, Common::kPlatformUnknown },  	{ "430bc518017b6fac046f58bab6baad5d", "monkey2", "", "", Common::JA_JPN, Common::kPlatformFMTowns }, @@ -151,7 +151,7 @@ static const MD5Table md5table[] = {  	{ "47e75b1bdcb44c78cb94883d1731ccf8", "fbear", "HE 61", "Demo", Common::EN_ANY, Common::kPlatformPC },  	{ "48b9f04b348bc5013327753f0d12a144", "loom", "EGA", "EGA", Common::ES_ESP, Common::kPlatformAmiga },  	{ "49210e124e4c2b30f1290a9ef6306301", "monkey", "EGA", "EGA", Common::EN_ANY, Common::kPlatformPC }, -	{ "4973bbc3899e3826dbf316e1d7271ec7", "zak", "", "", Common::DE_DEU, Common::kPlatformC64 }, +	{ "4973bbc3899e3826dbf316e1d7271ec7", "zak", "V1", "", Common::DE_DEU, Common::kPlatformC64 },  	{ "499c958affc394f2a3868f1eb568c3ee", "freddi4", "HE 99", "Demo", Common::NL_NLD, Common::kPlatformWindows },  	{ "4af4a6b248103c1fe9edef619677f540", "puttmoon", "", "Demo", Common::EN_ANY, Common::kPlatformMacintosh },  	{ "4ba37f835be11a59d969f90f272f575b", "water", "HE 80", "", Common::EN_ANY, Common::kPlatformUnknown }, @@ -174,11 +174,11 @@ static const MD5Table md5table[] = {  	{ "50fcdc982a25063b78ad46bf389b8e8d", "tentacle", "", "Floppy", Common::IT_ITA, Common::kPlatformPC },  	{ "51305e929e330e24a75a0351c8f9975e", "freddi2", "HE 99", "Updated", Common::EN_ANY, Common::kPlatformUnknown },  	{ "5262a27afcaee04e5c4900220bd463e7", "PuttsFunShop", "", "", Common::EN_ANY, Common::kPlatformUnknown }, -	{ "52a4bae0746a11d7b1e8554e91a6645c", "zak", "", "V2", Common::FR_FRA, Common::kPlatformPC }, +	{ "52a4bae0746a11d7b1e8554e91a6645c", "zak", "V2", "V2", Common::FR_FRA, Common::kPlatformPC },  	{ "53e94115b55dd51d4b8ff0871aa1df1e", "spyfox", "", "Demo", Common::EN_ANY, Common::kPlatformUnknown },  	{ "54a936ad06161ff7bfefcb96200f7bff", "monkey", "VGA", "VGA Demo", Common::EN_ANY, Common::kPlatformAmiga },  	{ "55518cd73cf9c6d23ea29c51ee06bdfe", "ft", "", "", Common::IT_ITA, Common::kPlatformUnknown }, -	{ "55d3987641bf229c83bc729210173383", "zak", "", "", Common::EN_ANY, Common::kPlatformC64 }, +	{ "55d3987641bf229c83bc729210173383", "zak", "V1", "", Common::EN_ANY, Common::kPlatformC64 },  	{ "55e4cc866ff9046824e1c638ba2b8c7f", "ft", "", "", Common::RU_RUS, Common::kPlatformUnknown },  	{ "566165a7338fa11029e7c14d94fa70d0", "freddi", "HE 73", "Demo", Common::EN_ANY, Common::kPlatformWindows },  	{ "5798972220cd458be2626d54c80f71d7", "atlantis", "", "Floppy", Common::IT_ITA, Common::kPlatformAmiga }, @@ -196,11 +196,11 @@ static const MD5Table md5table[] = {  	{ "5e8fb66971a60e523e5afbc4c129c0e8", "socks", "HE 80", "", Common::EN_ANY, Common::kPlatformUnknown },  	{ "5fbe557049892eb4b709d90916ec97ca", "indy3", "EGA", "EGA", Common::EN_ANY, Common::kPlatformPC },  	{ "600abd3e9f47e63e670188b7e4e86ac7", "spyozon", "", "", Common::EN_ANY, Common::kPlatformUnknown }, -	{ "6027e9ca9c35746d95dee2068cec17e5", "zak", "", "V2", Common::DE_DEU, Common::kPlatformAmiga }, +	{ "6027e9ca9c35746d95dee2068cec17e5", "zak", "V2", "V2", Common::DE_DEU, Common::kPlatformAmiga },  	{ "60ba818dc3bede86d40357e3913f8505", "ft", "", "Version B", Common::EN_ANY, Common::kPlatformUnknown }, -	{ "613f64f78ea26c7353b2a5940eb61d6a", "zak", "", "V2", Common::FR_FRA, Common::kPlatformAtariST }, +	{ "613f64f78ea26c7353b2a5940eb61d6a", "zak", "V2", "V2", Common::FR_FRA, Common::kPlatformAtariST },  	{ "62050da376483d8edcbd98cd26b6cb57", "puttrace", "HE 99", "", Common::RU_RUS, Common::kPlatformWindows }, -	{ "624cdb93654667c869d204a64af7e57f", "maniac", "", "V2", Common::EN_ANY, Common::kPlatformPC }, +	{ "624cdb93654667c869d204a64af7e57f", "maniac", "V2", "V2", Common::EN_ANY, Common::kPlatformPC },  	{ "6271130f440066830eca9056c1d7926f", "water", "HE 80", "", Common::RU_RUS, Common::kPlatformWindows },  	{ "62b8c16b6db226ba95aaa8be73f9885c", "indy3", "EGA", "EGA", Common::ES_ESP, Common::kPlatformAmiga },  	{ "63fdcdc95cdeea00060883aed38e5504", "PuttTime", "HE 80", "", Common::EN_ANY, Common::kPlatformWindows }, @@ -210,7 +210,7 @@ static const MD5Table md5table[] = {  	{ "663743c03ae0c007f3d665cf631c0e6b", "puttrace", "HE 99", "Demo", Common::DE_DEU, Common::kPlatformUnknown },  	{ "66fd5ff9a810dfeb6d6bdada18221140", "monkey", "VGA", "VGA", Common::IT_ITA, Common::kPlatformPC },  	{ "672dec94b82f7f0877ebb5b5cf7f4bc1", "pajama", "", "", Common::EN_ANY, Common::kPlatformUnknown }, -	{ "675d71151e9b5a968c8ce46d9fbf4cbf", "zak", "", "V2", Common::EN_ANY, Common::kPlatformPC }, +	{ "675d71151e9b5a968c8ce46d9fbf4cbf", "zak", "V2", "V2", Common::EN_ANY, Common::kPlatformPC },  	{ "68155a6bf082221525f431c2cbdac8ab", "SamsFunShop", "", "", Common::EN_ANY, Common::kPlatformUnknown },  	{ "684732efb5799c0f78804c99d8de9aba", "puttputt", "HE 61", "", Common::EN_ANY, Common::kPlatformMacintosh },  	{ "688328c5bdc4c8ec4145688dfa077bf2", "freddi4", "HE 99", "Demo", Common::DE_DEU, Common::kPlatformUnknown }, @@ -244,7 +244,7 @@ static const MD5Table md5table[] = {  	{ "73e5ab7dbb9a8061cc6d25df02dbd1e7", "loom", "EGA", "EGA", Common::EN_ANY, Common::kPlatformPC },  	{ "746e88c172a5b7a1ae89ac0ee3ee681a", "freddi", "HE 90", "Updated", Common::RU_RUS, Common::kPlatformWindows },  	{ "754feb59d3bf86b8a00840df74fd7b26", "freddi3", "", "Demo", Common::NL_NLD, Common::kPlatformWindows }, -	{ "75ba23fff4fd63fa446c02864f2a5a4b", "zak", "", "V2", Common::IT_ITA, Common::kPlatformPC }, +	{ "75ba23fff4fd63fa446c02864f2a5a4b", "zak", "V2", "V2", Common::IT_ITA, Common::kPlatformPC },  	{ "75bff95816b84672b877d22a911ab811", "freddi3", "HE 99", "", Common::RU_RUS, Common::kPlatformWindows },  	{ "771bc18ec6f93837b839c992b211904b", "monkey", "Demo", "EGA Demo", Common::DE_DEU, Common::kPlatformPC },  	{ "77f5c9cc0986eb729c1a6b4c8823bbae", "zak", "FM-TOWNS", "", Common::EN_ANY, Common::kPlatformFMTowns }, @@ -264,15 +264,15 @@ static const MD5Table md5table[] = {  	{ "7fc6cdb46b4c9d384c52327f4bca6416", "football", "", "", Common::EN_ANY, Common::kPlatformUnknown },  	{ "810a9da887aefa597b0cf3c77d262897", "BluesABCTime", "", "Demo", Common::EN_ANY, Common::kPlatformUnknown },  	{ "81bbfa181184cb494e7a81dcfa94fbd9", "maniac", "NES", "", Common::FR_FRA, Common::kPlatformNES }, -	{ "8299d9b8a1b0e7b881bae7a9971dc5e2", "zak", "", "Demo", Common::EN_ANY, Common::kPlatformAtariST }, +	{ "8299d9b8a1b0e7b881bae7a9971dc5e2", "zak", "V2", "Demo", Common::EN_ANY, Common::kPlatformAtariST },  	{ "8368f552b1e3eba559f8d559bcc4cadb", "freddi3", "", "", Common::UNK_LANG, Common::kPlatformUnknown },  	{ "83cedbe26aa8b58988e984e3d34cac8e", "freddi3", "HE 99", "", Common::DE_DEU, Common::kPlatformUnknown },  	{ "84e3c23a49ded8a6f9197735c8eb3de7", "PuttTime", "HE 80", "", Common::DE_DEU, Common::kPlatformWindows }, -	{ "861e59ed72a1cd0e6d454f7ee7e2bf3d", "comi", "", "", Common::RU_RUS, Common::kPlatformUnknown }, +	{ "861e59ed72a1cd0e6d454f7ee7e2bf3d", "comi", "", "", Common::RU_RUS, Common::kPlatformWindows },  	{ "86be8ada36371d4fdc35659d0e912a26", "indy3", "EGA", "EGA", Common::ES_ESP, Common::kPlatformPC },  	{ "86c9902b7bec1a17926d4dae85beaa45", "airport", "HE 71", "Demo", Common::EN_ANY, Common::kPlatformWindows },  	{ "870d1e3c86bc50846d808d14a36b4e08", "monkey", "VGA", "VGA", Common::ES_ESP, Common::kPlatformAmiga }, -	{ "87f6e8037b7cc996e13474b491a7a98e", "maniac", "", "V2", Common::IT_ITA, Common::kPlatformPC }, +	{ "87f6e8037b7cc996e13474b491a7a98e", "maniac", "V2", "V2", Common::IT_ITA, Common::kPlatformPC },  	{ "8801fb4a1200b347f7a38523339526dd", "jungle", "", "", Common::EN_ANY, Common::kPlatformWindows },  	{ "883af4b0af4f77a92f1dcf1d0a283140", "tentacle", "", "CD", Common::ES_ESP, Common::kPlatformUnknown },  	{ "898ce8eb1234a955ef75e87141902bb3", "freddi3", "", "", Common::RU_RUS, Common::kPlatformWindows }, @@ -288,12 +288,12 @@ static const MD5Table md5table[] = {  	{ "8eb84cee9b429314c7f0bdcf560723eb", "monkey", "FM-TOWNS", "", Common::EN_ANY, Common::kPlatformFMTowns },  	{ "8ee63cafb1fe9d62aa0d5a23117e70e7", "freddi2", "HE 100", "Updated", Common::EN_ANY, Common::kPlatformUnknown },  	{ "8f3758ff98c9c5d78e5d635222cad026", "atlantis", "", "Floppy", Common::IT_ITA, Common::kPlatformPC }, -	{ "8fec68383202d38c0d25e9e3b757c5df", "comi", "Demo", "Demo", Common::UNK_LANG, Common::kPlatformUnknown }, +	{ "8fec68383202d38c0d25e9e3b757c5df", "comi", "Demo", "Demo", Common::UNK_LANG, Common::kPlatformWindows },  	{ "8ffd618a776a4c0d8922bb28b09f8ce8", "airport", "", "Demo", Common::EN_ANY, Common::kPlatformWindows },  	{ "90a329d8ad5b7ce0690429e98cfbb32f", "funpack", "", "", Common::HB_ISR, Common::kPlatformPC },  	{ "90c755e1c9b9b8a4129d37b2259d0655", "chase", "HE 100", "Updated", Common::EN_ANY, Common::kPlatformUnknown },  	{ "910e31cffb28226bd68c569668a0d6b4", "monkey", "EGA", "EGA", Common::ES_ESP, Common::kPlatformPC }, -	{ "91469353f7be1b122fa88d23480a1320", "zak", "", "V2", Common::FR_FRA, Common::kPlatformAmiga }, +	{ "91469353f7be1b122fa88d23480a1320", "zak", "V2", "V2", Common::FR_FRA, Common::kPlatformAmiga },  	{ "91d5db93187fab54d823f73bd6441cb6", "maniac", "NES", "extracted", Common::EN_GRB, Common::kPlatformNES },  	{ "927a764615c7fcdd72f591355e089d8c", "monkey", "No Adlib", "EGA", Common::DE_DEU, Common::kPlatformAtariST },  	{ "92b078d9d6d9d751da9c26b8b3075779", "tentacle", "", "Floppy", Common::FR_FRA, Common::kPlatformPC }, @@ -305,10 +305,10 @@ static const MD5Table md5table[] = {  	{ "9708cf716ed8bcc9ff3fcfc69413b746", "puttputt", "HE 61", "", Common::EN_ANY, Common::kPlatformPC },  	{ "981e1e1891f2be7e25a01f50ae55a5af", "puttrace", "HE 98", "", Common::EN_ANY, Common::kPlatformUnknown },  	{ "98744fe66ff730e8c2b3b1f58803ab0b", "atlantis", "", "Demo", Common::EN_ANY, Common::kPlatformPC }, -	{ "99a3699f80b8f776efae592b44b9b991", "maniac", "", "V2", Common::FR_FRA, Common::kPlatformPC }, +	{ "99a3699f80b8f776efae592b44b9b991", "maniac", "V2", "V2", Common::FR_FRA, Common::kPlatformPC },  	{ "99b6f822b0b2612415407865438697d6", "atlantis", "", "Demo", Common::EN_ANY, Common::kPlatformPC },  	{ "9b7452b5cd6d3ffb2b2f5118010af84f", "ft", "Demo", "Demo", Common::EN_ANY, Common::kPlatformMacintosh }, -	{ "9bc548e179cdb0767009401c094d0895", "maniac", "", "V2", Common::DE_DEU, Common::kPlatformAmiga }, +	{ "9bc548e179cdb0767009401c094d0895", "maniac", "V2", "V2", Common::DE_DEU, Common::kPlatformAmiga },  	{ "9bd2a8f72613e715c199246dd511e10f", "atlantis", "", "Floppy", Common::ES_ESP, Common::kPlatformPC },  	{ "9bda5fee51d2fda5253d02c642016bf4", "spyfox", "HE 98.5", "", Common::NL_NLD, Common::kPlatformWindows },  	{ "9c0fee288ad564a7d25ec3e841810d79", "indy3", "EGA", "EGA", Common::EN_ANY, Common::kPlatformAmiga }, @@ -328,7 +328,7 @@ static const MD5Table md5table[] = {  	{ "a3036878840720fbefa41e6965fa4a0a", "samnmax", "", "Floppy", Common::EN_ANY, Common::kPlatformPC },  	{ "a525c1753c1db5011c00417da37887ef", "PuttTime", "HE 100", "", Common::EN_USA, Common::kPlatformUnknown },  	{ "a561d2e2413cc1c71d5a1bf87bf493ea", "lost", "HE 100", "Updated", Common::EN_ANY, Common::kPlatformUnknown }, -	{ "a570381b028972d891052ee1e51dc011", "maniac", "", "V2", Common::EN_ANY, Common::kPlatformAtariST }, +	{ "a570381b028972d891052ee1e51dc011", "maniac", "V2", "V2", Common::EN_ANY, Common::kPlatformAtariST },  	{ "a654fb60c3b67d6317a7894ffd9f25c5", "pajama3", "", "Demo", Common::EN_USA, Common::kPlatformUnknown },  	{ "a7cacad9c40c4dc9e1812abf6c8af9d5", "puttcircus", "", "Demo", Common::EN_ANY, Common::kPlatformUnknown },  	{ "a85856675429fe88051744f755b72f93", "farm", "", "", Common::EN_ANY, Common::kPlatformWindows }, @@ -345,7 +345,7 @@ static const MD5Table md5table[] = {  	{ "acad97ab1c6fc2a5b2d98abf6db4a190", "tentacle", "", "Floppy", Common::EN_ANY, Common::kPlatformUnknown },  	{ "ae94f110a14ce71fc515d5b648827a8f", "tentacle", "", "Floppy", Common::ES_ESP, Common::kPlatformPC },  	{ "b23f7cd7c304d7dff08e92a96120d5b4", "zak", "V1", "V1", Common::EN_ANY, Common::kPlatformPC }, -	{ "b250d0f9cc83f80ced56fe11a4fb057c", "maniac", "", "V2", Common::EN_ANY, Common::kPlatformPC }, +	{ "b250d0f9cc83f80ced56fe11a4fb057c", "maniac", "V2", "V2", Common::EN_ANY, Common::kPlatformPC },  	{ "b289a2a8cbedbf45786e0b4ad2f510f1", "samnmax", "", "Floppy", Common::IT_ITA, Common::kPlatformPC },  	{ "b5298a5c15ffbe8b381d51ea4e26d35c", "freddi4", "HE 99", "", Common::DE_DEU, Common::kPlatformUnknown },  	{ "b597e0403cc0002f69170e6caba7edd9", "indy3", "EGA", "EGA Demo", Common::EN_ANY, Common::kPlatformPC }, @@ -358,7 +358,7 @@ static const MD5Table md5table[] = {  	{ "bc4700bc0e12879f6d25d14d6be6cfdd", "spyfox2", "", "", Common::DE_DEU, Common::kPlatformUnknown },  	{ "bd126753de619a495f9f22adc951c8d5", "monkey2", "", "", Common::IT_ITA, Common::kPlatformPC },  	{ "be39a5d4db60e8aa736b9086778cb45c", "spyozon", "", "", Common::EN_ANY, Common::kPlatformWindows }, -	{ "be83e882b44f2767bc08d4f766ebc347", "maniac", "", "V2", Common::DE_DEU, Common::kPlatformAtariST }, +	{ "be83e882b44f2767bc08d4f766ebc347", "maniac", "V2", "V2", Common::DE_DEU, Common::kPlatformAtariST },  	{ "bf8b52fdd9a69c67f34e8e9fec72661c", "farm", "HE 71", "Demo", Common::EN_ANY, Common::kPlatformWindows },  	{ "bfdf584b01503f0762baded581f6a0a2", "SoccerMLS", "", "", Common::EN_ANY, Common::kPlatformWindows },  	{ "c0039ad982999c92d0de81910d640fa0", "freddi", "HE 71", "", Common::NL_NLD, Common::kPlatformWindows }, @@ -369,8 +369,8 @@ static const MD5Table md5table[] = {  	{ "c3196c5349e53e387aaff1533d95e53a", "samnmax", "", "Demo", Common::EN_ANY, Common::kPlatformPC },  	{ "c3b22fa4654bb580b20325ebf4174841", "puttzoo", "", "", Common::NL_NLD, Common::kPlatformWindows },  	{ "c3df37df9d3b481b45f75283a9907c47", "loom", "EGA", "EGA", Common::IT_ITA, Common::kPlatformPC }, -	{ "c4787c3e8b5e2dfda90850ee800af00f", "zak", "", "V2", Common::FR_FRA, Common::kPlatformPC }, -	{ "c4a7f7398ac9ae588940f9912ea5fd8f", "maniac", "", "", Common::DE_DEU, Common::kPlatformC64 }, +	{ "c4787c3e8b5e2dfda90850ee800af00f", "zak", "V2", "V2", Common::FR_FRA, Common::kPlatformPC }, +	{ "c4a7f7398ac9ae588940f9912ea5fd8f", "maniac", "C64", "", Common::DE_DEU, Common::kPlatformC64 },  	{ "c4ffae9fac495475d6bc3343ccc8faf9", "Soccer2004", "", "", Common::EN_ANY, Common::kPlatformUnknown },  	{ "c5d10e190d4b4d59114b824f2fdbd00e", "loom", "FM-TOWNS", "", Common::EN_ANY, Common::kPlatformFMTowns },  	{ "c63ee46143ba65f9ce14cf539ca51bd7", "atlantis", "", "Floppy", Common::EN_ANY, Common::kPlatformPC }, @@ -384,16 +384,16 @@ static const MD5Table md5table[] = {  	{ "cc04a076779379524ed4d9c5ee3c6fb1", "tentacle", "", "CD", Common::EN_ANY, Common::kPlatformMacintosh },  	{ "cc8ba2b0df2f9c450bcf055fe2711979", "samnmax", "", "Demo", Common::DE_DEU, Common::kPlatformPC },  	{ "cd9c05e755d7bf8e9b9590ad1ebe273e", "dig", "Demo", "Demo", Common::EN_ANY, Common::kPlatformMacintosh }, -	{ "cdd760228cf1010c2903f37e788ea31c", "zak", "", "V2", Common::DE_DEU, Common::kPlatformPC }, +	{ "cdd760228cf1010c2903f37e788ea31c", "zak", "V2", "V2", Common::DE_DEU, Common::kPlatformPC },  	{ "ce6a4cef315b20fef58a95bc40a2d8d3", "monkey", "EGA", "EGA", Common::FR_FRA, Common::kPlatformPC }, -	{ "ce7733f185b838e248927c7ba1a04204", "maniac", "", "V2", Common::FR_FRA, Common::kPlatformAmiga }, +	{ "ce7733f185b838e248927c7ba1a04204", "maniac", "V2", "V2", Common::FR_FRA, Common::kPlatformAmiga },  	{ "ce7fd0c382389a6791fc3e199c117ef4", "indy3", "EGA", "EGA", Common::ES_ESP, Common::kPlatformPC },  	{ "cea91e3dd47f2518ea418e41611aa77f", "spyfox2", "", "", Common::RU_RUS, Common::kPlatformUnknown },  	{ "cf4ef315214c7d8cdab6302cdb7e50db", "freddi", "HE 73", "Demo", Common::DE_DEU, Common::kPlatformWindows },  	{ "cf8d13446ec6cb6222287a925fd47c1d", "baseball", "", "", Common::EN_ANY, Common::kPlatformUnknown },  	{ "cf8ef3a1fb483c5c4b1c584d1167b2c4", "freddi", "HE 73", "", Common::DE_DEU, Common::kPlatformWindows },  	{ "cf90b4db5486ef798db78fe6fbf897e5", "pajama3", "", "Demo", Common::EN_USA, Common::kPlatformWindows }, -	{ "d06fbe28818fef7bfc45c2cdf0c0849d", "zak", "", "V2", Common::DE_DEU, Common::kPlatformPC }, +	{ "d06fbe28818fef7bfc45c2cdf0c0849d", "zak", "V2", "V2", Common::DE_DEU, Common::kPlatformPC },  	{ "d0b531227a27c6662018d2bd05aac52a", "monkey", "VGA", "VGA", Common::DE_DEU, Common::kPlatformPC },  	{ "d220d154aafbfa12bd6f3ab1b2dae420", "puttzoo", "", "Demo", Common::DE_DEU, Common::kPlatformMacintosh },  	{ "d37c55388294b66e53e7ced3af88fa68", "freddi2", "HE 100", "Updated Demo", Common::EN_ANY, Common::kPlatformUnknown }, @@ -402,14 +402,14 @@ static const MD5Table md5table[] = {  	{ "d4b8ee426b1afd3e53bc0cf020418cf6", "dog", "HE 99", "", Common::EN_ANY, Common::kPlatformWindows },  	{ "d4cccb5af88f3e77f370896e9ba8c5f9", "freddi", "HE 71", "", Common::UNK_LANG, Common::kPlatformWindows },  	{ "d4e79c3d8645b8266cd78c325bc35154", "pajama2", "", "", Common::EN_ANY, Common::kPlatformUnknown }, -	{ "d55eff37c2100f5065cde9de428621fa", "zak", "", "V2", Common::EN_ANY, Common::kPlatformAtariST }, +	{ "d55eff37c2100f5065cde9de428621fa", "zak", "V2", "V2", Common::EN_ANY, Common::kPlatformAtariST },  	{ "d62047a6729349ab36f7ee065bf26509", "dig", "", "", Common::RU_RUS, Common::kPlatformUnknown },  	{ "d62d248c3df6ec177405e2cb23d923b2", "indy3", "EGA", "EGA", Common::IT_ITA, Common::kPlatformPC },  	{ "d6334a5a9b61afe18c368540fdf522ca", "airport", "", "", Common::EN_ANY, Common::kPlatformMacintosh },  	{ "d6dd0646404768a63e963891a96daadd", "atlantis", "", "Floppy", Common::EN_ANY, Common::kPlatformMacintosh },  	{ "d7ab7cd6105546016e6a0d46fb36b964", "pajama", "HE 100", "Demo", Common::EN_ANY, Common::kPlatformUnknown },  	{ "d7b247c26bf1f01f8f7daf142be84de3", "balloon", "HE 99", "Updated", Common::EN_ANY, Common::kPlatformWindows }, -	{ "d831f7c048574dd9d5d85db2a1468099", "maniac", "", "", Common::EN_ANY, Common::kPlatformC64 }, +	{ "d831f7c048574dd9d5d85db2a1468099", "maniac", "C64", "", Common::EN_ANY, Common::kPlatformC64 },  	{ "d8323015ecb8b10bf53474f6e6b0ae33", "dig", "", "", Common::UNK_LANG, Common::kPlatformUnknown },  	{ "d8d07efcb88f396bee0b402b10c3b1c9", "maniac", "NES", "", Common::EN_USA, Common::kPlatformNES },  	{ "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "", "CD", Common::EN_ANY, Common::kPlatformUnknown }, @@ -417,9 +417,9 @@ static const MD5Table md5table[] = {  	{ "da09e666fc8f5b78d7b0ac65d1a3b56e", "monkey2", "", "", Common::EN_ANY, Common::kPlatformFMTowns },  	{ "da6269b18fcb08189c0aa9c95533cce2", "monkey", "CD", "CD", Common::IT_ITA, Common::kPlatformPC },  	{ "da669b20271b85182e9c17a2a37ea02e", "monkey2", "", "", Common::DE_DEU, Common::kPlatformAmiga }, -	{ "dd30a53035393baa5a5e222e716559af", "maniac", "", "V2", Common::FR_FRA, Common::kPlatformAtariST }, +	{ "dd30a53035393baa5a5e222e716559af", "maniac", "V2", "V2", Common::FR_FRA, Common::kPlatformAtariST },  	{ "de4efb910210736813c9a1185384bace", "puttzoo", "", "Demo", Common::EN_ANY, Common::kPlatformWindows }, -	{ "debe337f73d660e951ece7c1f1c81add", "zak", "", "V2", Common::EN_ANY, Common::kPlatformPC }, +	{ "debe337f73d660e951ece7c1f1c81add", "zak", "V2", "V2", Common::EN_ANY, Common::kPlatformPC },  	{ "defb8cb9ec4b0f91acfb6b61c6129ad9", "PuttTime", "HE 99", "", Common::RU_RUS, Common::kPlatformWindows },  	{ "df03ee021aa9b81d90cab9c26da07614", "indy3", "EGA", "EGA", Common::IT_ITA, Common::kPlatformAmiga },  	{ "df047cc4792150f601290357566d36a6", "freddi", "HE 90", "Updated", Common::EN_ANY, Common::kPlatformUnknown }, @@ -435,8 +435,8 @@ static const MD5Table md5table[] = {  	{ "e689bdf67f98b1d760ce4487ec0e8d06", "indy3", "EGA", "EGA", Common::FR_FRA, Common::kPlatformAmiga },  	{ "e6cd81b25ab1453a8a6d3482118c391e", "pass", "", "", Common::EN_ANY, Common::kPlatformPC },  	{ "e72bb4c2b613db2cf50f89ff6350e70a", "ft", "", "", Common::ES_ESP, Common::kPlatformUnknown }, -	{ "e781230da44a44e2f0770edb2b3b3633", "maniac", "", "V2", Common::EN_ANY, Common::kPlatformAmiga }, -	{ "e94c7cc3686fce406d3c91b5eae5a72d", "zak", "", "V2", Common::EN_ANY, Common::kPlatformAmiga }, +	{ "e781230da44a44e2f0770edb2b3b3633", "maniac", "V2", "V2", Common::EN_ANY, Common::kPlatformAmiga }, +	{ "e94c7cc3686fce406d3c91b5eae5a72d", "zak", "V2", "V2", Common::EN_ANY, Common::kPlatformAmiga },  	{ "e98b982ceaf9d253d730bde8903233d6", "monkey", "EGA", "EGA", Common::DE_DEU, Common::kPlatformPC },  	{ "eae95b2b3546d8ba86ae1d397c383253", "dog", "", "", Common::EN_ANY, Common::kPlatformUnknown },  	{ "ebd0b2c8a387f18887282afe6cad894a", "spyozon", "", "Demo", Common::EN_ANY, Common::kPlatformUnknown }, @@ -469,7 +469,7 @@ static const MD5Table md5table[] = {  	{ "fcb78ebecab2757264c590890c319cc5", "PuttTime", "HE 100", "", Common::NL_NLD, Common::kPlatformWindows },  	{ "fce4b8010704b103acfeea9413788f32", "freddi2", "HE 80", "", Common::DE_DEU, Common::kPlatformUnknown },  	{ "fe381e45117878b1e942cb876b050fd6", "ft", "", "", Common::EN_ANY, Common::kPlatformMacintosh }, -	{ "fe60d6b5ff51b0553ac59963123b5777", "comi", "", "", Common::UNK_LANG, Common::kPlatformUnknown }, -	{ "ff05c07990061d97647f059c48c1d05a", "zak", "", "V2", Common::DE_DEU, Common::kPlatformAtariST }, +	{ "fe60d6b5ff51b0553ac59963123b5777", "comi", "", "", Common::UNK_LANG, Common::kPlatformWindows }, +	{ "ff05c07990061d97647f059c48c1d05a", "zak", "V2", "V2", Common::DE_DEU, Common::kPlatformAtariST },  	{ 0, 0, 0, 0, Common::UNK_LANG, Common::kPlatformUnknown }  }; diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 957298b3a6..7715497ef6 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -78,10 +78,11 @@ namespace Scumm {  ScummEngine *g_scumm = 0; -ScummEngine::ScummEngine(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) +ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)  	: Engine(syst), -	  _game(gs), -	  _substResFileName(subst), +	  _game(dr.game), +	  _filenamePattern(dr.fp), +	  _language(dr.language),  	  _debugger(0),  	  _currentScript(0xFF), // Let debug() work on init stage  	  gdi(this), @@ -89,11 +90,8 @@ ScummEngine::ScummEngine(OSystem *syst, const GameSettings &gs, uint8 md5sum[16]  	  _pauseDialog(0), _mainMenuDialog(0), _versionDialog(0) {  	// Copy MD5 checksum -	memcpy(_gameMD5, md5sum, 16); +	memcpy(_gameMD5, dr.md5sum, 16); -	// Clean _substResFileNameBundle -	memset(&_substResFileNameBundle, 0, sizeof(_substResFileNameBundle)); -  	// Add default file directories.  	if (((_game.platform == Common::kPlatformAmiga) || (_game.platform == Common::kPlatformAtariST)) && (_game.version <= 4)) {  		// This is for the Amiga version of Indy3/Loom/Maniac/Zak @@ -146,14 +144,17 @@ ScummEngine::ScummEngine(OSystem *syst, const GameSettings &gs, uint8 md5sum[16]  	// This is the case of the NES, C64 and Mac versions of certain games.  	// Note: All of these can also occur in 'extracted' form, in which case they  	// are treated like any other SCUMM game. -	if (_substResFileName.almostGameID && _substResFileName.genMethod == kGenAsIs) { +	if (_filenamePattern.genMethod == kGenUnchanged) {  		if (_game.platform == Common::kPlatformNES) {  			// We read data directly from NES ROM instead of extracting it with  			// external tool  			assert(_game.id == GID_MANIAC);  			_fileHandle = new ScummNESFile(); -			_containerFile = _substResFileName.expandedName; +			_containerFile = _filenamePattern.pattern; +			 +			_filenamePattern.pattern = "%.2d.LFL"; +			_filenamePattern.genMethod = kGenRoomNum;  		} else if (_game.platform == Common::kPlatformC64) {  			// Read data from C64 disk images.  			const char *tmpBuf1, *tmpBuf2; @@ -168,6 +169,9 @@ ScummEngine::ScummEngine(OSystem *syst, const GameSettings &gs, uint8 md5sum[16]  			_fileHandle = new ScummC64File(tmpBuf1, tmpBuf2, _game.id == GID_MANIAC);  			_containerFile = tmpBuf1; + +			_filenamePattern.pattern = "%.2d.LFL"; +			_filenamePattern.genMethod = kGenRoomNum;  		} else if (_game.platform == Common::kPlatformMacintosh) {  			// The mac versions of Indy4, Sam&Max, DOTT, FT and The Dig used a  			// special meta (container) file format to store the actual SCUMM data @@ -179,13 +183,53 @@ ScummEngine::ScummEngine(OSystem *syst, const GameSettings &gs, uint8 md5sum[16]  			// handling).  			assert(_game.version >= 5 && _game.heversion == 0);  			_fileHandle = new ScummFile(); -			_containerFile = _substResFileName.expandedName; +			_containerFile = _filenamePattern.pattern; +			 +			 +			// We now have to determine the correct _filenamePattern. To do this +			// we simply hardcode the possibilites.  +			const char *p1 = 0, *p2 = 0; +			switch (_game.id) { +			case GID_INDY4: +				p1 = "atlantis.%03d"; +				break; +			case GID_TENTACLE: +				p1 = "tentacle.%03d"; +				p2 = "dottdemo.%03d"; +				break; +			case GID_SAMNMAX: +				p1 = "samnmax.%03d"; +				p2 = "samdemo.%03d"; +				break; +			case GID_FT: +				p1 = "ft.la%d"; +				p2 = "ftdemo.la%d"; +				break; +			case GID_DIG: +				p1 = "dig.la%d"; +				break; +			default: +				break; +			} + +			// Test which file name to use +			_filenamePattern.genMethod = kGenDiskNum; +			if (!_fileHandle->open(_containerFile)) +				error("Couldn't open container file '%s'", _containerFile.c_str()); + +			if ((_filenamePattern.pattern = p1) && _fileHandle->openSubFile(generateFilename(0))) { +				// Found regular version +			} else if ((_filenamePattern.pattern = p2) && _fileHandle->openSubFile(generateFilename(0))) { +				// Found demo +				_game.features |= GF_DEMO; +			} else +				error("Couldn't find known subfile inside container file '%s'", _containerFile.c_str()); +			 +			_fileHandle->close(); +			  		} else {  			error("kGenAsIs used with unsupported platform");  		} -		 -		// If a container file is used, we can turn of file name substitution. -		_substResFileName.almostGameID = 0;  	} else {  		// Regular access, no container file involved  		_fileHandle = new ScummFile(); @@ -537,11 +581,6 @@ ScummEngine::ScummEngine(OSystem *syst, const GameSettings &gs, uint8 md5sum[16]  	if (_bootParam)  		_debugMode = true; -	// Allow the user to override the game name with a custom string. -	// This allows some game versions to work which use filenames -	// differing from the regular version(s) of that game. -	_baseName = ConfMan.hasKey("basename") ? ConfMan.get("basename") : gs.gameid; -  	_copyProtection = ConfMan.getBool("copy_protection");  	if (ConfMan.getBool("demo_mode"))  		_game.features |= GF_DEMO; @@ -673,22 +712,22 @@ ScummEngine::~ScummEngine() {  	delete _debugger;  } -ScummEngine_v4::ScummEngine_v4(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v5(syst, gs, md5sum, subst) { +ScummEngine_v4::ScummEngine_v4(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v5(syst, dr) {  	_resourceHeaderSize = 6;  } -ScummEngine_v3::ScummEngine_v3(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v4(syst, gs, md5sum, subst) { +ScummEngine_v3::ScummEngine_v3(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v4(syst, dr) {  } -ScummEngine_v3old::ScummEngine_v3old(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v3(syst, gs, md5sum, subst) { +ScummEngine_v3old::ScummEngine_v3old(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v3(syst, dr) {  	_resourceHeaderSize = 4;  } -ScummEngine_v2::ScummEngine_v2(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v3old(syst, gs, md5sum, subst) { +ScummEngine_v2::ScummEngine_v2(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v3old(syst, dr) {  	VAR_SENTENCE_VERB = 0xFF;  	VAR_SENTENCE_OBJECT1 = 0xFF; @@ -701,14 +740,14 @@ ScummEngine_v2::ScummEngine_v2(OSystem *syst, const GameSettings &gs, uint8 md5s  	VAR_CLICK_OBJECT = 0xFF;  } -ScummEngine_c64::ScummEngine_c64(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v2(syst, gs, md5sum, subst) { +ScummEngine_c64::ScummEngine_c64(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v2(syst, dr) {  	_currentMode = 0;  } -ScummEngine_v6::ScummEngine_v6(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine(syst, gs, md5sum, subst) { +ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr) +	: ScummEngine(syst, dr) {  	_blastObjectQueuePos = 0;  	memset(_blastObjectQueue, 0, sizeof(_blastObjectQueue));  	_blastTextQueuePos = 0; @@ -729,8 +768,8 @@ ScummEngine_v6::ScummEngine_v6(OSystem *syst, const GameSettings &gs, uint8 md5s  }  #ifndef DISABLE_HE -ScummEngine_v70he::ScummEngine_v70he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v60he(syst, gs, md5sum, subst) { +ScummEngine_v70he::ScummEngine_v70he(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v60he(syst, dr) {  	if (_game.platform == Common::kPlatformMacintosh && (_game.heversion >= 72 && _game.heversion <= 73))  		_resExtractor = new MacResExtractor(this);  	else @@ -761,16 +800,16 @@ ScummEngine_v70he::~ScummEngine_v70he() {  	free(_storedFlObjects);  } -ScummEngine_v71he::ScummEngine_v71he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v70he(syst, gs, md5sum, subst) { +ScummEngine_v71he::ScummEngine_v71he(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v70he(syst, dr) {  	_auxBlocksNum = 0;  	memset(_auxBlocks, 0, sizeof(_auxBlocks));  	_auxEntriesNum = 0;  	memset(_auxEntries, 0, sizeof(_auxEntries));  } -ScummEngine_v72he::ScummEngine_v72he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v71he(syst, gs, md5sum, subst) { +ScummEngine_v72he::ScummEngine_v72he(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v71he(syst, dr) {  	VAR_NUM_ROOMS = 0xFF;  	VAR_NUM_SCRIPTS = 0xFF;  	VAR_NUM_SOUNDS = 0xFF; @@ -780,8 +819,8 @@ ScummEngine_v72he::ScummEngine_v72he(OSystem *syst, const GameSettings &gs, uint  	VAR_POLYGONS_ONLY = 0xFF;  } -ScummEngine_v80he::ScummEngine_v80he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v72he(syst, gs, md5sum, subst) { +ScummEngine_v80he::ScummEngine_v80he(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v72he(syst, dr) {  	_heSndResId = 0;  	_curSndId = 0;  	_sndPtrOffs = 0; @@ -793,8 +832,8 @@ ScummEngine_v80he::ScummEngine_v80he(OSystem *syst, const GameSettings &gs, uint  	VAR_COLOR_DEPTH = 0xFF;  } -ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v80he(syst, gs, md5sum, subst) { +ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v80he(syst, dr) {  	_sprite = new Sprite(this);  	VAR_NUM_SPRITE_GROUPS = 0xFF; @@ -818,8 +857,8 @@ ScummEngine_v90he::~ScummEngine_v90he() {  #endif  #ifndef DISABLE_SCUMM_7_8 -ScummEngine_v7::ScummEngine_v7(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v6(syst, gs, md5sum, subst) { +ScummEngine_v7::ScummEngine_v7(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v6(syst, dr) {  	_verbCharset = 0;  	_existLanguageFile = false;  	_languageBuffer = NULL; @@ -832,8 +871,8 @@ ScummEngine_v7::~ScummEngine_v7() {  	free(_languageIndex);  } -ScummEngine_v8::ScummEngine_v8(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst) -	: ScummEngine_v7(syst, gs, md5sum, subst) { +ScummEngine_v8::ScummEngine_v8(OSystem *syst, const DetectorResult &dr) +	: ScummEngine_v7(syst, dr) {  	_objectIDMap = 0;  } @@ -881,7 +920,6 @@ int ScummEngine::init() {  	setupMusic(_game.midi);  	// Load localization data, if present -	_language = Common::parseLanguage(ConfMan.get("language"));  	loadLanguageBundle();  	// Load CJK font, if present @@ -1305,19 +1343,10 @@ void ScummEngine_v99he::scummInit() {  	_hePalettes = (uint8 *)malloc((_numPalettes + 1) * 1024);  	memset(_hePalettes, 0, (_numPalettes + 1) * 1024); -	byte basename[256]; -	char buf1[128]; - -	strcpy((char *)basename, _baseName.c_str()); -	if (_substResFileName.almostGameID != 0) { -		generateSubstResFileName((char *)basename, buf1, sizeof(buf1)); -		strcpy((char *)basename, buf1); -	} -  	// Array 129 is set to base name -	int len = resStrLen(basename); +	int len = strlen(_filenamePattern.pattern);  	ArrayHeader *ah = defineArray(129, kStringArray, 0, 0, 0, len); -	memcpy(ah->data, basename, len); +	memcpy(ah->data, _filenamePattern.pattern, len);  }  #endif @@ -2015,9 +2044,5 @@ void ScummEngine::errorString(const char *buf1, char *buf2) {  	}  } -void ScummEngine::generateSubstResFileName(const char *filename, char *buf, int bufsize) { -	applySubstResFileName(_substResFileName, filename, buf, bufsize); -} -  } // End of namespace Scumm diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index ad6c84c667..e9813d1333 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -444,7 +444,7 @@ protected:  public:  	// Constructor / Destructor -	ScummEngine(OSystem *syst, const GameSettings &gs, uint8 md5sum[16], SubstResFileNames subst); +	ScummEngine(OSystem *syst, const DetectorResult &dr);  	virtual ~ScummEngine();  	/** Startup function, main loop. */ @@ -473,7 +473,6 @@ public:  	// Misc utility functions  	uint32 _debugFlags; -	const char *getBaseName() const { return _baseName.c_str(); }  	// Cursor/palette  	void updateCursor(); @@ -587,9 +586,9 @@ public:  	int _roomResource;  // FIXME - should be protected but Sound::pauseSounds uses it  	bool _egoPositioned;	// Used by Actor::putActor, hence public -	void generateSubstResFileName(const char *filename, char *buf, int bufsize); -	SubstResFileNames _substResFileName; -	SubstResFileNames _substResFileNameBundle; // Used with Mac bundles +	FilenamePattern _filenamePattern; + +	Common::String generateFilename(const int room) const;  protected:  	int _keyPressed; @@ -733,11 +732,10 @@ public:  	/** The name of the (macintosh/rescumm style) container file, if any. */  	Common::String _containerFile; -	bool openFile(BaseScummFile &file, const char *filename, bool resourceFile = false); +	bool openFile(BaseScummFile &file, const char *filename, bool resourceFile = false);	// TODO: Use Common::String  protected:  	int _resourceHeaderSize; -	Common::String _baseName;	// This is the name we use for opening resource files  	byte _resourceMapper[128];  	byte *_heV7DiskOffsets;  	uint32 *_heV7RoomIntOffsets; @@ -749,8 +747,8 @@ protected:  	void closeRoom();  	void deleteRoomOffsets();  	virtual void readRoomsOffsets(); -	void askForDisk(const char *filename, int disknum); -	bool openResourceFile(const char *filename, byte encByte); +	void askForDisk(const char *filename, int disknum);	// TODO: Use Common::String +	bool openResourceFile(const char *filename, byte encByte);	// TODO: Use Common::String  	void loadPtrToResource(int type, int i, const byte *ptr);  	virtual void readResTypeList(int id, const char *name); diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 2a94230ce6..9dfeecc80b 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -996,7 +996,6 @@ ScummFile *Sound::openSfxFile() {  	};  	char buf[256]; -	char buf1[128];  	ScummFile *file = new ScummFile();  	_offsetTable = NULL; @@ -1004,19 +1003,22 @@ ScummFile *Sound::openSfxFile() {  	 * That way, you can keep .sou files for multiple games in the  	 * same directory */ -	const char *basename[4] = { 0, 0, 0, 0 }; -	basename[0] = _vm->getBaseName(); -	basename[1] = "monster"; +	Common::String basename[2]; -	if (_vm->_substResFileName.almostGameID != 0) { -		_vm->generateSubstResFileName(basename[0], buf1, sizeof(buf1)); -		basename[2] = buf1; +	const char *ptr = strchr(_vm->_filenamePattern.pattern, '.'); +	if (ptr) { +		basename[0] = Common::String(_vm->_filenamePattern.pattern, ptr - _vm->_filenamePattern.pattern + 1); +	} else { +		basename[0] = _vm->_filenamePattern.pattern; +		basename[0] += '.';  	} +	basename[1] = "monster."; -	for (int j = 0; basename[j] && !file->isOpen(); ++j) { +	for (uint j = 0; j < 2 && !file->isOpen(); ++j) {  		for (int i = 0; extensions[i].ext; ++i) { -			sprintf(buf, "%s.%s", basename[j], extensions[i].ext); -			if (_vm->openFile(*file, buf)) { +			Common::String tmp(basename[j]); +			tmp += extensions[i].ext; +			if (_vm->openFile(*file, tmp.c_str())) {  				_soundMode = extensions[i].mode;  				break;  			} @@ -1025,15 +1027,11 @@ ScummFile *Sound::openSfxFile() {  	if (!file->isOpen()) {  		if ((_vm->_game.heversion <= 61 && _vm->_game.platform == Common::kPlatformMacintosh) || (_vm->_game.heversion >= 70)) { -			sprintf(buf, "%s.he2", _vm->getBaseName()); +			strncpy(buf, _vm->generateFilename(2).c_str(), sizeof(buf));  		} else { -			sprintf(buf, "%s.tlk", _vm->getBaseName()); +			sprintf(buf, "%s.tlk", _vm->_filenamePattern.pattern);  		} -		if (_vm->_substResFileName.almostGameID != 0) { -			_vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); -			strcpy(buf, buf1); -		}  		if (file->open(buf) && _vm->_game.heversion <= 73)  			file->setEnc(0x69);  		_soundMode = kVOCMode; diff --git a/tools/scumm-md5.txt b/tools/scumm-md5.txt index d8b9c74fa9..b95e3d3af5 100644 --- a/tools/scumm-md5.txt +++ b/tools/scumm-md5.txt @@ -24,8 +24,8 @@  #       that their description in the launcher doesn't start with "Zak McKracken"  #  maniac	Maniac Mansion -	d831f7c048574dd9d5d85db2a1468099	en	C64	-	-	-	 -	c4a7f7398ac9ae588940f9912ea5fd8f	de	C64	-	-	-	 +	d831f7c048574dd9d5d85db2a1468099	en	C64	C64	-	-	 +	c4a7f7398ac9ae588940f9912ea5fd8f	de	C64	C64	-	-	  	7f45ddd6dbfbf8f80c0c0efea4c295bc	en	DOS	V1	V1	-	  	d8d07efcb88f396bee0b402b10c3b1c9	us	NES	NES	-	-	 @@ -39,49 +39,49 @@ maniac	Maniac Mansion  	3a5ec90d556d4920976c5578bfbfaf79	de	NES	NES	extracted	-	  	6b5a3fef241e90d4b2e77f1e222773ee	se	NES	NES	extracted	-	 -	e781230da44a44e2f0770edb2b3b3633	en	Amiga	-	V2	-	dhewg, Andrea Petrucci -	ce7733f185b838e248927c7ba1a04204	fr	Amiga	-	V2	-	Tobias Fleischer -	9bc548e179cdb0767009401c094d0895	de	Amiga	-	V2	-	Norbert Lange -	a570381b028972d891052ee1e51dc011	en	Atari	-	V2	-	Andreas Bylund -	dd30a53035393baa5a5e222e716559af	fr	Atari	-	V2	-	Andreas Bylund -	be83e882b44f2767bc08d4f766ebc347	de	Atari	-	V2	-	Joachim Eberhard -	15240c59d3681ed53f714f8d925cb2d6	es	Atari	-	V2	-	VooD -	624cdb93654667c869d204a64af7e57f	en	DOS	-	V2	-	Kirben, Andrea Petrucci -	b250d0f9cc83f80ced56fe11a4fb057c	en	DOS	-	V2	alt?	Andrea Petrucci -	114acdc2659a273c220f86ee9edb24c1	fr	DOS	-	V2	-	Nicolas Sauzède -	99a3699f80b8f776efae592b44b9b991	fr	DOS	-	V2	from DOTT	Nicolas Sauzède, Andrea Petrucci -	183d7464902d40d00800e8ee1f04117c	de	DOS	-	V2	-	 -	87f6e8037b7cc996e13474b491a7a98e	it	DOS	-	V2	from DOTT	Andrea Petrucci -	0d1b69471605201ef2fa9cec1f5f02d2	es	DOS	-	V2	-	abnog, Andrea Petrucci - -	40564ec47da48a67787d1f9bd043902a	en	DOS	-	Demo	non-interactive	 +	e781230da44a44e2f0770edb2b3b3633	en	Amiga	V2	V2	-	dhewg, Andrea Petrucci +	ce7733f185b838e248927c7ba1a04204	fr	Amiga	V2	V2	-	Tobias Fleischer +	9bc548e179cdb0767009401c094d0895	de	Amiga	V2	V2	-	Norbert Lange +	a570381b028972d891052ee1e51dc011	en	Atari	V2	V2	-	Andreas Bylund +	dd30a53035393baa5a5e222e716559af	fr	Atari	V2	V2	-	Andreas Bylund +	be83e882b44f2767bc08d4f766ebc347	de	Atari	V2	V2	-	Joachim Eberhard +	15240c59d3681ed53f714f8d925cb2d6	es	Atari	V2	V2	-	VooD +	624cdb93654667c869d204a64af7e57f	en	DOS	V2	V2	-	Kirben, Andrea Petrucci +	b250d0f9cc83f80ced56fe11a4fb057c	en	DOS	V2	V2	alt?	Andrea Petrucci +	114acdc2659a273c220f86ee9edb24c1	fr	DOS	V2	V2	-	Nicolas Sauzède +	99a3699f80b8f776efae592b44b9b991	fr	DOS	V2	V2	from DOTT	Nicolas Sauzède, Andrea Petrucci +	183d7464902d40d00800e8ee1f04117c	de	DOS	V2	V2	-	 +	87f6e8037b7cc996e13474b491a7a98e	it	DOS	V2	V2	from DOTT	Andrea Petrucci +	0d1b69471605201ef2fa9cec1f5f02d2	es	DOS	V2	V2	-	abnog, Andrea Petrucci + +	40564ec47da48a67787d1f9bd043902a	en	DOS	Demo	Demo	non-interactive	  zak	Zak McKracken and the Alien Mindbenders -	55d3987641bf229c83bc729210173383	en	C64	-	-	-	 -	4973bbc3899e3826dbf316e1d7271ec7	de	C64	-	-	-	 +	55d3987641bf229c83bc729210173383	en	C64	V1	-	-	 +	4973bbc3899e3826dbf316e1d7271ec7	de	C64	V1	-	-	  	7020931d5a2be0a49d68e7a1882363e4	en	DOS	V1	V1	-	  	b23f7cd7c304d7dff08e92a96120d5b4	en	DOS	V1	V1	alt?	Andrea Petrucci -	e94c7cc3686fce406d3c91b5eae5a72d	en	Amiga	-	V2	-	dhweg -	91469353f7be1b122fa88d23480a1320	fr	Amiga	-	V2	-	Tobias Fleischer -	6027e9ca9c35746d95dee2068cec17e5	de	Amiga	-	V2	-	Norbert Lange -	27b3a4224ad63d5b04627595c1c1a025	it	Amiga	-	V2	-	Andrea Petrucci -	d55eff37c2100f5065cde9de428621fa	en	Atari	-	V2	-	 -	613f64f78ea26c7353b2a5940eb61d6a	fr	Atari	-	V2	-	Andreas Bylund -	ff05c07990061d97647f059c48c1d05a	de	Atari	-	V2	-	 -	675d71151e9b5a968c8ce46d9fbf4cbf	en	DOS	-	V2	-	Kirben -	debe337f73d660e951ece7c1f1c81add	en	DOS	-	V2	alt?	Andrea Petrucci -	52a4bae0746a11d7b1e8554e91a6645c	fr	DOS	-	V2	-	Andrea Petrucci -	c4787c3e8b5e2dfda90850ee800af00f	fr	DOS	-	V2	alt?	Qvist -	cdd760228cf1010c2903f37e788ea31c	de	DOS	-	V2	-	Max Horn -	d06fbe28818fef7bfc45c2cdf0c0849d	de	DOS	-	V2	from 5.25\" floppies	Nicolas Sauzède, Andrea Petrucci -	1900e501a52fbf55bde6e4196f6d2aa6	it	DOS	-	V2	-	Andrea Petrucci -	75ba23fff4fd63fa446c02864f2a5a4b	it	DOS	-	V2	alt?	Antti Leimi, Andrea Petrucci +	e94c7cc3686fce406d3c91b5eae5a72d	en	Amiga	V2	V2	-	dhweg +	91469353f7be1b122fa88d23480a1320	fr	Amiga	V2	V2	-	Tobias Fleischer +	6027e9ca9c35746d95dee2068cec17e5	de	Amiga	V2	V2	-	Norbert Lange +	27b3a4224ad63d5b04627595c1c1a025	it	Amiga	V2	V2	-	Andrea Petrucci +	d55eff37c2100f5065cde9de428621fa	en	Atari	V2	V2	-	 +	613f64f78ea26c7353b2a5940eb61d6a	fr	Atari	V2	V2	-	Andreas Bylund +	ff05c07990061d97647f059c48c1d05a	de	Atari	V2	V2	-	 +	675d71151e9b5a968c8ce46d9fbf4cbf	en	DOS	V2	V2	-	Kirben +	debe337f73d660e951ece7c1f1c81add	en	DOS	V2	V2	alt?	Andrea Petrucci +	52a4bae0746a11d7b1e8554e91a6645c	fr	DOS	V2	V2	-	Andrea Petrucci +	c4787c3e8b5e2dfda90850ee800af00f	fr	DOS	V2	V2	alt?	Qvist +	cdd760228cf1010c2903f37e788ea31c	de	DOS	V2	V2	-	Max Horn +	d06fbe28818fef7bfc45c2cdf0c0849d	de	DOS	V2	V2	from 5.25\" floppies	Nicolas Sauzède, Andrea Petrucci +	1900e501a52fbf55bde6e4196f6d2aa6	it	DOS	V2	V2	-	Andrea Petrucci +	75ba23fff4fd63fa446c02864f2a5a4b	it	DOS	V2	V2	alt?	Antti Leimi, Andrea Petrucci  	2d4536a56e01da4b02eb021e7770afa2	en	FM-TOWNS	FM-TOWNS	-	-	  	1ca86e2cf9aaa2068738a1e5ba477e60	jp	FM-TOWNS	FM-TOWNS	-	-	Andrea Petrucci -	8299d9b8a1b0e7b881bae7a9971dc5e2	en	Atari	-	Demo	non-interactive	 +	8299d9b8a1b0e7b881bae7a9971dc5e2	en	Atari	V2	Demo	non-interactive	  indy3	Indiana Jones and the Last Crusade  	9c0fee288ad564a7d25ec3e841810d79	en	Amiga	EGA	EGA	-	dhewg @@ -311,10 +311,10 @@ dig	The Dig  	cd9c05e755d7bf8e9b9590ad1ebe273e	en	Mac	Demo	Demo	Mac bundle	fingolfin  comi	The Curse of Monkey Island -	fe60d6b5ff51b0553ac59963123b5777	All	All	-	-	-	 -	861e59ed72a1cd0e6d454f7ee7e2bf3d	ru	All	-	-	-	 +	fe60d6b5ff51b0553ac59963123b5777	All	Windows	-	-	-	 +	861e59ed72a1cd0e6d454f7ee7e2bf3d	ru	Windows	-	-	-	 -	8fec68383202d38c0d25e9e3b757c5df	All	All	Demo	Demo	-	 +	8fec68383202d38c0d25e9e3b757c5df	All	Windows	Demo	Demo	-	  baseball	Backyard Baseball  	cf8d13446ec6cb6222287a925fd47c1d	en	All	-	-	-	sev  | 
