mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-18 16:03:05 +00:00
Merge pull request #1187 from bgK/detection-refactor-unknown
ENGINES: Return unknown game variants with the list of detected games
This commit is contained in:
commit
61f9398b04
@ -271,21 +271,21 @@ static int findGames(Game *games, int max, bool use_ini)
|
||||
}
|
||||
|
||||
if (!use_ini) {
|
||||
GameList candidates = EngineMan.detectGames(files);
|
||||
DetectedGames candidates = EngineMan.detectGames(files);
|
||||
|
||||
for (GameList::const_iterator ge = candidates.begin();
|
||||
for (DetectedGames::const_iterator ge = candidates.begin();
|
||||
ge != candidates.end(); ++ge)
|
||||
if (curr_game < max) {
|
||||
strcpy(games[curr_game].filename_base, ge->gameid().c_str());
|
||||
strcpy(games[curr_game].filename_base, ge->gameId.c_str());
|
||||
strcpy(games[curr_game].dir, dirs[curr_dir-1].name);
|
||||
games[curr_game].language = ge->language();
|
||||
games[curr_game].platform = ge->platform();
|
||||
games[curr_game].language = ge->language;
|
||||
games[curr_game].platform = ge->platform;
|
||||
if (uniqueGame(games[curr_game].filename_base,
|
||||
games[curr_game].dir,
|
||||
games[curr_game].language,
|
||||
games[curr_game].platform, games, curr_game)) {
|
||||
|
||||
strcpy(games[curr_game].text, ge->description().c_str());
|
||||
strcpy(games[curr_game].text, ge->description.c_str());
|
||||
#if 0
|
||||
printf("Registered game <%s> (l:%d p:%d) in <%s> <%s> because of <%s> <*>\n",
|
||||
games[curr_game].text,
|
||||
|
@ -687,9 +687,9 @@ static void listGames() {
|
||||
|
||||
const PluginList &plugins = EngineMan.getPlugins();
|
||||
for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); ++iter) {
|
||||
GameList list = (*iter)->get<MetaEngine>().getSupportedGames();
|
||||
for (GameList::iterator v = list.begin(); v != list.end(); ++v) {
|
||||
printf("%-20s %s\n", v->gameid().c_str(), v->description().c_str());
|
||||
PlainGameList list = (*iter)->get<MetaEngine>().getSupportedGames();
|
||||
for (PlainGameList::iterator v = list.begin(); v != list.end(); ++v) {
|
||||
printf("%-20s %s\n", v->gameId, v->description);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -714,10 +714,10 @@ static void listTargets() {
|
||||
// FIXME: At this point, we should check for a "gameid" override
|
||||
// to find the proper desc. In fact, the platform probably should
|
||||
// be taken into account, too.
|
||||
Common::String gameid(name);
|
||||
GameDescriptor g = EngineMan.findGame(gameid);
|
||||
if (g.description().size() > 0)
|
||||
description = g.description();
|
||||
const Common::String &gameid = name;
|
||||
PlainGameDescriptor g = EngineMan.findGame(gameid);
|
||||
if (g.description)
|
||||
description = g.description;
|
||||
}
|
||||
|
||||
targets.push_back(Common::String::format("%-20s %s", name.c_str(), description.c_str()));
|
||||
@ -770,7 +770,7 @@ static Common::Error listSaves(const Common::String &target) {
|
||||
|
||||
// Find the plugin that will handle the specified gameid
|
||||
const Plugin *plugin = nullptr;
|
||||
GameDescriptor game = EngineMan.findGame(gameid, &plugin);
|
||||
EngineMan.findGame(gameid, &plugin);
|
||||
|
||||
if (!plugin) {
|
||||
// If the target was specified, treat this as an error, and otherwise skip it.
|
||||
@ -854,61 +854,36 @@ static void listAudioDevices() {
|
||||
}
|
||||
|
||||
/** Display all games in the given directory, or current directory if empty */
|
||||
static GameList getGameList(const Common::FSNode &dir) {
|
||||
static DetectedGames getGameList(const Common::FSNode &dir) {
|
||||
Common::FSList files;
|
||||
|
||||
// Collect all files from directory
|
||||
if (!dir.getChildren(files, Common::FSNode::kListAll)) {
|
||||
printf("Path %s does not exist or is not a directory.\n", dir.getPath().c_str());
|
||||
return GameList();
|
||||
return DetectedGames();
|
||||
}
|
||||
|
||||
// detect Games
|
||||
GameList candidates(EngineMan.detectGames(files));
|
||||
Common::String dataPath = dir.getPath();
|
||||
// add game data path
|
||||
for (GameList::iterator v = candidates.begin(); v != candidates.end(); ++v) {
|
||||
(*v)["path"] = dataPath;
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
DetectionResults detectionResults = EngineMan.detectGames(files);
|
||||
|
||||
static bool addGameToConf(const GameDescriptor &gd) {
|
||||
const Common::String &domain = gd.preferredtarget();
|
||||
|
||||
// If game has already been added, don't add
|
||||
if (ConfMan.hasGameDomain(domain))
|
||||
return false;
|
||||
|
||||
// Add the name domain
|
||||
ConfMan.addGameDomain(domain);
|
||||
|
||||
// Copy all non-empty key/value pairs into the new domain
|
||||
for (GameDescriptor::const_iterator iter = gd.begin(); iter != gd.end(); ++iter) {
|
||||
if (!iter->_value.empty() && iter->_key != "preferredtarget")
|
||||
ConfMan.set(iter->_key, iter->_value, domain);
|
||||
if (detectionResults.foundUnknownGames()) {
|
||||
Common::String report = detectionResults.generateUnknownGameReport(false, 80);
|
||||
g_system->logMessage(LogMessageType::kInfo, report.c_str());
|
||||
}
|
||||
|
||||
// Display added game info
|
||||
printf("Game Added: \n GameID: %s\n Name: %s\n Language: %s\n Platform: %s\n",
|
||||
gd.gameid().c_str(),
|
||||
gd.description().c_str(),
|
||||
Common::getLanguageDescription(gd.language()),
|
||||
Common::getPlatformDescription(gd.platform()));
|
||||
|
||||
return true;
|
||||
return detectionResults.listRecognizedGames();
|
||||
}
|
||||
|
||||
static GameList recListGames(const Common::FSNode &dir, const Common::String &gameId, bool recursive) {
|
||||
GameList list = getGameList(dir);
|
||||
static DetectedGames recListGames(const Common::FSNode &dir, const Common::String &gameId, bool recursive) {
|
||||
DetectedGames list = getGameList(dir);
|
||||
|
||||
if (recursive) {
|
||||
Common::FSList files;
|
||||
dir.getChildren(files, Common::FSNode::kListDirectoriesOnly);
|
||||
for (Common::FSList::const_iterator file = files.begin(); file != files.end(); ++file) {
|
||||
GameList rec = recListGames(*file, gameId, recursive);
|
||||
for (GameList::const_iterator game = rec.begin(); game != rec.end(); ++game) {
|
||||
if (gameId.empty() || game->gameid().c_str() == gameId)
|
||||
DetectedGames rec = recListGames(*file, gameId, recursive);
|
||||
for (DetectedGames::const_iterator game = rec.begin(); game != rec.end(); ++game) {
|
||||
if (gameId.empty() || game->gameId == gameId)
|
||||
list.push_back(*game);
|
||||
}
|
||||
}
|
||||
@ -922,7 +897,7 @@ static Common::String detectGames(const Common::String &path, const Common::Stri
|
||||
bool noPath = path.empty();
|
||||
//Current directory
|
||||
Common::FSNode dir(path);
|
||||
GameList candidates = recListGames(dir, gameId, recursive);
|
||||
DetectedGames candidates = recListGames(dir, gameId, recursive);
|
||||
|
||||
if (candidates.empty()) {
|
||||
printf("WARNING: ScummVM could not find any game in %s\n", dir.getPath().c_str());
|
||||
@ -937,25 +912,34 @@ static Common::String detectGames(const Common::String &path, const Common::Stri
|
||||
// TODO this is not especially pretty
|
||||
printf("ID Description Full Path\n");
|
||||
printf("-------------- ---------------------------------------------------------- ---------------------------------------------------------\n");
|
||||
for (GameList::iterator v = candidates.begin(); v != candidates.end(); ++v) {
|
||||
printf("%-14s %-58s %s\n", v->gameid().c_str(), v->description().c_str(), (*v)["path"].c_str());
|
||||
for (DetectedGames::const_iterator v = candidates.begin(); v != candidates.end(); ++v) {
|
||||
printf("%-14s %-58s %s\n", v->gameId.c_str(), v->description.c_str(), v->path.c_str());
|
||||
}
|
||||
|
||||
return candidates[0].gameid();
|
||||
return candidates[0].gameId;
|
||||
}
|
||||
|
||||
static int recAddGames(const Common::FSNode &dir, const Common::String &game, bool recursive) {
|
||||
int count = 0;
|
||||
GameList list = getGameList(dir);
|
||||
for (GameList::iterator v = list.begin(); v != list.end(); ++v) {
|
||||
if (v->gameid().c_str() != game && !game.empty()) {
|
||||
printf("Found %s, only adding %s per --game option, ignoring...\n", v->gameid().c_str(), game.c_str());
|
||||
} else if (!addGameToConf(*v)) {
|
||||
// TODO Is it reall the case that !addGameToConf iff already added?
|
||||
printf("Found %s, but has already been added, skipping\n", v->gameid().c_str());
|
||||
DetectedGames list = getGameList(dir);
|
||||
for (DetectedGames::const_iterator v = list.begin(); v != list.end(); ++v) {
|
||||
if (v->gameId != game && !game.empty()) {
|
||||
printf("Found %s, only adding %s per --game option, ignoring...\n", v->gameId.c_str(), game.c_str());
|
||||
} else if (ConfMan.hasGameDomain(v->preferredTarget)) {
|
||||
// TODO Better check for game already added?
|
||||
printf("Found %s, but has already been added, skipping\n", v->gameId.c_str());
|
||||
} else {
|
||||
printf("Found %s, adding...\n", v->gameid().c_str());
|
||||
Common::String target = EngineMan.createTargetForGame(*v);
|
||||
count++;
|
||||
|
||||
// Display added game info
|
||||
printf("Game Added: \n Target: %s\n GameID: %s\n Name: %s\n Language: %s\n Platform: %s\n",
|
||||
target.c_str(),
|
||||
v->gameId.c_str(),
|
||||
v->description.c_str(),
|
||||
Common::getLanguageDescription(v->language),
|
||||
Common::getPlatformDescription(v->platform)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1014,11 +998,13 @@ static void runDetectorTest() {
|
||||
continue;
|
||||
}
|
||||
|
||||
GameList candidates(EngineMan.detectGames(files));
|
||||
DetectionResults detectionResults = EngineMan.detectGames(files);
|
||||
DetectedGames candidates = detectionResults.listRecognizedGames();
|
||||
|
||||
bool gameidDiffers = false;
|
||||
GameList::iterator x;
|
||||
DetectedGames::const_iterator x;
|
||||
for (x = candidates.begin(); x != candidates.end(); ++x) {
|
||||
gameidDiffers |= (scumm_stricmp(gameid.c_str(), x->gameid().c_str()) != 0);
|
||||
gameidDiffers |= (scumm_stricmp(gameid.c_str(), x->gameId.c_str()) != 0);
|
||||
}
|
||||
|
||||
if (candidates.empty()) {
|
||||
@ -1041,10 +1027,10 @@ static void runDetectorTest() {
|
||||
|
||||
for (x = candidates.begin(); x != candidates.end(); ++x) {
|
||||
printf(" gameid '%s', desc '%s', language '%s', platform '%s'\n",
|
||||
x->gameid().c_str(),
|
||||
x->description().c_str(),
|
||||
Common::getLanguageCode(x->language()),
|
||||
Common::getPlatformCode(x->platform()));
|
||||
x->gameId.c_str(),
|
||||
x->description.c_str(),
|
||||
Common::getLanguageDescription(x->language),
|
||||
Common::getPlatformDescription(x->platform));
|
||||
}
|
||||
}
|
||||
int total = domains.size();
|
||||
@ -1092,24 +1078,26 @@ void upgradeTargets() {
|
||||
Common::Platform plat = Common::parsePlatform(dom.getVal("platform"));
|
||||
Common::String desc(dom.getVal("description"));
|
||||
|
||||
GameList candidates(EngineMan.detectGames(files));
|
||||
GameDescriptor *g = 0;
|
||||
DetectionResults detectionResults = EngineMan.detectGames(files);
|
||||
DetectedGames candidates = detectionResults.listRecognizedGames();
|
||||
|
||||
DetectedGame *g = 0;
|
||||
|
||||
// We proceed as follows:
|
||||
// * If detection failed to produce candidates, skip.
|
||||
// * If there is a unique detector match, trust it.
|
||||
// * If there are multiple match, run over them comparing gameid, language and platform.
|
||||
// If we end up with a unique match, use it. Otherwise, skip.
|
||||
if (candidates.size() == 0) {
|
||||
if (candidates.empty()) {
|
||||
printf(" ... failed to detect game, skipping\n");
|
||||
continue;
|
||||
}
|
||||
if (candidates.size() > 1) {
|
||||
// Scan over all candidates, check if there is a unique match for gameid, language and platform
|
||||
GameList::iterator x;
|
||||
DetectedGames::iterator x;
|
||||
int matchesFound = 0;
|
||||
for (x = candidates.begin(); x != candidates.end(); ++x) {
|
||||
if (x->gameid() == gameid && x->language() == lang && x->platform() == plat) {
|
||||
if (x->gameId == gameid && x->language == lang && x->platform == plat) {
|
||||
matchesFound++;
|
||||
g = &(*x);
|
||||
}
|
||||
@ -1127,27 +1115,27 @@ void upgradeTargets() {
|
||||
// the target referred to by dom. We update several things
|
||||
|
||||
// Always set the gameid explicitly (in case of legacy targets)
|
||||
dom["gameid"] = g->gameid();
|
||||
dom["gameid"] = g->gameId;
|
||||
|
||||
// Always set the GUI options. The user should not modify them, and engines might
|
||||
// gain more features over time, so we want to keep this list up-to-date.
|
||||
if (g->contains("guioptions")) {
|
||||
printf(" -> update guioptions to '%s'\n", (*g)["guioptions"].c_str());
|
||||
dom["guioptions"] = (*g)["guioptions"];
|
||||
if (!g->getGUIOptions().empty()) {
|
||||
printf(" -> update guioptions to '%s'\n", g->getGUIOptions().c_str());
|
||||
dom["guioptions"] = g->getGUIOptions();
|
||||
} else if (dom.contains("guioptions")) {
|
||||
dom.erase("guioptions");
|
||||
}
|
||||
|
||||
// Update the language setting but only if none has been set yet.
|
||||
if (lang == Common::UNK_LANG && g->language() != Common::UNK_LANG) {
|
||||
printf(" -> set language to '%s'\n", Common::getLanguageCode(g->language()));
|
||||
dom["language"] = (*g)["language"];
|
||||
if (lang == Common::UNK_LANG && g->language != Common::UNK_LANG) {
|
||||
printf(" -> set language to '%s'\n", Common::getLanguageCode(g->language));
|
||||
dom["language"] = Common::getLanguageCode(g->language);
|
||||
}
|
||||
|
||||
// Update the platform setting but only if none has been set yet.
|
||||
if (plat == Common::kPlatformUnknown && g->platform() != Common::kPlatformUnknown) {
|
||||
printf(" -> set platform to '%s'\n", Common::getPlatformCode(g->platform()));
|
||||
dom["platform"] = (*g)["platform"];
|
||||
if (plat == Common::kPlatformUnknown && g->platform != Common::kPlatformUnknown) {
|
||||
printf(" -> set platform to '%s'\n", Common::getPlatformCode(g->platform));
|
||||
dom["platform"] = Common::getPlatformCode(g->platform);
|
||||
}
|
||||
|
||||
// TODO: We could also update the description. But not everybody will want that.
|
||||
@ -1156,8 +1144,8 @@ void upgradeTargets() {
|
||||
// should only be updated if the user explicitly requests this.
|
||||
#if 0
|
||||
if (desc != g->description()) {
|
||||
printf(" -> update desc from '%s' to\n '%s' ?\n", desc.c_str(), g->description().c_str());
|
||||
dom["description"] = (*g)["description"];
|
||||
printf(" -> update desc from '%s' to\n '%s' ?\n", desc.c_str(), g->description.c_str());
|
||||
dom["description"] = g->description;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -1254,8 +1242,8 @@ bool processSettings(Common::String &command, Common::StringMap &settings, Commo
|
||||
// domain (i.e. a target) matching this argument, or alternatively
|
||||
// whether there is a gameid matching that name.
|
||||
if (!command.empty()) {
|
||||
GameDescriptor gd = EngineMan.findGame(command);
|
||||
if (ConfMan.hasGameDomain(command) || !gd.gameid().empty()) {
|
||||
PlainGameDescriptor gd = EngineMan.findGame(command);
|
||||
if (ConfMan.hasGameDomain(command) || gd.gameId) {
|
||||
bool idCameFromCommandLine = false;
|
||||
|
||||
// WORKAROUND: Fix for bug #1719463: "DETECTOR: Launching
|
||||
|
@ -128,13 +128,13 @@ static const Plugin *detectPlugin() {
|
||||
printf("User picked target '%s' (gameid '%s')...\n", ConfMan.getActiveDomainName().c_str(), gameid.c_str());
|
||||
printf(" Looking for a plugin supporting this gameid... ");
|
||||
|
||||
GameDescriptor game = EngineMan.findGame(gameid, &plugin);
|
||||
PlainGameDescriptor game = EngineMan.findGame(gameid, &plugin);
|
||||
|
||||
if (plugin == 0) {
|
||||
printf("failed\n");
|
||||
warning("%s is an invalid gameid. Use the --list-games option to list supported gameid", gameid.c_str());
|
||||
} else {
|
||||
printf("%s\n Starting '%s'\n", plugin->getName(), game.description().c_str());
|
||||
printf("%s\n Starting '%s'\n", plugin->getName(), game.description);
|
||||
}
|
||||
|
||||
return plugin;
|
||||
@ -210,7 +210,10 @@ static Common::Error runGame(const Plugin *plugin, OSystem &system, const Common
|
||||
Common::String caption(ConfMan.get("description"));
|
||||
|
||||
if (caption.empty()) {
|
||||
caption = EngineMan.findGame(ConfMan.get("gameid")).description();
|
||||
PlainGameDescriptor game = EngineMan.findGame(ConfMan.get("gameid"));
|
||||
if (game.description) {
|
||||
caption = game.description;
|
||||
}
|
||||
}
|
||||
if (caption.empty())
|
||||
caption = ConfMan.getActiveDomainName(); // Use the domain (=target) name
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
#include "common/translation.h"
|
||||
#include "common/func.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/config-manager.h"
|
||||
@ -457,13 +458,11 @@ DECLARE_SINGLETON(EngineManager);
|
||||
* For the uncached version, we first try to find the plugin using the gameId
|
||||
* and only if we can't find it there, we loop through the plugins.
|
||||
**/
|
||||
GameDescriptor EngineManager::findGame(const Common::String &gameName, const Plugin **plugin) const {
|
||||
GameDescriptor result;
|
||||
|
||||
PlainGameDescriptor EngineManager::findGame(const Common::String &gameName, const Plugin **plugin) const {
|
||||
// First look for the game using the plugins in memory. This is critical
|
||||
// for calls coming from inside games
|
||||
result = findGameInLoadedPlugins(gameName, plugin);
|
||||
if (!result.gameid().empty()) {
|
||||
PlainGameDescriptor result = findGameInLoadedPlugins(gameName, plugin);
|
||||
if (result.gameId) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -471,7 +470,7 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Plu
|
||||
// by plugin
|
||||
if (PluginMan.loadPluginFromGameId(gameName)) {
|
||||
result = findGameInLoadedPlugins(gameName, plugin);
|
||||
if (!result.gameid().empty()) {
|
||||
if (result.gameId) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -480,7 +479,7 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Plu
|
||||
PluginMan.loadFirstPlugin();
|
||||
do {
|
||||
result = findGameInLoadedPlugins(gameName, plugin);
|
||||
if (!result.gameid().empty()) {
|
||||
if (result.gameId) {
|
||||
// Update with new plugin file name
|
||||
PluginMan.updateConfigWithFileName(gameName);
|
||||
break;
|
||||
@ -493,10 +492,9 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Plu
|
||||
/**
|
||||
* Find the game within the plugins loaded in memory
|
||||
**/
|
||||
GameDescriptor EngineManager::findGameInLoadedPlugins(const Common::String &gameName, const Plugin **plugin) const {
|
||||
PlainGameDescriptor EngineManager::findGameInLoadedPlugins(const Common::String &gameName, const Plugin **plugin) const {
|
||||
// Find the GameDescriptor for this target
|
||||
const PluginList &plugins = getPlugins();
|
||||
GameDescriptor result;
|
||||
|
||||
if (plugin)
|
||||
*plugin = 0;
|
||||
@ -504,18 +502,20 @@ GameDescriptor EngineManager::findGameInLoadedPlugins(const Common::String &game
|
||||
PluginList::const_iterator iter;
|
||||
|
||||
for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
|
||||
result = (*iter)->get<MetaEngine>().findGame(gameName.c_str());
|
||||
if (!result.gameid().empty()) {
|
||||
PlainGameDescriptor pgd = (*iter)->get<MetaEngine>().findGame(gameName.c_str());
|
||||
if (pgd.gameId) {
|
||||
if (plugin)
|
||||
*plugin = *iter;
|
||||
return result;
|
||||
return pgd;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
return PlainGameDescriptor::empty();
|
||||
}
|
||||
|
||||
GameList EngineManager::detectGames(const Common::FSList &fslist, bool useUnknownGameDialog) const {
|
||||
GameList candidates;
|
||||
DetectionResults EngineManager::detectGames(const Common::FSList &fslist) const {
|
||||
DetectedGames candidates;
|
||||
Common::String path = fslist.begin()->getParent().getPath();
|
||||
PluginList plugins;
|
||||
PluginList::const_iterator iter;
|
||||
PluginManager::instance().loadFirstPlugin();
|
||||
@ -524,16 +524,75 @@ GameList EngineManager::detectGames(const Common::FSList &fslist, bool useUnknow
|
||||
// Iterate over all known games and for each check if it might be
|
||||
// the game in the presented directory.
|
||||
for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
|
||||
candidates.push_back((*iter)->get<MetaEngine>().detectGames(fslist, useUnknownGameDialog));
|
||||
const MetaEngine &metaEngine = (*iter)->get<MetaEngine>();
|
||||
DetectedGames engineCandidates = metaEngine.detectGames(fslist);
|
||||
|
||||
for (uint i = 0; i < engineCandidates.size(); i++) {
|
||||
engineCandidates[i].engineName = metaEngine.getName();
|
||||
engineCandidates[i].path = path;
|
||||
candidates.push_back(engineCandidates[i]);
|
||||
}
|
||||
|
||||
}
|
||||
} while (PluginManager::instance().loadNextPlugin());
|
||||
return candidates;
|
||||
|
||||
return DetectionResults(candidates);
|
||||
}
|
||||
|
||||
const PluginList &EngineManager::getPlugins() const {
|
||||
return PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void addStringToConf(const Common::String &key, const Common::String &value, const Common::String &domain) {
|
||||
if (!value.empty())
|
||||
ConfMan.set(key, value, domain);
|
||||
}
|
||||
|
||||
} // End of anonymous namespace
|
||||
|
||||
Common::String EngineManager::createTargetForGame(const DetectedGame &game) {
|
||||
// The auto detector or the user made a choice.
|
||||
// Pick a domain name which does not yet exist (after all, we
|
||||
// are *adding* a game to the config, not replacing).
|
||||
Common::String domain = game.preferredTarget;
|
||||
|
||||
assert(!domain.empty());
|
||||
if (ConfMan.hasGameDomain(domain)) {
|
||||
int suffixN = 1;
|
||||
Common::String gameid(domain);
|
||||
|
||||
while (ConfMan.hasGameDomain(domain)) {
|
||||
domain = gameid + Common::String::format("-%d", suffixN);
|
||||
suffixN++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the name domain
|
||||
ConfMan.addGameDomain(domain);
|
||||
|
||||
// Copy all non-empty relevant values into the new domain
|
||||
addStringToConf("gameid", game.gameId, domain);
|
||||
addStringToConf("description", game.description, domain);
|
||||
addStringToConf("language", Common::getLanguageCode(game.language), domain);
|
||||
addStringToConf("platform", Common::getPlatformCode(game.platform), domain);
|
||||
addStringToConf("path", game.path, domain);
|
||||
addStringToConf("extra", game.extra, domain);
|
||||
addStringToConf("guioptions", game.getGUIOptions(), domain);
|
||||
|
||||
// TODO: Setting the description field here has the drawback
|
||||
// that the user does never notice when we upgrade our descriptions.
|
||||
// It might be nice to leave this field empty, and only set it to
|
||||
// a value when the user edits the description string.
|
||||
// However, at this point, that's impractical. Once we have a method
|
||||
// to query all backends for the proper & full description of a given
|
||||
// game target, we can change this (currently, you can only query
|
||||
// for the generic gameid description; it's not possible to obtain
|
||||
// a description which contains extended information like language, etc.).
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
// Music plugins
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
static Common::String sanitizeName(const char *name) {
|
||||
Common::String res;
|
||||
|
||||
if (g.flags & ADGF_USEEXTRAASTITLE) {
|
||||
title = g.extra;
|
||||
extra = "";
|
||||
} else {
|
||||
while (sg->gameId) {
|
||||
if (!scumm_stricmp(g.gameId, sg->gameId))
|
||||
title = sg->description;
|
||||
sg++;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
DetectedGame game(gameId, title, desc->language, desc->platform, extra);
|
||||
game.hasUnknownFiles = adGame.hasUnknownFiles;
|
||||
game.matchedFiles = adGame.matchedFiles;
|
||||
game.preferredTarget = generatePreferredTarget(desc);
|
||||
|
||||
void AdvancedMetaEngine::updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const {
|
||||
if (_singleId != NULL) {
|
||||
desc["preferredtarget"] = desc["gameid"];
|
||||
desc["gameid"] = _singleId;
|
||||
}
|
||||
game.gameSupportLevel = kStableGame;
|
||||
if (desc->flags & ADGF_UNSTABLE)
|
||||
game.gameSupportLevel = kUnstableGame;
|
||||
else if (desc->flags & ADGF_TESTING)
|
||||
game.gameSupportLevel = kTestingGame;
|
||||
|
||||
if (!desc.contains("preferredtarget"))
|
||||
desc["preferredtarget"] = desc["gameid"];
|
||||
game.setGUIOptions(desc->guiOptions + _guiOptions);
|
||||
game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(desc->language));
|
||||
|
||||
if (realDesc->flags & ADGF_AUTOGENTARGET) {
|
||||
if (*realDesc->extra)
|
||||
desc["preferredtarget"] = sanitizeName(realDesc->extra);
|
||||
}
|
||||
|
||||
desc["preferredtarget"] = generatePreferredTarget(desc["preferredtarget"], realDesc);
|
||||
if (desc->flags & ADGF_ADDENGLISH)
|
||||
game.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
|
||||
|
||||
if (_flags & kADFlagUseExtraAsHint)
|
||||
desc["extra"] = realDesc->extra;
|
||||
game.extra = desc->extra;
|
||||
|
||||
desc.setGUIOptions(realDesc->guiOptions + _guiOptions);
|
||||
desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language));
|
||||
|
||||
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;
|
||||
|
||||
if (getFileProperties(fslist.begin()->getParent(), allFiles, *agdesc, *filenames, tmp))
|
||||
(*filesProps)[*filenames] = tmp;
|
||||
}
|
||||
for (filenames = ptr->filenames; *filenames; ++filenames) {
|
||||
FileProperties 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)
|
||||
|
@ -47,20 +47,6 @@ struct ADGameFileDescription {
|
||||
int32 fileSize; ///< Size of the described file. Set to -1 to ignore.
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
ADDetectedGame CGE2MetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
|
||||
ADDetectedGame game = detectGameFilebased(allFiles, fslist, CGE2::fileBasedFallback);
|
||||
|
||||
const ADGameDescription *game;
|
||||
game = detectGameFilebased(allFiles, fslist, CGE2::fileBasedFallback, &filesProps);
|
||||
|
||||
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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
228
engines/game.cpp
228
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);
|
||||
|
||||
if (!guioptions.empty())
|
||||
setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
|
||||
PlainGameDescriptor PlainGameDescriptor::of(const char *gameId, const char *description) {
|
||||
PlainGameDescriptor pgd;
|
||||
pgd.gameId = gameId;
|
||||
pgd.description = description;
|
||||
return pgd;
|
||||
}
|
||||
|
||||
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() :
|
||||
engineName(nullptr),
|
||||
hasUnknownFiles(false),
|
||||
canBeAdded(true),
|
||||
language(Common::UNK_LANG),
|
||||
platform(Common::kPlatformUnknown),
|
||||
gameSupportLevel(kStableGame) {
|
||||
}
|
||||
|
||||
void GameDescriptor::setGUIOptions(Common::String guioptions) {
|
||||
if (!guioptions.empty())
|
||||
setVal("guioptions", Common::getGameGUIOptionsDescription(guioptions));
|
||||
else
|
||||
erase("guioptions");
|
||||
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::appendGUIOptions(const Common::String &str) {
|
||||
setVal("guioptions", getVal("guioptions", "") + " " + str);
|
||||
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::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::setGUIOptions(const Common::String &guioptions) {
|
||||
_guiOptions = Common::getGameGUIOptionsDescription(guioptions);
|
||||
}
|
||||
|
||||
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 += ")";
|
||||
setVal("description", descr);
|
||||
descr += "/";
|
||||
descr += Common::getPlatformDescription(platform);
|
||||
}
|
||||
if (hasCustomLanguage) {
|
||||
if (hasExtraDesc || hasCustomPlatform)
|
||||
descr += "/";
|
||||
descr += Common::getLanguageDescription(language);
|
||||
}
|
||||
|
||||
descr += ")";
|
||||
|
||||
return descr;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
return gsl;
|
||||
DetectionResults::DetectionResults(const DetectedGames &detectedGames) :
|
||||
_detectedGames(detectedGames) {
|
||||
}
|
||||
|
||||
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");
|
||||
bool DetectionResults::foundUnknownGames() const {
|
||||
for (uint i = 0; i < _detectedGames.size(); i++) {
|
||||
if (_detectedGames[i].hasUnknownFiles) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DetectedGames DetectionResults::listRecognizedGames() {
|
||||
DetectedGames candidates;
|
||||
for (uint i = 0; i < _detectedGames.size(); i++) {
|
||||
if (_detectedGames[i].canBeAdded) {
|
||||
candidates.push_back(_detectedGames[i]);
|
||||
}
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
182
engines/game.h
182
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.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* A record describing the properties of a file. Used on the existing
|
||||
* files while detecting a game.
|
||||
*/
|
||||
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; }
|
||||
|
||||
/**
|
||||
* The name of the engine supporting the detected game
|
||||
*/
|
||||
const char *engineName;
|
||||
|
||||
/**
|
||||
* 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 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.
|
||||
*/
|
||||
void updateDesc(const char *extra = 0);
|
||||
Common::String updateDesc() const;
|
||||
|
||||
void setGUIOptions(Common::String options);
|
||||
void appendGUIOptions(const Common::String &str);
|
||||
|
||||
/**
|
||||
* 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");
|
||||
}
|
||||
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
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
UnknownGameDialog::UnknownGameDialog(const DetectionResults &detectionResults) :
|
||||
Dialog(30, 20, 260, 124),
|
||||
_detectionResults(detectionResults) {
|
||||
Common::String reportTranslated = _detectionResults.generateUnknownGameReport(true);
|
||||
|
||||
_reportData = reportData;
|
||||
_reportTranslated = reportTranslated;
|
||||
_bugtrackerAffectedEngine = bugtrackerAffectedEngine;
|
||||
|
||||
//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:
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 {
|
||||
|
@ -600,13 +600,13 @@ void EventRecorder::setFileHeader() {
|
||||
return;
|
||||
}
|
||||
TimeDate t;
|
||||
GameDescriptor desc = EngineMan.findGame(ConfMan.getActiveDomainName());
|
||||
PlainGameDescriptor desc = EngineMan.findGame(ConfMan.getActiveDomainName());
|
||||
g_system->getTimeAndDate(t);
|
||||
if (_author.empty()) {
|
||||
setAuthor("Unknown Author");
|
||||
}
|
||||
if (_name.empty()) {
|
||||
g_eventRec.setName(Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description());
|
||||
g_eventRec.setName(Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description);
|
||||
}
|
||||
_playbackFile->getHeader().author = _author;
|
||||
_playbackFile->getHeader().notes = _desc;
|
||||
|
@ -95,7 +95,7 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
EditGameDialog::EditGameDialog(const String &domain)
|
||||
: OptionsDialog(domain, "GameOptions") {
|
||||
// Retrieve all game specific options.
|
||||
const Plugin *plugin = nullptr;
|
||||
@ -106,7 +106,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
gameId = domain;
|
||||
// Retrieve the plugin, since we need to access the engine's MetaEngine
|
||||
// implementation.
|
||||
EngineMan.findGame(gameId, &plugin);
|
||||
PlainGameDescriptor pgd = EngineMan.findGame(gameId, &plugin);
|
||||
if (plugin) {
|
||||
_engineOptions = plugin->get<MetaEngine>().getExtraGuiOptions(domain);
|
||||
} else {
|
||||
@ -120,8 +120,8 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
|
||||
// GAME: Determine the description string
|
||||
String description(ConfMan.get("description", domain));
|
||||
if (description.empty() && !desc.empty()) {
|
||||
description = desc;
|
||||
if (description.empty() && pgd.description) {
|
||||
description = pgd.description;
|
||||
}
|
||||
|
||||
// GUI: Add tab widget
|
||||
|
@ -40,8 +40,6 @@ class StaticTextWidget;
|
||||
class EditTextWidget;
|
||||
class SaveLoadChooser;
|
||||
|
||||
Common::String addGameToConf(const GameDescriptor &result);
|
||||
|
||||
/*
|
||||
* A dialog that allows the user to edit a config game entry.
|
||||
* TODO: add widgets for some/all of the following
|
||||
@ -62,7 +60,7 @@ class EditGameDialog : public OptionsDialog {
|
||||
typedef Common::String String;
|
||||
typedef Common::Array<Common::String> StringArray;
|
||||
public:
|
||||
EditGameDialog(const String &domain, const String &desc);
|
||||
EditGameDialog(const String &domain);
|
||||
|
||||
void open();
|
||||
virtual void apply();
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "gui/EventRecorder.h"
|
||||
#endif
|
||||
#include "gui/saveload.h"
|
||||
#include "engines/unknown-game-dialog.h"
|
||||
#include "gui/widgets/edittext.h"
|
||||
#include "gui/widgets/list.h"
|
||||
#include "gui/widgets/tab.h"
|
||||
@ -266,9 +267,9 @@ void LauncherDialog::updateListing() {
|
||||
if (gameid.empty())
|
||||
gameid = iter->_key;
|
||||
if (description.empty()) {
|
||||
GameDescriptor g = EngineMan.findGame(gameid);
|
||||
if (g.contains("description"))
|
||||
description = g.description();
|
||||
PlainGameDescriptor g = EngineMan.findGame(gameid);
|
||||
if (g.description)
|
||||
description = g.description;
|
||||
}
|
||||
|
||||
if (description.empty()) {
|
||||
@ -375,45 +376,6 @@ void LauncherDialog::addGame() {
|
||||
} while (looping);
|
||||
}
|
||||
|
||||
Common::String addGameToConf(const GameDescriptor &result) {
|
||||
// The auto detector or the user made a choice.
|
||||
// Pick a domain name which does not yet exist (after all, we
|
||||
// are *adding* a game to the config, not replacing).
|
||||
Common::String domain = result.preferredtarget();
|
||||
|
||||
assert(!domain.empty());
|
||||
if (ConfMan.hasGameDomain(domain)) {
|
||||
int suffixN = 1;
|
||||
Common::String gameid(domain);
|
||||
|
||||
while (ConfMan.hasGameDomain(domain)) {
|
||||
domain = gameid + Common::String::format("-%d", suffixN);
|
||||
suffixN++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the name domain
|
||||
ConfMan.addGameDomain(domain);
|
||||
|
||||
// Copy all non-empty key/value pairs into the new domain
|
||||
for (GameDescriptor::const_iterator iter = result.begin(); iter != result.end(); ++iter) {
|
||||
if (!iter->_value.empty() && iter->_key != "preferredtarget")
|
||||
ConfMan.set(iter->_key, iter->_value, domain);
|
||||
}
|
||||
|
||||
// TODO: Setting the description field here has the drawback
|
||||
// that the user does never notice when we upgrade our descriptions.
|
||||
// It might be nice ot leave this field empty, and only set it to
|
||||
// a value when the user edits the description string.
|
||||
// However, at this point, that's impractical. Once we have a method
|
||||
// to query all backends for the proper & full description of a given
|
||||
// game target, we can change this (currently, you can only query
|
||||
// for the generic gameid description; it's not possible to obtain
|
||||
// a description which contains extended information like language, etc.).
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
void LauncherDialog::removeGame(int item) {
|
||||
MessageDialog alert(_("Do you really want to remove this game configuration?"), _("Yes"), _("No"));
|
||||
|
||||
@ -442,7 +404,8 @@ void LauncherDialog::editGame(int item) {
|
||||
String gameId(ConfMan.get("gameid", _domains[item]));
|
||||
if (gameId.empty())
|
||||
gameId = _domains[item];
|
||||
EditGameDialog editDialog(_domains[item], EngineMan.findGame(gameId).description());
|
||||
|
||||
EditGameDialog editDialog(_domains[item]);
|
||||
if (editDialog.runModal() > 0) {
|
||||
// User pressed OK, so make changes permanent
|
||||
|
||||
@ -573,7 +536,17 @@ bool LauncherDialog::doGameDetection(const Common::String &path) {
|
||||
|
||||
// ...so let's determine a list of candidates, games that
|
||||
// could be contained in the specified directory.
|
||||
GameList candidates(EngineMan.detectGames(files, true));
|
||||
DetectionResults detectionResults = EngineMan.detectGames(files);
|
||||
|
||||
if (detectionResults.foundUnknownGames()) {
|
||||
Common::String report = detectionResults.generateUnknownGameReport(false, 80);
|
||||
g_system->logMessage(LogMessageType::kInfo, report.c_str());
|
||||
|
||||
UnknownGameDialog dialog(detectionResults);
|
||||
dialog.runModal();
|
||||
}
|
||||
|
||||
Common::Array<DetectedGame> candidates = detectionResults.listRecognizedGames();
|
||||
|
||||
int idx;
|
||||
if (candidates.empty()) {
|
||||
@ -589,22 +562,19 @@ bool LauncherDialog::doGameDetection(const Common::String &path) {
|
||||
// Display the candidates to the user and let her/him pick one
|
||||
StringArray list;
|
||||
for (idx = 0; idx < (int)candidates.size(); idx++)
|
||||
list.push_back(candidates[idx].description());
|
||||
list.push_back(candidates[idx].description);
|
||||
|
||||
ChooserDialog dialog(_("Pick the game:"));
|
||||
dialog.setList(list);
|
||||
idx = dialog.runModal();
|
||||
}
|
||||
if (0 <= idx && idx < (int)candidates.size()) {
|
||||
GameDescriptor result = candidates[idx];
|
||||
const DetectedGame &result = candidates[idx];
|
||||
|
||||
// TODO: Change the detectors to set "path" !
|
||||
result["path"] = dir.getPath();
|
||||
|
||||
Common::String domain = addGameToConf(result);
|
||||
Common::String domain = EngineMan.createTargetForGame(result);
|
||||
|
||||
// Display edit dialog for the new entry
|
||||
EditGameDialog editDialog(domain, result.description());
|
||||
EditGameDialog editDialog(domain);
|
||||
if (editDialog.runModal() > 0) {
|
||||
// User pressed OK, so make changes permanent
|
||||
|
||||
|
@ -38,8 +38,6 @@ class StaticTextWidget;
|
||||
class EditTextWidget;
|
||||
class SaveLoadChooser;
|
||||
|
||||
Common::String addGameToConf(const GameDescriptor &result);
|
||||
|
||||
class LauncherDialog : public Dialog {
|
||||
typedef Common::String String;
|
||||
typedef Common::Array<Common::String> StringArray;
|
||||
|
@ -28,10 +28,7 @@
|
||||
#include "common/taskbar.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "gui/launcher.h" // For addGameToConf()
|
||||
#include "gui/massadd.h"
|
||||
#include "gui/widget.h"
|
||||
#include "gui/widgets/list.h"
|
||||
|
||||
#ifndef DISABLE_MASS_ADD
|
||||
namespace GUI {
|
||||
@ -120,14 +117,14 @@ MassAddDialog::MassAddDialog(const Common::FSNode &startDir)
|
||||
}
|
||||
|
||||
struct GameTargetLess {
|
||||
bool operator()(const GameDescriptor &x, const GameDescriptor &y) const {
|
||||
return x.preferredtarget().compareToIgnoreCase(y.preferredtarget()) < 0;
|
||||
bool operator()(const DetectedGame &x, const DetectedGame &y) const {
|
||||
return x.preferredTarget.compareToIgnoreCase(y.preferredTarget) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct GameDescLess {
|
||||
bool operator()(const GameDescriptor &x, const GameDescriptor &y) const {
|
||||
return x.description().compareToIgnoreCase(y.description()) < 0;
|
||||
bool operator()(const DetectedGame &x, const DetectedGame &y) const {
|
||||
return x.description.compareToIgnoreCase(y.description) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
@ -143,13 +140,13 @@ void MassAddDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
|
||||
if (cmd == kOkCmd) {
|
||||
// Sort the detected games. This is not strictly necessary, but nice for
|
||||
// people who want to edit their config file by hand after a mass add.
|
||||
sort(_games.begin(), _games.end(), GameTargetLess());
|
||||
Common::sort(_games.begin(), _games.end(), GameTargetLess());
|
||||
// Add all the detected games to the config
|
||||
for (GameList::iterator iter = _games.begin(); iter != _games.end(); ++iter) {
|
||||
for (DetectedGames::iterator iter = _games.begin(); iter != _games.end(); ++iter) {
|
||||
debug(1, " Added gameid '%s', desc '%s'\n",
|
||||
(*iter)["gameid"].c_str(),
|
||||
(*iter)["description"].c_str());
|
||||
(*iter)["gameid"] = addGameToConf(*iter);
|
||||
iter->gameId.c_str(),
|
||||
iter->description.c_str());
|
||||
iter->gameId = EngineMan.createTargetForGame(*iter);
|
||||
}
|
||||
|
||||
// Write everything to disk
|
||||
@ -157,8 +154,8 @@ void MassAddDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
|
||||
|
||||
// And scroll to first detected game
|
||||
if (!_games.empty()) {
|
||||
sort(_games.begin(), _games.end(), GameDescLess());
|
||||
ConfMan.set("temp_selection", _games.front().gameid());
|
||||
Common::sort(_games.begin(), _games.end(), GameDescLess());
|
||||
ConfMan.set("temp_selection", _games.front().gameId);
|
||||
}
|
||||
|
||||
close();
|
||||
@ -187,7 +184,12 @@ void MassAddDialog::handleTickle() {
|
||||
}
|
||||
|
||||
// Run the detector on the dir
|
||||
GameList candidates(EngineMan.detectGames(files));
|
||||
DetectionResults detectionResults = EngineMan.detectGames(files);
|
||||
|
||||
if (detectionResults.foundUnknownGames()) {
|
||||
Common::String report = detectionResults.generateUnknownGameReport(false, 80);
|
||||
g_system->logMessage(LogMessageType::kInfo, report.c_str());
|
||||
}
|
||||
|
||||
// Just add all detected games / game variants. If we get more than one,
|
||||
// that either means the directory contains multiple games, or the detector
|
||||
@ -195,8 +197,10 @@ void MassAddDialog::handleTickle() {
|
||||
// case, let the user choose which entries he wants to keep.
|
||||
//
|
||||
// However, we only add games which are not already in the config file.
|
||||
for (GameList::const_iterator cand = candidates.begin(); cand != candidates.end(); ++cand) {
|
||||
GameDescriptor result = *cand;
|
||||
DetectedGames candidates = detectionResults.listRecognizedGames();
|
||||
for (DetectedGames::const_iterator cand = candidates.begin(); cand != candidates.end(); ++cand) {
|
||||
const DetectedGame &result = *cand;
|
||||
|
||||
Common::String path = dir.getPath();
|
||||
|
||||
// Remove trailing slashes
|
||||
@ -205,6 +209,9 @@ void MassAddDialog::handleTickle() {
|
||||
|
||||
// Check for existing config entries for this path/gameid/lang/platform combination
|
||||
if (_pathToTargets.contains(path)) {
|
||||
const char *resultPlatformCode = Common::getPlatformCode(result.platform);
|
||||
const char *resultLanguageCode = Common::getLanguageCode(result.language);
|
||||
|
||||
bool duplicate = false;
|
||||
const StringArray &targets = _pathToTargets[path];
|
||||
for (StringArray::const_iterator iter = targets.begin(); iter != targets.end(); ++iter) {
|
||||
@ -212,9 +219,9 @@ void MassAddDialog::handleTickle() {
|
||||
Common::ConfigManager::Domain *dom = ConfMan.getDomain(*iter);
|
||||
assert(dom);
|
||||
|
||||
if ((*dom)["gameid"] == result["gameid"] &&
|
||||
(*dom)["platform"] == result["platform"] &&
|
||||
(*dom)["language"] == result["language"]) {
|
||||
if ((*dom)["gameid"] == result.gameId &&
|
||||
(*dom)["platform"] == resultPlatformCode &&
|
||||
(*dom)["language"] == resultLanguageCode) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
@ -224,10 +231,9 @@ void MassAddDialog::handleTickle() {
|
||||
break; // Skip duplicates
|
||||
}
|
||||
}
|
||||
result["path"] = path;
|
||||
_games.push_back(result);
|
||||
|
||||
_list->append(result.description());
|
||||
_list->append(result.description);
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define MASSADD_DIALOG_H
|
||||
|
||||
#include "gui/dialog.h"
|
||||
#include "gui/widgets/list.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/stack.h"
|
||||
@ -44,13 +45,13 @@ public:
|
||||
|
||||
Common::String getFirstAddedTarget() const {
|
||||
if (!_games.empty())
|
||||
return _games.front().gameid();
|
||||
return _games.front().gameId;
|
||||
return Common::String();
|
||||
}
|
||||
|
||||
private:
|
||||
Common::Stack<Common::FSNode> _scanStack;
|
||||
GameList _games;
|
||||
DetectedGames _games;
|
||||
|
||||
/**
|
||||
* Map each path occuring in the config file to the target(s) using that path.
|
||||
|
@ -167,9 +167,9 @@ void RecorderDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
|
||||
case kRecordCmd: {
|
||||
TimeDate t;
|
||||
Common::String gameId = ConfMan.get("gameid", _target);
|
||||
GameDescriptor desc = EngineMan.findGame(gameId);
|
||||
PlainGameDescriptor desc = EngineMan.findGame(gameId);
|
||||
g_system->getTimeAndDate(t);
|
||||
EditRecordDialog editDlg(_("Unknown Author"), Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description(), "");
|
||||
EditRecordDialog editDlg(_("Unknown Author"), Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description, "");
|
||||
if (editDlg.runModal() != kOKCmd) {
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user