Example #1
0
bool GlulxeMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
	const char *const EXTENSIONS[3] = { ".ulx", ".blb", ".gblorb" };

	// Loop through the files of the folder
	for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
		// Check for a recognised filename
		if (file->isDirectory())
			continue;
		Common::String filename = file->getName();
		bool hasExt = false;
		for (int idx = 0; idx < 3 && !hasExt; ++idx)
			hasExt = filename.hasSuffixIgnoreCase(EXTENSIONS[idx]);
		if (!hasExt)
			continue;

		// Open up the file and calculate the md5
		Common::File gameFile;
		if (!gameFile.open(*file))
			continue;
		Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000);
		size_t filesize = gameFile.size();
		gameFile.close();

		// Check for known games
		const GlulxeGameDescription *p = GLULXE_GAMES;
		while (p->_gameId && (md5 != p->_md5 || filesize != p->_filesize))
			++p;

		DetectedGame gd;
		if (!p->_gameId) {
			if (filename.hasSuffixIgnoreCase(".blb"))
				continue;

			if (gDebugLevel > 0) {
				// Print an entry suitable for putting into the detection_tables.h, using the
				// name of the parent folder the game is in as the presumed game Id
				Common::String folderName = file->getParent().getName();
				if (folderName.hasSuffix("\\"))
					folderName.deleteLastChar();
				Common::String fname = filename;
				const char *dot = strchr(fname.c_str(), '.');
				if (dot)
					fname = Common::String(fname.c_str(), dot);

				debug("ENTRY0(\"%s\", \"%s\", %u),", fname.c_str(), md5.c_str(), (uint)filesize);
			}
			const PlainGameDescriptor &desc = GLULXE_GAME_LIST[0];
			gd = DetectedGame(desc.gameId, desc.description, Common::UNK_LANG, Common::kPlatformUnknown);
		} else {
			PlainGameDescriptor gameDesc = findGame(p->_gameId);
			gd = DetectedGame(p->_gameId, gameDesc.description, p->_language, Common::kPlatformUnknown, p->_extra);
			gd.setGUIOptions(GUIO4(GUIO_NOSPEECH, GUIO_NOSFX, GUIO_NOMUSIC, GUIO_NOSUBTITLES));
		}

		gd.addExtraEntry("filename", filename);
		gameList.push_back(gd);
	}

	return !gameList.empty();
}
Example #2
0
namespace Groovie {

#define GAMEOPTION_T7G_FAST_MOVIE_SPEED  GUIO_GAMEOPTIONS1

static const PlainGameDescriptor groovieGames[] = {
    // Games
    {"t7g", "The 7th Guest"},

#ifdef ENABLE_GROOVIE2
    {"11h", "The 11th Hour: The Sequel to The 7th Guest"},
    {"clandestiny", "Clandestiny"},
    {"unclehenry", "Uncle Henry's Playhouse"},
    {"tlc", "Tender Loving Care"},
#endif

    {0, 0}
};

static const GroovieGameDescription gameDescriptions[] = {

    // The 7th Guest DOS English
    {
        {
            "t7g", "",
            AD_ENTRY1s("script.grv", "d1b8033b40aa67c076039881eccce90d", 16659),
            Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS,
            GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED)
        },
        kGroovieT7G, 0
    },

    // The 7th Guest Mac English
    {
        {
            "t7g", "",
            AD_ENTRY1s("T7GMac", "acdc4a58dd3f007f65e99b99d78e0bce", 1814029),
            Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK,
            GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED)
        },
        kGroovieT7G, 0
    },

#if 0
    // These entries should now be identical to the first T7G Mac entry after
    // changing the app to only use the data part of the resource fork. They
    // are left disabled here as a reference.

    // The 7th Guest Mac English (Aztec single disc)
    {
        {
            "t7g", "",
            AD_ENTRY1s("T7GMac", "6bdee8d0f9eef6d58d02fcd7deec3fb2", 1830783),
            Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK,
            GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED)
        },
        kGroovieT7G, 0
    },

    // The 7th Guest Mac English (Aztec bundle, provided by Thefinaleofseem)
    {
        {
            "t7g", "",
            AD_ENTRY1s("T7GMac", "0d595d4b44ae1814082938d051e5174e", 1830783),
            Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK,
            GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED)
        },
        kGroovieT7G, 0
    },
#endif

    // The 7th Guest DOS Russian (Akella)
    {
        {
            "t7g", "",
            {
                { "script.grv", 0, "d1b8033b40aa67c076039881eccce90d", 16659},
                { "intro.gjd", 0, NULL, 31711554},
                { NULL, 0, NULL, 0}
            },
            Common::RU_RUS, Common::kPlatformDOS, ADGF_NO_FLAGS,
            GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED)
        },
        kGroovieT7G, 0
    },

    {
        {
            "t7g", "",
            {
                { "script.grv", 0, "d1b8033b40aa67c076039881eccce90d", 16659},
                { "SeventhGuest", 0, NULL, -1},
                { NULL, 0, NULL, 0}
            },
            Common::EN_ANY, Common::kPlatformIOS, ADGF_NO_FLAGS,
            GUIO3(GUIO_NOMIDI, GUIO_NOASPECT, GAMEOPTION_T7G_FAST_MOVIE_SPEED)
        },
        kGroovieT7G, 0
    },

#ifdef ENABLE_GROOVIE2
    // The 11th Hour DOS English
    {
        {
            "11h", "",
            AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227),
            Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE,
            GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT)
        },
        kGroovieV2, 1
    },

    // The 11th Hour Macintosh English
    {
        {
            "11h", "",
            {
                { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 },
                { "The 11th Hour Installer", 0, "bcdb4040b27f15b18f39fb9e496d384a", 1002987 },
                { 0, 0, 0, 0 }
            },
            Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE,
            GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT)
        },
        kGroovieV2, 1
    },

    // The 11th Hour Macintosh English (Installed)
    {
        {
            "11h", "Installed",
            {
                { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 },
                { "el01.mov", 0, "70f42dfc25b1488a08011dc45bb5145d", 6039 },
                { 0, 0, 0, 0 }
            },
            Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE,
            GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT)
        },
        kGroovieV2, 1
    },

    // The 11th Hour DOS Demo English
    {
        {
            "11h", "Demo",
            AD_ENTRY1s("disk.1", "aacb32ce07e0df2894bd83a3dee40c12", 70),
            Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE,
            GUIO5(GUIO_NOLAUNCHLOAD, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT)
        },
        kGroovieV2, 1
    },

    // The Making of The 11th Hour DOS English
    {
        {
            "11h", "Making Of",
            AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227),
            Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE,
            GUIO3(GUIO_NOMIDI, GUIO_NOLAUNCHLOAD, GUIO_NOASPECT)
        },
        kGroovieV2, 2
    },

    // The Making of The 11th Hour Macintosh English
    {
        {
            "11h", "Making Of",
            {
                { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 },
                { "The 11th Hour Installer", 0, "bcdb4040b27f15b18f39fb9e496d384a", 1002987 },
                { 0, 0, 0, 0 }
            },
            Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE,
            GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT)
        },
        kGroovieV2, 2
    },

    // The Making of The 11th Hour Macintosh English (Installed)
    {
        {
            "11h", "Making Of (Installed)",
            {
                { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 },
                { "el01.mov", 0, "70f42dfc25b1488a08011dc45bb5145d", 6039 },
                { 0, 0, 0, 0 }
            },
            Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE,
            GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT)
        },
        kGroovieV2, 2
    },

    // Clandestiny Trailer DOS English
    {
        {
            "clandestiny", "Trailer",
            AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227),
            Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE,
            GUIO3(GUIO_NOMIDI, GUIO_NOLAUNCHLOAD, GUIO_NOASPECT)
        },
        kGroovieV2, 3
    },

    // Clandestiny Trailer Macintosh English
    {
        {
            "clandestiny", "Trailer",
            {
                { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 },
                { "The 11th Hour Installer", 0, "bcdb4040b27f15b18f39fb9e496d384a", 1002987 },
                { 0, 0, 0, 0 }
            },
            Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE,
            GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT)
        },
        kGroovieV2, 3
    },

    // Clandestiny Trailer Macintosh English (Installed)
    {
        {
            "clandestiny", "Trailer (Installed)",
            {
                { "disk.1", 0, "5c0428cd3659fc7bbcd0aa16485ed5da", 227 },
                { "el01.mov", 0, "70f42dfc25b1488a08011dc45bb5145d", 6039 },
                { 0, 0, 0, 0 }
            },
            Common::EN_ANY, Common::kPlatformMacintosh, ADGF_UNSTABLE,
            GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_NOASPECT)
        },
        kGroovieV2, 3
    },

    // Clandestiny DOS English
    {
        {
            "clandestiny", "",
            AD_ENTRY1s("disk.1", "f79fc1515174540fef6a34132efc4c53", 76),
            Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE,
            GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)
        },
        kGroovieV2, 1
    },

    // Uncle Henry's Playhouse PC English
    {
        {
            "unclehenry", "",
            AD_ENTRY1s("disk.1", "0e1b1d3cecc4fc7efa62a968844d1f7a", 72),
            Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE,
            GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)
        },
        kGroovieV2, 1
    },

    // Tender Loving Care PC English
    {
        {
            "tlc", "",
            AD_ENTRY1s("disk.1", "32a1afa68478f1f9d2b25eeea427f2e3", 84),
            Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE,
            GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)
        },
        kGroovieV2, 1
    },
#endif

    {AD_TABLE_END_MARKER, kGroovieT7G, 0}
};

static const char *directoryGlobs[] = {
    "MIDI",
    0
};

static const ADExtraGuiOptionsMap optionsList[] = {
    {
        GAMEOPTION_T7G_FAST_MOVIE_SPEED,
        {
            _s("Fast movie speed"),
            _s("Play movies at an increased speed"),
            "fast_movie_speed",
            false
        }
    },

    AD_EXTRA_GUI_OPTIONS_TERMINATOR
};

class GroovieMetaEngine : public AdvancedMetaEngine {
public:
    GroovieMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(GroovieGameDescription), groovieGames, optionsList) {
        // Use kADFlagUseExtraAsHint in order to distinguish the 11th hour from
        // its "Making of" as well as the Clandestiny Trailer; they all share
        // the same MD5.
        // TODO: Is this the only reason, or are there others (like the three
        // potentially sharing a single directory) ? In the former case, then
        // perhaps a better solution would be to add additional files
        // to the detection entries. In the latter case, this TODO should be
        // replaced with an according explanation.
        _flags = kADFlagUseExtraAsHint;
        _guioptions = GUIO3(GUIO_NOSUBTITLES, GUIO_NOSFX, GUIO_NOASPECT);

        // Need MIDI directory to detect 11H Mac Installed
        _maxScanDepth = 2;
        _directoryGlobs = directoryGlobs;
    }

    const char *getEngineID() const {
        return "groovie";
    }

    const char *getName() const {
        return "Groovie";
    }

    const char *getOriginalCopyright() const {
        return "Groovie Engine (C) 1990-1996 Trilobyte";
    }

    bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;

    bool hasFeature(MetaEngineFeature f) const;
    SaveStateList listSaves(const char *target) const;
    int getMaximumSaveSlot() const;
    void removeSaveState(const char *target, int slot) const;
    SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
};

bool GroovieMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const {
    if (gd) {
        *engine = new GroovieEngine(syst, (const GroovieGameDescription *)gd);
    }
    return gd != 0;
}

bool GroovieMetaEngine::hasFeature(MetaEngineFeature f) const {
    return
        (f == kSupportsListSaves) ||
        (f == kSupportsLoadingDuringStartup) ||
        (f == kSupportsDeleteSave) ||
        (f == kSavesSupportMetaInfo);
}

SaveStateList GroovieMetaEngine::listSaves(const char *target) const {
    return SaveLoad::listValidSaves(target);
}

int GroovieMetaEngine::getMaximumSaveSlot() const {
    return SaveLoad::getMaximumSlot();
}

void GroovieMetaEngine::removeSaveState(const char *target, int slot) const {
    if (!SaveLoad::isSlotValid(slot)) {
        // Invalid slot, do nothing
        return;
    }

    Common::String filename = SaveLoad::getSlotSaveName(target, slot);
    g_system->getSavefileManager()->removeSavefile(filename);
}

SaveStateDescriptor GroovieMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
    SaveStateDescriptor desc;

    Common::InSaveFile *savefile = SaveLoad::openForLoading(target, slot, &desc);
    delete savefile;

    return desc;
}

} // End of namespace Groovie
Example #3
0
const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
	bool foundResMap = false;
	bool foundRes000 = false;

	// Set some defaults
	s_fallbackDesc.extra = "";
	s_fallbackDesc.language = Common::EN_ANY;
	s_fallbackDesc.flags = ADGF_NO_FLAGS;
	s_fallbackDesc.platform = Common::kPlatformPC;	// default to PC platform
	s_fallbackDesc.gameid = "sci";
	s_fallbackDesc.guioptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);

	if (allFiles.contains("resource.map") || allFiles.contains("Data1")
	    || allFiles.contains("resmap.001") || allFiles.contains("resmap.001")) {
		foundResMap = true;
	}

	// Determine if we got a CD version and set the CD flag accordingly, by checking for
	// resource.aud for SCI1.1 CD games, or audio001.002 for SCI1 CD games. We assume that
	// the file should be over 10MB, as it contains all the game speech and is usually
	// around 450MB+. The size check is for some floppy game versions like KQ6 floppy, which
	// also have a small resource.aud file
	if (allFiles.contains("resource.aud") || allFiles.contains("audio001.002")) {
		Common::FSNode file = allFiles.contains("resource.aud") ? allFiles["resource.aud"] :  allFiles["audio001.002"];
		Common::SeekableReadStream *tmpStream = file.createReadStream();
		if (tmpStream->size() > 10 * 1024 * 1024) {
			// We got a CD version, so set the CD flag accordingly
			s_fallbackDesc.flags |= ADGF_CD;
		}
		delete tmpStream;
	}

	if (allFiles.contains("resource.000") || allFiles.contains("resource.001")
		|| allFiles.contains("ressci.000") || allFiles.contains("ressci.001"))
		foundRes000 = true;

	// Data1 contains both map and volume for SCI1.1+ Mac games
	if (allFiles.contains("Data1")) {
		foundResMap = foundRes000 = true;
		 s_fallbackDesc.platform = Common::kPlatformMacintosh;
	}

	// Determine the game platform
	// The existence of any of these files indicates an Amiga game
	if (allFiles.contains("9.pat") || allFiles.contains("spal") ||
		allFiles.contains("patch.005") || allFiles.contains("bank.001"))
			s_fallbackDesc.platform = Common::kPlatformAmiga;

	// The existence of 7.pat or patch.200 indicates a Mac game
	if (allFiles.contains("7.pat") || allFiles.contains("patch.200"))
		s_fallbackDesc.platform = Common::kPlatformMacintosh;

	// The data files for Atari ST versions are the same as their DOS counterparts


	// If these files aren't found, it can't be SCI
	if (!foundResMap && !foundRes000) {
		return 0;
	}

	ResourceManager resMan;
	resMan.addAppropriateSources(fslist);
	resMan.init(true);
	// TODO: Add error handling.

#ifndef ENABLE_SCI32
	// Is SCI32 compiled in? If not, and this is a SCI32 game,
	// stop here
	if (getSciVersion() >= SCI_VERSION_2) {
		return (const ADGameDescription *)&s_fallbackDesc;
	}
#endif

	ViewType gameViews = resMan.getViewType();

	// Have we identified the game views? If not, stop here
	// Can't be SCI (or unsupported SCI views). Pinball Creep by sierra also uses resource.map/resource.000 files
	//  but doesnt share sci format at all, if we dont return 0 here we will detect this game as SCI
	if (gameViews == kViewUnknown) {
		return 0;
	}

	// Set the platform to Amiga if the game is using Amiga views
	if (gameViews == kViewAmiga)
		s_fallbackDesc.platform = Common::kPlatformAmiga;

	// Determine the game id
	Common::String sierraGameId = resMan.findSierraGameId();

	// If we don't have a game id, the game is not SCI
	if (sierraGameId.empty()) {
		return 0;
	}

	Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
	strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
	s_fallbackGameIdBuf[sizeof(s_fallbackGameIdBuf) - 1] = 0;	// Make sure string is NULL terminated
	s_fallbackDesc.gameid = s_fallbackGameIdBuf;

	// Try to determine the game language
	// Load up text 0 and start looking for "#" characters
	// Non-English versions contain strings like XXXX#YZZZZ
	// Where XXXX is the English string, #Y a separator indicating the language
	// (e.g. #G for German) and ZZZZ is the translated text
	// NOTE: This doesn't work for games which use message instead of text resources
	// (like, for example, Eco Quest 1 and all SCI1.1 games and newer, e.g. Freddy Pharkas).
	// As far as we know, these games store the messages of each language in separate
	// resources, and it's not possible to detect that easily
	// Also look for "%J" which is used in japanese games
	Resource *text = resMan.findResource(ResourceId(kResourceTypeText, 0), 0);
	uint seeker = 0;
	if (text) {
		while (seeker < text->size) {
			if (text->data[seeker] == '#')  {
				if (seeker + 1 < text->size)
					s_fallbackDesc.language = charToScummVMLanguage(text->data[seeker + 1]);
				break;
			}
			if (text->data[seeker] == '%') {
				if ((seeker + 1 < text->size) && (text->data[seeker + 1] == 'J')) {
					s_fallbackDesc.language = charToScummVMLanguage(text->data[seeker + 1]);
					break;
				}
			}
			seeker++;
		}
	}


	// Fill in "extra" field

	// Is this an EGA version that might have a VGA pendant? Then we want
	// to mark it as such in the "extra" field.
	const bool markAsEGA = (gameViews == kViewEga && s_fallbackDesc.platform != Common::kPlatformAmiga
			&& getSciVersion() > SCI_VERSION_1_EGA_ONLY);

	const bool isDemo = (s_fallbackDesc.flags & ADGF_DEMO);
	const bool isCD = (s_fallbackDesc.flags & ADGF_CD);

	if (!isCD)
		s_fallbackDesc.guioptions = GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);

	if (gameId.hasSuffix("sci")) {
		s_fallbackDesc.extra = "SCI";

		// Differentiate EGA versions from the VGA ones, where needed
		if (markAsEGA)
			s_fallbackDesc.extra = "SCI/EGA";

		// Mark as demo.
		// Note: This overwrites the 'EGA' info, if it was previously set.
		if (isDemo)
			s_fallbackDesc.extra = "SCI/Demo";
	} else {
		if (markAsEGA)
			s_fallbackDesc.extra = "EGA";

		// Set "CD" and "Demo" as appropriate.
		// Note: This overwrites the 'EGA' info, if it was previously set.
		if (isDemo && isCD)
			s_fallbackDesc.extra = "CD Demo";
		else if (isDemo)
			s_fallbackDesc.extra = "Demo";
		else if (isCD)
			s_fallbackDesc.extra = "CD";
	}

	return &s_fallbackDesc;
}