[Scummvm-cvs-logs] SF.net SVN: scummvm:[40141] scummvm/trunk/engines/tinsel

dreammaster at users.sourceforge.net dreammaster at users.sourceforge.net
Sat Apr 25 08:42:01 CEST 2009


Revision: 40141
          http://scummvm.svn.sourceforge.net/scummvm/?rev=40141&view=rev
Author:   dreammaster
Date:     2009-04-25 06:42:01 +0000 (Sat, 25 Apr 2009)

Log Message:
-----------
Added code to enable Discworld 2 to play directly from the CD (only the first CD - Cd swap still doesn't work) or from files copied to the hard disk without the .smp/txt/idx files being properly renamed (again only for the first Cd).

Modified Paths:
--------------
    scummvm/trunk/engines/tinsel/detection.cpp
    scummvm/trunk/engines/tinsel/drives.cpp
    scummvm/trunk/engines/tinsel/drives.h
    scummvm/trunk/engines/tinsel/handle.cpp
    scummvm/trunk/engines/tinsel/sound.cpp
    scummvm/trunk/engines/tinsel/sound.h
    scummvm/trunk/engines/tinsel/strres.cpp
    scummvm/trunk/engines/tinsel/tinsel.cpp

Modified: scummvm/trunk/engines/tinsel/detection.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/detection.cpp	2009-04-25 06:36:20 UTC (rev 40140)
+++ scummvm/trunk/engines/tinsel/detection.cpp	2009-04-25 06:42:01 UTC (rev 40141)
@@ -27,6 +27,7 @@
 
 #include "engines/advancedDetector.h"
 #include "common/file.h"
+#include "common/md5.h"
 #include "common/savefile.h"
 
 #include "tinsel/cursor.h"
@@ -475,6 +476,7 @@
 	}
 
 	virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+	const ADGameDescription *fallbackDetect(const Common::FSList &fslist) const;
 
 	virtual bool hasFeature(MetaEngineFeature f) const;
 	virtual SaveStateList listSaves(const char *target) const;
@@ -542,6 +544,162 @@
 	return gd != 0;
 }
 
+struct SizeMD5 {
+	int size;
+	char md5[32+1];
+};
+typedef Common::HashMap<Common::String, SizeMD5, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SizeMD5Map;
+typedef Common::HashMap<Common::String, Common::FSNode, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
+typedef Common::Array<const ADGameDescription*> ADGameDescList;
+
+/**
+ * Fallback detection scans the list of Discworld 2 targets to see if it can detect an installation
+ * where the files haven't been renamed (i.e. don't have the '1' just before the extension)
+ */
+const ADGameDescription *TinselMetaEngine::fallbackDetect(const Common::FSList &fslist) const {
+	Common::String extra;
+	FileMap allFiles;
+	SizeMD5Map filesSizeMD5;
+
+	const ADGameFileDescription *fileDesc;
+	const Tinsel::TinselGameDescription *g;
+
+	if (fslist.empty())
+		return NULL;
+
+	// First we compose a hashmap of all files in fslist.
+	// Includes nifty stuff like removing trailing dots and ignoring case.
+	for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+		if (file->isDirectory()) {
+			if (!scumm_stricmp(file->getName().c_str(), "dw2")) {
+				// Probably Discworld 2 subfolder on CD, so add it's contents as well
+				Common::FSList files;
+				if (file->getChildren(files, Common::FSNode::kListAll)) {
+					Common::FSList::const_iterator file2;
+					for (file2 = files.begin(); file2 != files.end(); ++file2) {
+						if (file2->isDirectory())
+							continue;
+
+						Common::String fname = file2->getName();
+						allFiles[fname] = *file2;
+					}
+				}
+			}
+			continue;
+		}
+
+		Common::String tstr = file->getName();
+
+		allFiles[tstr] = *file;	// Record the presence of this file
+	}
+
+	// Check which files are included in some dw2 ADGameDescription *and* present
+	// in fslist without a '1' suffix character. Compute MD5s and file sizes for these files.
+	for (g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) {
+		if (strcmp(g->desc.gameid, "dw2") != 0)
+			continue;
+
+		for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) {
+			// Get the next filename, stripping off any '1' suffix character
+			char tempFilename[50];
+			strcpy(tempFilename, fileDesc->fileName);
+			char *pOne = strchr(tempFilename, '1');
+			if (pOne) strcpy(pOne, pOne + 1);
+
+			Common::String fname(tempFilename);
+			if (allFiles.contains(fname) && !filesSizeMD5.contains(fname)) {
+				SizeMD5 tmp;
+				if (!md5_file_string(allFiles[fname], tmp.md5, detectionParams.md5Bytes))
+					tmp.md5[0] = 0;
+
+				Common::File testFile;
+				if (testFile.open(allFiles[fname]))
+					tmp.size = (int32)testFile.size();
+				else
+					tmp.size = -1;
+
+				filesSizeMD5[fname] = tmp;
+			}
+		}
+	}
+
+	ADGameDescList matched;
+	int maxFilesMatched = 0;
+	bool gotAnyMatchesWithAllFiles = false;
+
+	// MD5 based matching
+	uint i;
+	for (i = 0, g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) {
+		if (strcmp(g->desc.gameid, "dw2") != 0)
+			continue;
+
+		bool fileMissing = false;
+
+		if ((detectionParams.flags & kADFlagUseExtraAsHint) && !extra.empty() && g->desc.extra != extra)
+			continue;
+
+		bool allFilesPresent = true;
+
+		// Try to match all files for this game
+		for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) {
+			// Get the next filename, stripping off any '1' suffix character
+			char tempFilename[50];
+			strcpy(tempFilename, fileDesc->fileName);
+			char *pOne = strchr(tempFilename, '1');
+			if (pOne) strcpy(pOne, pOne + 1);
+
+			Common::String tstr(tempFilename);
+
+			if (!filesSizeMD5.contains(tstr)) {
+				fileMissing = true;
+				allFilesPresent = false;
+				break;
+			}
+
+			if (fileDesc->md5 != NULL && 0 != strcmp(fileDesc->md5, filesSizeMD5[tstr].md5)) {
+				fileMissing = true;
+				break;
+			}
+
+			if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesSizeMD5[tstr].size) {
+				fileMissing = true;
+				break;
+			}
+		}
+
+		if (allFilesPresent)
+			gotAnyMatchesWithAllFiles = true;
+
+		if (!fileMissing) {
+			// Count the number of matching files. Then, only keep those
+			// entries which match a maximal amount of files.
+			int curFilesMatched = 0;
+			for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++)
+				curFilesMatched++;
+
+			if (curFilesMatched > maxFilesMatched) {
+				maxFilesMatched = curFilesMatched;
+
+				for (uint j = 0; j < matched.size();) {
+					if (matched[j]->flags & ADGF_KEEPMATCH)
+						 ++j;
+					else
+						matched.remove_at(j);
+				}
+				matched.push_back((const ADGameDescription *)g);
+			} else if (curFilesMatched == maxFilesMatched) {
+				matched.push_back((const ADGameDescription *)g);
+			}
+		}
+	}
+
+	// We didn't find a match
+	if (matched.empty())
+		return NULL;
+
+	return *matched.begin();
+}
+
 int TinselMetaEngine::getMaximumSaveSlot() const { return 99; }
 
 void TinselMetaEngine::removeSaveState(const char *target, int slot) const {

Modified: scummvm/trunk/engines/tinsel/drives.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/drives.cpp	2009-04-25 06:36:20 UTC (rev 40140)
+++ scummvm/trunk/engines/tinsel/drives.cpp	2009-04-25 06:42:01 UTC (rev 40141)
@@ -24,6 +24,7 @@
  * CD/drive handling functions
  */
 
+#include "gui/message.h"
 #include "tinsel/drives.h"
 #include "tinsel/scene.h"
 #include "tinsel/tinsel.h"
@@ -32,7 +33,7 @@
 
 namespace Tinsel {
 
-static char currentCD = '1';
+char currentCD = '1';
 static uint32 cdFlags[] = { fCd1, fCd2, fCd3, fCd4, fCd5, fCd6, fCd7, fCd8 };
 
 static bool bChangingCD = false;
@@ -93,9 +94,29 @@
 	return cd;
 }
 
+static uint32 lastTime = 0;
+extern LANGUAGE sampleLanguage;
+
 void DoCdChange(void) {
-	if (bChangingCD) {
+	if (bChangingCD && (g_system->getMillis() > (lastTime + 1000))) {
+		lastTime = g_system->getMillis();
 		_vm->_sound->closeSampleStream();
+
+		// Use the filesize of the sample file to determine, for Discworld 2, which CD it is
+		if (TinselV2) {
+			TinselFile f;
+			if (!f.open(_vm->getSampleFile(sampleLanguage)))
+				// No CD present
+				return;
+
+			char sampleCdNumber = (f.size() >= (200 * 1024 * 1024)) ? '1' : '2';
+
+			f.close();
+
+			if (currentCD != sampleCdNumber)
+				return;
+		}
+
 		_vm->_sound->openSampleFiles();
 		ChangeLanguage(TextLanguage());
 		bChangingCD = false;
@@ -126,4 +147,33 @@
 	return true;
 }
 
+bool TinselFile::_warningShown = false;
+
+bool TinselFile::open(const Common::String &filename) {
+	if (Common::File::open(filename)) {
+		// If it's the sample file, strip off the CD number from the filename
+
+
+		return true;
+	}
+
+	if (!TinselV2)
+		return false;
+
+	// Check if the file being requested is the *1.* or *2.* files
+	const char *fname = filename.c_str();
+	const char *p = strchr(fname, '1');
+	if (!p)
+		p = strchr(fname, '2');
+	if (!p || (*(p + 1) != '.'))
+		return false;
+
+	// Form a filename without the CD number character
+	char newFilename[50];
+	strncpy(newFilename, fname, p - fname);
+	strcpy(newFilename + (p - fname), p + 1);
+
+	return Common::File::open(newFilename);
+}
+
 } // end of namespace Tinsel

Modified: scummvm/trunk/engines/tinsel/drives.h
===================================================================
--- scummvm/trunk/engines/tinsel/drives.h	2009-04-25 06:36:20 UTC (rev 40140)
+++ scummvm/trunk/engines/tinsel/drives.h	2009-04-25 06:42:01 UTC (rev 40141)
@@ -27,6 +27,7 @@
 #ifndef TINSEL_DRIVES_H
 #define TINSEL_DRIVES_H
 
+#include "common/file.h"
 #include "tinsel/dw.h"
 #include "tinsel/coroutine.h"
 
@@ -44,6 +45,8 @@
 
 #define fAllCds	(fCd1|fCd2|fCd3|fCd4|fCd5|fCd6|fCd7|fCd8)
 
+extern char currentCD;
+
 void DoCdChange(void);
 
 void CdCD(CORO_PARAM);
@@ -58,6 +61,15 @@
 
 bool GotoCD(void);
 
+class TinselFile: public Common::File {
+private:
+	static bool _warningShown;
+public:
+	virtual bool open(const Common::String &filename);
+	char getCdNumber();
+};
+
+
 } // end of namespace Tinsel
 
 #endif /* TINSEL_DRIVES_H */

Modified: scummvm/trunk/engines/tinsel/handle.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/handle.cpp	2009-04-25 06:36:20 UTC (rev 40140)
+++ scummvm/trunk/engines/tinsel/handle.cpp	2009-04-25 06:42:01 UTC (rev 40141)
@@ -420,6 +420,10 @@
 		if (pH->pNode->pBaseAddr == NULL)
 			error("Out of memory");
 
+		if (TinselV2) {
+			SetCD(pH->flags2 & fAllCds);
+			CdCD(nullContext);
+		}
 		LoadFile(pH, true);
 
 		// make sure address is valid

Modified: scummvm/trunk/engines/tinsel/sound.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/sound.cpp	2009-04-25 06:36:20 UTC (rev 40140)
+++ scummvm/trunk/engines/tinsel/sound.cpp	2009-04-25 06:42:01 UTC (rev 40141)
@@ -399,7 +399,7 @@
 	if (_vm->getFeatures() & GF_FLOPPY || _vm->getFeatures() & GF_DEMO)
 		return;
 
-	Common::File f;
+	TinselFile f;
 
 	if (_sampleIndex)
 		// already allocated

Modified: scummvm/trunk/engines/tinsel/sound.h
===================================================================
--- scummvm/trunk/engines/tinsel/sound.h	2009-04-25 06:36:20 UTC (rev 40140)
+++ scummvm/trunk/engines/tinsel/sound.h	2009-04-25 06:42:01 UTC (rev 40141)
@@ -34,6 +34,7 @@
 
 #include "tinsel/dw.h"
 #include "tinsel/tinsel.h"
+#include "tinsel/drives.h"
 
 namespace Tinsel {
 
@@ -87,7 +88,7 @@
 	long _sampleIndexLen;
 
 	/** file stream for sample file */
-	Common::File _sampleStream;
+	TinselFile _sampleStream;
 
 	bool offscreenChecks(int x, int &y);
 	int8 getPan(int x);

Modified: scummvm/trunk/engines/tinsel/strres.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/strres.cpp	2009-04-25 06:36:20 UTC (rev 40140)
+++ scummvm/trunk/engines/tinsel/strres.cpp	2009-04-25 06:42:01 UTC (rev 40141)
@@ -25,6 +25,7 @@
  */
 
 #include "tinsel/dw.h"
+#include "tinsel/drives.h"
 #include "tinsel/sound.h"
 #include "tinsel/strres.h"
 #include "common/file.h"
@@ -80,7 +81,7 @@
  * @param newLang			The new language
  */
 void ChangeLanguage(LANGUAGE newLang) {
-	Common::File f;
+	TinselFile f;
 	uint32 textLen = 0;	// length of buffer
 
 	textLanguage = newLang;

Modified: scummvm/trunk/engines/tinsel/tinsel.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/tinsel.cpp	2009-04-25 06:36:20 UTC (rev 40140)
+++ scummvm/trunk/engines/tinsel/tinsel.cpp	2009-04-25 06:42:01 UTC (rev 40141)
@@ -862,6 +862,9 @@
 	_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
 	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
 
+	// Add DW2 subfolder to search path in case user is running directly from the CDs
+	Common::File::addDefaultDirectory(_gameDataDir.getChild("dw2"));
+
 	const GameSettings *g;
 
 	const char *gameid = ConfMan.get("gameid").c_str();


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




More information about the Scummvm-git-logs mailing list