Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

const ADGameDescription * AgiMetaEngine::fallbackDetect ( const Common::FSList fslist ) const [virtual]

An (optional) generic fallback detect function which is invoked if both the regular MD5 based detection as well as the file based fallback failed to detect anything.

Reimplemented from AdvancedMetaEngine.

Definition at line 1124 of file detection.cpp.

References Agi::WagFileParser::checkAgiVersionProperty(), Agi::WagFileParser::convertToAgiVersionNumber(), ADGameDescription::flags, Agi::WagProperty::getData(), Agi::WagFileParser::getProperty(), Agi::WagFileParser::parse(), Agi::WagProperty::PC_GAMEDESC, Agi::WagProperty::PC_GAMEID, Agi::WagProperty::PC_GAMELAST, Agi::WagProperty::PC_GAMEVERSION, Agi::WagProperty::PC_INTVERSION, and Common::String::toLowercase().

      typedef Common::HashMap<Common::String, int32> IntMap;
      IntMap allFiles;
      bool matchedUsingFilenames = false;
      bool matchedUsingWag = false;
      int wagFileCount = 0;
      WagFileParser wagFileParser;
      Common::FSNode wagFileNode;
      Common::String description;

      // // Set the defaults for gameid and extra
      _gameid = "agi-fanmade";

      // Set the default values for the fallback descriptor's ADGameDescription part.
      g_fallbackDesc.desc.language = Common::UNK_LANG;
      g_fallbackDesc.desc.platform = Common::kPlatformPC;
      g_fallbackDesc.desc.flags = ADGF_NO_FLAGS;

      // Set default values for the fallback descriptor's AGIGameDescription part.
      g_fallbackDesc.gameID = GID_FANMADE;
      g_fallbackDesc.features = GF_FANMADE;
      g_fallbackDesc.version = 0x2917;

      // First grab all filenames and at the same time count the number of *.wag files
      for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
            if (file->isDirectory()) continue;
            Common::String filename = file->getName();
            allFiles[filename] = true; // Save the filename in a hash table

            if (filename.hasSuffix(".wag")) {
                  // Save latest found *.wag file's path (Can be used to open the file, the name can't)
                  wagFileNode = *file;
                  wagFileCount++; // Count found *.wag files

      if (allFiles.contains("logdir") && allFiles.contains("object") &&
            allFiles.contains("picdir") && allFiles.contains("snddir") &&
            allFiles.contains("viewdir") && allFiles.contains("vol.0") &&
            allFiles.contains("words.tok")) { // Check for v2

            // The default AGI interpreter version 0x2917 is okay for v2 games
            // so we don't have to change it here.
            matchedUsingFilenames = true;

            // Check for AGIPAL by checking for existence of any of the files "pal.100" - "pal.109"
            bool agipal = false;
            char agipalFile[] = "pal.xxx";
            for (uint i = 100; i <= 109; i++) {
                  sprintf(agipalFile, "pal.%d", i);
                  if (allFiles.contains(agipalFile)) {
                        agipal = true; // We found a file "pal.x" where 100 <= x <= 109 so it's AGIPAL

            if (agipal) { // Check if it is AGIPAL
                  description = "Unknown v2 AGIPAL Game";
                  g_fallbackDesc.features |= GF_AGIPAL; // Add AGIPAL feature flag
            } else { // Not AGIPAL so just plain v2
                  description = "Unknown v2 Game";
      } else { // Try v3
            char name[8];

            for (IntMap::const_iterator f = allFiles.begin(); f != allFiles.end(); ++f) {
                  if (f->_key.hasSuffix("vol.0")) {
                        memset(name, 0, 8);
                        strncpy(name, f->_key.c_str(), MIN((uint)8, f->_key.size() > 5 ? f->_key.size() - 5 : f->_key.size()));

                        if (allFiles.contains("object") && allFiles.contains("words.tok") &&
                              allFiles.contains(Common::String(name) + "dir")) {
                              matchedUsingFilenames = true;
                              description = "Unknown v3 Game";
                              g_fallbackDesc.version = 0x3149; // Set the default AGI version for an AGI v3 game

      // WinAGI produces *.wag file with interpreter version, game name and other parameters.
      // If there's exactly one *.wag file and it parses successfully then we'll use its information.
      if (wagFileCount == 1 && wagFileParser.parse(wagFileNode)) {
            matchedUsingWag = true;

            const WagProperty *wagAgiVer = wagFileParser.getProperty(WagProperty::PC_INTVERSION);
            const WagProperty *wagGameID = wagFileParser.getProperty(WagProperty::PC_GAMEID);
            const WagProperty *wagGameDesc = wagFileParser.getProperty(WagProperty::PC_GAMEDESC);
            const WagProperty *wagGameVer = wagFileParser.getProperty(WagProperty::PC_GAMEVERSION);
            const WagProperty *wagGameLastEdit = wagFileParser.getProperty(WagProperty::PC_GAMELAST);

            // If there is an AGI version number in the *.wag file then let's use it
            if (wagAgiVer != NULL && wagFileParser.checkAgiVersionProperty(*wagAgiVer)) {
                  // TODO/FIXME: Check that version number is something we support before trying to use it.
                  //     If the version number is unsupported then it'll get switched to 0x2917 later.
                  //     But there's the possibility that file based detection has detected something else
                  //     than a v2 AGI game. So there's a possibility for conflicting information.
                  g_fallbackDesc.version = wagFileParser.convertToAgiVersionNumber(*wagAgiVer);

            // Set gameid according to *.wag file information if it's present and it doesn't contain whitespace.
            if (wagGameID != NULL && !Common::String(wagGameID->getData()).contains(" ")) {
                  _gameid = wagGameID->getData();
                  debug(3, "Agi::fallbackDetector: Using game id (%s) from WAG file", _gameid.c_str());

            // Set game description and extra according to *.wag file information if they're present
            if (wagGameDesc != NULL) {
                  description = wagGameDesc->getData();
                  debug(3, "Agi::fallbackDetector: Game description (%s) from WAG file", wagGameDesc->getData());

                  // If there's game version in the *.wag file, set extra to it
                  if (wagGameVer != NULL) {
                        _extra = wagGameVer->getData();
                        debug(3, "Agi::fallbackDetector: Game version (%s) from WAG file", wagGameVer->getData());

                  // If there's game last edit date in the *.wag file, add it to extra
                  if (wagGameLastEdit != NULL) {
                        if (!_extra.empty() ) _extra += " ";
                        _extra += wagGameLastEdit->getData();
                        debug(3, "Agi::fallbackDetector: Game's last edit date (%s) from WAG file", wagGameLastEdit->getData());
      } else if (wagFileCount > 1) { // More than one *.wag file, confusing! So let's not use them.
            warning("More than one (%d) *.wag files found. WAG files ignored", wagFileCount);

      // Check that the AGI interpreter version is a supported one
      if (!(g_fallbackDesc.version >= 0x2000 && g_fallbackDesc.version < 0x4000)) {
            warning("Unsupported AGI interpreter version 0x%x in AGI's fallback detection. Using default 0x2917", g_fallbackDesc.version);
            g_fallbackDesc.version = 0x2917;

      // Set game type (v2 or v3) according to the AGI interpreter version number
      if (g_fallbackDesc.version >= 0x2000 && g_fallbackDesc.version < 0x3000)
            g_fallbackDesc.gameType = GType_V2;
      else if (g_fallbackDesc.version >= 0x3000 && g_fallbackDesc.version < 0x4000)
            g_fallbackDesc.gameType = GType_V3;

      // Check if we found a match with any of the fallback methods
      if (matchedUsingWag || matchedUsingFilenames) {
            _extra = description + (!_extra.empty() ? " " : "") + _extra; // Let's combine the description and extra

            // Override the gameid & extra values in g_fallbackDesc.desc. This only works
            // until the fallback detector is called again, and while the MetaEngine instance
            // is alive (as else the string storage is modified/deleted).
            g_fallbackDesc.desc.gameid = _gameid.c_str();
            g_fallbackDesc.desc.extra = _extra.c_str();

            printf("Your game version has been detected using fallback matching as a\n");
            printf("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra);
            printf("If this is an original and unmodified version or new made Fanmade game,\n");
            printf("please report any, information previously printed by ScummVM to the team.\n");

            return (const ADGameDescription *)&g_fallbackDesc;

      return 0;

Here is the call graph for this function:

Generated by  Doxygen 1.6.0   Back to index