aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/adl/detection.cpp69
-rw-r--r--engines/advancedDetector.cpp341
-rw-r--r--engines/advancedDetector.h59
-rw-r--r--engines/agi/detection.cpp8
-rw-r--r--engines/agos/detection.cpp2
-rw-r--r--engines/cge/detection.cpp32
-rw-r--r--engines/cge2/detection.cpp34
-rw-r--r--engines/cine/detection.cpp2
-rw-r--r--engines/director/detection.cpp8
-rw-r--r--engines/game.cpp222
-rw-r--r--engines/game.h176
-rw-r--r--engines/gob/detection/detection.cpp29
-rw-r--r--engines/made/detection.cpp6
-rw-r--r--engines/metaengine.h21
-rw-r--r--engines/mohawk/detection.cpp2
-rw-r--r--engines/obsolete.cpp10
-rw-r--r--engines/obsolete.h2
-rw-r--r--engines/queen/detection.cpp10
-rw-r--r--engines/saga/detection.cpp2
-rw-r--r--engines/sci/detection.cpp14
-rw-r--r--engines/scumm/detection.cpp29
-rw-r--r--engines/sky/detection.cpp33
-rw-r--r--engines/sludge/detection.cpp18
-rw-r--r--engines/sword1/detection.cpp74
-rw-r--r--engines/sword2/sword2.cpp35
-rw-r--r--engines/tinsel/detection.cpp21
-rw-r--r--engines/toon/detection.cpp2
-rw-r--r--engines/touche/detection.cpp11
-rw-r--r--engines/tucker/detection.cpp7
-rw-r--r--engines/unknown-game-dialog.cpp70
-rw-r--r--engines/unknown-game-dialog.h18
-rw-r--r--engines/wintermute/detection.cpp8
32 files changed, 738 insertions, 637 deletions
diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index 14646c78e3..2276576baa 100644
--- a/engines/adl/detection.cpp
+++ b/engines/adl/detection.cpp
@@ -332,9 +332,9 @@ public:
int getMaximumSaveSlot() const { return 'O' - 'A'; }
SaveStateList listSaves(const char *target) const;
void removeSaveState(const char *target, int slot) const;
- virtual ADGameDescList detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra, bool useUnknownGameDialog = false) const;
+ ADDetectedGames detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const override;
- bool addFileProps(const FileMap &allFiles, Common::String fname, ADFilePropertiesMap &filePropsMap) const;
+ bool addFileProps(const FileMap &allFiles, Common::String fname, FilePropertiesMap &filePropsMap) const;
bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
};
@@ -492,14 +492,14 @@ Common::Platform getPlatform(const AdlGameDescription &adlDesc) {
return adlDesc.desc.platform;
}
-bool AdlMetaEngine::addFileProps(const FileMap &allFiles, Common::String fname, ADFilePropertiesMap &filePropsMap) const {
+bool AdlMetaEngine::addFileProps(const FileMap &allFiles, Common::String fname, FilePropertiesMap &filePropsMap) const {
if (filePropsMap.contains(fname))
return true;
if (!allFiles.contains(fname))
return false;
- ADFileProperties fileProps;
+ FileProperties fileProps;
fileProps.size = computeMD5(allFiles[fname], fileProps.md5, 16384);
if (fileProps.size != -1) {
@@ -511,42 +511,39 @@ bool AdlMetaEngine::addFileProps(const FileMap &allFiles, Common::String fname,
}
// Based on AdvancedMetaEngine::detectGame
-ADGameDescList AdlMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra, bool useUnknownGameDialog) const {
+ADDetectedGames AdlMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
// We run the file-based detector first and then add to the returned list
- ADGameDescList matched = AdvancedMetaEngine::detectGame(parent, allFiles, language, platform, extra, useUnknownGameDialog);
+ ADDetectedGames matched = AdvancedMetaEngine::detectGame(parent, allFiles, language, platform, extra);
debug(3, "Starting disk image detection in dir '%s'", parent.getPath().c_str());
- ADFilePropertiesMap filesProps;
- ADGameIdList matchedGameIds;
+ FilePropertiesMap filesProps;
bool gotAnyMatchesWithAllFiles = false;
for (uint g = 0; gameDiskDescriptions[g].desc.gameId != 0; ++g) {
- const ADGameDescription &desc = gameDiskDescriptions[g].desc;
+ ADDetectedGame game(&gameDiskDescriptions[g].desc);
// Skip games that don't meet the language/platform/extra criteria
- if (language != Common::UNK_LANG && desc.language != Common::UNK_LANG) {
- if (desc.language != language && !(language == Common::EN_ANY && (desc.flags & ADGF_ADDENGLISH)))
- continue;
+ if (language != Common::UNK_LANG && game.desc->language != Common::UNK_LANG) {
+ if (game.desc->language != language && !(language == Common::EN_ANY && (game.desc->flags & ADGF_ADDENGLISH)))
+ continue;
}
- if (platform != Common::kPlatformUnknown && desc.platform != Common::kPlatformUnknown && desc.platform != platform)
+ if (platform != Common::kPlatformUnknown && game.desc->platform != Common::kPlatformUnknown && game.desc->platform != platform)
continue;
- if ((_flags & kADFlagUseExtraAsHint) && !extra.empty() && desc.extra != extra)
+ if ((_flags & kADFlagUseExtraAsHint) && !extra.empty() && game.desc->extra != extra)
continue;
- bool fileMissing = false;
bool allFilesPresent = true;
- bool hashOrSizeMismatch = false;
- for (uint f = 0; desc.filesDescriptions[f].fileName; ++f) {
- const ADGameFileDescription &fDesc = desc.filesDescriptions[f];
+ for (uint f = 0; game.desc->filesDescriptions[f].fileName; ++f) {
+ const ADGameFileDescription &fDesc = game.desc->filesDescriptions[f];
Common::String fileName;
bool foundDiskImage = false;
for (uint e = 0; e < ARRAYSIZE(diskImageExts); ++e) {
- if (diskImageExts[e].platform == desc.platform) {
+ if (diskImageExts[e].platform == game.desc->platform) {
Common::String testFileName(fDesc.fileName);
testFileName += diskImageExts[e].extension;
@@ -563,49 +560,41 @@ ADGameDescList AdlMetaEngine::detectGame(const Common::FSNode &parent, const Fil
}
if (!foundDiskImage) {
- fileMissing = true;
allFilesPresent = false;
break;
}
- if (hashOrSizeMismatch)
+ game.matchedFiles[fileName] = filesProps[fileName];
+
+ if (game.hasUnknownFiles)
continue;
if (fDesc.md5 && fDesc.md5 != filesProps[fileName].md5) {
debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fDesc.md5, filesProps[fileName].md5.c_str());
- fileMissing = true;
- hashOrSizeMismatch = true;
+ game.hasUnknownFiles = true;
continue;
}
if (fDesc.fileSize != -1 && fDesc.fileSize != filesProps[fileName].size) {
debug(3, "Size Mismatch. Skipping");
- fileMissing = true;
- hashOrSizeMismatch = true;
+ game.hasUnknownFiles = true;
continue;
}
debug(3, "Matched file: %s", fileName.c_str());
}
- if (!fileMissing) {
- debug(2, "Found game: %s (%s/%s) (%d)", desc.gameId, getPlatformDescription(desc.platform), getLanguageDescription(desc.language), g);
- matched.push_back(&desc);
+ if (allFilesPresent && !game.hasUnknownFiles) {
+ debug(2, "Found game: %s (%s/%s) (%d)", game.desc->gameId, getPlatformDescription(game.desc->platform), getLanguageDescription(game.desc->language), g);
+ gotAnyMatchesWithAllFiles = true;
+ matched.push_back(game);
} else {
- if (allFilesPresent) {
- gotAnyMatchesWithAllFiles = true;
- if (!matchedGameIds.size() || strcmp(matchedGameIds.back(), desc.gameId) != 0)
- matchedGameIds.push_back(desc.gameId);
+ if (allFilesPresent && !gotAnyMatchesWithAllFiles) {
+ if (matched.empty() || strcmp(matched.back().desc->gameId, game.desc->gameId) != 0)
+ matched.push_back(game);
}
- debug(5, "Skipping game: %s (%s/%s) (%d)", desc.gameId, getPlatformDescription(desc.platform), getLanguageDescription(desc.language), g);
- }
- }
-
- // TODO: This could be improved to handle matched and unknown games together in a single directory
- if (matched.empty()) {
- if (!filesProps.empty() && gotAnyMatchesWithAllFiles) {
- reportUnknown(parent, filesProps, matchedGameIds, useUnknownGameDialog);
+ debug(5, "Skipping game: %s (%s/%s) (%d)", game.desc->gameId, getPlatformDescription(game.desc->platform), getLanguageDescription(game.desc->language), g);
}
}
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp
index d258f49621..3167dd9581 100644
--- a/engines/advancedDetector.cpp
+++ b/engines/advancedDetector.cpp
@@ -30,37 +30,19 @@
#include "common/textconsole.h"
#include "common/translation.h"
#include "gui/EventRecorder.h"
-#include "gui/gui-manager.h"
-#include "engines/unknown-game-dialog.h"
#include "engines/advancedDetector.h"
#include "engines/obsolete.h"
-static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGameDescriptor *sg) {
- const char *title = 0;
- const char *extra;
-
- if (g.flags & ADGF_USEEXTRAASTITLE) {
- title = g.extra;
- extra = "";
- } else {
- while (sg->gameId) {
- if (!scumm_stricmp(g.gameId, sg->gameId))
- title = sg->description;
- sg++;
- }
+static Common::String sanitizeName(const char *name) {
+ Common::String res;
- extra = g.extra;
+ while (*name) {
+ if (Common::isAlnum(*name))
+ res += tolower(*name);
+ name++;
}
- GameSupportLevel gsl = kStableGame;
- if (g.flags & ADGF_UNSTABLE)
- gsl = kUnstableGame;
- else if (g.flags & ADGF_TESTING)
- gsl = kTestingGame;
-
- GameDescriptor gd(g.gameId, title, g.language, g.platform, 0, gsl);
- gd.updateDesc(extra);
- return gd;
+ return res;
}
/**
@@ -69,8 +51,14 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa
* or (if ADGF_DEMO has been set)
* GAMEID-demo-PLAFORM-LANG
*/
-static Common::String generatePreferredTarget(const Common::String &id, const ADGameDescription *desc) {
- Common::String res(id);
+static Common::String generatePreferredTarget(const ADGameDescription *desc) {
+ Common::String res;
+
+ if (desc->flags & ADGF_AUTOGENTARGET && desc->extra && *desc->extra) {
+ res = sanitizeName(desc->extra);
+ } else {
+ res = desc->gameId;
+ }
if (desc->flags & ADGF_DEMO) {
res = res + "-demo";
@@ -91,49 +79,50 @@ static Common::String generatePreferredTarget(const Common::String &id, const AD
return res;
}
-static Common::String sanitizeName(const char *name) {
- Common::String res;
+DetectedGame AdvancedMetaEngine::toDetectedGame(const ADDetectedGame &adGame) const {
+ const ADGameDescription *desc = adGame.desc;
- while (*name) {
- if (Common::isAlnum(*name))
- res += tolower(*name);
- name++;
- }
+ const char *gameId = _singleId ? _singleId : desc->gameId;
- return res;
-}
-
-void AdvancedMetaEngine::updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const {
- if (_singleId != NULL) {
- desc["preferredtarget"] = desc["gameid"];
- desc["gameid"] = _singleId;
+ const char *title;
+ const char *extra;
+ if (desc->flags & ADGF_USEEXTRAASTITLE) {
+ title = desc->extra;
+ extra = "";
+ } else {
+ const PlainGameDescriptor *pgd = findPlainGameDescriptor(desc->gameId, _gameIds);
+ title = pgd->description;
+ extra = desc->extra;
}
- if (!desc.contains("preferredtarget"))
- desc["preferredtarget"] = desc["gameid"];
+ DetectedGame game(gameId, title, desc->language, desc->platform, extra);
+ game.hasUnknownFiles = adGame.hasUnknownFiles;
+ game.matchedFiles = adGame.matchedFiles;
+ game.preferredTarget = generatePreferredTarget(desc);
- if (realDesc->flags & ADGF_AUTOGENTARGET) {
- if (*realDesc->extra)
- desc["preferredtarget"] = sanitizeName(realDesc->extra);
- }
+ game.gameSupportLevel = kStableGame;
+ if (desc->flags & ADGF_UNSTABLE)
+ game.gameSupportLevel = kUnstableGame;
+ else if (desc->flags & ADGF_TESTING)
+ game.gameSupportLevel = kTestingGame;
- desc["preferredtarget"] = generatePreferredTarget(desc["preferredtarget"], realDesc);
+ game.setGUIOptions(desc->guiOptions + _guiOptions);
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(desc->language));
- if (_flags & kADFlagUseExtraAsHint)
- desc["extra"] = realDesc->extra;
+ if (desc->flags & ADGF_ADDENGLISH)
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
- desc.setGUIOptions(realDesc->guiOptions + _guiOptions);
- desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language));
+ if (_flags & kADFlagUseExtraAsHint)
+ game.extra = desc->extra;
- if (realDesc->flags & ADGF_ADDENGLISH)
- desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
+ return game;
}
-bool cleanupPirated(ADGameDescList &matched) {
+bool cleanupPirated(ADDetectedGames &matched) {
// OKay, now let's sense presence of pirated games
if (!matched.empty()) {
for (uint j = 0; j < matched.size();) {
- if (matched[j]->flags & ADGF_PIRATED)
+ if (matched[j].desc->flags & ADGF_PIRATED)
matched.remove_at(j);
else
++j;
@@ -150,35 +139,46 @@ bool cleanupPirated(ADGameDescList &matched) {
}
-GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist, bool useUnknownGameDialog) const {
- ADGameDescList matches;
- GameList detectedGames;
+DetectedGames AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
FileMap allFiles;
if (fslist.empty())
- return detectedGames;
+ return DetectedGames();
// Compose a hashmap of all files in fslist.
composeFileHashMap(allFiles, fslist, (_maxScanDepth == 0 ? 1 : _maxScanDepth));
// Run the detector on this
- matches = detectGame(fslist.begin()->getParent(), allFiles, Common::UNK_LANG, Common::kPlatformUnknown, "", useUnknownGameDialog);
+ ADDetectedGames matches = detectGame(fslist.begin()->getParent(), allFiles, Common::UNK_LANG, Common::kPlatformUnknown, "");
- if (matches.empty()) {
- // Use fallback detector if there were no matches by other means
- const ADGameDescription *fallbackDesc = fallbackDetect(allFiles, fslist);
- if (fallbackDesc != 0) {
- GameDescriptor desc(toGameDescriptor(*fallbackDesc, _gameIds));
- updateGameDescriptor(desc, fallbackDesc);
- detectedGames.push_back(desc);
+ cleanupPirated(matches);
+
+ DetectedGames detectedGames;
+ for (uint i = 0; i < matches.size(); i++) {
+ DetectedGame game = toDetectedGame(matches[i]);
+
+ if (game.hasUnknownFiles) {
+ // Non fallback games with unknown files cannot be added/launched
+ game.canBeAdded = false;
}
- } else {
- // Otherwise use the found matches
- cleanupPirated(matches);
- for (uint i = 0; i < matches.size(); i++) {
- GameDescriptor desc(toGameDescriptor(*matches[i], _gameIds));
- updateGameDescriptor(desc, matches[i]);
- detectedGames.push_back(desc);
+
+ detectedGames.push_back(game);
+ }
+
+ bool foundKnownGames = false;
+ for (uint i = 0; i < detectedGames.size(); i++) {
+ foundKnownGames |= detectedGames[i].canBeAdded;
+ }
+
+ if (!foundKnownGames) {
+ // Use fallback detector if there were no matches by other means
+ ADDetectedGame fallbackDetectionResult = fallbackDetect(allFiles, fslist);
+
+ if (fallbackDetectionResult.desc) {
+ DetectedGame fallbackDetectedGame = toDetectedGame(fallbackDetectionResult);
+ fallbackDetectedGame.preferredTarget += "-fallback";
+
+ detectedGames.push_back(fallbackDetectedGame);
}
}
@@ -216,7 +216,6 @@ const ExtraGuiOptions AdvancedMetaEngine::getExtraGuiOptions(const Common::Strin
Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) const {
assert(engine);
- const ADGameDescription *agdDesc = 0;
Common::Language language = Common::UNK_LANG;
Common::Platform platform = Common::kPlatformUnknown;
Common::String extra;
@@ -266,46 +265,43 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
composeFileHashMap(allFiles, files, (_maxScanDepth == 0 ? 1 : _maxScanDepth));
// Run the detector on this
- ADGameDescList matches = detectGame(files.begin()->getParent(), allFiles, language, platform, extra);
+ ADDetectedGames matches = detectGame(files.begin()->getParent(), allFiles, language, platform, extra);
if (cleanupPirated(matches))
return Common::kNoGameDataFoundError;
- if (_singleId == NULL) {
- // Find the first match with correct gameid.
- for (uint i = 0; i < matches.size(); i++) {
- if (matches[i]->gameId == gameid) {
- agdDesc = matches[i];
- break;
- }
+ ADDetectedGame agdDesc;
+ for (uint i = 0; i < matches.size(); i++) {
+ if ((_singleId || matches[i].desc->gameId == gameid) && !matches[i].hasUnknownFiles) {
+ agdDesc = matches[i];
+ break;
}
- } else if (matches.size() > 0) {
- agdDesc = matches[0];
}
- if (agdDesc == 0) {
+ if (!agdDesc.desc) {
// Use fallback detector if there were no matches by other means
- agdDesc = fallbackDetect(allFiles, files);
- if (agdDesc != 0) {
+ ADDetectedGame fallbackDetectedGame = fallbackDetect(allFiles, files);
+ agdDesc = fallbackDetectedGame;
+ if (agdDesc.desc) {
// Seems we found a fallback match. But first perform a basic
// sanity check: the gameid must match.
- if (_singleId == NULL && agdDesc->gameId != gameid)
- agdDesc = 0;
+ if (!_singleId && agdDesc.desc->gameId != gameid)
+ agdDesc = ADDetectedGame();
}
}
- if (agdDesc == 0)
+ if (!agdDesc.desc)
return Common::kNoGameDataFoundError;
// If the GUI options were updated, we catch this here and update them in the users config
// file transparently.
- Common::String lang = getGameGUIOptionsDescriptionLanguage(agdDesc->language);
- if (agdDesc->flags & ADGF_ADDENGLISH)
+ Common::String lang = getGameGUIOptionsDescriptionLanguage(agdDesc.desc->language);
+ if (agdDesc.desc->flags & ADGF_ADDENGLISH)
lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY);
- Common::updateGameGUIOptions(agdDesc->guiOptions + _guiOptions, lang);
+ Common::updateGameGUIOptions(agdDesc.desc->guiOptions + _guiOptions, lang);
- GameDescriptor gameDescriptor = toGameDescriptor(*agdDesc, _gameIds);
+ DetectedGame gameDescriptor = toDetectedGame(agdDesc);
bool showTestingWarning = false;
@@ -313,72 +309,20 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
showTestingWarning = true;
#endif
- if (((gameDescriptor.getSupportLevel() == kUnstableGame
- || (gameDescriptor.getSupportLevel() == kTestingGame
+ if (((gameDescriptor.gameSupportLevel == kUnstableGame
+ || (gameDescriptor.gameSupportLevel == kTestingGame
&& showTestingWarning)))
&& !Engine::warnUserAboutUnsupportedGame())
return Common::kUserCanceled;
- debug(2, "Running %s", gameDescriptor.description().c_str());
- initSubSystems(agdDesc);
- if (!createInstance(syst, engine, agdDesc))
+ debug(2, "Running %s", gameDescriptor.description.c_str());
+ initSubSystems(agdDesc.desc);
+ if (!createInstance(syst, engine, agdDesc.desc))
return Common::kNoGameDataFoundError;
else
return Common::kNoError;
}
-void AdvancedMetaEngine::reportUnknown(const Common::FSNode &path, const ADFilePropertiesMap &filesProps, const ADGameIdList &matchedGameIds, bool useUnknownGameDialog) const {
- const char *reportCommon = _s("The game in '%s' seems to be an unknown %s engine game "
- "variant.\n\nPlease report the following data to the ScummVM "
- "team at %s along with the name of the game you tried to add and "
- "its version, language, etc.:");
- Common::String report = Common::String::format(reportCommon, path.getPath().c_str(), getName(), "https://bugs.scummvm.org/");
- Common::String reportTranslated = Common::String::format(_(reportCommon), path.getPath().c_str(), getName(), "https://bugs.scummvm.org/");
- Common::String bugtrackerAffectedEngine = getName();
-
- if (matchedGameIds.size()) {
- report += "\n\n";
- reportTranslated += "\n\n";
- report += "Matched game IDs:";
- reportTranslated += _("Matched game IDs:");
- report += " ";
- reportTranslated += " ";
-
- for (ADGameIdList::const_iterator gameId = matchedGameIds.begin(); gameId != matchedGameIds.end(); ++gameId) {
- if (gameId != matchedGameIds.begin()) {
- report += ", ";
- reportTranslated += ", ";
- }
- report += *gameId;
- reportTranslated += *gameId;
- }
- }
-
- report += "\n\n";
- reportTranslated += "\n\n";
-
- reportTranslated.wordWrap(65);
- Common::String reportLog = report;
- reportLog.wordWrap(80);
-
- Common::String unknownFiles;
- for (ADFilePropertiesMap::const_iterator file = filesProps.begin(); file != filesProps.end(); ++file)
- unknownFiles += Common::String::format(" {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5.c_str(), file->_value.size);
-
- report += unknownFiles;
- reportTranslated += unknownFiles;
- reportLog += unknownFiles + "\n";
-
- // Write the original message about the unknown game to the log file
- g_system->logMessage(LogMessageType::kInfo, reportLog.c_str());
-
- // Check if the GUI is running, show the UnknownGameDialog and print the translated unknown game information
- if (GUI::GuiManager::hasInstance() && g_gui.isActive() && useUnknownGameDialog == true) {
- UnknownGameDialog dialog(report, reportTranslated, bugtrackerAffectedEngine);
- dialog.runModal();
- }
-}
-
void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::String &parentName) const {
if (depth <= 0)
return;
@@ -419,7 +363,7 @@ void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSL
}
}
-bool AdvancedMetaEngine::getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, ADFileProperties &fileProps) const {
+bool AdvancedMetaEngine::getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const {
// FIXME/TODO: We don't handle the case that a file is listed as a regular
// file and as one with resource fork.
@@ -449,8 +393,9 @@ bool AdvancedMetaEngine::getFileProperties(const Common::FSNode &parent, const F
return true;
}
-ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra, bool useUnknownGameDialog) const {
- ADFilePropertiesMap filesProps;
+ADDetectedGames AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const {
+ FilePropertiesMap filesProps;
+ ADDetectedGames matched;
const ADGameFileDescription *fileDesc;
const ADGameDescription *g;
@@ -460,12 +405,12 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
// Check which files are included in some ADGameDescription *and* are present.
// Compute MD5s and file sizes for these files.
- for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize) {
+ for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != nullptr; descPtr += _descItemSize) {
g = (const ADGameDescription *)descPtr;
for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
Common::String fname = fileDesc->fileName;
- ADFileProperties tmp;
+ FileProperties tmp;
if (filesProps.contains(fname))
continue;
@@ -477,16 +422,13 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
}
}
- ADGameDescList matched;
- ADGameIdList matchedGameIds;
int maxFilesMatched = 0;
bool gotAnyMatchesWithAllFiles = false;
// MD5 based matching
uint i;
- for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize, ++i) {
+ for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != nullptr; descPtr += _descItemSize, ++i) {
g = (const ADGameDescription *)descPtr;
- bool fileMissing = false;
// Do not even bother to look at entries which do not have matching
// language and platform (if specified).
@@ -499,34 +441,33 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
if ((_flags & kADFlagUseExtraAsHint) && !extra.empty() && g->extra != extra)
continue;
+ ADDetectedGame game(g);
bool allFilesPresent = true;
int curFilesMatched = 0;
- bool hashOrSizeMismatch = false;
// Try to match all files for this game
- for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
+ for (fileDesc = game.desc->filesDescriptions; fileDesc->fileName; fileDesc++) {
Common::String tstr = fileDesc->fileName;
if (!filesProps.contains(tstr)) {
- fileMissing = true;
allFilesPresent = false;
break;
}
- if (hashOrSizeMismatch)
+ game.matchedFiles[tstr] = filesProps[tstr];
+
+ if (game.hasUnknownFiles)
continue;
- if (fileDesc->md5 != NULL && fileDesc->md5 != filesProps[tstr].md5) {
+ if (fileDesc->md5 != nullptr && fileDesc->md5 != filesProps[tstr].md5) {
debug(3, "MD5 Mismatch. Skipping (%s) (%s)", fileDesc->md5, filesProps[tstr].md5.c_str());
- fileMissing = true;
- hashOrSizeMismatch = true;
+ game.hasUnknownFiles = true;
continue;
}
if (fileDesc->fileSize != -1 && fileDesc->fileSize != filesProps[tstr].size) {
debug(3, "Size Mismatch. Skipping");
- fileMissing = true;
- hashOrSizeMismatch = true;
+ game.hasUnknownFiles = true;
continue;
}
@@ -543,13 +484,12 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
// Potentially this could rule out variants where some particular file
// is really missing, but the developers should better know about such
// cases.
- if (allFilesPresent) {
- gotAnyMatchesWithAllFiles = true;
- if (!matchedGameIds.size() || strcmp(matchedGameIds.back(), g->gameId) != 0)
- matchedGameIds.push_back(g->gameId);
+ if (allFilesPresent && !gotAnyMatchesWithAllFiles) {
+ if (matched.empty() || strcmp(matched.back().desc->gameId, g->gameId) != 0)
+ matched.push_back(game);
}
- if (!fileMissing) {
+ if (allFilesPresent && !game.hasUnknownFiles) {
debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameId, g->extra,
getPlatformDescription(g->platform), getLanguageDescription(g->language), i);
@@ -558,37 +498,29 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
maxFilesMatched = curFilesMatched;
matched.clear(); // Remove any prior, lower ranked matches.
- matched.push_back(g);
+ matched.push_back(game);
} else if (curFilesMatched == maxFilesMatched) {
- matched.push_back(g);
+ matched.push_back(game);
} else {
debug(2, " ... skipped");
}
+ gotAnyMatchesWithAllFiles = true;
} else {
debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameId, g->extra,
getPlatformDescription(g->platform), getLanguageDescription(g->language), i);
}
}
- // We didn't find a match
- if (matched.empty()) {
- if (!filesProps.empty() && gotAnyMatchesWithAllFiles) {
- reportUnknown(parent, filesProps, matchedGameIds, useUnknownGameDialog);
- }
-
- // Filename based fallback
- }
-
return matched;
}
-const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback, ADFilePropertiesMap *filesProps) const {
+ADDetectedGame AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback) const {
const ADFileBasedFallback *ptr;
const char* const* filenames;
int maxNumMatchedFiles = 0;
- const ADGameDescription *matchedDesc = 0;
+ ADDetectedGame result;
for (ptr = fileBasedFallback; ptr->desc; ++ptr) {
const ADGameDescription *agdesc = ptr->desc;
@@ -609,35 +541,36 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &
debug(4, "Matched: %s", agdesc->gameId);
if (numMatchedFiles > maxNumMatchedFiles) {
- matchedDesc = agdesc;
maxNumMatchedFiles = numMatchedFiles;
debug(4, "and overridden");
- if (filesProps) {
- for (filenames = ptr->filenames; *filenames; ++filenames) {
- ADFileProperties tmp;
+ ADDetectedGame game(agdesc);
+ game.hasUnknownFiles = true;
+
+ for (filenames = ptr->filenames; *filenames; ++filenames) {
+ FileProperties tmp;
- if (getFileProperties(fslist.begin()->getParent(), allFiles, *agdesc, *filenames, tmp))
- (*filesProps)[*filenames] = tmp;
- }
+ if (getFileProperties(fslist.begin()->getParent(), allFiles, *agdesc, *filenames, tmp))
+ game.matchedFiles[*filenames] = tmp;
}
+ result = game;
}
}
}
- return matchedDesc;
+ return result;
}
-GameList AdvancedMetaEngine::getSupportedGames() const {
+PlainGameList AdvancedMetaEngine::getSupportedGames() const {
if (_singleId != NULL) {
- GameList gl;
+ PlainGameList gl;
const PlainGameDescriptor *g = _gameIds;
while (g->gameId) {
if (0 == scumm_stricmp(_singleId, g->gameId)) {
- gl.push_back(GameDescriptor(g->gameId, g->description));
+ gl.push_back(*g);
return gl;
}
@@ -646,17 +579,17 @@ GameList AdvancedMetaEngine::getSupportedGames() const {
error("Engine %s doesn't have its singleid specified in ids list", _singleId);
}
- return GameList(_gameIds);
+ return PlainGameList(_gameIds);
}
-GameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const {
+PlainGameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const {
// First search the list of supported gameids for a match.
const PlainGameDescriptor *g = findPlainGameDescriptor(gameId, _gameIds);
if (g)
- return GameDescriptor(*g);
+ return *g;
// No match found
- return GameDescriptor();
+ return PlainGameDescriptor::empty();
}
AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions)
diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h
index d7e85f86fe..326cb79c49 100644
--- a/engines/advancedDetector.h
+++ b/engines/advancedDetector.h
@@ -48,20 +48,6 @@ struct ADGameFileDescription {
};
/**
- * A record describing the properties of a file. Used on the existing
- * files while detecting a game.
- */
-struct ADFileProperties {
- int32 size;
- Common::String md5;
-};
-
-/**
- * A map of all relevant existing files in a game directory while detecting.
- */
-typedef Common::HashMap<Common::String, ADFileProperties, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ADFilePropertiesMap;
-
-/**
* A shortcut to produce an empty ADGameFileDescription record. Used to mark
* the end of a list of these.
*/
@@ -112,14 +98,19 @@ struct ADGameDescription {
};
/**
- * A list of pointers to ADGameDescription structs (or subclasses thereof).
+ * A game installation matching an AD game description
*/
-typedef Common::Array<const ADGameDescription *> ADGameDescList;
+struct ADDetectedGame {
+ bool hasUnknownFiles;
+ FilePropertiesMap matchedFiles;
+ const ADGameDescription *desc;
-/**
- * A list of raw game ID strings.
- */
-typedef Common::Array<const char *> ADGameIdList;
+ ADDetectedGame() : desc(nullptr), hasUnknownFiles(false) {}
+ explicit ADDetectedGame(const ADGameDescription *d) : desc(d), hasUnknownFiles(false) {}
+};
+
+/** A list of games detected by the AD */
+typedef Common::Array<ADDetectedGame> ADDetectedGames;
/**
* End marker for a table of ADGameDescription structs. Use this to
@@ -274,11 +265,11 @@ public:
* Returns list of targets supported by the engine.
* Distinguishes engines with single ID
*/
- virtual GameList getSupportedGames() const;
+ PlainGameList getSupportedGames() const override;
- virtual GameDescriptor findGame(const char *gameId) const;
+ PlainGameDescriptor findGame(const char *gameId) const override;
- virtual GameList detectGames(const Common::FSList &fslist, bool useUnknownGameDialog = false) const;
+ DetectedGames detectGames(const Common::FSList &fslist) const override;
virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
@@ -294,8 +285,8 @@ protected:
* An (optional) generic fallback detect function which is invoked
* if the regular MD5 based detection failed to detect anything.
*/
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- return 0;
+ virtual ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ return ADDetectedGame();
}
private:
@@ -313,7 +304,7 @@ protected:
* @param extra restrict results to specified extra string (only if kADFlagUseExtraAsHint is set)
* @return list of ADGameDescription pointers corresponding to matched games
*/
- virtual ADGameDescList detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra, bool useUnknownGameDialog = false) const;
+ virtual ADDetectedGames detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const;
/**
* Iterates over all ADFileBasedFallback records inside fileBasedFallback.
@@ -327,16 +318,7 @@ protected:
* @param fileBasedFallback a list of ADFileBasedFallback records, zero-terminated
* @param filesProps if not 0, return a map of properties for all detected files here
*/
- const ADGameDescription *detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback, ADFilePropertiesMap *filesProps = 0) const;
-
- /**
- * Log and print a report that we found an unknown game variant, together with the file
- * names, sizes and MD5 sums.
- */
- void reportUnknown(const Common::FSNode &path, const ADFilePropertiesMap &filesProps, const ADGameIdList &matchedGameIds = ADGameIdList(), bool useUnknownGameDialog = false) const;
-
- // TODO
- void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const;
+ ADDetectedGame detectGameFilebased(const FileMap &allFiles, const Common::FSList &fslist, const ADFileBasedFallback *fileBasedFallback) const;
/**
* Compose a hashmap of all files in fslist.
@@ -345,7 +327,10 @@ protected:
void composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::String &parentName = Common::String()) const;
/** Get the properties (size and MD5) of this file. */
- bool getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, ADFileProperties &fileProps) const;
+ bool getFileProperties(const Common::FSNode &parent, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const;
+
+ /** Convert an AD game description into the shared game description format */
+ DetectedGame toDetectedGame(const ADDetectedGame &adGame) const;
};
#endif
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 817be08f2c..39275c4f70 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -220,7 +220,7 @@ public:
virtual void removeSaveState(const char *target, int slot) const;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
};
bool AgiMetaEngine::hasFeature(MetaEngineFeature f) const {
@@ -421,7 +421,7 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl
}
}
-const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const {
+ADDetectedGame AgiMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const {
typedef Common::HashMap<Common::String, int32> IntMap;
IntMap allFiles;
bool matchedUsingFilenames = false;
@@ -584,10 +584,10 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
g_system->logMessage(LogMessageType::kWarning, fallbackWarning.c_str());
- return (const ADGameDescription *)&g_fallbackDesc;
+ return ADDetectedGame(&g_fallbackDesc.desc);
}
- return 0;
+ return ADDetectedGame();
}
#if PLUGIN_ENABLED_DYNAMIC(AGI)
diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp
index dbc4ee9145..1847434200 100644
--- a/engines/agos/detection.cpp
+++ b/engines/agos/detection.cpp
@@ -99,7 +99,7 @@ public:
_directoryGlobs = directoryGlobs;
}
- virtual GameDescriptor findGame(const char *gameId) const {
+ PlainGameDescriptor findGame(const char *gameId) const override {
return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index 4c23939d60..f6399d484c 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -126,7 +126,7 @@ public:
return "Soltys (C) 1994-1996 L.K. Avalon";
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual int getMaximumSaveSlot() const;
@@ -135,13 +135,8 @@ public:
virtual void removeSaveState(const char *target, int slot) const;
};
-static const ADFileBasedFallback fileBasedFallback[] = {
- { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } },
- { 0, { 0 } }
-};
-
static ADGameDescription s_fallbackDesc = {
- "Soltys",
+ "soltys",
"Unknown version",
AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
Common::UNK_LANG,
@@ -150,28 +145,29 @@ static ADGameDescription s_fallbackDesc = {
GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
};
-const ADGameDescription *CGEMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- ADFilePropertiesMap filesProps;
+static const ADFileBasedFallback fileBasedFallback[] = {
+ { &s_fallbackDesc, { "vol.cat", "vol.dat", 0 } },
+ { 0, { 0 } }
+};
- const ADGameDescription *game;
- game = detectGameFilebased(allFiles, fslist, CGE::fileBasedFallback, &filesProps);
+ADDetectedGame CGEMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame game = detectGameFilebased(allFiles, fslist, CGE::fileBasedFallback);
- if (!game)
- return nullptr;
+ if (!game.desc)
+ return ADDetectedGame();
SearchMan.addDirectory("CGEMetaEngine::fallbackDetect", fslist.begin()->getParent());
ResourceManager *resman;
resman = new ResourceManager();
- bool result = resman->exist("CGE.SAY");
+ bool sayFileFound = resman->exist("CGE.SAY");
delete resman;
SearchMan.remove("CGEMetaEngine::fallbackDetect");
- if (!result)
- return nullptr;
+ if (!sayFileFound)
+ return ADDetectedGame();
- reportUnknown(fslist.begin()->getParent(), filesProps);
- return &s_fallbackDesc;
+ return game;
}
bool CGEMetaEngine::hasFeature(MetaEngineFeature f) const {
diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp
index 648dcc01e2..ec6925ac74 100644
--- a/engines/cge2/detection.cpp
+++ b/engines/cge2/detection.cpp
@@ -132,7 +132,7 @@ public:
return "Sfinx (C) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual int getMaximumSaveSlot() const;
@@ -141,13 +141,8 @@ public:
virtual void removeSaveState(const char *target, int slot) const;
};
-static const ADFileBasedFallback fileBasedFallback[] = {
- { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } },
- { 0, { 0 } }
-};
-
static ADGameDescription s_fallbackDesc = {
- "Sfinx",
+ "sfinx",
"Unknown version",
AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
Common::UNK_LANG,
@@ -156,30 +151,31 @@ static ADGameDescription s_fallbackDesc = {
GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
};
+static const ADFileBasedFallback fileBasedFallback[] = {
+ { &s_fallbackDesc, { "vol.cat", "vol.dat", 0 } },
+ { 0, { 0 } }
+};
+
// This fallback detection looks identical to the one used for CGE. In fact, the difference resides
// in the ResourceManager which handles a different archive format. The rest of the detection is identical.
-const ADGameDescription *CGE2MetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- ADFilePropertiesMap filesProps;
-
- const ADGameDescription *game;
- game = detectGameFilebased(allFiles, fslist, CGE2::fileBasedFallback, &filesProps);
+ADDetectedGame CGE2MetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame game = detectGameFilebased(allFiles, fslist, CGE2::fileBasedFallback);
- if (!game)
- return 0;
+ if (!game.desc)
+ return ADDetectedGame();
SearchMan.addDirectory("CGE2MetaEngine::fallbackDetect", fslist.begin()->getParent());
ResourceManager *resman;
resman = new ResourceManager();
- bool result = resman->exist("CGE.SAY");
+ bool sayFileFound = resman->exist("CGE.SAY");
delete resman;
SearchMan.remove("CGE2MetaEngine::fallbackDetect");
- if (!result)
- return 0;
+ if (!sayFileFound)
+ return ADDetectedGame();
- reportUnknown(fslist.begin()->getParent(), filesProps);
- return &s_fallbackDesc;
+ return game;
}
bool CGE2MetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp
index 6c8b4a676d..f1636c902b 100644
--- a/engines/cine/detection.cpp
+++ b/engines/cine/detection.cpp
@@ -84,7 +84,7 @@ public:
_guiOptions = GUIO2(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD);
}
- virtual GameDescriptor findGame(const char *gameId) const {
+ PlainGameDescriptor findGame(const char *gameId) const override {
return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
diff --git a/engines/director/detection.cpp b/engines/director/detection.cpp
index 16d838fcca..9d293846bc 100644
--- a/engines/director/detection.cpp
+++ b/engines/director/detection.cpp
@@ -112,7 +112,7 @@ public:
return "Macromedia Director (C) Macromedia";
}
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
};
@@ -141,7 +141,7 @@ static Director::DirectorGameDescription s_fallbackDesc = {
static char s_fallbackFileNameBuffer[51];
-const ADGameDescription *DirectorMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame DirectorMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
// TODO: Handle Mac fallback
// reset fallback description
@@ -230,10 +230,10 @@ const ADGameDescription *DirectorMetaEngine::fallbackDetect(const FileMap &allFi
warning("Director fallback detection D%d", desc->version);
- return (ADGameDescription *)desc;
+ return ADDetectedGame(&desc->desc);
}
- return 0;
+ return ADDetectedGame();
}
#if PLUGIN_ENABLED_DYNAMIC(DIRECTOR)
diff --git a/engines/game.cpp b/engines/game.cpp
index 7ff51a99cc..ee14acf7c8 100644
--- a/engines/game.cpp
+++ b/engines/game.cpp
@@ -22,6 +22,7 @@
#include "engines/game.h"
#include "common/gui_options.h"
+#include "common/translation.h"
const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list) {
@@ -34,93 +35,182 @@ const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const Pla
return 0;
}
-GameDescriptor::GameDescriptor() {
- setVal("gameid", "");
- setVal("description", "");
+PlainGameDescriptor PlainGameDescriptor::empty() {
+ PlainGameDescriptor pgd;
+ pgd.gameId = nullptr;
+ pgd.description = nullptr;
+ return pgd;
}
-GameDescriptor::GameDescriptor(const PlainGameDescriptor &pgd, Common::String guioptions) {
- setVal("gameid", pgd.gameId);
- setVal("description", pgd.description);
+PlainGameDescriptor PlainGameDescriptor::of(const char *gameId, const char *description) {
+ PlainGameDescriptor pgd;
+ pgd.gameId = gameId;
+ pgd.description = description;
+ return pgd;
+}
- if (!guioptions.empty())
- setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
+DetectedGame::DetectedGame() :
+ engineName(nullptr),
+ hasUnknownFiles(false),
+ canBeAdded(true),
+ language(Common::UNK_LANG),
+ platform(Common::kPlatformUnknown),
+ gameSupportLevel(kStableGame) {
}
-GameDescriptor::GameDescriptor(const Common::String &g, const Common::String &d, Common::Language l, Common::Platform p, Common::String guioptions, GameSupportLevel gsl) {
- setVal("gameid", g);
- setVal("description", d);
- if (l != Common::UNK_LANG)
- setVal("language", Common::getLanguageCode(l));
- if (p != Common::kPlatformUnknown)
- setVal("platform", Common::getPlatformCode(p));
- if (!guioptions.empty())
- setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
-
- setSupportLevel(gsl);
+DetectedGame::DetectedGame(const PlainGameDescriptor &pgd) :
+ engineName(nullptr),
+ hasUnknownFiles(false),
+ canBeAdded(true),
+ language(Common::UNK_LANG),
+ platform(Common::kPlatformUnknown),
+ gameSupportLevel(kStableGame) {
+
+ gameId = pgd.gameId;
+ preferredTarget = pgd.gameId;
+ description = pgd.description;
}
-void GameDescriptor::setGUIOptions(Common::String guioptions) {
- if (!guioptions.empty())
- setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
- else
- erase("guioptions");
+DetectedGame::DetectedGame(const Common::String &id, const Common::String &d, Common::Language l, Common::Platform p, const Common::String &ex) :
+ engineName(nullptr),
+ hasUnknownFiles(false),
+ canBeAdded(true),
+ gameSupportLevel(kStableGame) {
+
+ gameId = id;
+ preferredTarget = id;
+ description = d;
+ language = l;
+ platform = p;
+ extra = ex;
+
+ // Append additional information, if set, to the description.
+ description += updateDesc();
}
-void GameDescriptor::appendGUIOptions(const Common::String &str) {
- setVal("guioptions", getVal("guioptions", "") + " " + str);
+void DetectedGame::setGUIOptions(const Common::String &guioptions) {
+ _guiOptions = Common::getGameGUIOptionsDescription(guioptions);
}
-void GameDescriptor::updateDesc(const char *extra) {
- const bool hasCustomLanguage = (language() != Common::UNK_LANG);
- const bool hasCustomPlatform = (platform() != Common::kPlatformUnknown);
- const bool hasExtraDesc = (extra && extra[0]);
+void DetectedGame::appendGUIOptions(const Common::String &str) {
+ if (!_guiOptions.empty())
+ _guiOptions += " ";
+
+ _guiOptions += str;
+}
+
+Common::String DetectedGame::updateDesc() const {
+ const bool hasCustomLanguage = (language != Common::UNK_LANG);
+ const bool hasCustomPlatform = (platform != Common::kPlatformUnknown);
+ const bool hasExtraDesc = !extra.empty();
// Adapt the description string if custom platform/language is set.
- if (hasCustomLanguage || hasCustomPlatform || hasExtraDesc) {
- Common::String descr = description();
+ Common::String descr;
+ if (!hasCustomLanguage && !hasCustomPlatform && !hasExtraDesc)
+ return descr;
- descr += " (";
+ descr += " (";
+
+ if (hasExtraDesc)
+ descr += extra;
+ if (hasCustomPlatform) {
if (hasExtraDesc)
- descr += extra;
- if (hasCustomPlatform) {
- if (hasExtraDesc)
- descr += "/";
- descr += Common::getPlatformDescription(platform());
- }
- if (hasCustomLanguage) {
- if (hasExtraDesc || hasCustomPlatform)
- descr += "/";
- descr += Common::getLanguageDescription(language());
+ descr += "/";
+ descr += Common::getPlatformDescription(platform);
+ }
+ if (hasCustomLanguage) {
+ if (hasExtraDesc || hasCustomPlatform)
+ descr += "/";
+ descr += Common::getLanguageDescription(language);
+ }
+
+ descr += ")";
+
+ return descr;
+}
+
+DetectionResults::DetectionResults(const DetectedGames &detectedGames) :
+ _detectedGames(detectedGames) {
+}
+
+bool DetectionResults::foundUnknownGames() const {
+ for (uint i = 0; i < _detectedGames.size(); i++) {
+ if (_detectedGames[i].hasUnknownFiles) {
+ return true;
}
- descr += ")";
- setVal("description", descr);
}
+ return false;
}
-GameSupportLevel GameDescriptor::getSupportLevel() {
- GameSupportLevel gsl = kStableGame;
- if (contains("gsl")) {
- Common::String gslString = getVal("gsl");
- if (gslString.equals("unstable"))
- gsl = kUnstableGame;
- else if (gslString.equals("testing"))
- gsl = kTestingGame;
+DetectedGames DetectionResults::listRecognizedGames() {
+ DetectedGames candidates;
+ for (uint i = 0; i < _detectedGames.size(); i++) {
+ if (_detectedGames[i].canBeAdded) {
+ candidates.push_back(_detectedGames[i]);
+ }
}
- return gsl;
+ return candidates;
}
-void GameDescriptor::setSupportLevel(GameSupportLevel gsl) {
- switch (gsl) {
- case kUnstableGame:
- setVal("gsl", "unstable");
- break;
- case kTestingGame:
- setVal("gsl", "testing");
- break;
- case kStableGame:
- // Fall Through intended
- default:
- erase("gsl");
+Common::String DetectionResults::generateUnknownGameReport(bool translate, uint32 wordwrapAt) const {
+ assert(!_detectedGames.empty());
+
+ const char *reportStart = _s("The game in '%s' seems to be an unknown game variant.\n\n"
+ "Please report the following data to the ScummVM team at %s "
+ "along with the name of the game you tried to add and "
+ "its version, language, etc.:");
+ const char *reportEngineHeader = _s("Matched game IDs for the %s engine:");
+
+ Common::String report = Common::String::format(
+ translate ? _(reportStart) : reportStart, _detectedGames[0].path.c_str(),
+ "https://bugs.scummvm.org/"
+ );
+ report += "\n";
+
+ FilePropertiesMap matchedFiles;
+
+ const char *currentEngineName = nullptr;
+ for (uint i = 0; i < _detectedGames.size(); i++) {
+ const DetectedGame &game = _detectedGames[i];
+
+ if (!game.hasUnknownFiles) continue;
+
+ if (!currentEngineName || strcmp(currentEngineName, game.engineName) != 0) {
+ currentEngineName = game.engineName;
+
+ // If the engine is not the same as for the previous entry, print an engine line header
+ report += "\n";
+ report += Common::String::format(
+ translate ? _(reportEngineHeader) : reportEngineHeader,
+ game.engineName
+ );
+ report += " ";
+
+ } else {
+ report += ", ";
+ }
+
+ // Add the gameId to the list of matched games for the engine
+ // TODO: Use the gameId here instead of the preferred target.
+ // This is currently impossible due to the AD singleId feature losing the information.
+ report += game.preferredTarget;
+
+ // Consolidate matched files across all engines and detection entries
+ for (FilePropertiesMap::const_iterator it = game.matchedFiles.begin(); it != game.matchedFiles.end(); it++) {
+ matchedFiles.setVal(it->_key, it->_value);
+ }
+ }
+
+ if (wordwrapAt) {
+ report.wordWrap(wordwrapAt);
}
+
+ report += "\n\n";
+
+ for (FilePropertiesMap::const_iterator file = matchedFiles.begin(); file != matchedFiles.end(); ++file)
+ report += Common::String::format(" {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5.c_str(), file->_value.size);
+
+ report += "\n";
+
+ return report;
}
diff --git a/engines/game.h b/engines/game.h
index e01e5c6885..14f9962ce6 100644
--- a/engines/game.h
+++ b/engines/game.h
@@ -38,6 +38,9 @@
struct PlainGameDescriptor {
const char *gameId;
const char *description;
+
+ static PlainGameDescriptor empty();
+ static PlainGameDescriptor of(const char *gameId, const char *description);
};
/**
@@ -47,6 +50,18 @@ struct PlainGameDescriptor {
*/
const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list);
+class PlainGameList : public Common::Array<PlainGameDescriptor> {
+public:
+ PlainGameList() {}
+ PlainGameList(const PlainGameList &list) : Common::Array<PlainGameDescriptor>(list) {}
+ PlainGameList(const PlainGameDescriptor *g) {
+ while (g->gameId) {
+ push_back(*g);
+ g++;
+ }
+ }
+};
+
/**
* Ths is an enum to describe how done a game is. This also indicates what level of support is expected.
*/
@@ -56,63 +71,138 @@ enum GameSupportLevel {
kUnstableGame // the game is not even ready for public testing yet
};
+
/**
- * A hashmap describing details about a given game. In a sense this is a refined
- * version of PlainGameDescriptor, as it also contains a gameid and a description string.
- * But in addition, platform and language settings, as well as arbitrary other settings,
- * can be contained in a GameDescriptor.
- * This is an essential part of the glue between the game engines and the launcher code.
+ * A record describing the properties of a file. Used on the existing
+ * files while detecting a game.
*/
-class GameDescriptor : public Common::StringMap {
-public:
- GameDescriptor();
- GameDescriptor(const PlainGameDescriptor &pgd, Common::String guioptions = Common::String());
- GameDescriptor(const Common::String &gameid,
- const Common::String &description,
- Common::Language language = Common::UNK_LANG,
- Common::Platform platform = Common::kPlatformUnknown,
- Common::String guioptions = Common::String(),
- GameSupportLevel gsl = kStableGame);
+struct FileProperties {
+ int32 size;
+ Common::String md5;
+
+ FileProperties() : size(-1) {}
+};
+
+/**
+ * A map of all relevant existing files while detecting.
+ */
+typedef Common::HashMap<Common::String, FileProperties, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FilePropertiesMap;
+
+/**
+ * Details about a given game.
+ *
+ * While PlainGameDescriptor refers to a game supported by an engine, this refers to a game copy
+ * that has been detected by an engine's detector.
+ * It contains all the necessary data to add the game to the configuration manager and / or to launch it.
+ */
+struct DetectedGame {
+ DetectedGame();
+ explicit DetectedGame(const PlainGameDescriptor &pgd);
+ DetectedGame(const Common::String &id,
+ const Common::String &description,
+ Common::Language language = Common::UNK_LANG,
+ Common::Platform platform = Common::kPlatformUnknown,
+ const Common::String &extra = Common::String());
+
+ void setGUIOptions(const Common::String &options);
+ void appendGUIOptions(const Common::String &str);
+ Common::String getGUIOptions() const { return _guiOptions; }
/**
- * Update the description string by appending (EXTRA/PLATFORM/LANG) to it.
- * Values that are missing are omitted, so e.g. (EXTRA/LANG) would be
- * added if no platform has been specified but a language and an extra string.
+ * The name of the engine supporting the detected game
*/
- void updateDesc(const char *extra = 0);
+ const char *engineName;
- void setGUIOptions(Common::String options);
- void appendGUIOptions(const Common::String &str);
+ /**
+ * A game was detected, but some files were not recognized
+ *
+ * This can happen when the md5 or size of the detected files did not match the engine's detection tables.
+ * When this is true, the list of matched files below contains detail about the unknown files.
+ *
+ * @see matchedFiles
+ */
+ bool hasUnknownFiles;
+
+ /**
+ * An optional list of the files that were used to match the game with the engine's detection tables
+ */
+ FilePropertiesMap matchedFiles;
+
+ /**
+ * This detection entry contains enough data to add the game to the configuration manager and launch it
+ *
+ * @see matchedGame
+ */
+ bool canBeAdded;
+
+ Common::String gameId;
+ Common::String preferredTarget;
+ Common::String description;
+ Common::Language language;
+ Common::Platform platform;
+ Common::String path;
+ Common::String extra;
/**
* What level of support is expected of this game
*/
- GameSupportLevel getSupportLevel();
- void setSupportLevel(GameSupportLevel gsl);
-
- Common::String &gameid() { return getVal("gameid"); }
- Common::String &description() { return getVal("description"); }
- const Common::String &gameid() const { return getVal("gameid"); }
- const Common::String &description() const { return getVal("description"); }
- Common::Language language() const { return contains("language") ? Common::parseLanguage(getVal("language")) : Common::UNK_LANG; }
- Common::Platform platform() const { return contains("platform") ? Common::parsePlatform(getVal("platform")) : Common::kPlatformUnknown; }
-
- const Common::String &preferredtarget() const {
- return contains("preferredtarget") ? getVal("preferredtarget") : getVal("gameid");
- }
+ GameSupportLevel gameSupportLevel;
+
+private:
+ /**
+ * Update the description string by appending (EXTRA/PLATFORM/LANG) to it.
+ * Values that are missing are omitted, so e.g. (EXTRA/LANG) would be
+ * added if no platform has been specified but a language and an extra string.
+ */
+ Common::String updateDesc() const;
+
+ Common::String _guiOptions;
};
/** List of games. */
-class GameList : public Common::Array<GameDescriptor> {
+typedef Common::Array<DetectedGame> DetectedGames;
+
+/**
+ * Contains a list of games found by the engines' detectors.
+ *
+ * Each detected game can either:
+ * - be fully recognized (e.g. an exact match was found in the detection tables of an engine)
+ * - be an unknown variant (e.g. a game using files with the same name was found in the detection tables)
+ * - be recognized with unknown files (e.g. the game was exactly not found in the detection tables,
+ * but the detector was able to gather enough data to allow launching the game)
+ *
+ * Practically, this means a detected game can be in both the recognized game list and in the unknown game
+ * report handled by this class.
+ */
+class DetectionResults {
public:
- GameList() {}
- GameList(const GameList &list) : Common::Array<GameDescriptor>(list) {}
- GameList(const PlainGameDescriptor *g) {
- while (g->gameId) {
- push_back(GameDescriptor(*g));
- g++;
- }
- }
+ explicit DetectionResults(const DetectedGames &detectedGames);
+
+ /**
+ * List all the games that were recognized by the engines
+ *
+ * Recognized games can be added to the configuration manager and then launched.
+ */
+ DetectedGames listRecognizedGames();
+
+ /**
+ * Were unknown game variants found by the engines?
+ *
+ * When unknown game variants are found, an unknown game report can be generated.
+ */
+ bool foundUnknownGames() const;
+
+ /**
+ * Generate a report that we found an unknown game variant, together with the file
+ * names, sizes and MD5 sums.
+ *
+ * @param translate translate the report to the currently active GUI language
+ * @param wordwrapAt word wrap the text part of the report after a number of characters
+ */
+ Common::String generateUnknownGameReport(bool translate, uint32 wordwrapAt = 0) const;
+
+private:
+ DetectedGames _detectedGames;
};
#endif
diff --git a/engines/gob/detection/detection.cpp b/engines/gob/detection/detection.cpp
index e204ced1e8..864a701aa6 100644
--- a/engines/gob/detection/detection.cpp
+++ b/engines/gob/detection/detection.cpp
@@ -33,9 +33,9 @@ class GobMetaEngine : public AdvancedMetaEngine {
public:
GobMetaEngine();
- virtual GameDescriptor findGame(const char *gameId) const;
+ PlainGameDescriptor findGame(const char *gameId) const override;
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual const char *getName() const;
virtual const char *getOriginalCopyright() const;
@@ -59,29 +59,26 @@ GobMetaEngine::GobMetaEngine() :
_guiOptions = GUIO1(GUIO_NOLAUNCHLOAD);
}
-GameDescriptor GobMetaEngine::findGame(const char *gameId) const {
+PlainGameDescriptor GobMetaEngine::findGame(const char *gameId) const {
return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
-const ADGameDescription *GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- ADFilePropertiesMap filesProps;
+ADDetectedGame GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame detectedGame = detectGameFilebased(allFiles, fslist, Gob::fileBased);
+ if (!detectedGame.desc) {
+ return ADDetectedGame();
+ }
- const Gob::GOBGameDescription *game;
- game = (const Gob::GOBGameDescription *)detectGameFilebased(allFiles, fslist, Gob::fileBased, &filesProps);
- if (!game)
- return 0;
+ const Gob::GOBGameDescription *game = (const Gob::GOBGameDescription *)detectedGame.desc;
if (game->gameType == Gob::kGameTypeOnceUponATime) {
game = detectOnceUponATime(fslist);
- if (!game)
- return 0;
+ if (game) {
+ detectedGame.desc = &game->desc;
+ }
}
- ADGameIdList gameIds;
- gameIds.push_back(game->desc.gameId);
-
- reportUnknown(fslist.begin()->getParent(), filesProps, gameIds);
- return (const ADGameDescription *)game;
+ return detectedGame;
}
const Gob::GOBGameDescription *GobMetaEngine::detectOnceUponATime(const Common::FSList &fslist) {
diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp
index 636c2d147c..bf05385c88 100644
--- a/engines/made/detection.cpp
+++ b/engines/made/detection.cpp
@@ -535,7 +535,7 @@ public:
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
};
@@ -557,7 +557,7 @@ bool MadeMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGame
return gd != 0;
}
-const ADGameDescription *MadeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame MadeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
// Set the default values for the fallback descriptor's ADGameDescription part.
Made::g_fallbackDesc.desc.language = Common::UNK_LANG;
Made::g_fallbackDesc.desc.platform = Common::kPlatformDOS;
@@ -569,7 +569,7 @@ const ADGameDescription *MadeMetaEngine::fallbackDetect(const FileMap &allFiles,
Made::g_fallbackDesc.version = 3;
//return (const ADGameDescription *)&Made::g_fallbackDesc;
- return NULL;
+ return ADDetectedGame();
}
#if PLUGIN_ENABLED_DYNAMIC(MADE)
diff --git a/engines/metaengine.h b/engines/metaengine.h
index 68f4b36848..a95ff1593e 100644
--- a/engines/metaengine.h
+++ b/engines/metaengine.h
@@ -69,17 +69,17 @@ public:
virtual const char *getOriginalCopyright() const = 0;
/** Returns a list of games supported by this engine. */
- virtual GameList getSupportedGames() const = 0;
+ virtual PlainGameList getSupportedGames() const = 0;
- /** Query the engine for a GameDescriptor for the specified gameid, if any. */
- virtual GameDescriptor findGame(const char *gameid) const = 0;
+ /** Query the engine for a PlainGameDescriptor for the specified gameid, if any. */
+ virtual PlainGameDescriptor findGame(const char *gameId) const = 0;
/**
* Runs the engine's game detector on the given list of files, and returns a
* (possibly empty) list of games supported by the engine which it was able
* to detect amongst the given files.
*/
- virtual GameList detectGames(const Common::FSList &fslist, bool useUnknownGameDialog = false) const = 0;
+ virtual DetectedGames detectGames(const Common::FSList &fslist) const = 0;
/**
* Tries to instantiate an engine instance based on the settings of
@@ -267,10 +267,17 @@ public:
*/
class EngineManager : public Common::Singleton<EngineManager> {
public:
- GameDescriptor findGameInLoadedPlugins(const Common::String &gameName, const Plugin **plugin = NULL) const;
- GameDescriptor findGame(const Common::String &gameName, const Plugin **plugin = NULL) const;
- GameList detectGames(const Common::FSList &fslist, bool useUnknownGameDialog = false) const;
+ PlainGameDescriptor findGameInLoadedPlugins(const Common::String &gameName, const Plugin **plugin = NULL) const;
+ PlainGameDescriptor findGame(const Common::String &gameName, const Plugin **plugin = NULL) const;
+ DetectionResults detectGames(const Common::FSList &fslist) const;
const PluginList &getPlugins() const;
+
+ /**
+ * Create a target from the supplied game descriptor
+ *
+ * Returns the created target name.
+ */
+ Common::String createTargetForGame(const DetectedGame &game);
};
/** Convenience shortcut for accessing the engine manager. */
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index 9e177b7632..58d1483bee 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -177,7 +177,7 @@ public:
_directoryGlobs = directoryGlobs;
}
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
return detectGameFilebased(allFiles, fslist, Mohawk::fileBased);
}
diff --git a/engines/obsolete.cpp b/engines/obsolete.cpp
index d65fb13ec1..ea96cff42e 100644
--- a/engines/obsolete.cpp
+++ b/engines/obsolete.cpp
@@ -55,7 +55,7 @@ void upgradeTargetIfNecessary(const ObsoleteGameID *obsoleteList) {
}
}
-GameDescriptor findGameID(
+PlainGameDescriptor findGameID(
const char *gameid,
const PlainGameDescriptor *gameids,
const ObsoleteGameID *obsoleteList
@@ -63,7 +63,7 @@ GameDescriptor findGameID(
// First search the list of supported gameids for a match.
const PlainGameDescriptor *g = findPlainGameDescriptor(gameid, gameids);
if (g)
- return GameDescriptor(*g);
+ return *g;
// If we didn't find the gameid in the main list, check if it
// is an obsolete game id.
@@ -73,16 +73,16 @@ GameDescriptor findGameID(
if (0 == scumm_stricmp(gameid, o->from)) {
g = findPlainGameDescriptor(o->to, gameids);
if (g && g->description)
- return GameDescriptor(gameid, "Obsolete game ID (" + Common::String(g->description) + ")");
+ return PlainGameDescriptor::of(gameid, g->description);
else
- return GameDescriptor(gameid, "Obsolete game ID");
+ return PlainGameDescriptor::of(gameid, "Obsolete game ID");
}
o++;
}
}
// No match found
- return GameDescriptor();
+ return PlainGameDescriptor::empty();
}
} // End of namespace Engines
diff --git a/engines/obsolete.h b/engines/obsolete.h
index be0963a7dc..7c7249e52b 100644
--- a/engines/obsolete.h
+++ b/engines/obsolete.h
@@ -66,7 +66,7 @@ void upgradeTargetIfNecessary(const ObsoleteGameID *obsoleteList);
* Optionally can take a list of obsolete game ids into account in order
* to support obsolete gameids.
*/
-GameDescriptor findGameID(
+PlainGameDescriptor findGameID(
const char *gameid,
const PlainGameDescriptor *gameids,
const ObsoleteGameID *obsoleteList = 0
diff --git a/engines/queen/detection.cpp b/engines/queen/detection.cpp
index 0ad1b8322c..b9a7c5dff6 100644
--- a/engines/queen/detection.cpp
+++ b/engines/queen/detection.cpp
@@ -486,7 +486,7 @@ public:
virtual int getMaximumSaveSlot() const { return 99; }
virtual void removeSaveState(const char *target, int slot) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
};
bool QueenMetaEngine::hasFeature(MetaEngineFeature f) const {
@@ -496,7 +496,7 @@ bool QueenMetaEngine::hasFeature(MetaEngineFeature f) const {
(f == kSupportsDeleteSave);
}
-const ADGameDescription *QueenMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame QueenMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
static ADGameDescription desc;
// Iterate over all files in the given directory
@@ -531,11 +531,13 @@ const ADGameDescription *QueenMetaEngine::fallbackDetect(const FileMap &allFiles
desc.extra = "Talkie";
desc.guiOptions = GAMEOPTION_ALT_INTRO;
}
- return (const ADGameDescription *)&desc;
+
+ return ADDetectedGame(&desc);
}
}
}
- return 0;
+
+ return ADDetectedGame();
}
SaveStateList QueenMetaEngine::listSaves(const char *target) const {
diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp
index fcd78502d9..82c29d3389 100644
--- a/engines/saga/detection.cpp
+++ b/engines/saga/detection.cpp
@@ -105,7 +105,7 @@ public:
_singleId = "saga";
}
- virtual GameDescriptor findGame(const char *gameId) const {
+ PlainGameDescriptor findGame(const char *gameId) const override {
return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index bc7241269d..9a70429e47 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -562,7 +562,7 @@ public:
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
@@ -590,7 +590,7 @@ Common::Language charToScummVMLanguage(const char c) {
}
}
-const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame SciMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
bool foundResMap = false;
bool foundRes000 = false;
@@ -647,7 +647,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// If these files aren't found, it can't be SCI
if (!foundResMap && !foundRes000)
- return 0;
+ return ADDetectedGame();
ResourceManager resMan(true);
resMan.addAppropriateSourcesForDetection(fslist);
@@ -658,7 +658,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// Is SCI32 compiled in? If not, and this is a SCI32 game,
// stop here
if (getSciVersionForDetection() >= SCI_VERSION_2)
- return 0;
+ return ADDetectedGame();
#endif
ViewType gameViews = resMan.getViewType();
@@ -667,7 +667,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// Can't be SCI (or unsupported SCI views). Pinball Creep by Sierra also uses resource.map/resource.000 files
// but doesn't share SCI format at all
if (gameViews == kViewUnknown)
- return 0;
+ return ADDetectedGame();
// Set the platform to Amiga if the game is using Amiga views
if (gameViews == kViewAmiga)
@@ -678,7 +678,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
// If we don't have a game id, the game is not SCI
if (sierraGameId.empty())
- return 0;
+ return ADDetectedGame();
Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
@@ -753,7 +753,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
s_fallbackDesc.extra = "CD";
}
- return &s_fallbackDesc;
+ return ADDetectedGame(&s_fallbackDesc);
}
bool SciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index 9573db55cd..fccb30b0fa 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -959,9 +959,9 @@ public:
virtual const char *getOriginalCopyright() const;
virtual bool hasFeature(MetaEngineFeature f) const;
- virtual GameList getSupportedGames() const;
- virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const Common::FSList &fslist, bool useUnknownGameDialog = false) const;
+ PlainGameList getSupportedGames() const override;
+ PlainGameDescriptor findGame(const char *gameid) const override;
+ virtual DetectedGames detectGames(const Common::FSList &fslist) const override;
virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
@@ -992,11 +992,11 @@ bool ScummEngine::hasFeature(EngineFeature f) const {
(f == kSupportsSubtitleOptions);
}
-GameList ScummMetaEngine::getSupportedGames() const {
- return GameList(gameDescriptions);
+PlainGameList ScummMetaEngine::getSupportedGames() const {
+ return PlainGameList(gameDescriptions);
}
-GameDescriptor ScummMetaEngine::findGame(const char *gameid) const {
+PlainGameDescriptor ScummMetaEngine::findGame(const char *gameid) const {
return Engines::findGameID(gameid, gameDescriptions, obsoleteGameIDsTable);
}
@@ -1026,29 +1026,26 @@ static Common::String generatePreferredTarget(const DetectorResult &x) {
return res;
}
-GameList ScummMetaEngine::detectGames(const Common::FSList &fslist, bool /*useUnknownGameDialog*/) const {
- GameList detectedGames;
+DetectedGames ScummMetaEngine::detectGames(const Common::FSList &fslist) const {
+ DetectedGames detectedGames;
Common::List<DetectorResult> results;
-
::detectGames(fslist, results, 0);
for (Common::List<DetectorResult>::iterator
x = results.begin(); x != results.end(); ++x) {
const PlainGameDescriptor *g = findPlainGameDescriptor(x->game.gameid, gameDescriptions);
assert(g);
- GameDescriptor dg(x->game.gameid, g->description, x->language, x->game.platform);
- // Append additional information, if set, to the description.
- dg.updateDesc(x->extra);
+ DetectedGame game = DetectedGame(x->game.gameid, g->description, x->language, x->game.platform, x->extra);
// Compute and set the preferred target name for this game.
// Based on generateComplexID() in advancedDetector.cpp.
- dg["preferredtarget"] = generatePreferredTarget(*x);
+ game.preferredTarget = generatePreferredTarget(*x);
- dg.setGUIOptions(x->game.guioptions + MidiDriver::musicType2GUIO(x->game.midi));
- dg.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(x->language));
+ game.setGUIOptions(x->game.guioptions + MidiDriver::musicType2GUIO(x->game.midi));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(x->language));
- detectedGames.push_back(dg);
+ detectedGames.push_back(game);
}
return detectedGames;
diff --git a/engines/sky/detection.cpp b/engines/sky/detection.cpp
index a74b63fb8c..642e4d31a7 100644
--- a/engines/sky/detection.cpp
+++ b/engines/sky/detection.cpp
@@ -76,10 +76,10 @@ public:
virtual const char *getOriginalCopyright() const;
virtual bool hasFeature(MetaEngineFeature f) const;
- virtual GameList getSupportedGames() const;
+ PlainGameList getSupportedGames() const override;
virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
- virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const Common::FSList &fslist, bool useUnknownGameDialog = false) const;
+ PlainGameDescriptor findGame(const char *gameid) const override;
+ DetectedGames detectGames(const Common::FSList &fslist) const override;
virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
@@ -110,8 +110,8 @@ bool Sky::SkyEngine::hasFeature(EngineFeature f) const {
(f == kSupportsSavingDuringRuntime);
}
-GameList SkyMetaEngine::getSupportedGames() const {
- GameList games;
+PlainGameList SkyMetaEngine::getSupportedGames() const {
+ PlainGameList games;
games.push_back(skySetting);
return games;
}
@@ -135,14 +135,14 @@ const ExtraGuiOptions SkyMetaEngine::getExtraGuiOptions(const Common::String &ta
return options;
}
-GameDescriptor SkyMetaEngine::findGame(const char *gameid) const {
+PlainGameDescriptor SkyMetaEngine::findGame(const char *gameid) const {
if (0 == scumm_stricmp(gameid, skySetting.gameId))
return skySetting;
- return GameDescriptor();
+ return PlainGameDescriptor::empty();
}
-GameList SkyMetaEngine::detectGames(const Common::FSList &fslist, bool /*useUnknownGameDialog*/) const {
- GameList detectedGames;
+DetectedGames SkyMetaEngine::detectGames(const Common::FSList &fslist) const {
+ DetectedGames detectedGames;
bool hasSkyDsk = false;
bool hasSkyDnr = false;
int dinnerTableEntries = -1;
@@ -173,18 +173,25 @@ GameList SkyMetaEngine::detectGames(const Common::FSList &fslist, bool /*useUnkn
// Match found, add to list of candidates, then abort inner loop.
// The game detector uses US English by default. We want British
// English to match the recorded voices better.
- GameDescriptor dg(skySetting.gameId, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown);
const SkyVersion *sv = skyVersions;
while (sv->dinnerTableEntries) {
if (dinnerTableEntries == sv->dinnerTableEntries &&
(sv->dataDiskSize == dataDiskSize || sv->dataDiskSize == -1)) {
- dg.updateDesc(Common::String::format("v0.0%d %s", sv->version, sv->extraDesc).c_str());
- dg.setGUIOptions(sv->guioptions);
break;
}
++sv;
}
- detectedGames.push_back(dg);
+
+ if (sv->dinnerTableEntries) {
+ Common::String extra = Common::String::format("v0.0%d %s", sv->version, sv->extraDesc);
+
+ DetectedGame game = DetectedGame(skySetting.gameId, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown, extra);
+ game.setGUIOptions(sv->guioptions);
+
+ detectedGames.push_back(game);
+ } else {
+ detectedGames.push_back(DetectedGame(skySetting.gameId, skySetting.description));
+ }
}
return detectedGames;
diff --git a/engines/sludge/detection.cpp b/engines/sludge/detection.cpp
index 361d44b1e1..8c5c0ac13d 100644
--- a/engines/sludge/detection.cpp
+++ b/engines/sludge/detection.cpp
@@ -100,10 +100,10 @@ public:
}
// for fall back detection
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
};
-const ADGameDescription *SludgeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ADDetectedGame SludgeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
// reset fallback description
s_fallbackDesc.desc.gameId = "sludge";
s_fallbackDesc.desc.extra = "";
@@ -147,9 +147,19 @@ const ADGameDescription *SludgeMetaEngine::fallbackDetect(const FileMap &allFile
s_fallbackFileNameBuffer[50] = '\0';
s_fallbackDesc.desc.filesDescriptions[0].fileName = s_fallbackFileNameBuffer;
- return (const ADGameDescription *)&s_fallbackDesc;
+ ADDetectedGame game;
+ game.desc = &s_fallbackDesc.desc;
+
+ FileProperties tmp;
+ if (getFileProperties(file->getParent(), allFiles, s_fallbackDesc.desc, fileName, tmp)) {
+ game.hasUnknownFiles = true;
+ game.matchedFiles[fileName] = tmp;
+ }
+
+ return game;
}
- return 0;
+
+ return ADDetectedGame();
}
#if PLUGIN_ENABLED_DYNAMIC(SLUDGE)
diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp
index ddfc4b8c14..52394cec41 100644
--- a/engines/sword1/detection.cpp
+++ b/engines/sword1/detection.cpp
@@ -87,9 +87,9 @@ public:
}
virtual bool hasFeature(MetaEngineFeature f) const;
- virtual GameList getSupportedGames() const;
- virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const Common::FSList &fslist, bool useUnknownGameDialog = false) const;
+ PlainGameList getSupportedGames() const override;
+ PlainGameDescriptor findGame(const char *gameId) const override;
+ DetectedGames detectGames(const Common::FSList &fslist) const override;
virtual SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
virtual void removeSaveState(const char *target, int slot) const;
@@ -116,31 +116,31 @@ bool Sword1::SwordEngine::hasFeature(EngineFeature f) const {
(f == kSupportsLoadingDuringRuntime);
}
-GameList SwordMetaEngine::getSupportedGames() const {
- GameList games;
- games.push_back(GameDescriptor(sword1FullSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1DemoSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1MacFullSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1MacDemoSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1PSXSettings, GUIO_NOMIDI));
- games.push_back(GameDescriptor(sword1PSXDemoSettings, GUIO_NOMIDI));
+PlainGameList SwordMetaEngine::getSupportedGames() const {
+ PlainGameList games;
+ games.push_back(sword1FullSettings);
+ games.push_back(sword1DemoSettings);
+ games.push_back(sword1MacFullSettings);
+ games.push_back(sword1MacDemoSettings);
+ games.push_back(sword1PSXSettings);
+ games.push_back(sword1PSXDemoSettings);
return games;
}
-GameDescriptor SwordMetaEngine::findGame(const char *gameid) const {
- if (0 == scumm_stricmp(gameid, sword1FullSettings.gameId))
+PlainGameDescriptor SwordMetaEngine::findGame(const char *gameId) const {
+ if (0 == scumm_stricmp(gameId, sword1FullSettings.gameId))
return sword1FullSettings;
- if (0 == scumm_stricmp(gameid, sword1DemoSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1DemoSettings.gameId))
return sword1DemoSettings;
- if (0 == scumm_stricmp(gameid, sword1MacFullSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1MacFullSettings.gameId))
return sword1MacFullSettings;
- if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1MacDemoSettings.gameId))
return sword1MacDemoSettings;
- if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1PSXSettings.gameId))
return sword1PSXSettings;
- if (0 == scumm_stricmp(gameid, sword1PSXDemoSettings.gameId))
+ if (0 == scumm_stricmp(gameId, sword1PSXDemoSettings.gameId))
return sword1PSXDemoSettings;
- return GameDescriptor();
+ return PlainGameDescriptor::empty();
}
void Sword1CheckDirectory(const Common::FSList &fslist, bool *filesFound, bool recursion = false) {
@@ -175,9 +175,9 @@ void Sword1CheckDirectory(const Common::FSList &fslist, bool *filesFound, bool r
}
}
-GameList SwordMetaEngine::detectGames(const Common::FSList &fslist, bool /*useUnknownGameDialog*/) const {
+DetectedGames SwordMetaEngine::detectGames(const Common::FSList &fslist) const {
int i, j;
- GameList detectedGames;
+ DetectedGames detectedGames;
bool filesFound[NUM_FILES_TO_CHECK];
for (i = 0; i < NUM_FILES_TO_CHECK; i++)
filesFound[i] = false;
@@ -212,31 +212,33 @@ GameList SwordMetaEngine::detectGames(const Common::FSList &fslist, bool /*useUn
if (!filesFound[i] || psxFilesFound)
psxDemoFilesFound = false;
- GameDescriptor gd;
+ DetectedGame game;
if (mainFilesFound && pcFilesFound && demoFilesFound)
- gd = GameDescriptor(sword1DemoSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1DemoSettings);
else if (mainFilesFound && pcFilesFound && psxFilesFound)
- gd = GameDescriptor(sword1PSXSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1PSXSettings);
else if (mainFilesFound && pcFilesFound && psxDemoFilesFound)
- gd = GameDescriptor(sword1PSXDemoSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1PSXDemoSettings);
else if (mainFilesFound && pcFilesFound && !psxFilesFound)
- gd = GameDescriptor(sword1FullSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1FullSettings);
else if (mainFilesFound && macFilesFound)
- gd = GameDescriptor(sword1MacFullSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1MacFullSettings);
else if (mainFilesFound && macDemoFilesFound)
- gd = GameDescriptor(sword1MacDemoSettings, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+ game = DetectedGame(sword1MacDemoSettings);
else
return detectedGames;
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::DE_DEU));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::FR_FRA));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::IT_ITA));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::ES_ESP));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::PT_BRA));
- gd.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::CZ_CZE));
+ game.setGUIOptions(GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
- detectedGames.push_back(gd);
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::DE_DEU));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::FR_FRA));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::IT_ITA));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::ES_ESP));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::PT_BRA));
+ game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::CZ_CZE));
+
+ detectedGames.push_back(game);
return detectedGames;
}
diff --git a/engines/sword2/sword2.cpp b/engines/sword2/sword2.cpp
index 10ddda7d2e..4d8399e630 100644
--- a/engines/sword2/sword2.cpp
+++ b/engines/sword2/sword2.cpp
@@ -92,10 +92,10 @@ public:
}
virtual bool hasFeature(MetaEngineFeature f) const;
- virtual GameList getSupportedGames() const;
+ PlainGameList getSupportedGames() const override;
virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
- virtual GameDescriptor findGame(const char *gameid) const;
- virtual GameList detectGames(const Common::FSList &fslist, bool useUnknownGameDialog = false) const;
+ PlainGameDescriptor findGame(const char *gameid) const override;
+ virtual DetectedGames detectGames(const Common::FSList &fslist) const;
virtual SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
virtual void removeSaveState(const char *target, int slot) const;
@@ -119,11 +119,11 @@ bool Sword2::Sword2Engine::hasFeature(EngineFeature f) const {
(f == kSupportsLoadingDuringRuntime);
}
-GameList Sword2MetaEngine::getSupportedGames() const {
+PlainGameList Sword2MetaEngine::getSupportedGames() const {
const Sword2::GameSettings *g = Sword2::sword2_settings;
- GameList games;
+ PlainGameList games;
while (g->gameid) {
- games.push_back(GameDescriptor(g->gameid, g->description));
+ games.push_back(PlainGameDescriptor::of(g->gameid, g->description));
g++;
}
return games;
@@ -135,20 +135,20 @@ const ExtraGuiOptions Sword2MetaEngine::getExtraGuiOptions(const Common::String
return options;
}
-GameDescriptor Sword2MetaEngine::findGame(const char *gameid) const {
+PlainGameDescriptor Sword2MetaEngine::findGame(const char *gameid) const {
const Sword2::GameSettings *g = Sword2::sword2_settings;
while (g->gameid) {
if (0 == scumm_stricmp(gameid, g->gameid))
break;
g++;
}
- return GameDescriptor(g->gameid, g->description);
+ return PlainGameDescriptor::of(g->gameid, g->description);
}
bool isFullGame(const Common::FSList &fslist) {
Common::FSList::const_iterator file;
- // We distinguish between the two versions by the presense of paris.clu
+ // We distinguish between the two versions by the presence of paris.clu
for (file = fslist.begin(); file != fslist.end(); ++file) {
if (!file->isDirectory()) {
if (file->getName().equalsIgnoreCase("paris.clu"))
@@ -159,8 +159,8 @@ bool isFullGame(const Common::FSList &fslist) {
return false;
}
-GameList detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
- GameList detectedGames;
+DetectedGames detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
+ DetectedGames detectedGames;
const Sword2::GameSettings *g;
Common::FSList::const_iterator file;
bool isFullVersion = isFullGame(fslist);
@@ -192,7 +192,10 @@ GameList detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
continue;
// Match found, add to list of candidates, then abort inner loop.
- detectedGames.push_back(GameDescriptor(g->gameid, g->description, Common::UNK_LANG, Common::kPlatformUnknown, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)));
+ DetectedGame game = DetectedGame(g->gameid, g->description);
+ game.setGUIOptions(GUIO2(GUIO_NOMIDI, GUIO_NOASPECT));
+
+ detectedGames.push_back(game);
break;
}
}
@@ -208,7 +211,7 @@ GameList detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
if (file->getName().equalsIgnoreCase("clusters")) {
Common::FSList recList;
if (file->getChildren(recList, Common::FSNode::kListAll)) {
- GameList recGames(detectGamesImpl(recList, true));
+ DetectedGames recGames = detectGamesImpl(recList, true);
if (!recGames.empty()) {
detectedGames.push_back(recGames);
break;
@@ -223,7 +226,7 @@ GameList detectGamesImpl(const Common::FSList &fslist, bool recursion = false) {
return detectedGames;
}
-GameList Sword2MetaEngine::detectGames(const Common::FSList &fslist, bool /*useUnknownGameDialog*/) const {
+DetectedGames Sword2MetaEngine::detectGames(const Common::FSList &fslist) const {
return detectGamesImpl(fslist);
}
@@ -278,10 +281,10 @@ Common::Error Sword2MetaEngine::createInstance(OSystem *syst, Engine **engine) c
// Invoke the detector
Common::String gameid = ConfMan.get("gameid");
- GameList detectedGames = detectGames(fslist);
+ DetectedGames detectedGames = detectGames(fslist);
for (uint i = 0; i < detectedGames.size(); i++) {
- if (detectedGames[i].gameid() == gameid) {
+ if (detectedGames[i].gameId == gameid) {
*engine = new Sword2::Sword2Engine(syst);
return Common::kNoError;
}
diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp
index d6bcfe5ea0..1c60c5eb8a 100644
--- a/engines/tinsel/detection.cpp
+++ b/engines/tinsel/detection.cpp
@@ -97,7 +97,7 @@ public:
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual SaveStateList listSaves(const char *target) const;
@@ -185,7 +185,7 @@ 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 FileMap &allFilesXXX, const Common::FSList &fslist) const {
+ADDetectedGame TinselMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const {
Common::String extra;
FileMap allFiles;
SizeMD5Map filesSizeMD5;
@@ -194,7 +194,7 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
const Tinsel::TinselGameDescription *g;
if (fslist.empty())
- return NULL;
+ return ADDetectedGame();
// TODO: The following code is essentially a slightly modified copy of the
// complete code of function detectGame() in engines/advancedDetector.cpp.
@@ -262,7 +262,7 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
}
}
- ADGameDescList matched;
+ ADDetectedGame matched;
int maxFilesMatched = 0;
// MD5 based matching
@@ -310,22 +310,15 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++)
curFilesMatched++;
- if (curFilesMatched > maxFilesMatched) {
+ if (curFilesMatched >= maxFilesMatched) {
maxFilesMatched = curFilesMatched;
- matched.clear(); // Remove any prior, lower ranked matches.
- matched.push_back((const ADGameDescription *)g);
- } else if (curFilesMatched == maxFilesMatched) {
- matched.push_back((const ADGameDescription *)g);
+ matched = ADDetectedGame(&g->desc);
}
}
}
- // We didn't find a match
- if (matched.empty())
- return NULL;
-
- return *matched.begin();
+ return matched;
}
int TinselMetaEngine::getMaximumSaveSlot() const { return 99; }
diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp
index 6eb38c4883..634d286c7c 100644
--- a/engines/toon/detection.cpp
+++ b/engines/toon/detection.cpp
@@ -132,7 +132,7 @@ public:
_directoryGlobs = directoryGlobs;
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
return detectGameFilebased(allFiles, fslist, Toon::fileBasedFallback);
}
diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp
index dcb58ffae6..51b17b26d9 100644
--- a/engines/touche/detection.cpp
+++ b/engines/touche/detection.cpp
@@ -133,15 +133,8 @@ public:
_directoryGlobs = directoryGlobs;
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
- ADFilePropertiesMap filesProps;
-
- const ADGameDescription *matchedDesc = detectGameFilebased(allFiles, fslist, Touche::fileBasedFallback, &filesProps);
- if (!matchedDesc)
- return 0;
-
- reportUnknown(fslist.begin()->getParent(), filesProps);
- return matchedDesc;
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
+ return detectGameFilebased(allFiles, fslist, Touche::fileBasedFallback);
}
virtual const char *getName() const {
diff --git a/engines/tucker/detection.cpp b/engines/tucker/detection.cpp
index 119d60f23a..2318947b12 100644
--- a/engines/tucker/detection.cpp
+++ b/engines/tucker/detection.cpp
@@ -149,18 +149,19 @@ public:
return desc != 0;
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ virtual ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
for (Common::FSList::const_iterator d = fslist.begin(); d != fslist.end(); ++d) {
Common::FSList audiofslist;
if (d->isDirectory() && d->getName().equalsIgnoreCase("audio") && d->getChildren(audiofslist, Common::FSNode::kListFilesOnly)) {
for (Common::FSList::const_iterator f = audiofslist.begin(); f != audiofslist.end(); ++f) {
if (!f->isDirectory() && f->getName().equalsIgnoreCase("demorolc.raw")) {
- return &tuckerDemoGameDescription;
+ return ADDetectedGame(&tuckerDemoGameDescription);
}
}
}
}
- return 0;
+
+ return ADDetectedGame();
}
virtual SaveStateList listSaves(const char *target) const {
diff --git a/engines/unknown-game-dialog.cpp b/engines/unknown-game-dialog.cpp
index f737eb1c67..1b7dd73a92 100644
--- a/engines/unknown-game-dialog.cpp
+++ b/engines/unknown-game-dialog.cpp
@@ -20,14 +20,16 @@
*
*/
+#include "engines/unknown-game-dialog.h"
+
#include "common/translation.h"
#include "common/str-array.h"
#include "common/system.h"
+
#include "gui/gui-manager.h"
#include "gui/message.h"
#include "gui/ThemeEval.h"
#include "gui/widgets/popup.h"
-#include "engines/unknown-game-dialog.h"
enum {
kCopyToClipboard = 'cpcl',
@@ -35,36 +37,33 @@ enum {
kClose = 'clse'
};
-UnknownGameDialog::UnknownGameDialog(const Common::String &reportData, const Common::String &reportTranslated, const Common::String &bugtrackerAffectedEngine)
- : Dialog(30, 20, 260, 124) {
-
- _reportData = reportData;
- _reportTranslated = reportTranslated;
- _bugtrackerAffectedEngine = bugtrackerAffectedEngine;
+UnknownGameDialog::UnknownGameDialog(const DetectionResults &detectionResults) :
+ Dialog(30, 20, 260, 124),
+ _detectionResults(detectionResults) {
+ Common::String reportTranslated = _detectionResults.generateUnknownGameReport(true);
- //Check if we have clipboard functionality and expand the reportTranslated message if needed...
+ // Check if we have clipboard functionality and expand the reportTranslated message if needed...
if (g_system->hasFeature(OSystem::kFeatureClipboardSupport)) {
- _reportTranslated += "\n";
- _reportTranslated += _("Use the button below to copy the required game information into your clipboard.");
+ reportTranslated += "\n";
+ reportTranslated += _("Use the button below to copy the required game information into your clipboard.");
}
#if 0
- //Check if we have support for opening URLs and expand the reportTranslated message if needed...
+ // Check if we have support for opening URLs and expand the reportTranslated message if needed...
if (g_system->hasFeature(OSystem::kFeatureOpenUrl)) {
- _reportTranslated += "\n";
- _reportTranslated += _("You can also directly report your game to the Bug Tracker!");
+ reportTranslated += "\n";
+ reportTranslated += _("You can also directly report your game to the Bug Tracker.");
}
#endif
const int screenW = g_system->getOverlayWidth();
- const int screenH = g_system->getOverlayHeight();
int buttonWidth = g_gui.xmlEval()->getVar("Globals.Button.Width", 0);
int buttonHeight = g_gui.xmlEval()->getVar("Globals.Button.Height", 0);
- //Calculate the size the dialog needs
+ // Calculate the size the dialog needs
Common::Array<Common::String> lines;
- int maxlineWidth = g_gui.getFont().wordWrapText(_reportTranslated, screenW - 2 * 20, lines);
+ int maxlineWidth = g_gui.getFont().wordWrapText(reportTranslated, screenW - 2 * 20, lines);
int lineCount = lines.size() + 1;
_h = 3 * kLineHeight + lineCount * kLineHeight;
@@ -84,7 +83,7 @@ UnknownGameDialog::UnknownGameDialog(const Common::String &reportData, const Com
int buttonPos = _w - closeButtonWidth - 10;
new GUI::ButtonWidget(this, buttonPos, _h - buttonHeight - 8, buttonWidth, buttonHeight, _("Close"), 0, kClose);
- //Check if we have clipboard functionality
+ // Check if we have clipboard functionality
if (g_system->hasFeature(OSystem::kFeatureClipboardSupport)) {
buttonPos -= copyToClipboardButtonWidth + 5;
new GUI::ButtonWidget(this, buttonPos, _h - buttonHeight - 8, copyToClipboardButtonWidth, buttonHeight, _("Copy to clipboard"), 0, kCopyToClipboard);
@@ -98,15 +97,10 @@ UnknownGameDialog::UnknownGameDialog(const Common::String &reportData, const Com
// https://www.scummvm.org/unknowngame?engine=Foo&description=Bar) that would
// redirect to whatever our bugtracker system is.
- //Check if we have support for opening URLs
+ // Check if we have support for opening URLs
if (g_system->hasFeature(OSystem::kFeatureOpenUrl)) {
buttonPos -= openBugtrackerURLButtonWidth + 5;
new GUI::ButtonWidget(this, buttonPos, _h - buttonHeight - 8, openBugtrackerURLButtonWidth, buttonHeight, _("Report game"), 0, kOpenBugtrackerURL);
- //Formatting the reportData for bugtracker submission [replace line breaks]...
- _bugtrackerGameData = _reportData;
- while (_bugtrackerGameData.contains("\n")) {
- Common::replace(_bugtrackerGameData, "\n", "%0A");
- }
}
#endif
@@ -126,27 +120,39 @@ void UnknownGameDialog::reflowLayout() {
}
Common::String UnknownGameDialog::generateBugtrackerURL() {
- return Common::String::format((
+ // TODO: Remove the filesystem path from the bugtracker report
+ Common::String report = _detectionResults.generateUnknownGameReport(false);
+
+ // Formatting the report for bugtracker submission [replace line breaks]...
+ while (report.contains("\n")) {
+ Common::replace(report, "\n", "%0A");
+ }
+
+ return Common::String::format(
"https://bugs.scummvm.org/newticket?"
- "summary=[UNK] Unknown game for engine %s:"
"&description=%s"
- "&component=Engine%%3A%s"
"&type=enhancement"
- "&keywords=unknown-game,%s"),
- _bugtrackerAffectedEngine.c_str(), _bugtrackerGameData.c_str(), _bugtrackerAffectedEngine.c_str(), _bugtrackerAffectedEngine.c_str());
+ "&keywords=unknown-game",
+ report.c_str());
}
void UnknownGameDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
switch(cmd) {
- case kCopyToClipboard:
- g_system->setTextInClipboard(_reportData);
- if (g_system->setTextInClipboard(_reportData)) {
- g_system->displayMessageOnOSD(_("All necessary information about your game has been copied into the clipboard"));
+ case kCopyToClipboard: {
+ // TODO: Remove the filesystem path from the report
+ Common::String report = _detectionResults.generateUnknownGameReport(false);
+
+ if (g_system->setTextInClipboard(report)) {
+ g_system->displayMessageOnOSD(
+ _("All necessary information about your game has been copied into the clipboard"));
} else {
g_system->displayMessageOnOSD(_("Copying the game information to the clipboard has failed!"));
}
break;
+ }
case kClose:
+ // When the detection entry comes from the fallback detector, the game can be added / launched anyways.
+ // TODO: Add a button to cancel adding the game. And make it clear that launching the game may not work properly.
close();
break;
case kOpenBugtrackerURL:
diff --git a/engines/unknown-game-dialog.h b/engines/unknown-game-dialog.h
index 51adf27996..0878406244 100644
--- a/engines/unknown-game-dialog.h
+++ b/engines/unknown-game-dialog.h
@@ -22,16 +22,18 @@
#include "gui/dialog.h"
+#include "engines/metaengine.h"
+
class UnknownGameDialog : public GUI::Dialog {
public:
- UnknownGameDialog(const Common::String &reportData, const Common::String &reportTranslated, const Common::String &bugtrackerAffectedEngine);
- void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
- virtual Common::String generateBugtrackerURL();
- virtual void reflowLayout();
+ UnknownGameDialog(const DetectionResults &detectionResults);
private:
- Common::String _reportData;
- Common::String _reportTranslated;
- Common::String _bugtrackerGameData;
- Common::String _bugtrackerAffectedEngine;
+ // Dialog API
+ void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
+ void reflowLayout() override;
+
+ Common::String generateBugtrackerURL();
+
+ const DetectionResults &_detectionResults;
};
diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp
index df5cc41b10..6208d775a6 100644
--- a/engines/wintermute/detection.cpp
+++ b/engines/wintermute/detection.cpp
@@ -100,7 +100,7 @@ public:
return "Copyright (C) 2011 Jan Nedoma";
}
- virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override {
// Set some defaults
s_fallbackDesc.extra = "";
s_fallbackDesc.language = Common::UNK_LANG;
@@ -130,10 +130,12 @@ public:
s_fallbackDesc.extra = offset;
s_fallbackDesc.flags |= ADGF_USEEXTRAASTITLE;
}
- return &s_fallbackDesc;
+
+ return ADDetectedGame(&s_fallbackDesc);
} // Fall through to return 0;
}
- return 0;
+
+ return ADDetectedGame();
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {