From 4631c0e2edb686534649dd073eecb6da9684bb19 Mon Sep 17 00:00:00 2001 From: Pawel Kolodziejski Date: Sun, 4 Oct 2020 23:59:26 +0200 Subject: [PATCH] ALL: Sync with ScummVM rev: a4002bdeee5ec11b4e5968912c0dc759bb60c8a3 --- .gitignore | 1 + Makefile | 4 + Makefile.common | 36 ++- .../surfacesdl/surfacesdl-graphics.cpp | 8 + base/commandLine.cpp | 36 ++- base/internal_plugins.h | 2 + base/main.cpp | 49 +++- base/plugins.cpp | 216 +++++++++++++++--- base/plugins.h | 77 ++++++- common/achievements.h | 10 + common/algorithm.h | 13 ++ common/archive.h | 14 ++ common/array.h | 54 +++++ common/bitstream.h | 10 + common/bufferedstream.h | 11 + common/callback.h | 11 + common/config-manager.h | 12 + common/coroutines.h | 16 +- common/cosinetables.h | 11 + common/dcl.h | 25 +- common/dct.h | 11 + common/debug-channels.h | 11 + common/debug.h | 10 + common/dialogs.h | 11 + common/encoding.cpp | 44 ++-- common/encoding.h | 11 + common/endian.h | 12 +- common/error.h | 18 +- common/events.h | 10 +- common/fft.h | 13 +- common/file.h | 11 + common/frac.h | 11 + common/fs.h | 10 + common/func.h | 12 + common/gui_options.h | 10 + common/hash-ptr.h | 11 + common/hashmap.h | 11 + common/huffman.h | 16 +- common/iff_container.h | 12 + common/ini-file.h | 12 + common/installshield_cab.h | 12 + common/keyboard.h | 12 + common/language.h | 12 + common/list.h | 12 + common/localization.h | 12 + common/macresman.h | 24 +- common/md5.h | 11 + common/memory.h | 10 + common/memorypool.h | 10 + common/memstream.h | 10 + common/mutex.h | 9 + common/noncopyable.h | 10 + common/osd_message_queue.h | 10 + common/platform.h | 10 + common/ptr.h | 10 + common/queue.h | 10 + common/quicktime.h | 17 +- common/random.h | 11 + common/rational.h | 11 + common/rdft.h | 15 +- common/rect.h | 11 + common/rendermode.h | 10 + common/safe-bool.h | 10 + common/savefile.h | 10 + common/serializer.h | 10 + common/sinetables.h | 11 + common/singleton.h | 11 + common/stack.h | 11 + common/str-array.h | 10 + common/str.h | 11 + common/stream.h | 10 + common/substream.h | 10 + common/system.h | 12 + common/taskbar.h | 11 + common/text-to-speech.h | 11 + common/textconsole.h | 11 + common/timer.h | 11 + common/tokenizer.h | 12 + common/translation.h | 11 + common/unarj.h | 11 + common/unzip.h | 11 + common/updates.h | 11 + common/ustr.h | 12 + common/util.h | 18 ++ common/winexe.h | 11 + common/winexe_ne.h | 11 + common/winexe_pe.h | 11 + common/xmlparser.h | 11 + common/zlib.h | 11 + configure | 60 +++++ devtools/create_project/create_project.cpp | 138 ++++++++++- devtools/create_project/create_project.h | 6 +- devtools/create_project/xcode.cpp | 33 ++- devtools/credits.pl | 124 +--------- devtools/encode-macbinary.sh | 5 + dists/ps3/ICON0.PNG | Bin 28014 -> 0 bytes dists/ps3/readme-ps3.md | 55 ----- dists/ps3/sfo.xml | 33 --- engines/advancedDetector.cpp | 97 ++++++-- engines/advancedDetector.h | 69 +++++- engines/dialogs.cpp | 2 +- engines/engine.cpp | 14 +- engines/engine.h | 2 + engines/metaengine.cpp | 19 +- engines/metaengine.h | 196 ++++++++++------ engines/wintermute/base/base_engine.h | 91 +------- engines/wintermute/base/base_sprite.cpp | 2 +- engines/wintermute/detection.cpp | 186 ++------------- engines/wintermute/ext/wme_galaxy.cpp | 2 +- engines/wintermute/ext/wme_steam.cpp | 2 +- engines/wintermute/module.mk | 5 +- engines/wintermute/wintermute.cpp | 2 +- engines/wintermute/wintermute.h | 10 +- gui/about.cpp | 2 +- gui/editgamedialog.cpp | 30 ++- gui/launcher.cpp | 40 ++-- gui/saveload-dialog.h | 18 +- gui/saveload.cpp | 12 +- rules.mk | 3 + test/common/array.h | 10 + video/flic_decoder.cpp | 6 + 121 files changed, 1977 insertions(+), 740 deletions(-) delete mode 100644 dists/ps3/ICON0.PNG delete mode 100644 dists/ps3/readme-ps3.md delete mode 100644 dists/ps3/sfo.xml diff --git a/.gitignore b/.gitignore index c7b6023e6e8..ea7953fd390 100644 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,7 @@ project.xcworkspace /plugins +/engines/detection_table.h /engines/plugins_table.h /engines/engines.mk diff --git a/Makefile b/Makefile index 0b022e33c42..8e2631bd116 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,10 @@ DEPDIR := .deps MODULES := MODULE_DIRS := +# All game detection-related object files for engines +DETECT_OBJS := +LOAD_RULES_MK := 1 + # Load the make rules generated by configure -include config.mk diff --git a/Makefile.common b/Makefile.common index 46331ff7933..257cd9e828c 100644 --- a/Makefile.common +++ b/Makefile.common @@ -54,6 +54,38 @@ CPPFLAGS := $(DEFINES) $(INCLUDES) # Include the build instructions for all modules -include $(addprefix $(srcdir)/, $(addsuffix /module.mk,$(MODULES))) +# Store original info +MODULES_ORIG:= $(MODULES) +MODULE_DIRS_ORIG := $(MODULE_DIRS) +KYRARPG_COMMON_OBJ_ORIG := $(KYRARPG_COMMON_OBJ) + +# Skip rules for these files, by resetting the LOAD_RULES_MK +LOAD_RULES_MK := + +# Reset detection objects, which uptill now are filled with only +# enabled engines. +DETECT_OBJS := + +# Include all engine's module files, which populate DETECT_OBJS +-include $(srcdir)/engines/*/module.mk + +# Reset stuff +MODULES := $(MODULES_ORIG) +MODULE := +MODULE_OBJS := +MODULE_DIRS := $(MODULE_DIRS_ORIG) +PLUGIN := +KYRARPG_COMMON_OBJ := $(KYRARPG_COMMON_OBJ_ORIG) + +# Enable-rules again +LOAD_RULES_MK := 1 + +ifneq ($(DETECTION_STATIC), 1) +-include $(srcdir)/engines/detect_modules.mk +else +MODULE_DIRS += $(sort $(dir $(DETECT_OBJS))) +endif + # Depdir information DEPDIRS = $(addsuffix $(DEPDIR),$(MODULE_DIRS)) DEPFILES = @@ -88,7 +120,7 @@ endif endif # The build rule for the ResidualVM executable -$(EXECUTABLE): $(OBJS) +$(EXECUTABLE): $(DETECT_OBJS) $(OBJS) $(QUIET_LINK)$(LD) $(LDFLAGS) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) -o $@ ifdef SPLIT_DWARF @@ -101,7 +133,7 @@ distclean: clean clean-devtools clean: $(RM_REC) $(DEPDIRS) - $(RM) $(OBJS) $(EXECUTABLE) + $(RM) $(OBJS) $(DETECT_OBJS) $(EXECUTABLE) ifdef SPLIT_DWARF $(RM) $(OBJS:.o=.dwo) $(RM) $(EXECUTABLE).dwp diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index a2be54a8878..790e29c64b3 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -2635,6 +2635,14 @@ SDL_Surface *SurfaceSdlGraphicsManager::SDL_SetVideoMode(int width, int height, return nullptr; } +#if defined(MACOSX) && SDL_VERSION_ATLEAST(2, 0, 10) + // WORKAROUND: Bug #11430: "macOS: blurry content on Retina displays" + // Since SDL 2.0.10, Metal takes priority over OpenGL rendering on macOS, + // but this causes blurriness issues on Retina displays. Just switch + // back to OpenGL for now. + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); +#endif + _renderer = SDL_CreateRenderer(_window->getSDLWindow(), -1, 0); if (!_renderer) { deinitializeRenderer(); diff --git a/base/commandLine.cpp b/base/commandLine.cpp index 52ae2511a66..04ba50191f8 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -335,6 +335,10 @@ void registerDefaults() { ConfMan.registerDefault("gui_browser_show_hidden", false); ConfMan.registerDefault("gui_browser_native", true); + // Specify threshold for scanning directories in the launcher + // If number of game entries in scummvm.ini exceeds the specified + // number, then skip scanning. -1 = scan always + ConfMan.registerDefault("gui_list_max_scan_entries", -1); ConfMan.registerDefault("game", ""); #ifdef USE_FLUIDSYNTH @@ -850,7 +854,7 @@ static void listGames() { const PluginList &plugins = EngineMan.getPlugins(); for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); ++iter) { - const MetaEngine &metaengine = (*iter)->get(); + const MetaEngineStatic &metaengine = (*iter)->get(); PlainGameList list = metaengine.getSupportedGames(); for (PlainGameList::const_iterator v = list.begin(); v != list.end(); ++v) { @@ -866,7 +870,7 @@ static void listEngines() { const PluginList &plugins = EngineMan.getPlugins(); for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); ++iter) { - const MetaEngine &metaEngine = (*iter)->get(); + const MetaEngineStatic &metaEngine = (*iter)->get(); printf("%-15s %s\n", metaEngine.getEngineId(), metaEngine.getName()); } } @@ -933,15 +937,18 @@ static Common::Error listSaves(const Common::String &singleTarget) { // the specified game name, or alternatively whether there is a matching game id. Common::String currentTarget; QualifiedGameDescriptor game; - const Plugin *plugin = nullptr; + + const Plugin *metaEnginePlugin = nullptr; + const Plugin *enginePlugin = nullptr; + if (ConfMan.hasGameDomain(*i)) { // The name is a known target currentTarget = *i; EngineMan.upgradeTargetIfNecessary(*i); - game = EngineMan.findTarget(*i, &plugin); + game = EngineMan.findTarget(*i, &metaEnginePlugin); } else if (game = findGameMatchingName(*i), !game.gameId.empty()) { // The name is a known game id - plugin = EngineMan.findPlugin(game.engineId); + metaEnginePlugin = EngineMan.findPlugin(game.engineId); currentTarget = createTemporaryTarget(game.engineId, game.gameId); } else { return Common::Error(Common::kEnginePluginNotFound, Common::String::format("target '%s'", singleTarget.c_str())); @@ -950,16 +957,27 @@ static Common::Error listSaves(const Common::String &singleTarget) { // If we actually found a domain, we're going to change the domain ConfMan.setActiveDomain(currentTarget); - if (!plugin) { + if (!metaEnginePlugin) { // If the target was specified, treat this as an error, and otherwise skip it. if (!singleTarget.empty()) - return Common::Error(Common::kEnginePluginNotFound, + return Common::Error(Common::kMetaEnginePluginNotFound, Common::String::format("target '%s'", i->c_str())); - printf("Plugin could not be loaded for target '%s'\n", i->c_str()); + printf("MetaEnginePlugin could not be loaded for target '%s'\n", i->c_str()); continue; + } else { + enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + + if (!enginePlugin) { + // If the target was specified, treat this as an error, and otherwise skip it. + if (!singleTarget.empty()) + return Common::Error(Common::kEnginePluginNotFound, + Common::String::format("target '%s'", i->c_str())); + printf("EnginePlugin could not be loaded for target '%s'\n", i->c_str()); + continue; + } } - const MetaEngine &metaEngine = plugin->get(); + const MetaEngine &metaEngine = enginePlugin->get(); Common::String qualifiedGameId = buildQualifiedGameName(game.engineId, game.gameId); if (!metaEngine.hasFeature(MetaEngine::kSupportsListSaves)) { diff --git a/base/internal_plugins.h b/base/internal_plugins.h index 1af16070225..6eb98e747f1 100644 --- a/base/internal_plugins.h +++ b/base/internal_plugins.h @@ -17,3 +17,5 @@ #else #define PLUGIN_ENABLED_DYNAMIC(ID) 0 #endif + +#define PLUGIN_ENABLED(ID) (ENABLE_##ID) diff --git a/base/main.cpp b/base/main.cpp index 01154e60229..b5554e1944a 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -133,7 +133,7 @@ static const Plugin *detectPlugin() { // Query the plugin for the game descriptor printf(" Looking for a plugin supporting this target... %s\n", plugin->getName()); - PlainGameDescriptor game = plugin->get().findGame(gameId.c_str()); + PlainGameDescriptor game = plugin->get().findGame(gameId.c_str()); if (!game.gameId) { warning("'%s' is an invalid game ID for the engine '%s'. Use the --list-games option to list supported game IDs", gameId.c_str(), engineId.c_str()); return 0; @@ -153,6 +153,8 @@ void saveLastLaunchedTarget(const Common::String &target) { // TODO: specify the possible return values here static Common::Error runGame(const Plugin *plugin, OSystem &system, const Common::String &edebuglevels) { + assert(plugin); + // Determine the game data path, for validation and error messages Common::FSNode dir(ConfMan.get("path")); Common::String target = ConfMan.getActiveDomainName(); @@ -179,17 +181,28 @@ static Common::Error runGame(const Plugin *plugin, OSystem &system, const Common err = Common::kPathNotDirectory; } - // Create the game engine - const MetaEngine &metaEngine = plugin->get(); + // Create the game's MetaEngine. + const MetaEngineStatic &metaEngine = plugin->get(); if (err.getCode() == Common::kNoError) { // Set default values for all of the custom engine options // Apparently some engines query them in their constructor, thus we // need to set this up before instance creation. metaEngine.registerDefaultSettings(target); - - err = metaEngine.createInstance(&system, &engine); } + // Right now we have a MetaEngine plugin. We must find the matching engine plugin to + // call createInstance and other connecting functions. + Plugin *enginePluginToLaunchGame = PluginMan.getEngineFromMetaEngine(plugin); + + if (!enginePluginToLaunchGame) { + err = Common::kEnginePluginNotFound; + return err; + } + + // Create the game's MetaEngineConnect. + const MetaEngine &metaEngineConnect = enginePluginToLaunchGame->get(); + err = metaEngineConnect.createInstance(&system, &engine); + // Check for errors if (!engine || err.getCode() != Common::kNoError) { @@ -279,7 +292,7 @@ static Common::Error runGame(const Plugin *plugin, OSystem &system, const Common #endif // USE_TRANSLATION // Initialize any game-specific keymaps - Common::KeymapArray gameKeymaps = metaEngine.initKeymaps(target.c_str()); + Common::KeymapArray gameKeymaps = metaEngineConnect.initKeymaps(target.c_str()); Common::Keymapper *keymapper = system.getEventManager()->getKeymapper(); for (uint i = 0; i < gameKeymaps.size(); i++) { keymapper->addGameKeymap(gameKeymaps[i]); @@ -423,8 +436,10 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { gDebugChannelsOnly = true; + ConfMan.registerDefault("always_run_fallback_detection_extern", true); PluginManager::instance().init(); PluginManager::instance().loadAllPlugins(); // load plugins for cached plugin manager + PluginManager::instance().loadDetectionPlugin(); // load detection plugin for uncached plugin manager // If we received an invalid music parameter via command line we check this here. // We can't check this before loading the music plugins. @@ -536,12 +551,23 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { EngineMan.upgradeTargetIfNecessary(ConfMan.getActiveDomainName()); - // Try to find a plugin which feels responsible for the specified game. + // Try to find a MetaEnginePlugin which feels responsible for the specified game. const Plugin *plugin = detectPlugin(); if (plugin) { - // Unload all plugins not needed for this game, - // to save memory - PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, plugin); + // Unload all plugins not needed for this game, to save memory + + // Right now, we have a MetaEngine plugin, and we want to unload all except Engine. + // First, get the relevant Engine plugin from MetaEngine. + const Plugin *enginePlugin = PluginMan.getEngineFromMetaEngine(plugin); + + // Then, pass in the pointer to enginePlugin, with the matching type, so our function behaves as-is. + PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, enginePlugin); + +#if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES) + // Unload all MetaEngines not needed for the current engine, if we're using uncached plugins + // to save extra memory. + PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_METAENGINE, plugin); +#endif #ifdef ENABLE_EVENTRECORDER Common::String recordMode = ConfMan.get("record_mode"); @@ -582,6 +608,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { #if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES) // do our best to prevent fragmentation by unloading as soon as we can PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); + PluginManager::instance().unloadDetectionPlugin(); // reallocate the config manager to get rid of any fragmentation ConfMan.defragment(); // The keymapper keeps pointers to the configuration domains. It needs to be reinitialized. @@ -637,6 +664,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { } PluginManager::instance().loadAllPluginsOfType(PLUGIN_TYPE_ENGINE); // only for cached manager + PluginManager::instance().loadDetectionPlugin(); // only for uncached manager } else { GUI::displayErrorDialog(_("Could not find any engine capable of running the selected game")); @@ -660,6 +688,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { Cloud::CloudManager::destroy(); #endif #endif + PluginManager::instance().unloadDetectionPlugin(); PluginManager::instance().unloadAllPlugins(); PluginManager::destroy(); GUI::GuiManager::destroy(); diff --git a/base/plugins.cpp b/base/plugins.cpp index d54f2da22ad..d64bea1904d 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -30,11 +30,15 @@ #include "common/fs.h" #endif +#include "engines/detection.h" + // Plugin versioning int pluginTypeVersions[PLUGIN_TYPE_MAX] = { + PLUGIN_TYPE_METAENGINE_VERSION, PLUGIN_TYPE_ENGINE_VERSION, PLUGIN_TYPE_MUSIC_VERSION, + PLUGIN_TYPE_DETECTION_VERSION, }; @@ -48,22 +52,27 @@ const char *Plugin::getName() const { return _pluginObject->getName(); } -class StaticPlugin : public Plugin { -public: - StaticPlugin(PluginObject *pluginobject, PluginType type) { - assert(pluginobject); - assert(type < PLUGIN_TYPE_MAX); - _pluginObject = pluginobject; - _type = type; +const char *Plugin::getEngineId() const { + if (_type == PLUGIN_TYPE_METAENGINE) { + return _pluginObject->getEngineId(); } - ~StaticPlugin() { - delete _pluginObject; - } + return nullptr; +} - virtual bool loadPlugin() { return true; } - virtual void unloadPlugin() {} -}; +StaticPlugin::StaticPlugin(PluginObject *pluginobject, PluginType type) { + assert(pluginobject); + assert(type < PLUGIN_TYPE_MAX); + _pluginObject = pluginobject; + _type = type; +} + +StaticPlugin::~StaticPlugin() { + delete _pluginObject; +} + +bool StaticPlugin::loadPlugin() { return true; } +void StaticPlugin::unloadPlugin() {} class StaticPluginProvider : public PluginProvider { public: @@ -87,6 +96,11 @@ public: // Engine plugins #include "engines/plugins_table.h" + #ifdef DETECTION_STATIC + // Engine-detection plugins are included if we don't use uncached plugins. + #include "engines/detection_table.h" + #endif + // Music plugins // TODO: Use defines to disable or enable each MIDI driver as a // static/dynamic plugin, like it's done for the engines @@ -257,15 +271,86 @@ void PluginManager::addPluginProvider(PluginProvider *pp) { _providers.push_back(pp); } +Plugin *PluginManager::getEngineFromMetaEngine(const Plugin *plugin) { + assert(plugin->getType() == PLUGIN_TYPE_METAENGINE); + + Plugin *enginePlugin = nullptr; + bool found = false; + + // Use the engineID from MetaEngine for comparasion. + Common::String metaEnginePluginName = plugin->getEngineId(); + PluginMan.loadFirstPlugin(); + do { + PluginList pl = PluginMan.getPlugins(PLUGIN_TYPE_ENGINE); + // Iterate over all engine plugins. + for (PluginList::const_iterator itr = pl.begin(); itr != pl.end(); itr++) { + // The getName() provides a name which is similiar to getEngineId. + // Because engines are engines themselves, this function is simply named getName. + Common::String enginePluginName((*itr)->getName()); + + if (metaEnginePluginName.equalsIgnoreCase(enginePluginName)) { + enginePlugin = (*itr); + found = true; + break; + } + } + } while (!found && PluginMan.loadNextPlugin()); + + if (enginePlugin) { + debug(9, "MetaEngine: %s \t matched to \t Engine: %s", plugin->getName(), enginePlugin->getFileName()); + return enginePlugin; + } + + debug(9, "MetaEngine: %s couldn't find a match for an engine plugin.", plugin->getName()); + return nullptr; +} + +Plugin *PluginManager::getMetaEngineFromEngine(const Plugin *plugin) { + assert(plugin->getType() == PLUGIN_TYPE_ENGINE); + + Plugin *metaEngine = nullptr; + + PluginList pl = PluginMan.getPlugins(PLUGIN_TYPE_METAENGINE); + + // This will return a name of the Engine plugin, which will be identical to + // a getEngineID from a relevant MetaEngine. + Common::String enginePluginName(plugin->getName()); + + for (PluginList::const_iterator itr = pl.begin(); itr != pl.end(); itr++) { + Common::String metaEngineName = (*itr)->getEngineId(); + + if (metaEngineName.equalsIgnoreCase(enginePluginName)) { + metaEngine = (*itr); + break; + } + } + + if (metaEngine) { + debug(9, "Engine: %s matched to MetaEngine: %s", plugin->getFileName(), metaEngine->getName()); + return metaEngine; + } + + debug(9, "Engine: %s couldn't find a match for an MetaEngine plugin.", plugin->getFileName()); + return nullptr; +} + /** * This should only be called once by main() **/ void PluginManagerUncached::init() { unloadAllPlugins(); _allEnginePlugins.clear(); + ConfMan.setBool("always_run_fallback_detection_extern", false); unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); // empty the engine plugins + Common::String detectPluginName = "detection"; +#ifdef PLUGIN_SUFFIX + detectPluginName += PLUGIN_SUFFIX; +#endif + + bool foundDetectPlugin = false; + for (ProviderList::iterator pp = _providers.begin(); pp != _providers.end(); ++pp) { @@ -276,6 +361,16 @@ void PluginManagerUncached::init() { // file plugins. Currently this is the case. If it changes, we // should find a fast way of detecting whether a plugin is a // music or an engine plugin. + if (!foundDetectPlugin && (*pp)->isFilePluginProvider()) { + Common::String pName = (*p)->getFileName(); + if (pName.hasSuffix(detectPluginName)) { + _detectionPlugin = (*p); + foundDetectPlugin = true; + debug(9, "Detection plugin found!"); + continue; + } + } + if ((*pp)->isFilePluginProvider()) { _allEnginePlugins.push_back(*p); } else if ((*p)->loadPlugin()) { // and this is the proper method @@ -348,6 +443,48 @@ void PluginManagerUncached::updateConfigWithFileName(const Common::String &engin } } +void PluginManagerUncached::loadDetectionPlugin() { + bool linkMetaEngines = false; + + if (_isDetectionLoaded) { + debug(9, "Detection plugin is already loaded. Adding each available engines to the memory."); + linkMetaEngines = true; + } else { + if (_detectionPlugin) { + if (_detectionPlugin->loadPlugin()) { + assert((_detectionPlugin)->getType() == PLUGIN_TYPE_DETECTION); + + linkMetaEngines = true; + _isDetectionLoaded = true; + } else { + debug(9, "Detection plugin was not loaded correctly."); + return; + } + } else { + debug(9, "Detection plugin not found."); + return; + } + } + + if (linkMetaEngines) { + _pluginsInMem[PLUGIN_TYPE_METAENGINE].clear(); + const Detection &detectionConnect = _detectionPlugin->get(); + const PluginList &pl = detectionConnect.getPlugins(); + Common::for_each(pl.begin(), pl.end(), Common::bind1st(Common::mem_fun(&PluginManagerUncached::tryLoadPlugin), this)); + } + +} + +void PluginManagerUncached::unloadDetectionPlugin() { + if (_isDetectionLoaded) { + _pluginsInMem[PLUGIN_TYPE_METAENGINE].clear(); + _detectionPlugin->unloadPlugin(); + _isDetectionLoaded = false; + } else { + debug(9, "Detection plugin is already unloaded."); + } +} + void PluginManagerUncached::loadFirstPlugin() { unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false); @@ -424,8 +561,9 @@ void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin, b found = *p; } else { (*p)->unloadPlugin(); - if (deletePlugin) + if (deletePlugin) { delete *p; + } } } _pluginsInMem[type].clear(); @@ -498,7 +636,7 @@ QualifiedGameList EngineManager::findGamesMatching(const Common::String &engineI // If we got an engine name, look for THE game only in that engine const Plugin *p = EngineMan.findPlugin(engineId); if (p) { - const MetaEngine &engine = p->get(); + const MetaEngineStatic &engine = p->get(); PlainGameDescriptor pluginResult = engine.findGame(gameId.c_str()); if (pluginResult.gameId) { @@ -527,7 +665,7 @@ QualifiedGameList EngineManager::findGameInLoadedPlugins(const Common::String &g PluginList::const_iterator iter; for (iter = plugins.begin(); iter != plugins.end(); ++iter) { - const MetaEngine &engine = (*iter)->get(); + const MetaEngineStatic &engine = (*iter)->get(); PlainGameDescriptor pluginResult = engine.findGame(gameId.c_str()); if (pluginResult.gameId) { @@ -542,29 +680,29 @@ DetectionResults EngineManager::detectGames(const Common::FSList &fslist) const DetectedGames candidates; PluginList plugins; PluginList::const_iterator iter; - PluginMan.loadFirstPlugin(); - do { - plugins = getPlugins(); - // 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) { - const MetaEngine &metaEngine = (*iter)->get(); - DetectedGames engineCandidates = metaEngine.detectGames(fslist); - for (uint i = 0; i < engineCandidates.size(); i++) { - engineCandidates[i].path = fslist.begin()->getParent().getPath(); - engineCandidates[i].shortPath = fslist.begin()->getParent().getDisplayName(); - candidates.push_back(engineCandidates[i]); - } + // MetaEngines are always loaded into memory, so, get them and + // run detection for all of them. + plugins = getPlugins(PLUGIN_TYPE_METAENGINE); + // 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) { + const MetaEngineStatic &metaEngine = (*iter)->get(); + DetectedGames engineCandidates = metaEngine.detectGames(fslist); + + for (uint i = 0; i < engineCandidates.size(); i++) { + engineCandidates[i].path = fslist.begin()->getParent().getPath(); + engineCandidates[i].shortPath = fslist.begin()->getParent().getDisplayName(); + candidates.push_back(engineCandidates[i]); } - } while (PluginMan.loadNextPlugin()); + } return DetectionResults(candidates); } -const PluginList &EngineManager::getPlugins() const { - return PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE); +const PluginList &EngineManager::getPlugins(const PluginType fetchPluginType) const { + return PluginManager::instance().getPlugins(fetchPluginType); } namespace { @@ -628,7 +766,7 @@ const Plugin *EngineManager::findLoadedPlugin(const Common::String &engineId) co const PluginList &plugins = getPlugins(); for (PluginList::const_iterator iter = plugins.begin(); iter != plugins.end(); iter++) - if (engineId == (*iter)->get().getEngineId()) + if (engineId == (*iter)->get().getEngineId()) return *iter; return 0; @@ -680,7 +818,7 @@ QualifiedGameDescriptor EngineManager::findTarget(const Common::String &target, } // Make sure it does support the game ID - const MetaEngine &engine = foundPlugin->get(); + const MetaEngineStatic &engine = foundPlugin->get(); PlainGameDescriptor desc = engine.findGame(domain->getVal("gameid").c_str()); if (!desc.gameId) { return QualifiedGameDescriptor(); @@ -698,6 +836,14 @@ void EngineManager::upgradeTargetIfNecessary(const Common::String &target) const if (!domain->contains("engineid")) { upgradeTargetForEngineId(target); + } else { + if (domain->getVal("engineid").equals("fullpipe")) { + domain->setVal("engineid", "ngi"); + + debug("Upgrading engineid from 'fullpipe' to 'ngi'"); + + ConfMan.flushToDisk(); + } } } @@ -737,7 +883,7 @@ void EngineManager::upgradeTargetForEngineId(const Common::String &target) const } // Take the first detection entry - const MetaEngine &metaEngine = plugin->get(); + const MetaEngineStatic &metaEngine = plugin->get(); DetectedGames candidates = metaEngine.detectGames(files); if (candidates.empty()) { warning("No games supported by the engine '%s' were found in path '%s' when upgrading target '%s'", diff --git a/base/plugins.h b/base/plugins.h index 9919c1a3782..50f933b2534 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -60,8 +60,10 @@ #define PLUGIN_VERSION 1 enum PluginType { - PLUGIN_TYPE_ENGINE = 0, + PLUGIN_TYPE_METAENGINE = 0, + PLUGIN_TYPE_ENGINE, PLUGIN_TYPE_MUSIC, + PLUGIN_TYPE_DETECTION, /* PLUGIN_TYPE_SCALER, */ // TODO: Add graphics scaler plugins PLUGIN_TYPE_MAX @@ -69,8 +71,10 @@ enum PluginType { // TODO: Make the engine API version depend on ScummVM's version // because of the backlinking (posibly from the checkout revision) -#define PLUGIN_TYPE_ENGINE_VERSION 1 +#define PLUGIN_TYPE_METAENGINE_VERSION 1 +#define PLUGIN_TYPE_ENGINE_VERSION 2 #define PLUGIN_TYPE_MUSIC_VERSION 1 +#define PLUGIN_TYPE_DETECTION_VERSION 1 extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; @@ -150,6 +154,18 @@ public: /** Returns the name of the plugin. */ virtual const char *getName() const = 0; + + /** + * Returns the engine id of the plugin, if implemented. + * This mostly has the use with MetaEngines, but if another + * type of plugins request this, we return a nullptr. + * This is used because MetaEngines are now available in the + * executable, and querying this we can match a MetaEngine + * with it's related engine. + */ + virtual const char *getEngineId() const { + return nullptr; + } }; /** @@ -180,6 +196,7 @@ public: **/ PluginType getType() const; const char *getName() const; + const char *getEngineId() const; template T &get() const { @@ -198,6 +215,15 @@ public: virtual const char *getFileName() const { return 0; } }; +class StaticPlugin : public Plugin { +public: + StaticPlugin(PluginObject *pluginobject, PluginType type); + ~StaticPlugin(); + virtual bool loadPlugin(); + virtual void unloadPlugin(); +}; + + /** List of Plugin instances. */ typedef Common::Array PluginList; @@ -311,12 +337,38 @@ public: void addPluginProvider(PluginProvider *pp); + /** + * A method which takes in a plugin of type ENGINE, + * and returns the appropriate & matching METAENGINE. + * It uses the Engine plugin's getName method, which is an identifier, + * and then tries to matches it with each plugin present in memory. + * + * @param A plugin of type ENGINE. + * + * @return A plugin of type METAENGINE. + */ + Plugin *getMetaEngineFromEngine(const Plugin *plugin); + + /** + * A method which takes in a plugin of type METAENGINE, + * and returns the appropriate & matching ENGINE. + * It uses the MetaEngine's getEngineID to reconstruct the name + * of engine plugin, and then tries to matches it with each plugin in memory. + * + * @param A plugin of type METAENGINE. + * + * @return A plugin of type ENGINE. + */ + Plugin *getEngineFromMetaEngine(const Plugin *plugin); + // Functions used by the uncached PluginManager virtual void init() {} virtual void loadFirstPlugin() {} virtual bool loadNextPlugin() { return false; } virtual bool loadPluginFromEngineId(const Common::String &engineId) { return false; } virtual void updateConfigWithFileName(const Common::String &engineId) {} + virtual void loadDetectionPlugin() {} + virtual void unloadDetectionPlugin() {} // Functions used only by the cached PluginManager virtual void loadAllPlugins(); @@ -336,20 +388,25 @@ class PluginManagerUncached : public PluginManager { protected: friend class PluginManager; PluginList _allEnginePlugins; + Plugin *_detectionPlugin; PluginList::iterator _currentPlugin; - PluginManagerUncached() {} + bool _isDetectionLoaded; + + PluginManagerUncached() : _isDetectionLoaded(false) {} bool loadPluginByFileName(const Common::String &filename); public: - virtual void init(); - virtual void loadFirstPlugin(); - virtual bool loadNextPlugin(); - virtual bool loadPluginFromEngineId(const Common::String &engineId); - virtual void updateConfigWithFileName(const Common::String &engineId); + virtual void init() override; + virtual void loadFirstPlugin() override; + virtual bool loadNextPlugin() override; + virtual bool loadPluginFromEngineId(const Common::String &engineId) override; + virtual void updateConfigWithFileName(const Common::String &engineId) override; + virtual void loadDetectionPlugin() override; + virtual void unloadDetectionPlugin() override; - virtual void loadAllPlugins() {} // we don't allow these - virtual void loadAllPluginsOfType(PluginType type) {} + virtual void loadAllPlugins() override {} // we don't allow these + virtual void loadAllPluginsOfType(PluginType type) override {} }; #endif diff --git a/common/achievements.h b/common/achievements.h index 550aecd8e49..0355374ed80 100644 --- a/common/achievements.h +++ b/common/achievements.h @@ -30,6 +30,15 @@ namespace Common { +/** + * @defgroup common_achieve Achievements + * @ingroup common + * + * @brief API related to in-game achievements. + * + * @{ + */ + /** * List of game achievements provider platforms. * Possible candidates are XBOX Gamerscore, PSN Trophies, Kongregate Badges, etc... @@ -96,6 +105,7 @@ private: /** Shortcut for accessing the achievements manager. */ #define AchMan Common::AchievementsManager::instance() +/** @} */ } // End of namespace Common diff --git a/common/algorithm.h b/common/algorithm.h index 1aac0376dbc..5e669e7e119 100644 --- a/common/algorithm.h +++ b/common/algorithm.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_alg Algorithms + * @ingroup common + * + * @brief Templates for algorithms used to manipulate data. + * + * @{ + */ + /** * Copies data from the range [first, last) to [dst, dst + (last - first)). * It requires the range [dst, dst + (last - first)) to be valid. @@ -308,5 +317,9 @@ void replace(It begin, It end, const Dat &original, const Dat &replaced) { } } +/** @} */ + + } // End of namespace Common + #endif diff --git a/common/archive.h b/common/archive.h index 2cf75553713..c7a0f731f75 100644 --- a/common/archive.h +++ b/common/archive.h @@ -30,6 +30,18 @@ namespace Common { +/** + * @defgroup common_arch Archive + * @ingroup common + * + * @brief The Archive module allows managing the member of arbitrary containers in a uniform + * fashion. + * It also supports looking up by names and file names, opening a file, and returning usable input stream. + * + * @{ + */ + + class FSNode; class SeekableReadStream; @@ -276,6 +288,8 @@ private: /** Shortcut for accessing the search manager. */ #define SearchMan Common::SearchManager::instance() +/** @} */ + } // namespace Common #endif diff --git a/common/array.h b/common/array.h index c57d0a109d4..191febf3c36 100644 --- a/common/array.h +++ b/common/array.h @@ -28,8 +28,22 @@ #include "common/textconsole.h" // For error() #include "common/memory.h" +#ifdef USE_CXX11 +#include "common/initializer_list.h" +#endif + namespace Common { +/** + * @defgroup common_array Arrays + * @ingroup common + * + * @brief Functions for working on arrays. + * + * @{ + */ + + /** * This class implements a dynamically sized container, which * can be accessed similar to a regular C++ array. Accessing @@ -84,6 +98,26 @@ public: } } +#ifdef USE_CXX11 + /** + * Constructs an array as a copy of the given array using the c++11 move semantic. + */ + Array(Array &&old) : _capacity(old._capacity), _size(old._size), _storage(old._storage) { + old._storage = nullptr; + old._capacity = 0; + old._size = 0; + } + + /** + * Constructs an array using list initialization. + */ + Array(std::initializer_list list) : _size(list.size()) { + allocCapacity(list.size()); + if (_storage) + Common::uninitialized_copy(list.begin(), list.end(), _storage); + } +#endif + /** * Construct an array by copying data from a regular array. */ @@ -210,6 +244,24 @@ public: return *this; } +#ifdef USE_CXX11 + Array &operator=(Array &&old) { + if (this == &old) + return *this; + + freeStorage(_storage, _size); + _capacity = old._capacity; + _size = old._size; + _storage = old._storage; + + old._storage = nullptr; + old._capacity = 0; + old._size = 0; + + return *this; + } +#endif + size_type size() const { return _size; } @@ -456,6 +508,8 @@ private: Comparator _comparator; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/bitstream.h b/common/bitstream.h index 81976efdc89..775a83abaa6 100644 --- a/common/bitstream.h +++ b/common/bitstream.h @@ -33,6 +33,15 @@ namespace Common { +/** + * @defgroup common_bitstream Bit stream + * @ingroup common + * + * @brief API for implementing a bit stream. + * + * @{ + */ + /** * A template implementing a bit stream for different data memory layouts. * @@ -470,6 +479,7 @@ typedef BitStreamImpl BitStreamMemory32 /** 32-bit big-endian data, LSB to MSB. */ typedef BitStreamImpl BitStreamMemory32BELSB; +/** @} */ } // End of namespace Common diff --git a/common/bufferedstream.h b/common/bufferedstream.h index bbd25722a84..94117276bcb 100644 --- a/common/bufferedstream.h +++ b/common/bufferedstream.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_buffstream Buffered stream + * @ingroup common + * + * @brief API for implementing a buffered stream. + * + * @{ + */ + /** * Take an arbitrary ReadStream and wrap it in a custom stream which * transparently provides buffering. @@ -61,6 +70,8 @@ SeekableReadStream *wrapBufferedSeekableReadStream(SeekableReadStream *parentStr */ WriteStream *wrapBufferedWriteStream(WriteStream *parentStream, uint32 bufSize); +/** @} */ + } // End of namespace Common #endif diff --git a/common/callback.h b/common/callback.h index c6c249a511c..c1ada14c34b 100644 --- a/common/callback.h +++ b/common/callback.h @@ -25,6 +25,15 @@ namespace Common { +/** + * @defgroup common_callback Callbacks + * @ingroup common + * + * @brief Callback templates. + * + * @{ + */ + /** * BaseCallback is a simple base class for object-oriented callbacks. * @@ -133,6 +142,8 @@ public: void operator()(S data) { (_object->*_method)(_outerCallback, data); } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/config-manager.h b/common/config-manager.h index 0295abf1709..f2cfd7b145b 100644 --- a/common/config-manager.h +++ b/common/config-manager.h @@ -31,6 +31,16 @@ namespace Common { +/** + * @defgroup common_config Configuration manager + * @ingroup common + * + * @brief The (singleton) configuration manager, used to query & set configuration + * values using string keys. + * + * @{ + */ + class WriteStream; class SeekableReadStream; @@ -207,6 +217,8 @@ private: String _filename; }; +/** @} */ + } // End of namespace Common /** Shortcut for accessing the configuration manager. */ diff --git a/common/coroutines.h b/common/coroutines.h index 10e0bb28da3..68f0fa692d9 100644 --- a/common/coroutines.h +++ b/common/coroutines.h @@ -31,14 +31,16 @@ namespace Common { /** - * @defgroup Coroutine support for simulating multi-threading. + * @defgroup common_coroutine Coroutine support for simulating multi-threading + * @ingroup common * - * The following is loosely based on an article by Simon Tatham: - * . - * However, many improvements and tweaks have been made, in particular - * by taking advantage of C++ features not available in C. + * @brief The following implementation is loosely based on an article by Simon Tatham: + * @linkCoroutine. + * However, many improvements and tweaks have been made, in particular + * by taking advantage of C++ features not available in C. + * + * @{ */ -//@{ #define CoroScheduler (Common::CoroutineScheduler::instance()) @@ -555,7 +557,7 @@ public: void pulseEvent(uint32 pidEvent); }; -//@} +/** @} */ } // end of namespace Common diff --git a/common/cosinetables.h b/common/cosinetables.h index 65cfc2e6b9c..d790c757ada 100644 --- a/common/cosinetables.h +++ b/common/cosinetables.h @@ -25,6 +25,15 @@ namespace Common { +/** + * @defgroup common_cosinetables Cosine tables + * @ingroup common + * + * @brief Functions for working with cosine tables. + * + * @{ + */ + class CosineTable { public: /** @@ -69,6 +78,8 @@ private: int _nPoints; // range of operator[] }; +/** @} */ + } // End of namespace Common #endif // COMMON_COSINETABLES_H diff --git a/common/dcl.h b/common/dcl.h index ade7ebd9854..fa7b95d6be4 100644 --- a/common/dcl.h +++ b/common/dcl.h @@ -21,12 +21,8 @@ */ /** - * @file - * PKWARE DCL ("explode") ("PKWARE data compression library") decompressor used in engines: - * - agos (exclusively for Simon 2 setup.shr file) - * - mohawk - * - neverhood - * - sci + * + */ #ifndef COMMON_DCL_H @@ -36,6 +32,21 @@ namespace Common { +/** + * @defgroup common_dcl Data compression library + * @ingroup common + * + * @brief PKWARE data compression library. + * + * @details PKWARE DCL ("explode") ("PKWARE data compression library") decompressor used in engines: + * - agos (exclusively for Simon 2 setup.shr file) + * - mohawk + * - neverhood + * - sci + * + * @{ + */ + class ReadStream; class SeekableReadStream; @@ -57,6 +68,8 @@ SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream, uint32 packe */ SeekableReadStream *decompressDCL(SeekableReadStream *sourceStream); +/** @} */ + } // End of namespace Common #endif diff --git a/common/dct.h b/common/dct.h index 882856a8a9b..c8d025d5172 100644 --- a/common/dct.h +++ b/common/dct.h @@ -37,6 +37,15 @@ namespace Common { +/** + * @defgroup common_dct Discrete Cosine Transforms + * @ingroup common + * + * @brief Discrete Cosine Transforms. + * + * @{ + */ + /** * (Inverse) Discrete Cosine Transforms. * @@ -74,6 +83,8 @@ private: void calcDSTI (float *data); }; +/** @} */ + } // End of namespace Common #endif // COMMON_DCT_H diff --git a/common/debug-channels.h b/common/debug-channels.h index a2df35102ff..2cef6b40beb 100644 --- a/common/debug-channels.h +++ b/common/debug-channels.h @@ -34,6 +34,15 @@ namespace Common { +/** + * @defgroup common_debug_channels Debug channels + * @ingroup common_debug + * + * @brief Functions for managing debug channels. + * + * @{ + */ + // TODO: Find a better name for this class DebugManager : public Singleton { public: @@ -148,6 +157,8 @@ private: /** Shortcut for accessing the debug manager. */ #define DebugMan Common::DebugManager::instance() +/** @} */ + } // End of namespace Common #endif diff --git a/common/debug.h b/common/debug.h index 5ec37f2f1ed..7beef8acb0c 100644 --- a/common/debug.h +++ b/common/debug.h @@ -38,6 +38,14 @@ inline void debugCN(uint32 debugChannels, const char *s, ...) {} #else +/** + * @defgroup common_debug Debug functions + * @ingroup common + * + * @brief Debug functions. + * + * @{ + */ /** * Print a debug message to the text console (stdout). @@ -144,4 +152,6 @@ enum GlobalDebugLevels { kDebugLevelEventRec = 1 << 30 }; +/** @} */ + #endif diff --git a/common/dialogs.h b/common/dialogs.h index fd165e9ee29..083104d3b59 100644 --- a/common/dialogs.h +++ b/common/dialogs.h @@ -33,6 +33,15 @@ namespace Common { +/** + * @defgroup common_dialogs Dialog Manager + * @ingroup common + * + * @brief The Dialog Manager allows GUI code to interact with native system dialogs. + * + * @{ + */ + /** * The DialogManager allows GUI code to interact with native system dialogs. */ @@ -97,6 +106,8 @@ protected: } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/encoding.cpp b/common/encoding.cpp index 0b7fbab899e..5d701d3cd10 100644 --- a/common/encoding.cpp +++ b/common/encoding.cpp @@ -44,7 +44,7 @@ String addUtfEndianness(const String &str) { return str + "LE"; #endif } else - return String(str); + return str; } Encoding::Encoding(const String &to, const String &from) @@ -55,7 +55,7 @@ Encoding::Encoding(const String &to, const String &from) char *Encoding::switchEndian(const char *string, int length, int bitCount) { assert(bitCount % 8 == 0); assert(length % (bitCount / 8) == 0); - char *newString = (char *)malloc(length); + char *newString = (char *)calloc(sizeof(char), length + 4); if (!newString) { warning("Could not allocate memory for string conversion"); return nullptr; @@ -98,19 +98,33 @@ char *Encoding::convertWithTransliteration(const String &to, const String &from, return result; } - if ((addUtfEndianness(to).equalsIgnoreCase("utf-16be") && - addUtfEndianness(from).equalsIgnoreCase("utf-16le")) || - (addUtfEndianness(to).equalsIgnoreCase("utf-16le") && - addUtfEndianness(from).equalsIgnoreCase("utf-16be")) || - (addUtfEndianness(to).equalsIgnoreCase("utf-32be") && - addUtfEndianness(from).equalsIgnoreCase("utf-32le")) || - (addUtfEndianness(to).equalsIgnoreCase("utf-32le") && - addUtfEndianness(from).equalsIgnoreCase("utf-32be"))) { - // The encoding is the same, we just need to switch the endianness - if (to.hasPrefixIgnoreCase("utf-16")) - return switchEndian(string, length, 16); - else - return switchEndian(string, length, 32); + if ((to.hasPrefixIgnoreCase("utf-16") && from.hasPrefixIgnoreCase("utf-16")) || + (to.hasPrefixIgnoreCase("utf-32") && from.hasPrefixIgnoreCase("utf-32"))) { + // Since the two strings are not equal as this is already checked above, + // this likely mean that one or both has an endianness suffix, and we + // just need to switch the endianess. +#ifdef SCUMM_BIG_ENDIAN + bool fromBigEndian = !from.hasSuffixIgnoreCase("le"); + bool toBigEndian = !to.hasSuffixIgnoreCase("le"); +#else + bool fromBigEndian = from.hasSuffixIgnoreCase("be"); + bool toBigEndian = to.hasSuffixIgnoreCase("be"); +#endif + if (fromBigEndian == toBigEndian) { + // don't convert, just copy the string and return it + char *result = (char *)calloc(sizeof(char), length + 4); + if (!result) { + warning("Could not allocate memory for string conversion"); + return nullptr; + } + memcpy(result, string, length); + return result; + } else { + if (to.hasPrefixIgnoreCase("utf-16")) + return switchEndian(string, length, 16); + else + return switchEndian(string, length, 32); + } } char *newString = nullptr; diff --git a/common/encoding.h b/common/encoding.h index 503fbf5ab8f..6d91bb3a462 100644 --- a/common/encoding.h +++ b/common/encoding.h @@ -30,6 +30,15 @@ namespace Common { +/** + * @defgroup common_encoding Text encoding + * @ingroup common + * + * @brief Functions for managing text encoding. + * + * @{ + */ + /** * A class, that allows conversion between different text encoding, * the encodings available depend on the current backend and if the @@ -221,6 +230,8 @@ class Encoding { static uint32 *transliterateUTF32(const uint32 *string, size_t length); }; +/** @} */ + } #endif // COMMON_ENCODING_H diff --git a/common/endian.h b/common/endian.h index fad9f3ccae8..6ba2709b5eb 100644 --- a/common/endian.h +++ b/common/endian.h @@ -25,10 +25,14 @@ #include "common/scummsys.h" + /** - * \file endian.h - * Endian conversion and byteswap conversion functions or macros + * @defgroup common_endian Endian conversions + * @ingroup common * + * @brief Endian conversion and byteswap conversion functions and macros. + * + * @details * SWAP_BYTES_??(a) - inverse byte order * SWAP_CONSTANT_??(a) - inverse byte order, implemented as macro. * Use with compiletime-constants only, the result will be a compiletime-constant aswell. @@ -42,6 +46,8 @@ * CONSTANT_??_??(a) - convert LE/BE value v to native, implemented as macro. * Use with compiletime-constants only, the result will be a compiletime-constant aswell. * Unlike most other functions these can be used for eg. switch-case labels + * + * @{ */ // Sanity check @@ -632,4 +638,6 @@ inline void WRITE_BE_INT32(void *ptr, int32 value) { WRITE_BE_UINT32(ptr, static_cast(value)); } +/** @} */ + #endif diff --git a/common/error.h b/common/error.h index 00495e06b28..4962c84ef76 100644 --- a/common/error.h +++ b/common/error.h @@ -28,11 +28,14 @@ namespace Common { /** - * This file contains an enum with commonly used error codes. + * @defgroup common_error Error codes + * @ingroup common + * + * @brief Commonly used error codes. + * + * @{ */ - - /** * Error codes which may be reported by plugins under various circumstances. * @@ -60,7 +63,12 @@ enum ErrorCode { kWritingFailed, ///< Failure to write data -- disk full? // The following are used by --list-saves - kEnginePluginNotFound, ///< Failed to find plugin to handle target + + // Failed to find a MetaEnginePlugin. This should never happen, because all MetaEngines must always + // be built into the executable, regardless if the engine plugins are present or not. + kMetaEnginePluginNotFound, ///< See comment above + + kEnginePluginNotFound, ///< Failed to find a Engine plugin to handle target kEnginePluginNotSupportSaves, ///< Failed if plugin does not support listing save states kUserCanceled, ///< User has canceled the launching of the game @@ -103,6 +111,8 @@ public: ErrorCode getCode() const { return _code; } }; +/** @} */ + } // End of namespace Common #endif //COMMON_ERROR_H diff --git a/common/events.h b/common/events.h index 5ed445baa43..bd100301878 100644 --- a/common/events.h +++ b/common/events.h @@ -34,14 +34,18 @@ namespace Common { /** - * The types of events backends may generate. - * @see Event + * @defgroup common_events Events + * @ingroup common + * + * @brief The types of events backends may generate. * * @todo Merge EVENT_LBUTTONDOWN, EVENT_RBUTTONDOWN and EVENT_WHEELDOWN; * likewise EVENT_LBUTTONUP, EVENT_RBUTTONUP, EVENT_WHEELUP. * To do that, we just have to add a field to the Event which * indicates which button was pressed. + * @{ */ + enum EventType { EVENT_INVALID = 0, /** A key was pressed, details in Event::kbd. */ @@ -555,6 +559,8 @@ protected: */ EventSource *makeKeyboardRepeatingEventSource(EventSource *eventSource); +/** @} */ + } // End of namespace Common #endif diff --git a/common/fft.h b/common/fft.h index ed66d32b717..2a9f2166505 100644 --- a/common/fft.h +++ b/common/fft.h @@ -34,10 +34,19 @@ namespace Common { +/** + * @defgroup common_fft Fast Fourier Transform (FFT) + * @ingroup common + * + * @brief API for the FFT algorithm. + * + * @{ + */ + class CosineTable; /** - * (Inverse) Fast Fourier Transform. + * (Inverse) Fast Fourier Transform * * Used in engines: * - scumm @@ -80,6 +89,8 @@ private: void fft(int n, int logn, Complex *z); }; +/** @} */ + } // End of namespace Common #endif // COMMON_FFT_H diff --git a/common/file.h b/common/file.h index 2d5232abccf..e06f75d5ca2 100644 --- a/common/file.h +++ b/common/file.h @@ -31,6 +31,15 @@ namespace Common { +/** + * @defgroup common_files Files + * @ingroup common + * + * @brief API for operations on files. + * + * @{ + */ + class Archive; /** @@ -168,6 +177,8 @@ public: virtual int32 size() const override; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/frac.h b/common/frac.h index 4e3bcf267f3..c6637b3bded 100644 --- a/common/frac.h +++ b/common/frac.h @@ -25,6 +25,15 @@ #include "common/scummsys.h" +/** + * @defgroup common_frac Fixed-point fractions + * @ingroup common + * + * @brief API for fixed-point fractions. + * + * @{ + */ + /** * The precision of the fractional (fixed point) type we define below. * Normally you should never have to modify this value. @@ -49,4 +58,6 @@ inline double fracToDouble(frac_t value) { return ((double)value) / FRAC_ONE; } inline frac_t intToFrac(int16 value) { return value * (1 << FRAC_BITS); } inline int16 fracToInt(frac_t value) { return value / (1 << FRAC_BITS); } +/** @} */ + #endif diff --git a/common/fs.h b/common/fs.h index 718f47ff561..e550bef34b9 100644 --- a/common/fs.h +++ b/common/fs.h @@ -34,6 +34,15 @@ class AbstractFSNode; namespace Common { +/** + * @defgroup common_fs File system + * @ingroup common + * + * @brief API for operations on the file system. + * + * @{ + */ + class FSNode; class SeekableReadStream; class WriteStream; @@ -371,6 +380,7 @@ public: virtual SeekableReadStream *createReadStreamForMember(const String &name) const; }; +/** @} */ } // End of namespace Common diff --git a/common/func.h b/common/func.h index b58474b2f39..3ffe78c934a 100644 --- a/common/func.h +++ b/common/func.h @@ -27,6 +27,16 @@ namespace Common { +/** + * @defgroup common_func Functions + * @ingroup common + * + * @brief API for managing functions. + * + * @{ + */ + + /** * Generic unary function. */ @@ -536,6 +546,8 @@ GENERATE_TRIVIAL_HASH_FUNCTOR(unsigned long); #undef GENERATE_TRIVIAL_HASH_FUNCTOR +/** @} */ + } // End of namespace Common #endif diff --git a/common/gui_options.h b/common/gui_options.h index e07da2709c0..4a10a8df891 100644 --- a/common/gui_options.h +++ b/common/gui_options.h @@ -95,6 +95,15 @@ namespace Common { +/** + * @defgroup common_gui_options GUI options + * @ingroup common + * + * @brief API for managing the options of the graphical user interface (GUI). + * + * @{ + */ + class String; bool checkGameGUIOption(const String &option, const String &str); @@ -108,6 +117,7 @@ const String getGameGUIOptionsDescription(const String &options); */ void updateGameGUIOptions(const String &options, const String &langOption); +/** @} */ } // End of namespace Common diff --git a/common/hash-ptr.h b/common/hash-ptr.h index 1099478c3b7..d27cdf41187 100644 --- a/common/hash-ptr.h +++ b/common/hash-ptr.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_hashmap_ptr Hash table pointer + * @ingroup common_hashmap + * + * @brief Template for a HashMap pointer. + * + * @{ + */ + /** * Partial specialization of the Hash functor to be able to use pointers as HashMap keys */ @@ -38,6 +47,8 @@ struct Hash { } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/hashmap.h b/common/hashmap.h index 861f0556628..804f179da9c 100644 --- a/common/hashmap.h +++ b/common/hashmap.h @@ -57,6 +57,15 @@ namespace Common { +/** + * @defgroup common_hashmap Hash table (HashMap) + * @ingroup common + * + * @brief API for operations on a hash table. + * + * @{ + */ + // The sgi IRIX MIPSpro Compiler has difficulties with nested templates. // This and the other __sgi conditionals below work around these problems. // The Intel C++ Compiler suffers from the same problems. @@ -624,6 +633,8 @@ void HashMap::erase(const Key &key) { #undef HASHMAP_DUMMY_NODE +/** @} */ + } // End of namespace Common #endif diff --git a/common/huffman.h b/common/huffman.h index 052c7bf8251..d98d90cc73f 100644 --- a/common/huffman.h +++ b/common/huffman.h @@ -31,6 +31,18 @@ namespace Common { +/** + * @defgroup common_huffmann Huffman bitstream decoding + * @ingroup common + * + * @brief API for operations related to Huffman bitstream decoding. + * + * @details Used in engines: + * - scumm + * + * @{ + */ + inline uint32 REVERSEBITS(uint32 x) { x = (((x & ~0x55555555) >> 1) | ((x & 0x55555555) << 1)); x = (((x & ~0x33333333) >> 2) | ((x & 0x33333333) << 2)); @@ -43,8 +55,6 @@ inline uint32 REVERSEBITS(uint32 x) { /** * Huffman bitstream decoding * - * Used in engines: - * - scumm */ template class Huffman { @@ -159,6 +169,8 @@ uint32 Huffman::getSymbol(BITSTREAM &bits) const { return 0; } +/** @} */ + } // End of namespace Common #endif // COMMON_HUFFMAN_H diff --git a/common/iff_container.h b/common/iff_container.h index a88b1597332..83bb62ac742 100644 --- a/common/iff_container.h +++ b/common/iff_container.h @@ -31,6 +31,16 @@ namespace Common { +/** + * @defgroup common_iff Interchange File Format (IFF) + * @ingroup common + * + * @brief API for operations on IFF container files. + * + * + * @{ + */ + typedef uint32 IFF_ID; #define ID_FORM MKTAG('F','O','R','M') @@ -265,6 +275,8 @@ public: uint32 read(void *dataPtr, uint32 dataSize); }; +/** @} */ + } // namespace Common #endif diff --git a/common/ini-file.h b/common/ini-file.h index f84ca6009c9..4b66936ac07 100644 --- a/common/ini-file.h +++ b/common/ini-file.h @@ -29,6 +29,16 @@ namespace Common { +/** + * @defgroup common_ini_file INI files + * @ingroup common + * + * @brief API for operations on INI configuration files. + * + * + * @{ + */ + class SeekableReadStream; class WriteStream; @@ -128,6 +138,8 @@ private: const Section *getSection(const String §ion) const; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/installshield_cab.h b/common/installshield_cab.h index d3c584815ed..af2699a70b4 100644 --- a/common/installshield_cab.h +++ b/common/installshield_cab.h @@ -27,6 +27,16 @@ namespace Common { +/** + * @defgroup common_installshield InstallShield + * @ingroup common + * + * @brief API for managing the InstallShield. + * + * + * @{ + */ + class Archive; class SeekableReadStream; @@ -38,6 +48,8 @@ class SeekableReadStream; */ Archive *makeInstallShieldArchive(SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); +/** @} */ + } // End of namespace Common #endif diff --git a/common/keyboard.h b/common/keyboard.h index fae2555286e..b06a309baed 100644 --- a/common/keyboard.h +++ b/common/keyboard.h @@ -36,6 +36,16 @@ namespace Common { +/** + * @defgroup common_keyboard Keyboard + * @ingroup common + * + * @brief API for keyboard operations. + * + * + * @{ + */ + enum KeyCode { KEYCODE_INVALID = 0, @@ -356,6 +366,8 @@ struct KeyState { } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/language.h b/common/language.h index 8c7369a8a3a..e787fe79f12 100644 --- a/common/language.h +++ b/common/language.h @@ -27,6 +27,16 @@ namespace Common { +/** + * @defgroup common_language Language + * @ingroup common + * + * @brief API for managing game language. + * + * + * @{ + */ + class String; /** @@ -93,6 +103,8 @@ const String getGameGUIOptionsDescriptionLanguage(Common::Language lang); // TODO: Document this GUIO related function bool checkGameGUIOptionLanguage(Common::Language lang, const String &str); +/** @} */ + } // End of namespace Common #endif diff --git a/common/list.h b/common/list.h index 31cf161d221..f889dbc9cba 100644 --- a/common/list.h +++ b/common/list.h @@ -27,6 +27,16 @@ namespace Common { +/** + * @defgroup common_list Lists + * @ingroup common + * + * @brief API and templates for managing lists. + * + * + * @{ + */ + /** * Simple double linked list, modeled after the list template of the standard * C++ library. @@ -255,6 +265,8 @@ protected: } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/localization.h b/common/localization.h index 51803279e75..f5c63a2db71 100644 --- a/common/localization.h +++ b/common/localization.h @@ -28,6 +28,16 @@ namespace Common { +/** + * @defgroup common_localization Localization + * @ingroup common + * + * @brief Functions for managing localized elements of the GUI. + * + * + * @{ + */ + /** * Get localized equivalents for Y/N buttons of the specified language. In * case there is no specialized keys for the given language it will fall back @@ -48,6 +58,8 @@ void getLanguageYesNo(Language id, KeyCode &keyYes, KeyCode &keyNo); */ void getLanguageYesNo(KeyCode &keyYes, KeyCode &keyNo); +/** @} */ + } // End of namespace Common #endif diff --git a/common/macresman.h b/common/macresman.h index 6ac831fe2e7..5ab2b4d6b70 100644 --- a/common/macresman.h +++ b/common/macresman.h @@ -22,12 +22,7 @@ /** * @file - * Macintosh resource fork manager used in engines: - * - groovie - * - mohawk - * - pegasus - * - sci - * - scumm + */ #include "common/array.h" @@ -40,6 +35,21 @@ namespace Common { +/** + * @defgroup common_macresman Macintosh resource fork manager + * @ingroup common + * + * @brief API for Macintosh resource fork manager. + * + * @details Used in engines: + * - groovie + * - mohawk + * - pegasus + * - sci + * - scumm + * @{ + */ + typedef Array MacResIDArray; typedef Array MacResTagArray; @@ -282,6 +292,8 @@ private: ResPtr *_resLists; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/md5.h b/common/md5.h index 640326efe77..62562b60630 100644 --- a/common/md5.h +++ b/common/md5.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_md5 MD5 checksum + * @ingroup common + * + * @brief API for computing the MD5 checksum. + * + * @{ + */ + class ReadStream; class String; @@ -54,6 +63,8 @@ bool computeStreamMD5(ReadStream &stream, uint8 digest[16], uint32 length = 0); */ String computeStreamMD5AsString(ReadStream &stream, uint32 length = 0); +/** @} */ + } // End of namespace Common #endif diff --git a/common/memory.h b/common/memory.h index 91a320080b5..bdd521a17a0 100644 --- a/common/memory.h +++ b/common/memory.h @@ -27,6 +27,14 @@ namespace Common { +/** + * @defgroup common_memory Memory + * @ingroup common + * + * @brief Functions for managing the memory. + * @{ + */ + /** * Copies data from the range [first, last) to [dst, dst + (last - first)). * It requires the range [dst, dst + (last - first)) to be valid and @@ -61,6 +69,8 @@ void uninitialized_fill_n(Type *dst, size_t n, const Value &x) { new ((void *)dst++) Type(x); } +/** @} */ + } // End of namespace Common #endif diff --git a/common/memorypool.h b/common/memorypool.h index b84012232cb..6567dbe59cb 100644 --- a/common/memorypool.h +++ b/common/memorypool.h @@ -29,6 +29,14 @@ namespace Common { +/** + * @defgroup common_memory_pool Memory pool + * @ingroup common_memory + * + * @brief API for managing the memory pool. + * @{ + */ + /** * This class provides a pool of memory 'chunks' of identical size. * The size of a chunk is determined when creating the memory pool. @@ -141,6 +149,8 @@ public: } }; +/** @} */ + } // End of namespace Common /** diff --git a/common/memstream.h b/common/memstream.h index 9452e4f24ba..5bfd7f08119 100644 --- a/common/memstream.h +++ b/common/memstream.h @@ -29,6 +29,14 @@ namespace Common { +/** + * @defgroup common_memory_pool Memory stream + * @ingroup common_memory + * + * @brief API for managing the memory stream. + * @{ + */ + /** * Simple memory based 'stream', which implements the ReadStream interface for * a plain memory block. @@ -334,6 +342,8 @@ public: byte *getData() { return _data; } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/mutex.h b/common/mutex.h index 1b52bb40dd2..3c64b0214c5 100644 --- a/common/mutex.h +++ b/common/mutex.h @@ -28,6 +28,14 @@ namespace Common { +/** + * @defgroup common_mutex Mutex + * @ingroup common + * + * @brief API for managing the mutex. + * @{ + */ + class Mutex; /** @@ -62,6 +70,7 @@ public: void unlock(); }; +/** @} */ } // End of namespace Common diff --git a/common/noncopyable.h b/common/noncopyable.h index 24021f42a66..8ab24e67288 100644 --- a/common/noncopyable.h +++ b/common/noncopyable.h @@ -25,6 +25,14 @@ namespace Common { +/** + * @defgroup common_noncopy NonCopyable class + * @ingroup common + * + * @brief API for NonCopyable class. + * @{ + */ + /** * Subclass of NonCopyable can not be copied due to the fact that * we made the copy constructor and assigment operator private. @@ -38,6 +46,8 @@ private: NonCopyable& operator=(const NonCopyable&); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/osd_message_queue.h b/common/osd_message_queue.h index 4da2f1d2e64..88dd89b1852 100644 --- a/common/osd_message_queue.h +++ b/common/osd_message_queue.h @@ -32,6 +32,14 @@ namespace Common { +/** + * @defgroup common_osd_message_queue OSD message queue + * @ingroup common + * + * @brief API for managing the queue of On Screen Display (OSD) messages. + * @{ + */ + /** * Queue OSD messages from any thread to be displayed by the graphic thread. */ @@ -68,6 +76,8 @@ private: uint32 _lastUpdate; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/platform.h b/common/platform.h index bdf1772807e..f9a3b8dedb0 100644 --- a/common/platform.h +++ b/common/platform.h @@ -27,6 +27,14 @@ namespace Common { +/** + * @defgroup common_platform Game platforms + * @ingroup common + * + * @brief API for managing game platforms. + * @{ + */ + class String; /** @@ -84,6 +92,8 @@ extern const char *getPlatformCode(Platform id); extern const char *getPlatformAbbrev(Platform id); extern const char *getPlatformDescription(Platform id); +/** @} */ + } // End of namespace Common #endif diff --git a/common/ptr.h b/common/ptr.h index 565c9d8ceea..cc247f12a66 100644 --- a/common/ptr.h +++ b/common/ptr.h @@ -30,6 +30,14 @@ namespace Common { +/** + * @defgroup common_ptr Pointers + * @ingroup common + * + * @brief API and templates for pointers. + * @{ + */ + class SharedPtrDeletionInternal { public: virtual ~SharedPtrDeletionInternal() {} @@ -329,6 +337,8 @@ private: DisposeAfterUse::Flag _dispose; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/queue.h b/common/queue.h index ee14d5b3644..ed5f964f1bc 100644 --- a/common/queue.h +++ b/common/queue.h @@ -28,6 +28,14 @@ namespace Common { +/** + * @defgroup common_queue Queue + * @ingroup common + * + * @brief API and templates for queues. + * @{ + */ + /** * Variable size Queue class, implemented using our List class. */ @@ -82,6 +90,8 @@ private: List _impl; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/quicktime.h b/common/quicktime.h index 26fc44ac713..4d8af4db6f4 100644 --- a/common/quicktime.h +++ b/common/quicktime.h @@ -41,13 +41,18 @@ namespace Common { class MacResManager; /** - * Parser for QuickTime/MPEG-4 files. + * @defgroup common_quicktime Quicktime file parser + * @ingroup common * - * File parser used in engines: - * - groovie - * - mohawk - * - sci + * @brief Parser for QuickTime/MPEG-4 files. + * + * @details File parser used in engines: + * - groovie + * - mohawk + * - sci + * @{ */ + class QuickTimeParser { public: QuickTimeParser(); @@ -211,6 +216,8 @@ private: int readSMI(Atom atom); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/random.h b/common/random.h index 48cde26dc5c..29f648ecd2a 100644 --- a/common/random.h +++ b/common/random.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_rng RNG + * @ingroup common + * + * @brief Random number generator (RNG) implementation. + * + * @{ + */ + class String; /** @@ -75,6 +84,8 @@ public: uint getRandomNumberRng(uint min, uint max); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/rational.h b/common/rational.h index bd240c99f3a..afa7c56a715 100644 --- a/common/rational.h +++ b/common/rational.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_rational Rational class + * @ingroup common + * + * @brief API for rational class. + * + * @{ + */ + /** A simple rational class that holds fractions. */ class Rational { public: @@ -108,6 +117,8 @@ bool operator<(int left, const Rational &right); bool operator>=(int left, const Rational &right); bool operator<=(int left, const Rational &right); +/** @} */ + } // End of namespace Common #endif diff --git a/common/rdft.h b/common/rdft.h index ae06c72ef82..f8316981622 100644 --- a/common/rdft.h +++ b/common/rdft.h @@ -37,9 +37,18 @@ namespace Common { /** - * (Inverse) Real Discrete Fourier Transform. + * @defgroup common_rdft RDFT algorithm + * @ingroup common * - * Used in audio: + * @brief API for the Real Discrete Fourier Transform (RDFT) algorithm. + * + * @{ + */ + +/** + * @brief (Inverse) Real Discrete Fourier Transform. + * + * @details Used in audio: * - QDM2 * * Used in engines: @@ -107,6 +116,8 @@ private: FFT *_fft; }; +/** @} */ + } // End of namespace Common #endif // COMMON_RDFT_H diff --git a/common/rect.h b/common/rect.h index 96fbe0cbf69..c6a066603ef 100644 --- a/common/rect.h +++ b/common/rect.h @@ -31,6 +31,15 @@ namespace Common { +/** + * @defgroup common_rect Rectangular zones + * @ingroup common + * + * @brief API for operations on rectangular zones. + * + * @{ + */ + /** * Simple class for handling both 2D position and size. */ @@ -297,6 +306,8 @@ struct Rect { } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/rendermode.h b/common/rendermode.h index ae1a7bc7902..7432dcb5aa4 100644 --- a/common/rendermode.h +++ b/common/rendermode.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_rendermode Render modes + * @ingroup common + * + * @brief API for render modes. + * + * @{ + */ + class String; /** @@ -70,6 +79,7 @@ extern String renderMode2GUIO(RenderMode id); // TODO: Rename the following to something better; also, document it extern String allRenderModesGUIOs(); +/** @} */ } // End of namespace Common diff --git a/common/safe-bool.h b/common/safe-bool.h index 92c8af51aac..978040ece40 100644 --- a/common/safe-bool.h +++ b/common/safe-bool.h @@ -40,6 +40,15 @@ namespace Common { }; } + /** + * @defgroup common_safe_bool Safe Boolean + * @ingroup common + * + * @brief Template for a SafeBool function. + * + * @{ + */ + /** * Prevents `operator bool` from implicitly converting to other types. */ @@ -60,6 +69,7 @@ namespace Common { &impl_t::stub : 0; } }; + /** @} */ } // End of namespace Common #endif diff --git a/common/savefile.h b/common/savefile.h index bc76de5659c..8a1bd285530 100644 --- a/common/savefile.h +++ b/common/savefile.h @@ -31,6 +31,14 @@ namespace Common { +/** + * @defgroup common_savefile Save files + * @ingroup common + * + * @brief API for managing save files. + * + * @{ + */ /** * A class which allows game engines to load game state data. @@ -209,6 +217,8 @@ public: virtual void updateSavefilesList(StringArray &lockedFiles) = 0; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/serializer.h b/common/serializer.h index 18fb38563be..84780307593 100644 --- a/common/serializer.h +++ b/common/serializer.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_serializer Serializer + * @ingroup common + * + * @brief API for serializing data. + * + * @{ + */ + #define VER(x) Common::Serializer::Version(x) #define SYNC_AS(SUFFIX,TYPE,SIZE) \ @@ -280,6 +289,7 @@ public: virtual void saveLoadWithSerializer(Serializer &ser) = 0; }; +/** @} */ } // End of namespace Common diff --git a/common/sinetables.h b/common/sinetables.h index bd030ca8330..321983ec0fc 100644 --- a/common/sinetables.h +++ b/common/sinetables.h @@ -25,6 +25,15 @@ namespace Common { +/** + * @defgroup common_sinetables Sine tables + * @ingroup common + * + * @brief API for managing sine tables. + * + * @{ + */ + class SineTable { public: /** @@ -69,6 +78,8 @@ private: int _nPoints; // range of operator[] }; +/** @} */ + } // End of namespace Common #endif // COMMON_SINETABLES_H diff --git a/common/singleton.h b/common/singleton.h index 7deb1dd7dc7..cc0b09400d2 100644 --- a/common/singleton.h +++ b/common/singleton.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_singleton Singleton + * @ingroup common + * + * @brief API for managing singletons. + * + * @{ + */ + /** * Generic template base class for implementing the singleton design pattern. */ @@ -101,6 +110,8 @@ protected: #define DECLARE_SINGLETON(T) \ template<> T *Singleton::_singleton = 0 +/** @} */ + } // End of namespace Common #endif diff --git a/common/stack.h b/common/stack.h index cba3fb124d3..5ee7fad5174 100644 --- a/common/stack.h +++ b/common/stack.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_stack Stack + * @ingroup common + * + * @brief Fixed-size stack implementation. + * + * @{ + */ + /** * Extremly simple fixed size stack class. */ @@ -140,6 +149,8 @@ public: } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/str-array.h b/common/str-array.h index ecd10b459a7..b0693674798 100644 --- a/common/str-array.h +++ b/common/str-array.h @@ -29,12 +29,22 @@ namespace Common { +/** + * @defgroup common_str_array String array + * @ingroup common_str + * + * @brief String array implementation. + * + * @{ + */ + /** * An array of of strings. */ typedef Array StringArray; typedef Array U32StringArray; +/** @} */ } // End of namespace Common diff --git a/common/str.h b/common/str.h index ce1d79fa95c..33c8aa29b7a 100644 --- a/common/str.h +++ b/common/str.h @@ -31,6 +31,15 @@ namespace Common { +/** + * @defgroup common_str Strings + * @ingroup common + * + * @brief API for working with strings. + * + * @{ + */ + class U32String; /** @@ -566,6 +575,8 @@ size_t strnlen(const char *src, size_t maxSize); */ String toPrintable(const String &src, bool keepNewLines = true); +/** @} */ + } // End of namespace Common extern int scumm_stricmp(const char *s1, const char *s2); diff --git a/common/stream.h b/common/stream.h index 1da3cba5609..1dafd841800 100644 --- a/common/stream.h +++ b/common/stream.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_stream Streams + * @ingroup common + * + * @brief API for managing readable and writable data streams. + * + * @{ + */ + class ReadStream; class SeekableReadStream; @@ -714,6 +723,7 @@ public: SeekableReadStreamEndian(bool bigEndian) : ReadStreamEndian(bigEndian) {} }; +/** @} */ } // End of namespace Common diff --git a/common/substream.h b/common/substream.h index 8bc68cc8a99..01cecf1bb5d 100644 --- a/common/substream.h +++ b/common/substream.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_substream Substreams + * @ingroup common_stream + * + * @brief API for managing readable data substreams. + * + * @{ + */ + /** * SubReadStream provides access to a ReadStream restricted to the range * [currentPosition, currentPosition+end). @@ -124,6 +133,7 @@ public: virtual uint32 read(void *dataPtr, uint32 dataSize); }; +/** @} */ } // End of namespace Common diff --git a/common/system.h b/common/system.h index 8776389ab7a..c48b2c7b967 100644 --- a/common/system.h +++ b/common/system.h @@ -69,6 +69,15 @@ class Encoding; typedef Array KeymapArray; } +/** + * @defgroup common_system System + * @ingroup common + * + * @brief Operating system related API. + * + * @{ + */ + class AudioCDManager; class FilesystemFactory; class PaletteManager; @@ -822,6 +831,7 @@ public: */ virtual int getStretchMode() const { return 0; } + /** * Set the size and color format of the virtual screen. Typical sizes include: * - 320x200 (e.g. for most SCUMM games, and Simon) @@ -1699,4 +1709,6 @@ protected: /** The global OSystem instance. Initialized in main(). */ extern OSystem *g_system; +/** @} */ + #endif diff --git a/common/taskbar.h b/common/taskbar.h index d5e62087ba4..cdcee74913d 100644 --- a/common/taskbar.h +++ b/common/taskbar.h @@ -33,6 +33,15 @@ namespace Common { +/** + * @defgroup common_taskbar Taskbar Manager + * @ingroup common + * + * @brief The TaskbarManager module allows for interaction with the ScummVM application icon. + * + * @{ + */ + /** * The TaskbarManager allows interaction with the ScummVM application icon: * - in the taskbar on Windows 7 and later @@ -187,6 +196,8 @@ return (path); \ } }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/text-to-speech.h b/common/text-to-speech.h index 041842aa850..e91ed872392 100644 --- a/common/text-to-speech.h +++ b/common/text-to-speech.h @@ -32,6 +32,15 @@ namespace Common { +/** + * @defgroup common_text_speech Text-to-speech Manager + * @ingroup common + * + * @brief The TTS module allows for speech synthesis. + * + * @{ + */ + /** * Text to speech voice class. */ @@ -340,6 +349,8 @@ protected: virtual void updateVoices() {}; }; +/** @} */ + } // End of namespace Common #endif // USE_TTS diff --git a/common/textconsole.h b/common/textconsole.h index e7654dd7e58..6a6baa45ed5 100644 --- a/common/textconsole.h +++ b/common/textconsole.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_text_console Text console + * @ingroup common + * + * @brief Output formatter, typically used for debugging. + * + * @{ + */ + /** * An output formatter takes a source string and 'decorates' it with * extra information, storing the result in a destination buffer. @@ -57,6 +66,8 @@ typedef void (*ErrorHandler)(const char *msg); */ void setErrorHandler(ErrorHandler handler); +/** @} */ + } // End of namespace Common diff --git a/common/timer.h b/common/timer.h index 2db163327de..d1662896201 100644 --- a/common/timer.h +++ b/common/timer.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_timer Timer + * @ingroup common + * + * @brief API for managing the timer. + * + * @{ + */ + class TimerManager : NonCopyable { public: typedef void (*TimerProc)(void *refCon); @@ -57,6 +66,8 @@ public: virtual void removeTimerProc(TimerProc proc) = 0; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/tokenizer.h b/common/tokenizer.h index 82befbd4af8..3dd0797aebc 100644 --- a/common/tokenizer.h +++ b/common/tokenizer.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_tokenizer String tokenizer + * @ingroup common + * + * @brief String tokenizer for creating tokens out of parts of a string. + * + * @{ + */ + /** * A simple non-optimized string tokenizer. * @@ -81,6 +90,9 @@ private: U32String::const_iterator _tokenBegin; ///< Latest found token's begin iterator (Valid after a call to nextToken()) U32String::const_iterator _tokenEnd; ///< Latest found token's end iterator (Valid after a call to nextToken()) }; + +/** @} */ + } // End of namespace Common #endif diff --git a/common/translation.h b/common/translation.h index e910b36ac00..02ad825ad20 100644 --- a/common/translation.h +++ b/common/translation.h @@ -34,6 +34,15 @@ namespace Common { +/** + * @defgroup common_translation Message translation manager + * @ingroup common + * + * @brief API related to translation. + * + * @{ + */ + class File; enum TranslationIDs { @@ -217,6 +226,8 @@ private: int _currentLang; }; +/** @} */ + } // End of namespace Common #define TransMan Common::TranslationManager::instance() diff --git a/common/unarj.h b/common/unarj.h index 2be514c9366..743984127da 100644 --- a/common/unarj.h +++ b/common/unarj.h @@ -33,6 +33,15 @@ namespace Common { +/** + * @defgroup common_unarj ARJ decompressor + * @ingroup common + * + * @brief API related to ARJ archive files. + * + * @{ + */ + class Archive; /** @@ -43,6 +52,8 @@ class Archive; */ Archive *makeArjArchive(const String &name); +/** @} */ + } // End of namespace Common #endif diff --git a/common/unzip.h b/common/unzip.h index f249c5db19b..51b3b18187d 100644 --- a/common/unzip.h +++ b/common/unzip.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_unzip ZIP decompressor + * @ingroup common + * + * @brief API related to ZIP archive files. + * + * @{ + */ + class Archive; class FSNode; class SeekableReadStream; @@ -57,6 +66,8 @@ Archive *makeZipArchive(const FSNode &node); */ Archive *makeZipArchive(SeekableReadStream *stream); +/** @} */ + } // End of namespace Common #endif diff --git a/common/updates.h b/common/updates.h index 1f1c190304d..f671b7cb726 100644 --- a/common/updates.h +++ b/common/updates.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_update Update Manager + * @ingroup common + * + * @brief The UpdateManager module allows for automatic update checking. + * + * @{ + */ + /** * The UpdateManager allows configuring of the automatic update checking * for systems that support it: @@ -127,6 +136,8 @@ public: static int normalizeInterval(int interval); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/ustr.h b/common/ustr.h index 261894bdfda..db4d078717e 100644 --- a/common/ustr.h +++ b/common/ustr.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_ustr UTF-32 strings + * @ingroup common_str + * + * @brief API for working with UTF-32 strings. + * + * @{ + */ + class String; class UnicodeBiDiText; @@ -280,6 +289,9 @@ private: }; U32String operator+(const U32String &x, const U32String &y); + +/** @} */ + } // End of namespace Common #endif diff --git a/common/util.h b/common/util.h index 58d2b981d63..273d0273183 100644 --- a/common/util.h +++ b/common/util.h @@ -26,6 +26,15 @@ #include "common/scummsys.h" #include "common/str.h" +/** + * @defgroup common_util Util + * @ingroup common + * + * @brief Various utility functions. + * + * @{ + */ + /** * Check whether a given pointer is aligned correctly. * Note that 'alignment' must be a power of two! @@ -105,8 +114,15 @@ template inline void ARRAYCLEAR(T (&array) [N], const T &v # define SCUMMVM_CURRENT_FUNCTION "" #endif +/** @} */ + namespace Common { +/** + * @addtogroup common_util + * @{ + */ + /** * Print a hexdump of the data passed in. The number of bytes per line is * customizable. @@ -252,6 +268,8 @@ bool isGraph(int c); */ Common::String getHumanReadableBytes(uint64 bytes, Common::String &unitsOut); +/** @} */ + } // End of namespace Common #endif diff --git a/common/winexe.h b/common/winexe.h index cab08675878..1bf203338a3 100644 --- a/common/winexe.h +++ b/common/winexe.h @@ -28,6 +28,15 @@ namespace Common { +/** + * @defgroup common_winexe Windows resources + * @ingroup common + * + * @brief API for managing Windows resources. + * + * @{ + */ + class SeekableReadStream; /** The default Windows resources. */ @@ -136,6 +145,8 @@ public: static VersionHash *parseVersionInfo(SeekableReadStream *stream); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/winexe_ne.h b/common/winexe_ne.h index 118629abe1d..85b42489c20 100644 --- a/common/winexe_ne.h +++ b/common/winexe_ne.h @@ -29,6 +29,15 @@ namespace Common { +/** + * @defgroup common_winexe_ne Windows New Executable resources + * @ingroup common_winexe + * + * @brief API for managing Windows New Executable resources. + * + * @{ + */ + template class Array; class SeekableReadStream; @@ -90,6 +99,8 @@ private: static String getResourceString(SeekableReadStream &exe, uint32 offset); }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/winexe_pe.h b/common/winexe_pe.h index 79b913043aa..67a34a3c7d9 100644 --- a/common/winexe_pe.h +++ b/common/winexe_pe.h @@ -30,6 +30,15 @@ namespace Common { +/** + * @defgroup common_winexe_ne Windows Portable Executable resources + * @ingroup common_winexe + * + * @brief API for managing Windows Portable Executable resources. + * + * @{ + */ + template class Array; class SeekableReadStream; @@ -92,6 +101,8 @@ private: TypeMap _resources; }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/xmlparser.h b/common/xmlparser.h index dbd9d0e0cb2..f555e64cead 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -36,6 +36,15 @@ namespace Common { +/** + * @defgroup common_xmlparser XML parser + * @ingroup common + * + * @brief The XML parser allows for parsing XML-like files. + * + * @{ + */ + class SeekableReadStream; #define MAX_XML_DEPTH 8 @@ -349,6 +358,8 @@ private: Stack _activeKey; /** Node stack of the parsed keys */ }; +/** @} */ + } // End of namespace Common #endif diff --git a/common/zlib.h b/common/zlib.h index a1723995111..839c23ba173 100644 --- a/common/zlib.h +++ b/common/zlib.h @@ -27,6 +27,15 @@ namespace Common { +/** + * @defgroup common_zlib zlib + * @ingroup common + * + * @brief API for zlib operations. + * + * @{ + */ + class SeekableReadStream; class WriteStream; @@ -145,6 +154,8 @@ SeekableReadStream *wrapCompressedReadStream(SeekableReadStream *toBeWrapped, ui */ WriteStream *wrapCompressedWriteStream(WriteStream *toBeWrapped); +/** @} */ + } // End of namespace Common #endif diff --git a/configure b/configure index 88bfb3363d1..46a4f729300 100755 --- a/configure +++ b/configure @@ -249,6 +249,8 @@ PANDOC="" _pandocpath="$PATH" _pandocformat="default" _pandocext="default" +# Detection features to be linked into executable or not +_detection_features_static=yes # The following variables are automatically detected, and should not # be modified otherwise. Consider them read-only. _posix=no @@ -275,6 +277,7 @@ add_feature vorbis "Vorbis file support" "_vorbis _tremor" add_feature zlib "zlib" "_zlib" add_feature lua "lua" "_lua" add_feature fribidi "FriBidi" "_fribidi" +add_feature cxx11 "c++11" "_use_cxx11" add_feature test_cxx11 "Test C++11" "_test_cxx11" # Directories for installing ScummVM. @@ -1008,6 +1011,8 @@ Game engines: $engines_help Optional Features: --enable-static build a static binary instead of using shared objects + --enable-detection-static build detection features into executable (default) + --enable-detection-dynamic build detection features into a library --enable-c++11 build as C++11 if the compiler allows that --disable-debug disable building with debugging symbols --enable-Werror treat warnings as errors @@ -1196,6 +1201,8 @@ for ac_option in $@; do --enable-dependency-tracking) ;; # End of ignored options. --enable-static) _static_build=yes ;; + --enable-detection-static) _detection_features_static=yes;; + --enable-detection-dynamic) _detection_features_static=no;; # --disable-16bit) _16bit=no ;; #ResidualVM: not supported # --enable-highres) _highres=yes ;; #ResidualVM: not supported # --disable-highres) _highres=no ;; #ResidualVM: not supported @@ -2286,6 +2293,32 @@ if test "$_use_cxx11" = "yes" ; then append_var CXXFLAGS "-std=c++11" fi echo $_use_cxx11 +define_in_config_if_yes "$_use_cxx11" 'USE_CXX11' + +# +# Additional tests for C++11 features that may not be present +# +if test "$_use_cxx11" = "yes" ; then + # Check if initializer list is available + echo_n "Checking if C++11 initializer list is available... " + cat > $TMPC << EOF +#include +#include +class FOO { +public: + FOO(std::initializer_list list) : _size(list.size()) {} + size_t _size; +}; +int main(int argc, char *argv[]) { return 0; } +EOF + cc_check + if test "$TMPR" -eq 0; then + echo yes + else + echo no + define_in_config_if_yes yes 'NO_CXX11_INITIALIZER_LIST' + fi +fi # # Determine extra build flags for debug and/or release builds @@ -4178,6 +4211,12 @@ if test "$_dynamic_modules" = yes ; then add_line_to_config_mk "PLUGIN_SUFFIX := $_plugin_suffix" fi +# +# Set up a define for detection to be used as static or not +# +define_in_config_if_yes "$_detection_features_static" "DETECTION_STATIC" +echo_n "Checking if detection features building statically... " +echo "$_detection_features_static" # # Check whether integrated MT-32 emulator support is requested @@ -6349,6 +6388,27 @@ EOF fi done +# Name which is suffixed to each detection plugin +detectId="_DETECTION" + +echo "Creating engines/detection_table.h" +cat > engines/detection_table.h << EOF +/* This file is automatically generated by configure */ +/* DO NOT EDIT MANUALLY */ +// This file is being included by "base/plugins.cpp" +EOF + +for engine in $_sorted_engines; do + if test "`get_engine_sub $engine`" = "no" ; then + j=`echo $engine | tr '[:lower:]' '[:upper:]'` + detectEngine="${j}${detectId}" + cat >> engines/detection_table.h << EOF +LINK_PLUGIN($detectEngine) +EOF + fi +done + + echo "Creating engines/plugins_table.h" cat > engines/plugins_table.h << EOF /* This file is automatically generated by configure */ diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp index eed1a1617d8..9d2d64c4ee1 100644 --- a/devtools/create_project/create_project.cpp +++ b/devtools/create_project/create_project.cpp @@ -103,6 +103,8 @@ enum ProjectType { kProjectXcode }; +std::map isEngineEnabled; + int main(int argc, char *argv[]) { #ifndef USE_WIN32_API // Initialize random number generator for UUID creation @@ -312,6 +314,7 @@ int main(int argc, char *argv[]) { break; } } + isEngineEnabled[i->name] = true; } } @@ -402,6 +405,10 @@ int main(int argc, char *argv[]) { setup.defines.push_back("USE_SDL2"); } + if (setup.useStaticDetection) { + setup.defines.push_back("DETECTION_STATIC"); + } + // List of global warnings and map of project-specific warnings // FIXME: As shown below these two structures have different behavior for // Code::Blocks and MSVC. In Code::Blocks this is used to enable *and* @@ -1059,6 +1066,9 @@ const Feature s_features[] = { // is just no current way of properly detecting this... { "text-console", "USE_TEXT_CONSOLE_FOR_DEBUGGER", false, false, "Text console debugger" }, // This feature is always applied in xcode projects // { "tts", "USE_TTS", false, true, "Text to speech support"} + {"builtin-resources", "BUILTIN_RESOURCES", false, true, "include resources (e.g. engine data, fonts) into the binary"}, + {"detection-static", "USE_DETECTION_FEATURES_STATIC", false, true, "Static linking of detection objects for engines."}, + { "cxx11", "USE_CXX11", false, true, "Compile with c++11 support"} }; const Tool s_tools[] = { @@ -1531,6 +1541,24 @@ void ProjectProvider::createProject(BuildSetup &setup) { //ResidualVM specific: createModuleList(setup.srcDir + "/math", setup.defines, setup.testDirs, in, ex); + // Create engine-detection submodules. + if (setup.useStaticDetection) { + std::vector detectionModuleDirs; + detectionModuleDirs.reserve(setup.engines.size()); + + for (EngineDescList::const_iterator i = setup.engines.begin(), end = setup.engines.end(); i != end; ++i) { + // We ignore all sub engines here because they require no special handling. + if (isSubEngine(i->name, setup.engines)) { + continue; + } + detectionModuleDirs.push_back(setup.srcDir + "/engines/" + i->name); + } + + for (std::string &str : detectionModuleDirs) { + createModuleList(str, setup.defines, setup.testDirs, in, ex, true); + } + } + // Resource files addResourceFiles(setup, in, ex); @@ -1554,7 +1582,7 @@ void ProjectProvider::createProject(BuildSetup &setup) { createOtherBuildFiles(setup); // In case we create the main ScummVM project files we will need to - // generate engines/plugins_table.h too. + // generate engines/plugins_table.h & engines/detection_table.h if (!setup.tests && !setup.devTools) { createEnginePluginsTable(setup); } @@ -1732,7 +1760,7 @@ void ProjectProvider::addFilesToProject(const std::string &dir, std::ofstream &p delete files; } -void ProjectProvider::createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList) const { +void ProjectProvider::createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList, bool forDetection) const { const std::string moduleMkFile = moduleDir + "/module.mk"; std::ifstream moduleMk(moduleMkFile.c_str()); if (!moduleMk) @@ -1744,6 +1772,7 @@ void ProjectProvider::createModuleList(const std::string &moduleDir, const Strin shouldInclude.push(true); StringList filesInVariableList; + std::string moduleRootDir; bool hadModule = false; std::string line; @@ -1777,6 +1806,10 @@ void ProjectProvider::createModuleList(const std::string &moduleDir, const Strin error("MODULE root " + moduleRoot + " does not match base dir " + moduleDir); hadModule = true; + if (forDetection) { + moduleRootDir = moduleRoot; + break; + } } else if (*i == "MODULE_OBJS") { if (tokens.size() < 3) error("Malformed MODULE_OBJS definition in " + moduleMkFile); @@ -1944,12 +1977,95 @@ void ProjectProvider::createModuleList(const std::string &moduleDir, const Strin shouldInclude.pop(); } else if (*i == "elif") { error("Unsupported operation 'elif' in " + moduleMkFile); - } else if (*i == "ifeq") { + } else if (*i == "ifeq" || *i == "ifneq") { //XXX shouldInclude.push(false); } } + if (forDetection) { + int p = moduleRootDir.find('/'); + std::string engineName = moduleRootDir.substr(p + 1); + std::string engineNameUpper; + + for (char &c : engineName) { + engineNameUpper += toupper(c); + } + for (;;) { + std::getline(moduleMk, line); + + if (moduleMk.eof()) + break; + + if (moduleMk.fail()) + error("Failed while reading from " + moduleMkFile); + + TokenList tokens = tokenize(line); + if (tokens.empty()) + continue; + + TokenList::const_iterator i = tokens.begin(); + + if (*i != "DETECT_OBJS" && *i != "ifneq") { + continue; + } + + if (*i == "ifneq") { + ++i; + if (*i != ("($(ENABLE_" + engineNameUpper + "),")) { + continue; + } + + // If the engine is already enabled, skip the additional + // dependencies for detection objects. + if (isEngineEnabled[engineName]) { + bool breakEarly = false; + while (true) { + std::getline(moduleMk, line); + if (moduleMk.eof()) { + error("Unexpected EOF found, while parsing for " + engineName + " engine's module file."); + } else if (line != "endif") { + continue; + } else { + breakEarly = true; + break; + } + } + if (breakEarly) { + break; + } + } + + while (*i != "DETECT_OBJS") { + std::getline(moduleMk, line); + if (moduleMk.eof()) { + break; + } + + tokens = tokenize(line); + + if (tokens.empty()) + continue; + i = tokens.begin(); + } + } + + + if (tokens.size() < 3) + error("Malformed DETECT_OBJS definition in " + moduleMkFile); + ++i; + + if (*i != "+=") + error("Malformed DETECT_OBJS definition in " + moduleMkFile); + + ++i; + + p = (*i).find('/'); + const std::string filename = moduleDir + "/" + (*i).substr(p + 1); + + includeList.push_back(filename); + } + } if (shouldInclude.size() != 1) error("Malformed file " + moduleMkFile); } @@ -1958,17 +2074,29 @@ void ProjectProvider::createEnginePluginsTable(const BuildSetup &setup) { // First we need to create the "engines" directory. createDirectory(setup.outputDir + "/engines"); - // Then, we can generate the actual "plugins_table.h" file. + // Then, we can generate the actual "plugins_table.h" & "detection_table.h" file. const std::string enginePluginsTableFile = setup.outputDir + "/engines/plugins_table.h"; + const std::string detectionTableFile = setup.outputDir + "/engines/detection_table.h"; + std::ofstream enginePluginsTable(enginePluginsTableFile.c_str()); + std::ofstream detectionTable(detectionTableFile.c_str()); + if (!enginePluginsTable) { error("Could not open \"" + enginePluginsTableFile + "\" for writing"); } + if (!detectionTable) { + error("Could not open \"" + detectionTableFile + "\" for writing"); + } + enginePluginsTable << "/* This file is automatically generated by create_project */\n" << "/* DO NOT EDIT MANUALLY */\n" << "// This file is being included by \"base/plugins.cpp\"\n"; + detectionTable << "/* This file is automatically generated by create_project */\n" + << "/* DO NOT EDIT MANUALLY */\n" + << "// This file is being included by \"base/plugins.cpp\"\n"; + for (EngineDescList::const_iterator i = setup.engines.begin(), end = setup.engines.end(); i != end; ++i) { // We ignore all sub engines here because they require no special // handling. @@ -1983,6 +2111,8 @@ void ProjectProvider::createEnginePluginsTable(const BuildSetup &setup) { enginePluginsTable << "#if PLUGIN_ENABLED_STATIC(" << engineName << ")\n" << "LINK_PLUGIN(" << engineName << ")\n" << "#endif\n"; + + detectionTable << "LINK_PLUGIN(" << engineName << "_DETECTION)\n"; } } } // namespace CreateProjectTool diff --git a/devtools/create_project/create_project.h b/devtools/create_project/create_project.h index a3a4fd20e89..1c4aaac7ece 100644 --- a/devtools/create_project/create_project.h +++ b/devtools/create_project/create_project.h @@ -29,7 +29,9 @@ #include #include +#include #include +#include #include @@ -238,6 +240,7 @@ struct BuildSetup { bool createInstaller; ///< Create installer after the build bool useSDL2; ///< Whether to use SDL2 or not. bool useCanonicalLibNames; ///< Whether to use canonical libraries names or default ones + bool useStaticDetection; ///< Whether to link detection features inside the executable or not. BuildSetup() { devTools = false; @@ -246,6 +249,7 @@ struct BuildSetup { createInstaller = false; useSDL2 = true; useCanonicalLibNames = false; + useStaticDetection = true; } }; @@ -565,7 +569,7 @@ protected: * @param includeList Reference to a list, where included files should be added. * @param excludeList Reference to a list, where excluded files should be added. */ - void createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList) const; + void createModuleList(const std::string &moduleDir, const StringList &defines, StringList &testDirs, StringList &includeList, StringList &excludeList, bool forDetection = false) const; /** * Creates an UUID for every enabled engine of the diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp index 0ba61630da9..83012996814 100644 --- a/devtools/create_project/xcode.cpp +++ b/devtools/create_project/xcode.cpp @@ -455,6 +455,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { DEF_SYSTBD("libiconv"); // Local libraries + if (CONTAINS_DEFINE(setup.defines, "USE_FAAD")) { + DEF_LOCALLIB_STATIC("libfaad"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FLAC")) { DEF_LOCALLIB_STATIC("libFLAC"); } @@ -476,6 +479,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { if (CONTAINS_DEFINE(setup.defines, "USE_MAD")) { DEF_LOCALLIB_STATIC("libmad"); } + if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { + DEF_LOCALLIB_STATIC("libmpeg2"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FRIBIDI")) { DEF_LOCALLIB_STATIC("libfribidi"); } @@ -494,12 +500,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { } if (CONTAINS_DEFINE(setup.defines, "USE_THEORADEC")) { DEF_LOCALLIB_STATIC("libtheoradec"); - } if (CONTAINS_DEFINE(setup.defines, "USE_GLEW")) { // ResidualVM specific DEF_LOCALLIB_STATIC("libGLEW"); } - if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { // ResidualVM specific - DEF_LOCALLIB_STATIC("libmpeg2"); } if (CONTAINS_DEFINE(setup.defines, "USE_ZLIB")) { DEF_SYSTBD("libz"); @@ -554,6 +557,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { frameworks_iOS.push_back("QuartzCore.framework"); frameworks_iOS.push_back("OpenGLES.framework"); + if (CONTAINS_DEFINE(setup.defines, "USE_FAAD")) { + frameworks_iOS.push_back("libfaad.a"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FLAC")) { frameworks_iOS.push_back("libFLAC.a"); } @@ -582,6 +588,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { if (CONTAINS_DEFINE(setup.defines, "USE_MAD")) { frameworks_iOS.push_back("libmad.a"); } + if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { + frameworks_iOS.push_back("libmpeg2.a"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FRIBIDI")) { frameworks_iOS.push_back("libfribidi.a"); } @@ -645,6 +654,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { frameworks_osx.push_back("OpenGL.framework"); // ResidualVM specific frameworks_osx.push_back("AudioUnit.framework"); + if (CONTAINS_DEFINE(setup.defines, "USE_FAAD")) { + frameworks_osx.push_back("libfaad.a"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FLAC")) { frameworks_osx.push_back("libFLAC.a"); } @@ -665,6 +677,9 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { if (CONTAINS_DEFINE(setup.defines, "USE_MAD")) { frameworks_osx.push_back("libmad.a"); } + if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { + frameworks_osx.push_back("libmpeg2.a"); + } if (CONTAINS_DEFINE(setup.defines, "USE_FRIBIDI")) { frameworks_osx.push_back("libfribidi.a"); } @@ -687,12 +702,12 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) { if (CONTAINS_DEFINE(setup.defines, "USE_GLEW")) { // ResidualVM specific frameworks_osx.push_back("libGLEW.a"); } - if (CONTAINS_DEFINE(setup.defines, "USE_MPEG2")) { // ResidualVM specific - frameworks_osx.push_back("libmpeg2.a"); - } if (CONTAINS_DEFINE(setup.defines, "USE_ZLIB")) { frameworks_osx.push_back("libz.tbd"); } + if (CONTAINS_DEFINE(setup.defines, "USE_DISCORD")) { + frameworks_osx.push_back("libdiscord-rpc.a"); + } if (setup.useSDL2) { frameworks_osx.push_back("libSDL2main.a"); @@ -939,6 +954,9 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) { ADD_SETTING(scummvm_Debug, "ALWAYS_SEARCH_USER_PATHS", "NO"); ADD_SETTING_QUOTE(scummvm_Debug, "USER_HEADER_SEARCH_PATHS", "$(SRCROOT) $(SRCROOT)/engines"); ADD_SETTING(scummvm_Debug, "CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED", "YES"); + if (CONTAINS_DEFINE(setup.defines, "USE_CXX11")) { + ADD_SETTING(scummvm_Debug, "CLANG_CXX_LANGUAGE_STANDARD", "\"c++0x\""); + } ADD_SETTING(scummvm_Debug, "CLANG_WARN_BOOL_CONVERSION", "YES"); ADD_SETTING(scummvm_Debug, "CLANG_WARN_CONSTANT_CONVERSION", "YES"); ADD_SETTING(scummvm_Debug, "CLANG_WARN_EMPTY_BODY", "YES"); @@ -1097,6 +1115,9 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) { ADD_SETTING(scummvmOSX_Debug, "COPY_PHASE_STRIP", "NO"); ADD_SETTING_QUOTE(scummvmOSX_Debug, "DEBUG_INFORMATION_FORMAT", "dwarf"); ADD_SETTING_QUOTE(scummvmOSX_Debug, "FRAMEWORK_SEARCH_PATHS", ""); + if (CONTAINS_DEFINE(setup.defines, "USE_CXX11")) { + ADD_SETTING(scummvmOSX_Debug, "CLANG_CXX_LANGUAGE_STANDARD", "\"c++0x\""); + } ADD_SETTING(scummvmOSX_Debug, "GCC_C_LANGUAGE_STANDARD", "c99"); ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_EXCEPTIONS", "NO"); ADD_SETTING(scummvmOSX_Debug, "GCC_ENABLE_CPP_RTTI", "YES"); diff --git a/devtools/credits.pl b/devtools/credits.pl index 668beea8782..563050c260f 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -6,8 +6,6 @@ # - The AUTHORS file # - The gui/credits.h header file # - The Credits.rtf file used by the Mac OS X port -# - The credits.xml file, part of the DocBook manual -# - The credits.xml, for use on the website (different format than the DocBook one) # - The credits.yaml, alternative version for use on the website # # Initial version written by Fingolfin in December 2004. @@ -40,17 +38,15 @@ my @section_count = ( 0, 0, 0 ); if ($#ARGV >= 0) { $mode = "TEXT" if ($ARGV[0] eq "--text"); # AUTHORS file - $mode = "XML-WEB" if ($ARGV[0] eq "--xml-website"); # credits.xml (for use on the website) $mode = "CPP" if ($ARGV[0] eq "--cpp"); # credits.h (for use by about.cpp) - $mode = "XML-DOC" if ($ARGV[0] eq "--xml-docbook"); # credits.xml (DocBook) $mode = "RTF" if ($ARGV[0] eq "--rtf"); # Credits.rtf (Mac OS X About box) $mode = "STRONGHELP" if ($ARGV[0] eq "--stronghelp"); # AUTHORS (RISC OS StrongHelp manual) - $mode = "YAML" if ($ARGV[0] eq "--yaml"); # YAML (Simple format) + $mode = "YAML" if ($ARGV[0] eq "--yaml"); # YAML (Simple format, used in the Website) } if ($mode eq "") { - print STDERR "Usage: $0 [--text | --xml-website | --cpp | --xml-docbook | --rtf | --stronghelp | --yaml]\n"; - print STDERR " Just pass --text / --xml-website / --cpp / --xml-docbook / --rtf / --stronghelp / --yaml as parameter, and credits.pl\n"; + print STDERR "Usage: $0 [--text | --cpp | --rtf | --stronghelp | --yaml]\n"; + print STDERR " Just pass --text / --cpp / --rtf / --stronghelp / --yaml as parameter, and credits.pl\n"; print STDERR " will print out the corresponding version of the credits to stdout.\n"; exit 1; } @@ -68,27 +64,6 @@ sub html_entities_to_ascii { my $text = shift; # For now we hardcode these mappings - # Á -> A - # á -> a - # é -> e - # í -> i - # ì -> i - # ó -> o - # ø -> o - # ú -> u - # ö -> o / oe - # ä -> a - # ë -> e - # ü -> ue - # å -> aa - # & -> & - # ą -> a - # Ł -> L - # ł -> l - # ś -> s - # Š -> S - # Ľ -> L - # ñ -> n $text =~ s/Á/A/g; $text =~ s/á/a/g; $text =~ s/é/e/g; @@ -236,9 +211,7 @@ sub html_entities_to_rtf { sub begin_credits { my $title = shift; - if ($mode eq "TEXT") { - #print html_entities_to_ascii($title)."\n"; - } elsif ($mode eq "RTF") { + if ($mode eq "RTF") { print '{\rtf1\mac\ansicpg10000' . "\n"; print '{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;}' . "\n"; print '{\colortbl;\red255\green255\blue255;\red0\green128\blue0;\red128\green128\blue128;}' . "\n"; @@ -247,26 +220,8 @@ sub begin_credits { } elsif ($mode eq "CPP") { print "// This file was generated by credits.pl. Do not edit by hand!\n"; print "static const char *credits[] = {\n"; - } elsif ($mode eq "XML-DOC") { - print "\n"; - print "\n"; - print "\n"; - print "\n"; - print " " . $title . "\n"; - print " \n"; - print " \n"; - print " \n"; - print " \n"; - print " \n"; - print " \n"; - } elsif ($mode eq "XML-WEB") { - print "\n"; - print "\n"; - print "\n"; } elsif ($mode eq "YAML") { print "# This file was generated by credits.pl. Do not edit by hand!\n"; - print "credits:\n"; } elsif ($mode eq "STRONGHELP") { print "ScummVM - AUTHORS\n"; print "# This file was generated by credits.pl. Do not edit by hand!\n"; @@ -279,13 +234,6 @@ sub end_credits { print "}\n"; } elsif ($mode eq "CPP") { print "};\n"; - } elsif ($mode eq "XML-DOC") { - print " \n"; - print " \n"; - print " \n"; - print "\n"; - } elsif ($mode eq "XML-WEB") { - print "\n"; } } @@ -336,30 +284,9 @@ sub begin_section { $title = html_entities_to_cpp($title); print '"C1""'.$title.'",' . "\n"; } - } elsif ($mode eq "XML-DOC") { - print " "; - print "" . $title . ":"; - print "\n"; - } elsif ($mode eq "XML-WEB") { - if ($section_level eq 0) { - print "\t
\n"; - print "\t\t" . $title . "\n"; - if ($anchor) { - print "\t\t" . $anchor . "\n"; - } - } elsif ($section_level eq 1) { - print "\t\t\n"; - print "\t\t\t" . $title . "\n"; - if ($anchor) { - print "\t\t\t" . $anchor . "\n"; - } - } else { - #print "\t\t\t" . $title . "\n"; - #print "\t\t\t\t" . $title . "\n"; - } } elsif ($mode eq "YAML") { - my $key = "section:\n"; - $indent = " " . (" " x $section_level); + my $key = ""; + $indent = (" " x ($section_level)); if ($section_level eq 1) { $key = "subsection:\n"; } @@ -405,16 +332,6 @@ sub end_section { # nothing } elsif ($mode eq "CPP") { print '"",' . "\n"; - } elsif ($mode eq "XML-DOC") { - print " \n\n"; - } elsif ($mode eq "XML-WEB") { - if ($section_level eq 0) { - print "\t
\n"; - } elsif ($section_level eq 1) { - print "\t\t\n"; - } else { - #print "\t\t\t\n"; - } } } @@ -422,12 +339,8 @@ sub begin_persons { my $title = shift; my $level = shift; - if ($mode eq "XML-WEB") { - print "\t\t\t\n"; - print "\t\t\t\t" . $title . "\n"; - #print "\t\t\t\t\n"; - } elsif ($mode eq "YAML") { - $group_indent = $level eq 1 ? " " : " " . (" " x $section_level); + if ($mode eq "YAML") { + $group_indent = $level eq 1 ? " " : (" " x $section_level); if ($group_started == 0) { print $group_indent . "group:\n"; $group_started = 1; @@ -443,9 +356,6 @@ sub end_persons { print "\n"; } elsif ($mode eq "RTF") { # nothing - } elsif ($mode eq "XML-WEB") { - #print "\t\t\t\t\n"; - print "\t\t\t\n"; } elsif ($mode eq "STRONGHELP") { print "\n"; } elsif ($mode eq "YAML") { @@ -504,17 +414,6 @@ sub add_person { $desc = html_entities_to_cpp($desc); print '"C2""'.$desc.'",' . "\n"; } - } elsif ($mode eq "XML-DOC") { - $name = $nick if $name eq ""; - print " " . $name . ""; - print "" . $desc . "\n"; - } elsif ($mode eq "XML-WEB") { - $name = "???" if $name eq ""; - print "\t\t\t\t\n"; - print "\t\t\t\t\t" . $name . "\n"; - print "\t\t\t\t\t" . $nick . "\n"; - print "\t\t\t\t\t" . $desc . "\n"; - print "\t\t\t\t\n"; } elsif ($mode eq "YAML") { $indent = $group_indent . " "; @@ -559,13 +458,8 @@ sub add_paragraph { my $line_end = '",'; print $line_start . $text . $line_end . "\n"; print $line_start . $line_end . "\n"; - } elsif ($mode eq "XML-DOC") { - print " " . $text . "\n"; - print " \n\n"; - } elsif ($mode eq "XML-WEB") { - print "\t\t" . $text . "\n"; } elsif ($mode eq "YAML") { - $indent = " " . (" " x $section_level); + $indent = (" " x $section_level); if ($paragraph_started eq 0) { print $indent . "paragraph:\n"; $paragraph_started = 1; diff --git a/devtools/encode-macbinary.sh b/devtools/encode-macbinary.sh index 25b2b5f1b7e..d8f18b109ca 100755 --- a/devtools/encode-macbinary.sh +++ b/devtools/encode-macbinary.sh @@ -104,6 +104,11 @@ for parm in "$@" ; do fi done # for parm in ... +if [[ $# -eq 0 ]] ; then + usage + exit 0 +fi + if [[ $1 == "macbinary" ]] ; then if ! `command -v macbinary >/dev/null 2>/dev/null` ; then echo "macbinary not found. Exiting" diff --git a/dists/ps3/ICON0.PNG b/dists/ps3/ICON0.PNG deleted file mode 100644 index 82b293328b28e5d5e29f53b50f6cb2c311387030..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28014 zcmeEsV{;`;*L7^$wr$&<*vW})I}_Ws?POwWqDdz9$q6R5llQtmJpbbDuGX&V54)>t z_wKb;jGBrpG6Det7#J9`yquH<7#O(NfAeNInE(19&o0>i25@%`SqZSld7`ub7BJ?D zvQl8*|EtCQRcZfO;9cbO+`+&QG5^=V!E*EQ{xiaQ$SX_3ZbK2kQF7fubd>#P!uOEY z^^kOSbObngfJwRm%sc>=WZt$OHe|B$%4#~HD7au?WMJ}A;#xkN7yaJ(06o3yPb2%w z{ssOFfs<{_Use7Zs`D}U*2xkCd+Z#xYvxav9Snr>Y+Lu zQ$t9YIqRIlJIg(cYtzROS{VPh-`1F ziUQNaC+*TqXnJTqC~kDbJ}3pQ_h5qDH~I6UZ`VGNZ*mQ>R0%YNIH93MxjzPn?n6xP zQ1{-Swq8!RSPr*svYY+Vi`joO>>M@DX5Q})^L+lb{3YHF^@6ncfu4WA2j)DVBrN^W zzG@ge&cnj*Onk{_(Y{&e)CccEa^pNSFap6u_i|ey*!6oJeD!FLv6%FQB(ZAd8DFrf6~Q*^M-K`Y2ij76r$vp$Nz2c4coh{LS!oY+b=f$17&B(5HUDS-7|B ze(#>;!T}CNm?$6;BDV!pNgU^6YLa1Ona@qO63m+e2(f@sKTwnhKE+eVZ1{jJV&RT)=oPTne9 zRU51eqBmqY^zjvZON{ZmD<^NXY{-RVmTxMFrNCJ21~}yT`jWlB9PB}R;+=GR`b=uE zMohJ&Wz86ebGwCUq z^=hO@kMAYr|D8418~jEZANO>AxA376fB|692GaqZ2$p?%>fC&wd2!@@OX||YVJb; zz8}`4H$MV)^z;o&=^aLJsUThcR#>ay3l2g0%i!1Y$3vu(f)4jLzS0HfO-2eW*ilKV z6Ox$I;%1CZO~EHGa)nTou@3%VwK(lA@s|WIYn|}xT<|>@;3~+iu!z-D?95% z`qAcmZ6Ss_yJ2)*1VH!*58$~0i72X$qj7&*3m5)Gy-B<`+Aj(j1g&tGK#LkW4Z+@d zD-*D$U4Qqw&wfJ=U4w3mAw*wjX(C%)SL~D>?E0yBd|epP&|9^9t~M0;wG+;oCV;Fj zk=y--)nFvNu)P%d%C0@lbGBd%-`qI{PJCIY{Z4{=-)~)f0s-4)#MNEsSiu1&FhTd6 zvfaTZ$lgN4f-GUYz%)wd{88c{k!AA?b^629NANwr3FU>Wd4_dxm$!cilM|Ihqyd$m z2DFqR?$9jX-XguueDWy^Y18Xr&M!>ZkSx#S`xrmPww**K6T)!wxHC zFwDnZ&(aO*P}-2NZ?_m&p|4l85_Gx(I$YYUawQsV=6UCHi{BE~&dckzyZ)(<23Un# z1fL+ele>OM&U4V@!f8G+;pqcuxxVUg^tdlN5m8&;`|98PfnWZO_b# zXp@=Rj3rAp99$X|e-mrCH&_16`DPf>b32XH+On)JoR|dX#kqDYQhPYD7fs$?92)OC z?Vkl#S!mtNrUpGx(GIzy8%D6cDc{LoRK?(eeJ_+JFG?sHd?XM!EO!Wr*;`@bI71^? zHzltBYK{8R54#VSJm4HrHaPGB6 zkodga`O`b_5bg7?UfN(0)I7}7$)3q9(;Q->P+8vOmFrZPu#TB>Q6(dTy7T1ns6!wv zW^4{q$WD*lLbstJ&hy>RwZ0JC!F~PJ1_RmL3QKw7Jg#AYO~YLdG8edlw2hI3$CzBl z#8PTkoUryQVM9*uoKOtZ##_Ys2^> z*KSlLuYQ%#ygPX72~IT@S;Ibi!YaoNvAP16z3`;A=MBoXnEgLO>9=@@3#MP)_c;5( zM^4xDzB13ETZi%EJLwS8v<3dfv^Ahy$3P*@#r<_%>kqyr*e`Pua3rhUrXj?Ac&>5! zJHC?OgTio1y8e+Q+vBfxpiIgvmvgT#_Vwp)^nV5TJ2h;Fk_4h8ve zF2UO#m8l{z9WchMbiC@CGn_|g-%}YCZ7`Fxq8lvZuhf&f-S1mPOFhiB8g;=ZJQjP& zZHZPqm$cu0;AQG&U}g~ry=M&44ubt-otz6tue{e(a1!+$+wRxEfG5N~(7lOoGL@_Q zTz)F7w`e}1$Ppl-%r!uB+AL_?Z_28*(cTwwaK zl?7we?T!uTE2ipQo^q3wXM4|@XrlS1rGeINYyJ+IT}hP&A?n4h6z;#afV{H+B`O85 zpHcsyG7vV~kCz8y?mOmNTAIdYS&Zgoudk{&xf5w$-uk+Z%`&FP7ZCPq5qa1>JZwrU zRhjqyF$@W;_tlR9VX?ftz=doPZz7k2ea{oJZU^@KIOX-nd0^%1-d!5VsT#}jLlDHU z4)4Um+~~?adtng5FrWa70JvZ3l@hVyQm$8>B3=cagoCe)UAGy|A~TaB_rzDh4>um} z=G(Q4L$jejh7!Kv$FBAFNpGj4F_C{wr;XnkaxK8@x~5KUhnQ50j=%YX3KoDng8{H} z!?Ly)!9UdqiiuffyRAIaPUkU#Z{X+BV6BwQvp}doNYUZv65gap6K{o$&Y7whZeFIg0&X*I7+c-RS!PF7?!yQ@th@YWT#$DIBP zVjB+Kyk>~Kw)#7-i0Ki zDsxDXA5Ko-GRvyRt&X$!4J0!Q8Ig0Wuh52rd{kV1r7nJ{V6~bpV625f@m>9A*79ir zox)1`J8|~NWVVP6L}4=gx12dPLAhBE#NAFuL`Ls9u-IgyZu&W4 zv!qMELb(eSxB3!i8TDbtB$ei=nx#uB#Gz%B$PHCo2=tFJ<7RF6mrHYW;7;oK_TACy zftjSL(qK}$pL9Ncto8;awy7A1SFuNP6_u}^hO{!VJi2`X7`r{reLrS--(GI2p4qs( z`XZOTpSadNf>0~e&=(G1k_4ugTt6!pefXwcvV z9y8(I2h+M|ei|Rn)0Te?djjb5cpD}F?2SQ4F|fnbBA3hr2@>RVOLP`+5NzOdWlQ2< z;`r7Qiv*HN^bHu)l2FrV0>q*1u^vBN8pO*v5m>C|az%pfaaoUxcDv#V@)Uz$e%J+c z%=^GEy1VmUSEV4opy1o9EbVBdjleYRAI)e$R02***~&5SwFJUaP^7RuHpDE+qSeH4 z#kI^PColwge@{&@&oWmPS+anysu+@$`7E>cWfxd8Rd7GBQBAVd%9D*sH5QTi#x_6l z#f3{6`ZpdP&%U2t3S8v`-40vm5-)1T^p($%vp{sOxPtHlna&ev@}vi++OcWUpj=`R ziDY2JRq%A$yeezjo!O{YIQqvx5lKd=aLxm+*!>wUEUbW;?~JAT^T%n@l(a#9M*reE ztz2f0757#MJ_{pbRqqXxY$OK_$yTI%$$S|&G=P{y{;~)R+`um*!9{u~cmbuw6lrJ# z>`)$*G7N|_Qz{w7pYxm5<)LX$~ z_0~UGi#rZWjjZqHy9VM>Kbm;&q6R+&j9uTy>vi>W&&>oeO(Z+j%qxFfdmm=YxFbpb ztMWxIg|6TXPU?_2!(hbC(CgvLKF~YJ68@xm&Nmc!y?5AYPX*2TCD)7Z6P#MY0nV$Z z$kgF+GhNkrS@gqN*w3}Smj8Nwe92k)x)n=q#XdV7yE1B?bh}vObi^?Nvs?laZjfKx z@_p0DGQ?PwwDQe!!Kao#nH5Tg^QHX5Z(|b^0?}F5JL2j1Zb`2dByc22 zU_umTb@6G=)yY-(4+RjMu)0lv+wBl;!P?|ghcInBnYW{Xv}bqc(A(e!CV5__^l478 z_pk)5v9RsabW#mCXv?zCv`sOc6wiAheF zDFels;k7o6K-LCbM;dS%6M*r6Z`{B^ssbg z`tck(e1@Sy=z>$B8CI;UWrr@M4DpxB!&BmKX&urmZkEq9fLs{Bz4NPjKa2dcy_wJ3 zHPM>-jX~)7mt(!b($5KtbO2oZ$PWff5J~xpV#S~F+6wG>QA*PtH|{(zN0a?q*wD!; zAK7^~2h(US_hO_?)_jNxbU;9|MmSF_ot6|QF1yp5MQ(7+-tal$5N@dG0&|YC`&e5e z%xn=C+I0_nm%af);8d6$fZ9{7Gqp_X(gKF!<)!_P?8n$i`+T9#}Fq$1*~B z?*ZUX!KS0|z#lczsV~Nu>%Ux_=LYECPSc9f&`PW_A<#u0&>MuLk!}bt?|m&ESVRlL zdL)a|&Y(hFLe|S6HHItB^0n|SS-KwS=n#gh!-U^KPEyl3qQkpv7JJ}VU`lB;Bb;E( z*ch6^c@R?4OXX4rVrM?k7zV4%oD7`wWzbTw3s+3 z!AD)D2ynfdYPZzWgfPkO_HLfR^>oA_7O6LMZ*C4#wBIY_(oi0^rDVhvhS<< zPhQ{$SiYZK0|;N#Kfchqeq$)+lVA#mux@@c;&i$$*uKPHx!=CKJ^aS_4j{ulU2y3O zYWZohND6MLEyo$&29p(9jD8|ax)g@Offk+?BBqzx9bO;}F8bLI?!@QL*`E=zB$LZ} zrO_5EpD)0&r+?6^npM-ad~5G!TUgAWEIP{BI+WpxcmvfBHa_QcNKB-nJ2ApJ%vrzo z+wIZTX#3fL^jUJG$5(3TD?-tN>>?tfxc)EA~93?WL#`TLP+OT-=%v%E_3bT<;N`{ zS)gn8`En?!_@=(^KozI1n%R3;cWV}gI``SeblAn(A@UD~n5L6eHS0|O1JXl@9kVG_*B5flxlAwK*rMiYy>9t&?4BtnqpBEwy7R^Tgq6JA15irnkCBCYcaBe~Kt3 zN|?Hq^98%JMon(EA3A(w45lMKf?G{Pz)q}f&DRAFggLIR3H`Uju3`adOS2WKpYh|T zedfJVaNh9dN`+gMqn><~_UMMDjwpIHo*5{W9wJcZO_zJBQ zA^|6I9Z61|Wjsa_A36fhyj4cQ%^~?fKSMt?^u_OVz-{PX#!mXL-sEaT9c{XTQb=)I zu{xjuF(bIeRCzoCH=Z$mS8_JPvN?k@ z)R*E_V?Uskkt;?dpz<-}C32k>V~6|2iJTW=F#r4FYJ1LJSv1Q_up+p6{2w*AwgMSG z1wlrrBII{}WI40ed7_>DYSi?x1e-7YT3A!Ul0@;a0JO|WzbRK(@m;Vq(JDe!@^4MV zj}3<=^njeXDz~f~R+`VRA1{Ynw7x~OvL7q!1kR;;ph88yZE&K)S%YVl_3OL2giJ30>pEEPeK^|bhPG5 z^5S!Gh>+|s8|djB9SB9TfbeoS1HBKRktOD4vb9C|v+wn?8(el!6YkxLuNxPF-%-n8B0$QVMvCmh@gkQ0g`Aw(4oGFQ0D^ zYNx{J@+0f;0=b{4!RwR?Q+vN@pAa!GN6%EatPjwLx9?CVQpm?9^ZG9#+e#r;xI(ce zox*)2@|@Ao^_XJd>t$+;AqBCMr9%I@$m2p&UF>?)S(l*TE;f1E>OQ_Qj)qgZQ@)la}n>Ki)H)F)dBkM_qf1b0L8&jb8|2oa5kya=Xp}rx7$--_@9xD z=E!2oCIF5heIyzbI50Y1ZePJ?jM-7lNVmVkO^Zkj71mVq zeqsps&6kul@Sr6H$h4^L8E9JF4EWsh;uOLt^Thq77ukZ-m@CmQDP#y*ABK@lvbqpv z66!QLCY-Xnb8kzwK0h%I!fg6=@3(0YwWx=DB9;$LTP*~WVkMEQcSt&v@#>8>4Du}n zr5Jt$ExvQm&Uq;*gusgv7Cru$30>+Yix@I3D0a+Xy8OMhe{Zk4YBPqPqE3sIs`9V< zINnM7F@r{QMhDdBzYvdCtWNvS>w0fYg{!J?qzyKT{yE=|#^jzCx z(AR_$0kL=3%VCUYD40Di{!AOKgbD*Z2cINZ-H)+KIwak}npRB&b@f6sgb<`G?iy|Z zBBGl6@u*xb0gjZzE(AG@pE5AM*HHsQdmje|r^fCix9ggxY?88`&P-dWMN=z28�j z$x0T|=rZ85xaR?@8a<((l*E<>p-swdOhKp81E@j)A$x(}YcJQ%Jz+8(k`2Ld($GX6 z0_+`DBNkDZ13tk5RlVE>7gVtlEWIwYxF*eM%z0}qmg=~hy7ANhJ?Ke4X8lvj#jPz# z8$IC?q&<$AiK$KRBGNtE1@SK}kB4;{bbrtB8jpuSe-2I z2~Rj$7ft_Rku+2_C1G3?FdL;9{V#(jB0f*H^t#(6Ck1R;iK(a4GOMnb>G=b#cwq9L zU=`Gqra3$#OnL#_gHJKxD_iu|_3_;&XFU-=z;wv)!XhAh)Jfcm8rBYM%<6cCN z;gSJwv(I zn)ro8k@&@LHT^q?2f@cFpu0}Gn2Pzh1m`)6{w-ZK)-AR=c~buPLwL2n$+#fi!{Zu= zN2nt%GYp8fr<@Mbf45K)Qb}c;3gT(tjNR{cCt8zn%E61I}lA9{H^?)`~`GDCuO9 znShn_gA)_04PxuXBkT|&*)2cb2Djs4MU19x65o1QGH-ct7YCiUM)o#&T;O-}LIMrwnPAEn{U2YBaab91?E-TepI_Lg zcYm_?0?!2AW(jSQkW%J2vgjB8PYZy~xrA^fSlxX+L>GMX=PwbS4Nz(>mzi`=2(TQ> zAuIFuXqtU0EfAGi3ykvv;%#@DwVK<2iIsj4{BS}CB#^F~{vv(53O`46e5yO+6TEze zt0WZ-jCddX#&Y%nA)nGwT$T^CglW=o>U@+j~%djfa!#s@L`?{(|f_>*M zw>?iTnT$G9Rfy6$VO(u7Wnr}_S$kX3m1hnMlN$`?PikiufZR_#D^X9kudG2asKHmR ziShXXVs#pc-4`R5`N8vN{{an&+;y34)lIl%M3--D7LPptfwPBK?}bNuSH2N;76*AC zVv_jR{VJ6}_x=uh?K^vCf9|gB=Crpd&Gy7V;sPYG+){_5xV4U3RZ8A`68bj+EEFlZrh@eScSyc2Up3N(g9@v07jD=-AN0< ztcB=n7ar#IoW+V_2%9BJnN4u&$pE^H*BJlfaJ$LTMWFH6(nvJM9?o$vrm0;{&A(7c%NcVEu|^Xz;L0r z2)fZcyyw23YHqif0da9V^3qpaK=eA8;7 zFYConyNOs)=y4fPb=JZA9jn`qoLx7B*8!ONlVfv`@kD+h^?_LOGHR*Cka3zjHW{xx z#uFi(-6(PnDeJ}NqX{|%`TWiTy__kGv<-~?U zAsVB_keN(P&0czu#CdDCVJG=2x!XgK&!SVJ0dIlt;3>%tw1*R2*)_&+^fghd$T^zT!##LiY?#hhO$ZDYz-uKh~ zV){|a#oFFlg!lr{KGSiHpgY7>PQO#~k@_M!JQ>)q3^-bFD0CLjh|r3T|?D-cv&V6=ef2rr_tGAAvp631w4@pG*7yzV2K zm2^l+{uxdxyT*sKk!&=N=rkxtjj>2L@>KWPi`yMc4aL8jWt-TB<_UA!m_moco{J8Nu(>HTQ6xZvWPF2 zFu82hW*doijnuIf&~yHc{zH&}(th8fM{z}oy#FhgdTnl%?p)9a zHLVjKJ*%b{mcVJJY!cQ605WtsoR{?mZzLdzie=RuXhk4X zq(AxJzNN}Y7tV<};OBXjI7m605I5xYT?jN&e9Y-=YUO>sd8H!JlGEHAr*Y8JOsNr! zAw*Ndag@@{*C&w;^AHpRf0%2h?O_LR>zXPIkdqU3B=IJwmK3y1?~XA=8WA^(s@g)N&#Ag> z#&`!85dcKhE2t4j?U+=Gt}JB*@N+2jCI+Qlv|_#N6q?eu(pG*`TBsBV$`{uSf1)+$ zC@p<2wXtBJX2@5w`1#`pO<)!|QqbC0+4bGI1lvTH2fq?~ea7ROs7Sg|_5ImWMq81p zDAfo|#O#Lmw>s&E;4ngwiN|8m6m`Z^H{x-Pj1F7E;Z6J(*P5wq5h@Xtpz9?Gi_pYl zR5wEx5EyycVG?y5(U0KcW@!-jhra~;Wwl!aeUBt1?x`dv8iokHA6nk!3M47pSiR_? za_1o^{sz%+UksjKH<>d4JQgD?8-*fF+Yh(=IiCJYqY1kj$PyzR0=8??SPSs05iiFG zNuGsxhVHi3TrDl51CS4YQ_DicDKytNjk)x*>-nm5)A+mzOwB)lSyW+C+GbAj+^v&t zcDb<&B$e3UJjyVgH8$HypYDX~q1eYC{6XwYo1pCWz>+*{KnAgGg2Km2ITrQ8R4lZr zhHc8GQw~s`uQKTyPkMu2sSUlBv~x#MQ#(mz*uyk%${dVy_tBVjY1g%*+IMAA$5IeG9}>$y%ni9K;qToRt%L& zF4Bla5nx(o7l+4eR;Pxugo;EOV3Ea97@EMZ8PMprME@n!b{l^Z2|B0@DeTkVAGu%H z*VzjYd@KoEU#ep7ESl1SA7u}#7FTOIZ3R9c-)zTK7M@HzGWtHwI-4t-)Y8Yur%GW=_uhe;^h|wz~$8hN(%Jsm`^WR zmJC|5Jwj6L!ZrAC4^z>y&iZaEi|fg1C>1ZIEYuprQ%W3=RMG(0t>qVkf8eYGz08#lc=jNFX2B% z#7elULRhIpwHM^>PFl2`HM=GW9jA!2%iNnirSUxteW3PE9@;f=#6nc+63QK2YWo(39?|(Rb3jarI%WcWRUD!C$Gh8DuM)5)B zh*u@DHDI>?tl^dQ^>T@C63I`l1WMHQT-Cb2ZWQ%|YJZaP2u3V<4l+oCVz3%o5bQco z{7DFp4&GsX_Y1)X{^K$HNo)U{dY8|!v}%t}e&`%Y1!y*UCf|l)N5_D8`$dgdH88+yN_oOeXqC$ zZAspFDe%Rzki=JpPf>pIOpKp$ja#yZa)t7gVvL1wlWW5kb1NX~zw>3GjBl~MQoGKl z=qdJJ$`N~bXPh=b?Q1}V{~))C(`H7x?8^z0u#dwm!IY%kL#3JhBSdFB(gWv;zMAnL z`k1#aJDF;QpHNAev#S2ezg9SRxiFYcCit_xP|8-(>Mgk#RtcYc2;Ec~I2Njmwk6(! z<;dBts6KPxA!qe#S_v9615SBt6X0jAp^%1`S3$=f^lhBcd+H?g)!>?wTyZAF6!1qt zH;Q%p3vMz?7hxz3wvMP?j}17&9W2xR*LB-Xg|zP7>bkoWcM(AmocG5WGfS82YucuGYIu-Yk}g4 zER~2FEALs`#aJzED6bnQU6IU@Q``AQD>wtT(9z`?IBC5y9w^**LhQXnBpf?7xyW_* zyId0A#pdv*i_0~ge-ZIvsO+TAehtc~XGxQyJE+sisn>l)~IrR_#e3f9#ru{BXo~p>MeSXIo zuoTK#O3WI#sBroZUaz0ad^DEF)Rs%13|_#dR5?Dqea{^_vNh;29*5jr!d~OlV)ChB zJLnwSqgEC3Pf`pPgU9JMHzvGGjkp2gW>~9DR%rn^(!5kOhc0%>-B{Y6FuG|%8@qH9 ziI8>Rm5sAAZ``|I%C8BHi5j$YQ;$?w^Sc;&xG4_h4$5``V1@GGyQ*CpB0L`j6!2X- zRyrn$-5bNqt-7kIYRqw=KZ4nw(F2BL9L?efZ#G=|Fn}OWK#tg)TP{L948Gu-X@X2U zMLq&EfkrG(BzhXqs3Er@==GZDx2|qzjoG@OZnESrTkL^JvYv;ZMr#&mps~t2j!ec;Z3#QRUgt z1BOvO(!s!8fvH+P%_mnHWCd#xk!oTYM0J}}`cV33H(*CrG8MgouRR2$%%li?vYiyx zI-aA2WuG1m`(}A@VCxjrDl7f+{PS`gR}KrgKDwv4^TO@hzu}Zl@14@2sB|p4j5iu6 zAod4~MY|P04+W;{>ixV(f%}5K^y3g^I`wD`3mlg@7`vRqqFyY;a185)nzovak|`Rt zc??>`v=bNg#|tp7cq&?xm)v|O!^v-Ehf7xcz+a+Nysj_Wn5#5&(Tua&Gy7$W zPbHwc!T`-Na6~%tD*!zoN)9J^Jl0CF@}kCdRvFi2x)HhjFD-m)5D|bXnoXZ_{_qb9 zjT41!6cY*>q8asg1OnB=s=zKH*)kuXxfUsu5*Z^m#wtJwkON5^8tXPpXwqCv1M#5` zNT%ICJ{a|Vo#_E0+>U**qiAQjz5Rh3k1-F8)i&<|Sfiqn+T5HDZ;oB#JZih>@wCi) zi6FA6oOFQ|@oAmR7bx0xT;!uv!!e!xf$~K>qa0-(xK+x#*NLR#4Q`7%TM=ATNu|#O z0%Zxdn+KE{@HtgUBL4Odkp1H6AoE+B)(zn(3t0*!X`;gg8Sqp3>Y&B_$yvC-kF25l z^_Rl$mxUp{W#Ar%(zCh8it;A@kS7co38f3r++FDFC*(QNJk5%}V<9mfXty6(;FOb4r_P15Ihd@Y(nT+OQe2S_Tf?~yK1*;`qlg|i?V6$S z&T|RD8u=&=dZnCdiU|6_Kg9Vk&qC>?CHV7_JP5e@*CPXK?qzItsCDeNEsGhLWY7Nj zqX^odvwIe?IK#L0DbQq6p&{rv&{b=F|5 z-au`c^PBNFja8)q(pBIuioe4*ULda%XiClP!#B5qOn-O+K%JPV;@ZC;3INaNW6oN0 zJm&o|X6;9fh?W7uR~64fR$;^fv@0x48#lkqrC{M@mE_+wCc64+LMLE`<0;Ze)KL=& ztsWYva=qLyY}q~r#TIO>w%Cp;=yzBz*8W`OaaMH_2dp!d8#}i62m4EWSTPoM&a-o6 zHv8OSgxL(Ok=o_;zM!;^EButSnOL;u65cTqgJpJPV~)_+Z66M49l)<-Brl=wQoDpJPqwKVh@2#KGr=~-`n0Lcyn_m5pinWV3L_o^pRK!NjZ1$zMDSg z{1#vM+Ww>v9G-uYBimLTVQ$2Kp6Fyz6I;Gr3Sgf*`S||($0i)~=sdV+<3r5wrmPVR5i>ohL+fzoh9$Lu}rOJu^Kv z5@VrYI$zZq0lFRL1IwP{Z&Ka;@1M*NqoEn9JID*QH`~0w*>(a?NzCM%cd+P=ymqD{tz2QgVmmq{?4MJ3VPDPu@Lw&`#V1w+71z)RFNK-(1H;s<7O}Y znvgoyrRqj==U<~3J3}(QuAOwMlqG#OnQ}Qyu!dMmGmaqOEgiHCD{y6&%CR?2c z2QPuo4n7m&h7g8!LZQ_IKg{<26S9yv-q(u_*!JAf4QfrsH6d;Oh1p!rTT=CBthmK; ztWiFg`{34^+9cM-b_Mg{jsxY=NG+?&NCTycD93Y!F!6w$91fzhV4(0yLCUc`cDfb~ zKYiXJok#32yL`jcrF}*;plp0{!0khTl(2LAea!5sL*<0HsW;!_Mnp*?yb(^xX*}jG z(;uvqd5)@V2`7xKT#Mng0aF7FqJ3$XLwk2qO~7Q5Im`>cVExZ@B(<_2l`ZTN^&*UN zEH)`8_YtP%{^{8dDFAm$&bIHWA5SB_MU?$Onp&~?gg4fRo`WHvd~gQ1(Eb|7`eVbL zs|ni=PsCkyA~^Vc+%Q-?qW!)9Z!M96dAe9;<`N5TzdR)2$$}z1Y3^+=YWMw@<;f_VNf%q#E!Q@%>XoI`14Rb!?aIN^%u>AHvSTR~ahTWG~a`JaNJibXnb z9IGwMaXEo}bWIV3z10i2QqH;MAgxW%A*~HZdaDRywI*ry zDh{?)M9O$FIt;v7_A#yF;(Xes9N}VHJp5#M~h;=feQkO$3_L5jP1+G&D&{fOadOs zC7!XX^eTG##AZHPavHiV4(Qenddk}bkOq@b_!xGBw+VP-wtx64we9cz!s>qj*IMLxS8LB{k%zkju;k%f}eMzUplwjTA!2|;Njt!ZNMWoyu*9h_r13ED=)pa z9(>-qVe_6=-M6EhSeGBz)-9556EB_E@WR1c;Hl6ylOsB7B`Wl_-c$8@PP$~rjE7XZTnb+Ni%z*&YORm{rB#?me_!`eD`itu2k)*aKe(>WxP$oCXHBftTQCnb9o?x4Q z88#*1tzljP1xQhs>0t2v+aUR|V!%Q~>bmpS;59Aj3)c8qQYW?RiJT%Kv2I{L5!{|V z2jD~lyil5;g#8$|;SvnE7febMR2I^uW&ucfs8yb4u+NmF=KrUuO64gnjed_>?@_r^ z6uspbxTzYPKfms#_rN%qhvoWy@)r0wE^6<--$EwYSU${4Itn=Za>q5XSFZc<{00Dx zq^_{UUc08M=&q|JO9|Mz^2k;Z&(B*C2{`Ix@D>PgjsjIh z6bqj#J z|7g8PK{?hZu1kK-P7F*cQUmWypG5f;(yfJ<`EZtNyRIb?@Y47TIxCF&!Zp|=W1~Yl zH>+Q9gYRw5%E^MKjCJF<%eetO;A!_ii~JvDjExJ*H%?10#~nJ!cX`6ZB$vji^>m@)&Mf>O zqu@ra%=NnsV-ZHxK=5+flPZr0o|^i^Gq(<0Q=2G+!Y}tF zT{85aWASppFXs=ASX~Jx6R_DxV&fkH@mZX8B54ARo`iOec7^FN-4*T7CnsKkg9B-( zUv;=CJVd1?X70(A3DHC<3{vnEe{Y4j@GUqK8b#-jpK*M;Fxn6-r;xLfb+a#7TUA#g=uhrS(&SsU+?%q33TBVq}VF*M!7Ndxr*DQzSKs+aTTL| z_$ea~#!{_0EsZF`g_B9fu&5jxKQlMz9K;pFl;C;@$^5K+&|&6reg}1E@P&DbCVMhn zb{?(kO&Yp;>Q8gRPUiFhgwJc?doB;9!qQ-BI25Qc;dT`7u)xDq$du_+LHd8%V<@l7 z`z89K^?c!$gGcjLcQ+BC_3f|xD(APFE@?H)m-tK@Y-pgB*4!)qJ-QpccW}_a=7>1M zGlhh|q(H_U2kwdTs6Hk-a^(t-eB4p@RDmvtVrr<+FCRXjjwwy}M@jpg1()w%H{0>R z@0t4#F`ma9CXlzN65_f^_z?vs6^MlW3psz!Whq1qkb$kf+3}&XRB9Q&;Q*pFU{gGj zT~Pt{*8iskz)iu+cbn2J!w@~zP}q}0o3W18(9ds;UMHJDN%5giKgsbm_;fQ#C@@IF z&cjhq=yW6*Uq_0QiDgl+N&o$k$~KcCpU9+VIY<7cm@dPh1*A0W`eb4qv&6X+E!2%k9P7VEk?OjuMB}}x;H<@5!+qP{RlT2)%WMbR4t%)(Q?VL<( z>x3t^d2|23{RQ`}pZcNKUVHVf+EvB7U<6;O=;DlwKZNeHA8fyK`z5z+-)pgEdXZ{G z>Rm`;dzuQx=U?zZ46?I?Rr^c16uXe%l{YjM7WbQ^9@;exC61xhg?Y|+VJ+zZx*)}W z78h)7JY`&6n+hB=4lPO!UDxI@j7#`XysR2ngFSsy>oceoffdDwOyJESZ>2ApDj`yW zo+=inOBf4%HUIHh+bd^Sjd6(H$WvXzeLj*&P*Jex=5o6j@7|L)H(DvOx?EwVJe@~o zevyhunxJLvIPfxuyu@F)_hSa*s&UILI>@+(EjvTZ>C-!vB|hWL-;8XZW$7qUd7@qMz%J!`PdbsY zP=#6Kdq|FYk2arwsPCEPSi@Gh6HSAo`zbIL^oGZ9aQP){B9gdd$_{b`D^%TUy z|GB(1$jYkO$jIsc_H|y6DwPS-Ex+Me=p9Wxpne|Q_JARNpUgM+sIyvrm z`s>sp4M?Ow zF3nhH(R-}6>{TKjV2=2HJTm7Sd4Tkcoahy1D$9aurZf=(%1U(?DoYH^44X0MoFkM9 z;VV74_1z#OM4GF*L<5yn3QyU&sNdNF6RNer?BB^}N+r@B6OY-X(&{Q>N@KX#GXDE6 z{>^+4a;M!U@dyomG!4s@hO4E5y=f`^SQLhXl&S%e%O>MMrf?$5apwoY*3k92a| z!x6_dD%E9`ri7Z<3$9FoEl>pvpbbo)Ea0%sW7z)5K>Vtg8}BFTY~yrZR$t>4A>Cdu@>0Ekt9(D%UEK!&8q=gv2ykpwe#3Z#D2uQ+`{1 zbU3}|*YGL&QS5HezZ>(7&{M4AdNsA4feUSy=H}O%87{q?R-%#Zk0N;<^k5YldR#dS z^5$mZa>P^UqguKuD<)b^iT-~ORWmLPIiWMTx45Pkv=RfPW*5Q$`HZeG&P5}~!^;j; zZC0+rquQ5CR=$mqE2Bwk%j(-rQ|q8XIc8Yh2A9z}RS8&?`!4?UT>Mol#+4ijH(2wE z)B=oJzpf(k;Dud+h(H?r2;3w;AlvU%B!59!Q>HdFo5_!t%L&AT0 z@P#-B$vkWKis5`7a_|nA^H|pdjbr<>2>zkEB-X@DWGA>gYRA>Xol*?^HrtZW5;rWF zXy$);PF#*-XV|ja~a(^?+7PERh?~ip*Zpz=f3SoR?3#6{EKboT z)cObgRhjVF98se7p-@3Z_71DK7%~YnUvhEJmlTHq^zhu;XHwg0qBYXp(EXtR>;kt9|{L-|>mSr25aO zqmv^8o;2e(&zxTEQ!9I;qFnP>Rw=AJK4~+2?_exFCQ-UDl=!&tjN#t^OAl6oEtnar zpImJ_Ccfx{vNlMi$)2-+Vo_9L8p$w#g0_&e4};y2bu|b~$WD~e|9%x?+TbgB+{aRu zQjrt+t>vRwGbE$$foh2DH%pA-%@kqQ^Pr%vM^=-Nu~u9m3sA10&nHI+e8_ zlzHNmz+nAnLR~43#qrubNljaFSvi50SCahB+XDDbsl?qAdM*_@$+J!O7&q#J0s`cKIebm-Pp;4ZEYeoG}WVV#-4#WM7Q6mq=r-xyCY!D=AXZzLtiy zD;?G9sKjW{d2$Sduu~}qPchxQ)UL0LM>AL9i8I#iIuZ? zQ+Wfz{02bg_s&-1j$~MNQ9V0y z^ypL}^#q)h`+bYaXN}`qc*Kr&Q6OAqnM{KNf2vP~c<5muB(2GdwfRSS{#s;(Ug$mr z7k~6G^{Oj{rC6PEtsIqM^(++p9m5U`AGtz(wzlE@9 zB^x;(jLvAxoO|iFV1O0r=?u+&AQ+H6TD|G*4r8toZ+oY0`z~WuMi!?EeLfd``?nb- z1xxM4iYyGv@NLD{GOFj%#2Ge>+0n?qA<>z&9QA{gU?;-v@Ij5s04r@Q1V(pKS76RVOs?Y6gvpBhiB5bZd9S zi9M+2M;?q^p~Y@G)?03Xn(uhi1bkDUw~@@w+wS>?x{u0N)vwfTJ6XmbgVT24RBkaL zW|Ul}J6=74{JliU?$$q)wEc0_Nr89^xGQ?HA~WKJQGrehT{5^I=7hqdsKV>;5|h9&cN#_H>LReol1J?HZL&W8a#FV z`Cv-YaoDl1NYZ@7o*J6&5HQE3$8%F^_Napd@?z zpXBKqI33CY_^UciB3b(nnBq#}3CS12in_>r`td+_6n~9xq&eHs7$^Kmo`?*RAUm=Z+v$gNI0@__L@#ZKnMv1QNJd5u0V^fnw16S&(MtLt4 z(QC*6l}u^~&x%2gr#NDjgQpL%Q`PS!od4|uz`0r<^z_i2p9w^8qF!Yx-%3x_2zS z=L5wXdE$DM*=|3zwKrGk0cX|+-RgUTaJUwkS=i5>2qgy8#6P`;4OR-O_S(BLvxfA6 z`XU_&#{F;y)_PlfXcwUCBYa!;Uf<{TJeGmRAP#R{GmY(ZvM{DC~r%b2hO}8 zzM43%s%(?GmKeIE)C$G*1%L~f_@tBaU^gjdUf_a8O7@=|NmcsLaHRP=4Fa+Zk`Vjg z{saP7&$luRRK*bdD|r=a7CNyA95X~z^P%To8$H%At@^F=Fs9BJ*~+i4(kUoP(4WxZ zq~EB2CW_IHYOzQ#rlS|GOb?^hjJV!yNSuBjc)m@d5iMydWIZbRE&}hvAyB95eSNt1 z7;}65XeirUW$AWzs{;rB-zEW@^H#_(d5&|47uqFqhl~mj*P?k}wIJmb--=f7WRZGl zcCI>SpE5ya&)KDbP=2F9JE!fJAyQ4@!kmTtB{6puCImOr_RPx4PaNA!W+r9_i&@A? z(l^BOKJzq<&dIL|`yAO`_qB@3c%xaj{!^FResU;i(TWm{x?TJa z00i@RmJa^4(~&+IqsjK9&7O!XWCBudMgNrIInE|k@{VnA7(iYtL=XBIlnh7jRJ^d& zBIkV@8JJ~KJ}tkfl#^vq&>R{i=M(+!aBEloDNKcF+*0M{F_Qz9ANg27$rC_MpUT~L zK6)^cpE3}xHh%EvSN-K$6}#79f9@b$M)GNJdY=#W=a#r=}=)vqLHtSkz^uZ ztk5uVGu%E=b5{hjb>t`96tZ$vY#4a70-I8D$^e;PBVzMmHf>SPv;#`$BaCKHYT6>Q zJ1=DWA`%rG%Dmgb{I9NjWfx=@0^&mN7#2G$^-U=1qMr4_V#c$TZYOcF&u`wMYVU4^p+h#PBVRB9vb^9PXR19H~3>vXdxWlL;Nc4p_Jc zY71ncxXhr8uJh0sXrh z&nWpl94LEFB833smjkAhOD{0PC+*mp9hB(dC;Ab=$u!4vtWG>dA%wyojHb`*9Nk4Q zj}z)j_Fd%ZsN0Xss-!vPDU@~`v1lRTa@v1_C3gbc z_ykG05VY)MnJTJrx!D-L>NM1-i7ZBZJTdNUC+(E9jWQq1=?u+q^yUHY>DLpVm!g^V zD^G8C!Fx>{DM|9l|EigC(I=V-H*a$_kr;mjB==3sA^g6Kq)Jt7YT4|*nqpqIXJW0B z<9;F=#W%+F>kr&~zH*cbx0Y`(Xl*D&k`{EWnqkW{pog&2B^q6hP3vzCHcu9j>bbR! zg)MZ9=JY^r<0#p(xqT{FB>%XZ_?F*uD=K#&8lvFy3uWiW-~k`oZ_;9^VJupL0h;2N zquP|!dZp_ZT?%TY>8ld^Gitinq*YWGs#(UsI%v!i3CBZq$a?aN)|4>zUD4Q+#(zQy zn1OV>YAN1{y`za#Q0XSI_oi&B;~O@>f@E7a;ud31UgbRQh>Tn4s)0haaGnd45&hj_ zan;etSCW%pp1h*7hxsz3S;O2v8_QCNGG_iURY7W7s`}s4Sxp%|?W~%nJzo*;(#umA z+iIqxa{J*7Hy%ry!gN;I+V&H(vh8oGVIJ7#A=FpnWTBXr+X!s1NMrm#>Kl^773q$& z|0Rl~aa3lJj~f)l-mwQrmZSeT#)28ArzVwbK-kqtZ za=e$+(v@sunlqP)d2DNj+wtK7M9fm)5EeOy&VFsBSRL~(2Abk_t@}VSC#8%f+2T_+ z!>L)nQ^*oCx$`jAQ}y#ks;zbUNMnH!5*_YReGwf(A#n6fM0lcFr}K4noL(DW%l=gr z5eRGQ#4IN%b0Qo+n}7i6bRq+69`ykqPyMnluk_JTgiBh`@#@B}FKbScKph0E0GPnX z5UmC6kLO?Lh!?BE%EcNQDR-r_%`y8RiNn)uu>D?Q^Ec4L0quU+J?8W=yrj7)W_$Ee z@sBmR7}OO#5MNqXvZ*3a&lGVhv3}#W&#pKoQAJplhB@oeh2C(&9c!IEivvwTf*=)_ zP{CvPK8a!c>B(?Yd>O%{2oVS0ls#H;I`TrLe{n^_p8HQb8_E^-nX7WU5K!iUh6^yBL_(At^lB zB0s%h{|YV+KAV%ReNx*h@v7PoN3U{p6_2-mQXmUBeMhw)7(?~1iG?ge)gf1utHP5| z8K0(3)HhjNZ>6r6ZU|LlwC^+ekG@W4=LUxojiRRqU3#njZ3_m;VZV4#lAqNxrhzcO zp3h#Fxrzi057Qk*1;4Q7(O$yn3cN@rVimFwczTjs%a|ndgDXbvyTd(n|C z2-E=a^fU*tQtobv&S+s|7yDAUl&0IVtU)FT54sG&dU7nFqCXI5HEbxHb9?r*;1ql7o|Z77S@oYm`&)W87owN8Dh`Ed z_0R!j$0nR($}4&SCf#)1T6~5?6=k}kfcF~%8Ics#Dax^I$dwOQ1*Mn-4*IjV5JPT` zA_^OMBzah6(BBrgJVDNpTA!!Or=s|-^p__JvDQSwbC~)RC;Md#9)Lj?QE3k^7|~D_ z94{%aApHtjMlDvHoY2eum5kWqUo}j9Aw)fqmur24?fCtm>G1j8zIP=K~T}foHxp+FkNycoL0}@Hhs5TdA89)l-(L(`MLuV zBZ&nb^#8~I6o;e+bsBEWhQn=X`+UMp3>bfbyYxLx-G^6HTi)HJLCIyyxprnT<9*E4 z*CHU;S94HjWs=!(3Sn*A2tt+F0~o+EWCJnQf!~ptJqa#)E?+mEb_u`!`YL*-+9s>l zUCI~(RDRhiaAc5WbzDGg;)GNiwAq_jgzWF{4i0}D(W>rr%$9#)@LYT;%{DyVk+vSE z(gQ3}P925e`6gIVY3h(@8%Rv~!N~v>E!?Wt>VB)!3P!0yJ#6z|d}}jjJV2>GS(Ywq zcj(tSeYlZzydl`xWRfYWNpJ{iniCM=Vh}clQvY6RpIEc_y>?DNU)HQXj@~tAG?SV- z4;%2v#QGF;S=Nsp1R%Zr+w|bBBrHP^?))4a3Mcv6WI*?uAo>xs-zAux{rVtz`G&5= z;=o!%xye(>OT*{8A2l01L+bdy7slXn2lYmryr@hI7R?Ga2XbERx_jSCqGyfV7=$Ax z@xvXNzR+rOU9Ho9I_fcT2|U7!lRP2ydAOGh@2SpnRhYV$?H0ca#zm|!mQiF9p?+ll z&~J{|NE=nyKYxJY!A4KVko{&l7z9w(Ci1yM>Al&RzTQFJ5;e#l$b`y?Onl#p91JZG z6l)(w0R9f0O$1v3Kx=7THJ03rx3`R?*e428u5IqMhkxS@{xy3&JP8m#O(S1hU)DM- z0%JZt*it{>WZSVG-HEV7os+uL;XWDL!qQJF@qmQrBdQlHV6;h+udPL5WTutYi9%|r`3+1 zwI6WdlX9-RHSthjUH{BJL?+p86qBGSW=eJB(k#vw%wDmaGvZ+{naI3V_zeYU!iJ6^ z_0UDtNBsVrj(ei~1gP!AV&_-RnI;PvhCMya7~noDuA^D~p7@L)N4521jqlQ_*!L`6 z?~wW?lk40LdTG{Dv@AK8&Xkt4172oP((>GMhK!6%nnyZ`Mhco-uHGPzKDKV??GEjl z5%ibTlj3O$nL>eP_A=KfLTlvn-{D$Cege4OzWs%qMy#PEaKAqo(eLf$ zdv3o@r_1-`1*gagAQWZy8(PnyCM5QC8vG)A8aa9+L1u<0C1zX$YsD zKf2#IM-(Tp85$kBqK(9nT_nr<5oF-N3A}0ceqiBepS<)r;u`BvY@ID$s`!Z)qkxY<#}US>6AKEb_~lWXPVp!a2W!3Y3r0CI@=O`kv`SzVX5sFxlk zQj;#YxF<8qhNY^CU3X;v=u3WTr5nWzS)iK18FPqf+f*HA#au`7B_}K9@m4;+b%TTK z(7s^e6kljd)nbT)?-?8EuvH|>yxKLi>P8MAF}sC3o80)1=fNCagM)7SpXKFJC0~|2 zVHl`nQ7AejY}2T9jY1=)-^MH9!969mmm+3&EM$)C?D2k_R&|Iyk(9{M4dp z-IgqQR?}&yfWnkrk%}E}GsS}6^tT54*XqJrMY^Y|XaCX<1Mae$JWqY&RFd+rNm~K%St(WN2bGr))2WyQYwKdze&D=i*?>H?gizP31 z9urEBcWb-SMu%^6^CX>?;P;cJdP}w#*+8x}4$Bs-4Ev@GJDraY-LR6l)iNqPpLhQ7 z)#g!EH&?1@oQ6=?O*L3@Qud5EQd`^(c;48GnAPi?(Q70C@H8i{%K3AP%l|bu$NMo4 z|GKR-Y_1O-hT&1rDuP^|a?EOhy&>)a56m#^@=KxyRUgte*v8tj%nV-9q7*-ecYXhC z6}oJS<9X>3A-`js!TOTF#a@3z-jGd>uNB!P&ZURc*jc)wQ&dTmRbQZV0< z09YOwucvjIjdOkXLDyjDkd@^;8Fn5TLA4k*Imw+J>jd{UHbqbxAzsiF3r3hxMau`W z+>pth_iYk6)NJ^_-2!pNEw6c!W{HAW-Qw#iD)nfJ92=UR#@_xXA8RX!XN;>pxYbo9 z&_Q=c$x;}84MDN8XIUW$zHTBC`)ZPaQ`?kSS*HMvF9J{Bu%H*7M|K_ew`{HGVBej~ z9{4WEr`=%;RzaWtJiv2?4~r&#kD7-4^flJ3+`N*`d`0szBn>!D!kX$hF{3DE1U!iT zSMI#`OKZ}Y(ox8tbMaTeY|PD3n4^rC8aGQsF}j#UOTetBQfv17Y?#u?6R}~VfUnv8 z*;%Q65^+!U5T@ymC15!XSrj`RW^jL!MV!V+0{-AC@3^=(qcTB5)33G=^p2BJVnURz zW31uxWjLS|1>FtdoQ|w`PZt7)lb$0l3YJO*) zt{V}+u1AShwdaVQF>|Tu*Wf7aIN)N=$9;O(HA$>5w)6X?kNS{&&CemY?@1IvJTXi& zOT8h*A%N+=km*V<0FjB??;y7&bDx&UZ6CqCieT){c&JwW<&pSq zuH904&S1zWHTXG%xe1e)OFv=PpSK4voqEob%|4)R?gm#7O`-FKGTltvv)9y}&lsR5 z_xj)x?@rPwBHN92%gcI5QIpPu^0*kOgn;gbi8a&hOwisov3}kW6_LZOmJgQQKP_wLesI8Ut1&)O1&NV zOt?9#fd8%13-$K+)w0r|E5Fh=?jH&#ecw*jxe{PyvpO+jf93{LIGyFI__(@91C*2> zN^9?XmUROMBf+ct__-NX0BY%Chx$ghw z5>%!P4jn(u{y^!sj$I;Nu{dB~ano}OFkwM#Bl_5tg!|aYIKJLTF}|m{LPqrnO?RID z&Zyy!i`9J~XvxWR`U@2glzS`N35?LxGu(+n)PJdr>xufK^I-CaRX?JTTO>*Qu;av~G`G0lg>}$=&M&!+jZa z&0ek|eIP)DJY!1r}sOw^A+N2>o^6L#2`X^s8i_f-+TMT$bRFei>Fd_Z!7CHdq7)PD&QBdL(N7c zSl93ZD*gMN+kkPkLutkktLaz&P>$(iV_F$f=HkUN_kWK9$U;|PKheAFj_)`5bans+ z-GSJ#K+C;G_F8tBitm8zpzt`pJORGxEi!0RjtF&=yafFu~vfy@>{Br|YKO z&N5V5C%koJIY1b!Dm`RqLjH-Sx(jZ!#qYWO#OhE-^U!=+oe>`JGyHeyhu}fSkPiHa z?6I~d?oLR03&<<_WUd|0hv>zX0ZzjR6SIw)FKaY7zmqVpu8nkj!0u4M>tFhCur8al ztZE54w?4M|qhH*%t3N!#_g#j88rym`^#q56dp!wtq2K3)7f}c@f=1#>b273_TNd>U zin0gdA#z_tyMK~<2-n?OY#AQ(t7dT?)1=k2+9=jS7b8V3AL&w0e&?KH62Mg##Mi$Hn)1Mfn(7tQ_?zJlAA zPdI+CFYuw$p$L}4?{cJi#VN^RdS~8*Z3+K1ko9!Vwa1$6hgk>P&Cl?0bFrLNmL#Er zFB>1Z?@`|TKq}ru{lAaF#5+F0>ObB-Zrfzf8NaBw{GRoQT1xV5A&IqBZMt#B zNM~|9kX{Xl94_HGGq%vc?0o%4rgQkbf;dz{%oiSObu3IIA%!qL?e%O;lGgiee~>12XDDZxQ@rf$GD0E-BT}Yoie9KTK?eBc@YZU`tiJCC67O0b^XBRG zpPFIk2KY?>I_hk3(=r;3Wj_>Ps~+`t-7X_9~zncM3Mf+2r%&SGIJ;6E?A?l%aEmom+d*qx#aL_51L}M4!j5^popCgaTSE zK6O^6p+Vh!r(zny*fr1HJCvThQ0Ko_0GAzRIru~K{LIVY3N4yv8asX&-ya|hkunb? zy@^TTeSO=e(_oIfjhk=N`y4FYx=lmRC&EcS{lji&`Td0vHn3XOJDK)KMYeEzPKBYi za5czl4Zc{I9lmoU=6U-X6>ukk9`;3e_TWA0laGYa}2w|JEL diff --git a/dists/ps3/readme-ps3.md b/dists/ps3/readme-ps3.md deleted file mode 100644 index 9304fcde8c4..00000000000 --- a/dists/ps3/readme-ps3.md +++ /dev/null @@ -1,55 +0,0 @@ -Prerequisites -============= -- A homebrew enabled PlayStation 3 console. As of now that mostly means having a custom firmware installed. Obtaining and installing such a software is out of the scope of this document. Sorry, but you're on your own for that one. -- At least one ResidualVM supported game. The list of compatible games can be seen here: https://www.residualvm.org/compatibility/ -- An USB drive. - -Installing -========== -From a computer, download the installable package of the PS3 port from ResidualVM's main site. It should be a .pkg file. Copy it to an USB drive. -After having plugged the USB drive to you PS3, the installation package should appear in the XMB under the "Games > Install Package" menu. Installing it copies ResidualVM and its dependencies to your PS3's hard drive. It also adds the "Games > PlayStation 3 > ResidualVM" XMB entry which is to be used to launch ResidualVM. - -Configuring and playing games -============================= -The user manual describes how to add games to ResidualVM and launch them : https://wiki.residualvm.org/index.php/Running_ResidualVM - -PlayStation 3 Specifics -======================= -Games can be launched either from an USB drive or from the internal hard drive. The internal hard drive has better performance though. -Savegames are wrote in the /hdd0/game/RESI12000/saves folder. - -Joypad button mapping -===================== -- Left stick => Mouse -- R1 + Left stick => Slow Mouse -- Cross => Left mouse button -- Circle => Right mouse button -- DPad => Cursor Keys (useful for character motion) -- R1 + DPad => Diagonal Cursor Keys -- L1 => Game menu (F5) -- R1 => Shift (used to enable Mass Add in menu) -- Square => Period '.' (used to skip dialog lines) -- R1 + Square => Space ' ' -- Triangle => Escape (used to skip cutscenes) -- R1 + Triangle => Return -- Start => ResidualVM's global in-game menu -- Select => Toggle virtual keyboard -- R1 + Select => AGI predictive input dialog - -Disclaimer -========== -Unauthorized distribution of an installable package with non freeware games included is a violation of the copyright law and is as such forbidden. - -Building from source -==================== -This port of ResidualVM to the PS3 is based on SDL2. It uses the open source SDK PSL1GHT. - -The dependencies needed to build it are : - -- The toolchain from https://github.com/ps3dev/ps3toolchain -- SDL from https://bitbucket.org/bgK/sdl_psl1ght -- ResidualVM from https://github.com/residualvm/residualvm - -Once all the dependencies are correctly setup, an installable package can be obtained from source by issuing the following command : - -./configure --host=ps3 && make ps3pkg diff --git a/dists/ps3/sfo.xml b/dists/ps3/sfo.xml deleted file mode 100644 index b2bd942db63..00000000000 --- a/dists/ps3/sfo.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - 0 - - - 1 - - - HG - - - 0 - - - 01.8000 - - - 63 - - - 279 - - - ResidualVM - - - RESI12000 - - - 01.00 - - diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index 58b162805a0..1d579ab7c76 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -40,7 +40,7 @@ */ class FileMapArchive : public Common::Archive { public: - FileMapArchive(const AdvancedMetaEngine::FileMap &fileMap) : _fileMap(fileMap) {} + FileMapArchive(const AdvancedMetaEngineStatic::FileMap &fileMap) : _fileMap(fileMap) {} bool hasFile(const Common::String &name) const override { return _fileMap.contains(name); @@ -48,7 +48,7 @@ public: int listMembers(Common::ArchiveMemberList &list) const override { int files = 0; - for (AdvancedMetaEngine::FileMap::const_iterator it = _fileMap.begin(); it != _fileMap.end(); ++it) { + for (AdvancedMetaEngineStatic::FileMap::const_iterator it = _fileMap.begin(); it != _fileMap.end(); ++it) { list.push_back(Common::ArchiveMemberPtr(new Common::FSNode(it->_value))); ++files; } @@ -57,7 +57,7 @@ public: } const Common::ArchiveMemberPtr getMember(const Common::String &name) const override { - AdvancedMetaEngine::FileMap::const_iterator it = _fileMap.find(name); + AdvancedMetaEngineStatic::FileMap::const_iterator it = _fileMap.find(name); if (it == _fileMap.end()) { return Common::ArchiveMemberPtr(); } @@ -71,7 +71,7 @@ public: } private: - const AdvancedMetaEngine::FileMap &_fileMap; + const AdvancedMetaEngineStatic::FileMap &_fileMap; }; static Common::String sanitizeName(const char *name) { @@ -120,7 +120,7 @@ static Common::String generatePreferredTarget(const ADGameDescription *desc) { return res; } -DetectedGame AdvancedMetaEngine::toDetectedGame(const ADDetectedGame &adGame) const { +DetectedGame AdvancedMetaEngineStatic::toDetectedGame(const ADDetectedGame &adGame) const { const ADGameDescription *desc = adGame.desc; const char *title; @@ -186,7 +186,7 @@ bool cleanupPirated(ADDetectedGames &matched) { } -DetectedGames AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const { +DetectedGames AdvancedMetaEngineStatic::detectGames(const Common::FSList &fslist) const { FileMap allFiles; if (fslist.empty()) @@ -232,7 +232,7 @@ DetectedGames AdvancedMetaEngine::detectGames(const Common::FSList &fslist) cons return detectedGames; } -const ExtraGuiOptions AdvancedMetaEngine::getExtraGuiOptions(const Common::String &target) const { +const ExtraGuiOptions AdvancedMetaEngineStatic::getExtraGuiOptions(const Common::String &target) const { if (!_extraGuiOptions) return ExtraGuiOptions(); @@ -260,7 +260,7 @@ const ExtraGuiOptions AdvancedMetaEngine::getExtraGuiOptions(const Common::Strin return options; } -Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) const { +Common::Error AdvancedMetaEngineStatic::createInstance(OSystem *syst, Engine **engine) const { assert(engine); Common::Language language = Common::UNK_LANG; @@ -348,13 +348,26 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) debug(2, "Running %s", gameDescriptor.description.c_str()); initSubSystems(agdDesc.desc); - if (!createInstance(syst, engine, agdDesc.desc)) - return Common::kNoGameDataFoundError; - else - return Common::kNoError; + + PluginList pl = EngineMan.getPlugins(PLUGIN_TYPE_ENGINE); + Plugin *plugin = nullptr; + + // By this point of time, we should have only one plugin in memory. + if (pl.size() == 1) { + plugin = pl[0]; + } + + if (plugin) { + // Call child class's createInstanceMethod. + if (plugin->get().createInstance(syst, engine, agdDesc.desc)) { + return Common::Error(Common::kNoError); + } + } + + return Common::Error(Common::kNoGameDataFoundError); } -void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::String &parentName) const { +void AdvancedMetaEngineStatic::composeFileHashMap(FileMap &allFiles, const Common::FSList &fslist, int depth, const Common::String &parentName) const { if (depth <= 0) return; @@ -394,7 +407,7 @@ void AdvancedMetaEngine::composeFileHashMap(FileMap &allFiles, const Common::FSL } } -bool AdvancedMetaEngine::getFileProperties(const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const { +bool AdvancedMetaEngineStatic::getFileProperties(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. @@ -426,7 +439,39 @@ bool AdvancedMetaEngine::getFileProperties(const FileMap &allFiles, const ADGame return true; } -ADDetectedGames AdvancedMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const { +bool AdvancedMetaEngine::getFilePropertiesExtern(uint md5Bytes, 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. + + if (game.flags & ADGF_MACRESFORK) { + FileMapArchive fileMapArchive(allFiles); + + Common::MacResManager macResMan; + + if (!macResMan.open(fname, fileMapArchive)) + return false; + + fileProps.md5 = macResMan.computeResForkMD5AsString(md5Bytes); + fileProps.size = macResMan.getResForkDataSize(); + + if (fileProps.size != 0) + return true; + } + + if (!allFiles.contains(fname)) + return false; + + Common::File testFile; + + if (!testFile.open(allFiles[fname])) + return false; + + fileProps.size = (int32)testFile.size(); + fileProps.md5 = Common::computeStreamMD5AsString(testFile, md5Bytes); + return true; +} + +ADDetectedGames AdvancedMetaEngineStatic::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const { FilePropertiesMap filesProps; ADDetectedGames matched; @@ -551,7 +596,7 @@ ADDetectedGames AdvancedMetaEngine::detectGame(const Common::FSNode &parent, con return matched; } -ADDetectedGame AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const { +ADDetectedGame AdvancedMetaEngineStatic::detectGameFilebased(const FileMap &allFiles, const ADFileBasedFallback *fileBasedFallback) const { const ADFileBasedFallback *ptr; const char* const* filenames; @@ -599,11 +644,11 @@ ADDetectedGame AdvancedMetaEngine::detectGameFilebased(const FileMap &allFiles, return result; } -PlainGameList AdvancedMetaEngine::getSupportedGames() const { +PlainGameList AdvancedMetaEngineStatic::getSupportedGames() const { return PlainGameList(_gameIds); } -PlainGameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const { +PlainGameDescriptor AdvancedMetaEngineStatic::findGame(const char *gameId) const { // First search the list of supported gameids for a match. const PlainGameDescriptor *g = findPlainGameDescriptor(gameId, _gameIds); if (g) @@ -613,7 +658,7 @@ PlainGameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const { return PlainGameDescriptor::empty(); } -AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions) +AdvancedMetaEngineStatic::AdvancedMetaEngineStatic(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions) : _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameIds(gameIds), _extraGuiOptions(extraGuiOptions) { @@ -625,10 +670,22 @@ AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, con _matchFullPaths = false; } -void AdvancedMetaEngine::initSubSystems(const ADGameDescription *gameDesc) const { +void AdvancedMetaEngineStatic::initSubSystems(const ADGameDescription *gameDesc) const { #ifdef ENABLE_EVENTRECORDER if (gameDesc) { g_eventRec.processGameDescription(gameDesc); } #endif } + +Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) const { + PluginList pl = PluginMan.getPlugins(PLUGIN_TYPE_ENGINE); + if (pl.size() == 1) { + Plugin *metaEnginePlugin = PluginMan.getMetaEngineFromEngine(pl[0]); + if (metaEnginePlugin) { + return metaEnginePlugin->get().createInstance(syst, engine); + } + } + + return Common::Error(); +} diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index 941f59d4976..a48b5cdb8af 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -166,9 +166,9 @@ struct ADExtraGuiOptionsMap { #define AD_EXTRA_GUI_OPTIONS_TERMINATOR { 0, { 0, 0, 0, 0 } } /** - * A MetaEngine implementation based around the advanced detector code. + * A MetaEngineStatic implementation based around the advanced detector code. */ -class AdvancedMetaEngine : public MetaEngine { +class AdvancedMetaEngineStatic : public MetaEngineStatic { protected: /** * Pointer to an array of objects which are either ADGameDescription @@ -246,7 +246,7 @@ protected: bool _matchFullPaths; public: - AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions = 0); + AdvancedMetaEngineStatic(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions = 0); /** * Returns list of targets supported by the engine. @@ -258,14 +258,16 @@ public: DetectedGames detectGames(const Common::FSList &fslist) const override; - virtual Common::Error createInstance(OSystem *syst, Engine **engine) const override; + /** + * A generic createInstance. + * For instantiating engine objects, this method is called first, + * and then the subclass implemented createInstance is called from within. + */ + Common::Error createInstance(OSystem *syst, Engine **engine) const; virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const override; protected: - // To be implemented by subclasses - virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const = 0; - typedef Common::HashMap FileMap; /** @@ -322,4 +324,57 @@ protected: friend class FileMapArchive; // for FileMap }; +/** + * A MetaEngine implementation of AdvancedMetaEngine. + */ +class AdvancedMetaEngine : public MetaEngine { +public: + /** + * Base createInstance for AMEC. + * The AME provides a default createInstance which is called first, so we should invoke that + * first. + * By the point of time we call this, we assume that we only have one + * plugin engine loaded in memory. + */ + virtual Common::Error createInstance(OSystem *syst, Engine **engine) const override; + + /** + * To be implemented by subclasses, which is called after we call the base + * createInstance function above. + */ + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const = 0; + + /** + * Provide the engineID here, must match the one from MetaEngine. + * + * @see MetaEngineConnect::getName(). + */ + virtual const char *getName() const override = 0; + +public: + typedef Common::HashMap FileMap; + + /** + * An (optional) generic fallback detect function which is invoked + * if the regular MD5 based detection failed to detect anything. + * NOTE: This is only meant to be used if fallback detection is heavily dependant on engine resources. + * + * To use this, implement the intended fallbackDetectExtern inside the relevant MetaEngineConnect class. + * Then, override the method "fallbackDetect" inside your MetaEngine class. + * Finally, provide a "hook" to fetch the relevant MetaEngineConnect class and then use the orignal detection + * method. + * + * An example for the way this is used can be found in the Wintermute Engine. + */ + virtual ADDetectedGame fallbackDetectExtern(uint md5Bytes, const FileMap &allFiles, const Common::FSList &fslist) const { + return ADDetectedGame(); + } + + /** + * Get the properties (size and MD5) of this file. + * Based on MetaEngine::getFileProperties. + */ + bool getFilePropertiesExtern(uint md5Bytes, const FileMap &allFiles, const ADGameDescription &game, const Common::String fname, FileProperties &fileProps) const; +}; + #endif diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp index 9314c0b9eeb..a6c6497e7e8 100644 --- a/engines/dialogs.cpp +++ b/engines/dialogs.cpp @@ -285,7 +285,7 @@ ConfigDialog::ConfigDialog() : int tabId = tab->addTab(_("Game"), "GlobalConfig_Engine"); if (g_engine->hasFeature(Engine::kSupportsChangingOptionsDuringRuntime)) { - _engineOptions = metaEngine.buildEngineOptionsWidget(tab, "GlobalConfig_Engine.Container", gameDomain); + _engineOptions = metaEngine.buildEngineOptionsWidgetDynamic(tab, "GlobalConfig_Engine.Container", gameDomain); } if (_engineOptions) { diff --git a/engines/engine.cpp b/engines/engine.cpp index 2c11f83fe7e..c4183d1dac1 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -875,10 +875,20 @@ EnginePlugin *Engine::getMetaEnginePlugin() const { */ -MetaEngine &Engine::getMetaEngine() { +MetaEngineStatic &Engine::getMetaEngineStatic() { const Plugin *plugin = EngineMan.findPlugin(ConfMan.get("engineid")); assert(plugin); - return plugin->get(); + return plugin->get(); +} + +MetaEngine &Engine::getMetaEngine() { + const Plugin *metaEnginePlugin = EngineMan.findPlugin(ConfMan.get("engineid")); + assert(metaEnginePlugin); + + const Plugin *enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + assert(enginePlugin); + + return enginePlugin->get(); } PauseToken::PauseToken() : _engine(nullptr) {} diff --git a/engines/engine.h b/engines/engine.h index dd0a81d5b7c..707000aeaae 100644 --- a/engines/engine.h +++ b/engines/engine.h @@ -31,6 +31,7 @@ #include "common/singleton.h" class OSystem; +class MetaEngineStatic; class MetaEngine; namespace Audio { @@ -386,6 +387,7 @@ public: */ static bool shouldQuit(); + static MetaEngineStatic &getMetaEngineStatic(); static MetaEngine &getMetaEngine(); /** diff --git a/engines/metaengine.cpp b/engines/metaengine.cpp index 2a8bc127bfe..2b1222ae580 100644 --- a/engines/metaengine.cpp +++ b/engines/metaengine.cpp @@ -260,9 +260,9 @@ WARN_UNUSED_RESULT bool MetaEngine::readSavegameHeader(Common::InSaveFile *in, E } -/////////////////////////////////////// -// MetaEngine default implementations -/////////////////////////////////////// +////////////////////////////////////////////// +// MetaEngineConnect default implementations +////////////////////////////////////////////// SaveStateList MetaEngine::listSaves(const char *target) const { if (!hasFeature(kSavesUseExtendedFormat)) @@ -334,7 +334,7 @@ SaveStateList MetaEngine::listSaves(const char *target, bool saveMode) const { return saveList; } -void MetaEngine::registerDefaultSettings(const Common::String &) const { +void MetaEngineStatic::registerDefaultSettings(const Common::String &) const { // Note that as we don't pass the target to getExtraGuiOptions // we get all the options, even those not relevant for the current // game. This is necessary because some engines unconditionally @@ -345,7 +345,16 @@ void MetaEngine::registerDefaultSettings(const Common::String &) const { } } -GUI::OptionsContainerWidget *MetaEngine::buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const { +GUI::OptionsContainerWidget *MetaEngineStatic::buildEngineOptionsWidgetStatic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const { + const ExtraGuiOptions engineOptions = getExtraGuiOptions(target); + if (engineOptions.empty()) { + return nullptr; + } + + return new GUI::ExtraGuiOptionsWidget(boss, name, target, engineOptions); +} + +GUI::OptionsContainerWidget *MetaEngine::buildEngineOptionsWidgetDynamic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const { const ExtraGuiOptions engineOptions = getExtraGuiOptions(target); if (engineOptions.empty()) { return nullptr; diff --git a/engines/metaengine.h b/engines/metaengine.h index 7e9657b7cfd..816a19f1da0 100644 --- a/engines/metaengine.h +++ b/engines/metaengine.h @@ -94,21 +94,17 @@ struct ExtendedSavegameHeader { }; /** - * A meta engine is essentially a factory for Engine instances with the + * A meta engine static is essentially a factory for Engine instances with the * added ability of listing and detecting supported games. - * Every engine "plugin" provides a hook to get an instance of a MetaEngine - * subclass for that "engine plugin". E.g. SCUMM povides ScummMetaEngine. + * Every engine "plugin" provides a hook to get an instance of a MetaEngineStatic + * subclass for that "engine plugin". E.g. SCUMM povides ScummMetaEngineStatic. * This is then in turn used by the frontend code to detect games, - * and instantiate actual Engine objects. + * and other useful functionality. To instantiate actual Engine objects, + * See the class MetaEngine below. */ -class MetaEngine : public PluginObject { -private: - /** - * Converts the current screen contents to a thumbnail, and saves it - */ - static void saveScreenThumbnail(Common::OutSaveFile *saveFile); +class MetaEngineStatic : public PluginObject { public: - virtual ~MetaEngine() {} + virtual ~MetaEngineStatic() {} /** Get the engine ID */ virtual const char *getEngineId() const = 0; @@ -129,6 +125,78 @@ public: */ virtual DetectedGames detectGames(const Common::FSList &fslist) const = 0; + /** + * Return a list of extra GUI options for the specified target. + * If no target is specified, all of the available custom GUI options are + * Returned for the plugin (used to set default values). + * + * Currently, this only supports options with checkboxes. + * + * The default implementation returns an empty list. + * + * @param target name of a config manager target + * @return a list of extra GUI options for an engine plugin and + * target + */ + virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const { + return ExtraGuiOptions(); + } + + /** + * Register the default values for the settings the engine uses into the + * configuration manager. + * + * @param target name of a config manager target + */ + virtual void registerDefaultSettings(const Common::String &target) const; + + /** + * Return a GUI widget container for configuring the specified target options. + * + * The returned widget is shown in the Engine tab in the edit game dialog. + * Engines can build custom options dialogs, but by default a simple widget + * allowing to configure the extra GUI options is used. + * + * Engines that don't want to have an Engine tab in the edit game dialog + * can return nullptr. + * + * @param boss the widget / dialog the returned widget is a child of + * @param name the name the returned widget must use + * @param target name of a config manager target + */ + virtual GUI::OptionsContainerWidget *buildEngineOptionsWidgetStatic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const; +}; + +/** + * A MetaEngine is another factory for Engine instances, and is very + * similiar to meta engines. This class, however, composes of bridged functionalities + * that can be used to connect an actual Engine with a MetaEngine. + * Every engine "plugin" provides a hook to get an instance of MetaEngine subclass + * for that "engine plugin.". E.g. SCUMM provides a ScummMetaEngine. + * This is then in turn used for things like instantiating engine objects, listing savefiles, + * querying save metadata, etc. + * Since engine plugins can be used a external runtime libraries, these can live and build inside + * the engine, while a MetaEngine will always build into the executable to be able to detect code. + */ +class MetaEngine : public PluginObject { +private: + /** + * Converts the current screen contents to a thumbnail, and saves it + */ + static void saveScreenThumbnail(Common::OutSaveFile *saveFile); +public: + virtual ~MetaEngine() {} + + /** + * Name of the engine plugin. + * Classes inheriting a MetaEngineConnect must provide a engineID here, + * which can then be used to match an Engine with MetaEngine. + * E.g. ScummMetaEngine inherits MetaEngine & provides a engineID of "Scumm". + * ScummMetaEngineConnect inherits MetaEngineConnect & provides the name "Scumm". + * This way, we can easily match a Engine with a MetaEngine. + */ + virtual const char *getName() const = 0; + /** * Tries to instantiate an engine instance based on the settings of * the currently active ConfMan target. That is, the MetaEngine should @@ -181,60 +249,6 @@ public: return 0; } - /** - * Return a list of extra GUI options for the specified target. - * If no target is specified, all of the available custom GUI options are - * Returned for the plugin (used to set default values). - * - * Currently, this only supports options with checkboxes. - * - * The default implementation returns an empty list. - * - * @param target name of a config manager target - * @return a list of extra GUI options for an engine plugin and - * target - */ - virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const { - return ExtraGuiOptions(); - } - - /** - * Register the default values for the settings the engine uses into the - * configuration manager. - * - * @param target name of a config manager target - */ - virtual void registerDefaultSettings(const Common::String &target) const; - - /** - * Return a GUI widget container for configuring the specified target options. - * - * The returned widget is shown in the Engine tab in the edit game dialog. - * Engines can build custom options dialogs, but by default a simple widget - * allowing to configure the extra GUI options is used. - * - * Engines that don't want to have an Engine tab in the edit game dialog - * can return nullptr. - * - * @param boss the widget / dialog the returned widget is a child of - * @param name the name the returned widget must use - * @param target name of a config manager target - */ - virtual GUI::OptionsContainerWidget *buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const; - - /** - * Return a list of achievement descriptions for the specified target. - * - * The default implementation returns an empty list. - * - * @param target name of a config manager target - * @return a list of achievement descriptions for an engine plugin - * and target - */ - virtual const Common::AchievementsInfo getAchievementsInfo(const Common::String &target) const { - return Common::AchievementsInfo(); - } - /** * Return the maximum save slot that the engine supports. * @@ -299,6 +313,28 @@ public: */ virtual Common::Array initKeymaps(const char *target) const; + virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const { + return ExtraGuiOptions(); + } + + /** + * Return a GUI widget container for configuring the specified target options. + * + * Engines can build custom options dialogs from here, but by default a simple widget + * allowing to configure the extra GUI options is used. + * + * A engine that builds the "Engines" tab in "Edit Game" uses a MetaEngine. + * A engine that specifies a custom dialog, when a game is running, uses a MetaEngineConnect. + * + * Engines that don't want to have an Engine tab in the edit game dialog + * can return nullptr. + * + * @param boss the widget / dialog the returned widget is a child of + * @param name the name the returned widget must use + * @param target name of a config manager target + */ + virtual GUI::OptionsContainerWidget *buildEngineOptionsWidgetDynamic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const; + /** @name MetaEngineFeature flags */ //@{ @@ -386,19 +422,31 @@ public: kSavesUseExtendedFormat }; + //@} + + /** + * Return a list of achievement descriptions for the specified target. + * + * The default implementation returns an empty list. + * + * @param target name of a config manager target + * @return a list of achievement descriptions for an engine plugin + * and target + */ + virtual const Common::AchievementsInfo getAchievementsInfo(const Common::String &target) const { + return Common::AchievementsInfo(); + } + /** * Determine whether the engine supports the specified MetaEngine feature. * Used by e.g. the launcher to determine whether to enable the "Load" button. */ virtual bool hasFeature(MetaEngineFeature f) const; - static void appendExtendedSave(Common::OutSaveFile *saveFile, uint32 playtime, - Common::String desc, bool isAutosave); + static void appendExtendedSave(Common::OutSaveFile *saveFile, uint32 playtime, Common::String desc, bool isAutosave); static void parseSavegameHeader(ExtendedSavegameHeader *header, SaveStateDescriptor *desc); static void fillDummyHeader(ExtendedSavegameHeader *header); static WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, ExtendedSavegameHeader *header, bool skipThumbnail = true); - - //@} }; /** @@ -416,8 +464,14 @@ public: /** Find a plugin by its engine ID */ const Plugin *findPlugin(const Common::String &engineId) const; - /** Get the list of all engine plugins */ - const PluginList &getPlugins() const; + /** + * Get the list of all plugins for the type specified. + * By default, it will get METAENGINES, for now. + * If usage of actual engines never occurs, we can skip + * the default arguments, and always have it return + * PLUGIN_TYPE_METAENGINE. + */ + const PluginList &getPlugins(const PluginType fetchPluginType = PLUGIN_TYPE_METAENGINE) const; /** Find a target */ QualifiedGameDescriptor findTarget(const Common::String &target, const Plugin **plugin = NULL) const; diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h index 5888b84a5e4..582c426d1b1 100644 --- a/engines/wintermute/base/base_engine.h +++ b/engines/wintermute/base/base_engine.h @@ -34,97 +34,10 @@ #include "common/random.h" #include "common/language.h" +#include "engines/wintermute/detection.h" + namespace Wintermute { -enum WMETargetExecutable { - OLDEST_VERSION, - WME_1_0_12, // DEAD:CODE 2003 - WME_1_0_19, // DEAD:CODE 2003 - WME_1_0_20, // DEAD:CODE 2003 - WME_1_0_22, // DEAD:CODE 2003 - WME_1_0_24, // DEAD:CODE 2003 - WME_1_0_25, // DEAD:CODE 2003 - WME_1_0_28, // DEAD:CODE 2003 - WME_1_0_30, // DEAD:CODE 2003 - WME_1_0_31, // DEAD:CODE 2003 - WME_1_1_33, // DEAD:CODE 2003 - WME_1_1_35, // DEAD:CODE 2003 - WME_1_1_37, // DEAD:CODE 2003 - WME_1_1_39, // DEAD:CODE 2004 - WME_1_2_43, // DEAD:CODE 2004 - WME_1_2_44, // DEAD:CODE 2004 - WME_1_3_0, // DEAD:CODE 2004 - WME_1_3_2, // DEAD:CODE 2004 - WME_1_3_3, // DEAD:CODE 2004 - WME_1_4_0, // DEAD:CODE 2005 - WME_1_4_1, // DEAD:CODE 2005 - WME_1_5_0, // DEAD:CODE 2005 - WME_1_5_2, // DEAD:CODE 2005 - WME_1_6_0, // DEAD:CODE 2006 - WME_1_6_1, // DEAD:CODE 2006 - WME_1_7_0, // DEAD:CODE 2007 - WME_1_7_1, // DEAD:CODE 2007 - WME_1_7_2, // DEAD:CODE 2007 - WME_1_7_3, // DEAD:CODE 2007 - WME_1_7_93, // DEAD:CODE 2007 - WME_1_7_94, // DEAD:CODE 2007 - WME_1_8_0, // DEAD:CODE 2007 - WME_1_8_1, // DEAD:CODE 2007 - WME_1_8_2, // DEAD:CODE 2008 - WME_1_8_3, // DEAD:CODE 2008 - WME_1_8_4, // DEAD:CODE 2008 - WME_1_8_5, // DEAD:CODE 2008 - WME_1_8_6, // DEAD:CODE 2008 - WME_1_8_7, // DEAD:CODE 2008, released as "1.8.7 beta" - WME_1_8_8, // DEAD:CODE 2008, released as "1.8.8 beta" - WME_1_8_9, // DEAD:CODE 2008, released as "1.8.9 beta" - WME_1_8_10, // DEAD:CODE 2009 - - // fork of WME_1_8_10 - WME_ANDISHE_VARAN, // Andishe Varan Engine 1.0.0.0 - - WME_1_8_11, // DEAD:CODE 2009 - WME_1_9_0, // DEAD:CODE 2009, released as "1.9.0 beta" - - // fork of WME_1_9_0 - WME_KINJAL_1_0, - WME_KINJAL_1_1, - WME_KINJAL_1_2, - WME_KINJAL_1_3, - WME_KINJAL_1_4, - - // fork of WME_KINJAL_1_4 - WME_HEROCRAFT, - - WME_1_9_1, // DEAD:CODE 2010 - - // fork of WME_1_9_1 - WME_KINJAL_1_5, - WME_KINJAL_1_6, - WME_KINJAL_1_7, - WME_KINJAL_1_7a, - WME_KINJAL_1_7b, - WME_KINJAL_1_8, - WME_KINJAL_1_9, - WME_KINJAL_2_0, - - WME_1_9_2, // DEAD:CODE 2010 - WME_1_9_3, // DEAD:CODE 2012, released as "1.10.1 beta" - WME_LITE, - LATEST_VERSION, - - // fork of WME_LITE - FOXTAIL_OLDEST_VERSION, - FOXTAIL_1_2_227, - FOXTAIL_1_2_230, - FOXTAIL_1_2_304, - FOXTAIL_1_2_362, - FOXTAIL_1_2_527, - FOXTAIL_1_2_896, - FOXTAIL_1_2_902, - FOXTAIL_LATEST_VERSION -}; - class BaseFileManager; class BaseRegistry; class BaseGame; diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp index cde1225eadb..eb88e3de097 100644 --- a/engines/wintermute/base/base_sprite.cpp +++ b/engines/wintermute/base/base_sprite.cpp @@ -41,7 +41,7 @@ #include "engines/wintermute/base/scriptables/script_value.h" #include "engines/wintermute/base/scriptables/script.h" #include "engines/wintermute/base/scriptables/script_stack.h" -#include "engines/wintermute/game_description.h" +#include "engines/wintermute/detection.h" namespace Wintermute { diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp index 1ad248c192b..4318d7e0b14 100644 --- a/engines/wintermute/detection.cpp +++ b/engines/wintermute/detection.cpp @@ -21,11 +21,7 @@ */ #include "engines/advancedDetector.h" -#include "engines/wintermute/wintermute.h" -#include "engines/wintermute/game_description.h" -#include "engines/wintermute/base/base_persistence_manager.h" -#include "common/achievements.h" #include "common/config-manager.h" #include "common/error.h" #include "common/fs.h" @@ -34,27 +30,11 @@ #include "engines/metaengine.h" -#include "engines/wintermute/achievements_tables.h" -#include "engines/wintermute/detection_tables.h" -#include "engines/wintermute/keymapper_tables.h" +#include "wintermute/detection.h" +#include "wintermute/detection_tables.h" namespace Wintermute { -/** - * The fallback game descriptor used by the Wintermute engine's fallbackDetector. - * Contents of this struct are overwritten by the fallbackDetector. (logic copied partially - * from the SCI-engine). - */ -static ADGameDescription s_fallbackDesc = { - "", - "", - AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor - Common::UNK_LANG, - Common::kPlatformWindows, - ADGF_UNSTABLE, - GUIO0() -}; - static const ADExtraGuiOptionsMap gameGuiOptions[] = { { GAMEOPTION_SHOW_FPS, @@ -79,8 +59,6 @@ static const ADExtraGuiOptionsMap gameGuiOptions[] = { AD_EXTRA_GUI_OPTIONS_TERMINATOR }; -static char s_fallbackExtraBuf[256]; - static const char *directoryGlobs[] = { "language", // To detect the various languages "languages", // To detect the various languages @@ -88,9 +66,9 @@ static const char *directoryGlobs[] = { 0 }; -class WintermuteMetaEngine : public AdvancedMetaEngine { +class WintermuteMetaEngineStatic : public AdvancedMetaEngineStatic { public: - WintermuteMetaEngine() : AdvancedMetaEngine(Wintermute::gameDescriptions, sizeof(WMEGameDescription), Wintermute::wintermuteGames, gameGuiOptions) { + WintermuteMetaEngineStatic() : AdvancedMetaEngineStatic(Wintermute::gameDescriptions, sizeof(WMEGameDescription), Wintermute::wintermuteGames, gameGuiOptions) { // Use kADFlagUseExtraAsHint to distinguish between SD and HD versions // of J.U.L.I.A. when their datafiles sit in the same directory (e.g. in Steam distribution). _flags = kADFlagUseExtraAsHint; @@ -112,153 +90,37 @@ public: } ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const override { - // Set some defaults - s_fallbackDesc.extra = ""; - s_fallbackDesc.language = Common::UNK_LANG; - s_fallbackDesc.flags = ADGF_UNSTABLE; - s_fallbackDesc.platform = Common::kPlatformWindows; // default to Windows - s_fallbackDesc.gameId = "wintermute"; - s_fallbackDesc.guiOptions = GUIO0(); + /** + * Fallback detection for Wintermute heavily depends on engine resources, so it's not possible + * to use them without the engine present in a clean way. + */ - if (!allFiles.contains("data.dcp")) { - return ADDetectedGame(); - } - - Common::String name, caption; - if (!WintermuteEngine::getGameInfo(fslist, name, caption)) { - return ADDetectedGame(); - } - - Common::String extra = caption; - if (extra.empty()) { - extra = name; - } - - if (!extra.empty()) { - Common::strlcpy(s_fallbackExtraBuf, extra.c_str(), sizeof(s_fallbackExtraBuf) - 1); - s_fallbackDesc.extra = s_fallbackExtraBuf; - s_fallbackDesc.flags |= ADGF_USEEXTRAASTITLE; - s_fallbackDesc.flags |= ADGF_AUTOGENTARGET; - } - - ADDetectedGame game(&s_fallbackDesc); - - for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { - if (file->isDirectory()) continue; - if (!file->getName().hasSuffixIgnoreCase(".dcp")) continue; - - FileProperties tmp; - if (getFileProperties(allFiles, s_fallbackDesc, file->getName(), tmp)) { - game.hasUnknownFiles = true; - game.matchedFiles[file->getName()] = tmp; + if (ConfMan.hasKey("always_run_fallback_detection_extern")) { + if (ConfMan.getBool("always_run_fallback_detection_extern") == false) { + warning("WINTERMUTE: Fallback detection is disabled."); + return ADDetectedGame(); } } - return game; - } + const Plugin *metaEnginePlugin = EngineMan.findPlugin(getEngineId()); - bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override { - assert(syst); - assert(engine); - const WMEGameDescription *gd = (const WMEGameDescription *)desc; - *engine = new Wintermute::WintermuteEngine(syst, gd); - return true; - } - - bool hasFeature(MetaEngineFeature f) const override { - switch (f) { - case MetaEngine::kSupportsListSaves: - return true; - case MetaEngine::kSupportsLoadingDuringStartup: - return true; - case MetaEngine::kSupportsDeleteSave: - return true; - case MetaEngine::kSavesSupportCreationDate: - return true; - case MetaEngine::kSavesSupportMetaInfo: - return true; - case MetaEngine::kSavesSupportThumbnail: - return true; - default: - return false; - } - } - - SaveStateList listSaves(const char *target) const override { - SaveStateList saves; - Wintermute::BasePersistenceManager pm(target, true); - for (int i = 0; i < getMaximumSaveSlot(); i++) { - if (pm.getSaveExists(i)) { - SaveStateDescriptor desc; - pm.getSaveStateDesc(i, desc); - saves.push_back(desc); - } - } - return saves; - } - - int getMaximumSaveSlot() const override { - return 100; - } - - void removeSaveState(const char *target, int slot) const override { - Wintermute::BasePersistenceManager pm(target, true); - pm.deleteSaveSlot(slot); - } - - SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override { - Wintermute::BasePersistenceManager pm(target, true); - SaveStateDescriptor retVal; - retVal.setDescription("Invalid savegame"); - pm.getSaveStateDesc(slot, retVal); - return retVal; - } - - const Common::AchievementsInfo getAchievementsInfo(const Common::String &target) const override { - Common::String gameId = ConfMan.get("gameid", target); - - // HACK: "juliauntold" is a DLC of "juliastars", they share the same achievements list - if (gameId == "juliauntold") { - gameId = "juliastars"; - } - - Common::AchievementsPlatform platform = Common::STEAM_ACHIEVEMENTS; - if (ConfMan.get("extra", target).contains("GOG")) { - platform = Common::GALAXY_ACHIEVEMENTS; - } - - // "(gameId, platform) -> result" search - Common::AchievementsInfo result; - for (const AchievementDescriptionList *i = achievementDescriptionList; i->gameId; i++) { - if (i->gameId == gameId && i->platform == platform) { - result.platform = i->platform; - result.appId = i->appId; - for (const Common::AchievementDescription *it = i->descriptions; it->id; it++) { - result.descriptions.push_back(*it); + if (metaEnginePlugin) { + const Plugin *enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + if (enginePlugin) { + return enginePlugin->get().fallbackDetectExtern(_md5Bytes, allFiles, fslist); + } else { + static bool warn = true; + if (warn) { + warning("Engine plugin for Wintermute not present. Fallback detection is disabled."); + warn = false; } - break; } } - return result; - } - - Common::KeymapArray initKeymaps(const char *target) const override { - Common::String gameId = ConfMan.get("gameid", target); - const char *gameDescr = "Unknown WME game"; - for (const PlainGameDescriptor *it = Wintermute::wintermuteGames; it->gameId ; it++ ) { - if (gameId == it->gameId) { - gameDescr = it->description; - } - } - return getWintermuteKeymaps(target, gameId, gameDescr); + return ADDetectedGame(); } }; } // End of namespace Wintermute -#if PLUGIN_ENABLED_DYNAMIC(WINTERMUTE) - REGISTER_PLUGIN_DYNAMIC(WINTERMUTE, PLUGIN_TYPE_ENGINE, Wintermute::WintermuteMetaEngine); -#else - REGISTER_PLUGIN_STATIC(WINTERMUTE, PLUGIN_TYPE_ENGINE, Wintermute::WintermuteMetaEngine); -#endif +REGISTER_PLUGIN_STATIC(WINTERMUTE_DETECTION, PLUGIN_TYPE_METAENGINE, Wintermute::WintermuteMetaEngineStatic); diff --git a/engines/wintermute/ext/wme_galaxy.cpp b/engines/wintermute/ext/wme_galaxy.cpp index 949839a046a..3d42cc4d432 100644 --- a/engines/wintermute/ext/wme_galaxy.cpp +++ b/engines/wintermute/ext/wme_galaxy.cpp @@ -50,7 +50,7 @@ SXWMEGalaxyAPI::SXWMEGalaxyAPI(BaseGame *inGame, ScStack *stack) : BaseScriptabl ////////////////////////////////////////////////////////////////////////// void SXWMEGalaxyAPI::init() { - MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); + const MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); const Common::String target = BaseEngine::instance().getGameTargetName(); _achievementsInfo = meta.getAchievementsInfo(target); diff --git a/engines/wintermute/ext/wme_steam.cpp b/engines/wintermute/ext/wme_steam.cpp index 47812abc324..c776d9ec35e 100644 --- a/engines/wintermute/ext/wme_steam.cpp +++ b/engines/wintermute/ext/wme_steam.cpp @@ -50,7 +50,7 @@ SXSteamAPI::SXSteamAPI(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame ////////////////////////////////////////////////////////////////////////// void SXSteamAPI::init() { - MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); + const MetaEngine &meta = ((WintermuteEngine *)g_engine)->getMetaEngine(); const Common::String target = BaseEngine::instance().getGameTargetName(); _achievementsInfo = meta.getAchievementsInfo(target); diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk index 5bbb30d6ced..7dd1dc68b29 100644 --- a/engines/wintermute/module.mk +++ b/engines/wintermute/module.mk @@ -156,10 +156,10 @@ MODULE_OBJS := \ debugger/script_monitor.o \ debugger/watch.o \ debugger/watch_instance.o \ - detection.o \ math/math_util.o \ math/matrix4.o \ math/vector2.o \ + metaengine.o \ platform_osystem.o \ system/sys_class.o \ system/sys_class_registry.o \ @@ -194,3 +194,6 @@ endif # Include common rules include $(srcdir)/rules.mk + +# Detection objects +DETECT_OBJS += $(MODULE)/detection.o diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp index 7c335b2daf1..0e7c2cf4556 100644 --- a/engines/wintermute/wintermute.cpp +++ b/engines/wintermute/wintermute.cpp @@ -35,9 +35,9 @@ #include "engines/wintermute/ad/ad_game.h" #include "engines/wintermute/wintermute.h" #include "engines/wintermute/debugger.h" -#include "engines/wintermute/game_description.h" #include "engines/wintermute/platform_osystem.h" #include "engines/wintermute/base/base_engine.h" +#include "engines/wintermute/detection.h" #include "engines/wintermute/base/sound/base_sound_manager.h" #include "engines/wintermute/base/base_file_manager.h" diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h index 655b287907f..1e9f8213ec4 100644 --- a/engines/wintermute/wintermute.h +++ b/engines/wintermute/wintermute.h @@ -26,6 +26,7 @@ #include "engines/engine.h" #include "gui/debugger.h" #include "common/fs.h" +#include "wintermute/detection.h" namespace Wintermute { @@ -33,7 +34,6 @@ class Console; class BaseGame; class SystemClassRegistry; class DebuggerController; -struct WMEGameDescription; const int INT_MAX_VALUE = 0x7fffffff; const int INT_MIN_VALUE = -INT_MAX_VALUE - 1; // WME3D @@ -48,14 +48,6 @@ enum { kWintermuteDebugGeneral = 1 << 5 }; -enum WintermuteGameFeatures { - /** A game with low-spec resources. */ - GF_LOWSPEC_ASSETS = 1 << 0, - GF_IGNORE_SD_FILES = 1 << 1, - GF_IGNORE_HD_FILES = 1 << 2, - GF_3D = 1 << 3 -}; - class WintermuteEngine : public Engine { public: WintermuteEngine(OSystem *syst, const WMEGameDescription *desc); diff --git a/gui/about.cpp b/gui/about.cpp index f1e91ae7d05..e008ec45af4 100644 --- a/gui/about.cpp +++ b/gui/about.cpp @@ -127,7 +127,7 @@ AboutDialog::AboutDialog() addLine(str); str = "C2"; - str += (*iter)->get().getOriginalCopyright(); + str += (*iter)->get().getOriginalCopyright(); addLine(str); //addLine(""); diff --git a/gui/editgamedialog.cpp b/gui/editgamedialog.cpp index 8ec1563a69a..1cc80bf000f 100644 --- a/gui/editgamedialog.cpp +++ b/gui/editgamedialog.cpp @@ -109,10 +109,16 @@ EditGameDialog::EditGameDialog(const String &domain) // Retrieve the plugin, since we need to access the engine's MetaEngine // implementation. - const Plugin *plugin = nullptr; - QualifiedGameDescriptor qgd = EngineMan.findTarget(domain, &plugin); - if (!plugin) { - warning("Plugin for target \"%s\" not found! Game specific settings might be missing", domain.c_str()); + const Plugin *metaEnginePlugin = nullptr; + const Plugin *enginePlugin = nullptr; + QualifiedGameDescriptor qgd = EngineMan.findTarget(domain, &metaEnginePlugin); + if (!metaEnginePlugin) { + warning("MetaEnginePlugin for target \"%s\" not found!", domain.c_str()); + } else { + enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + if (!enginePlugin) { + warning("Engine Plugin for target \"%s\" not found! Game specific settings might be missing.", domain.c_str()); + } } // GAME: Path to game data (r/o), extra data (r/o), and save data (r/w) @@ -176,12 +182,12 @@ EditGameDialog::EditGameDialog(const String &domain) // 2) The engine tab (shown only if the engine implements one or there are custom engine options) // - if (plugin) { + if (metaEnginePlugin) { int tabId = tab->addTab(_("Engine"), "GameOptions_Engine"); - const MetaEngine &metaEngine = plugin->get(); + const MetaEngineStatic &metaEngine = metaEnginePlugin->get(); metaEngine.registerDefaultSettings(_domain); - _engineOptions = metaEngine.buildEngineOptionsWidget(tab, "GameOptions_Engine.Container", _domain); + _engineOptions = metaEngine.buildEngineOptionsWidgetStatic(tab, "GameOptions_Engine.Container", _domain); if (_engineOptions) { _engineOptions->setParentDialog(this); @@ -225,8 +231,8 @@ EditGameDialog::EditGameDialog(const String &domain) // The Keymap tab // Common::KeymapArray keymaps; - if (plugin) { - keymaps = plugin->get().initKeymaps(domain.c_str()); + if (enginePlugin) { + keymaps = enginePlugin->get().initKeymaps(domain.c_str()); } if (!keymaps.empty()) { @@ -333,9 +339,9 @@ EditGameDialog::EditGameDialog(const String &domain) // // 9) The Achievements tab // - if (plugin) { - const MetaEngine &metaEngine = plugin->get(); - Common::AchievementsInfo achievementsInfo = metaEngine.getAchievementsInfo(domain); + if (enginePlugin) { + const MetaEngine &metaEngineConnect = enginePlugin->get(); + Common::AchievementsInfo achievementsInfo = metaEngineConnect.getAchievementsInfo(domain); if (achievementsInfo.descriptions.size() > 0) { tab->addTab(_("Achievements"), "GameOptions_Achievements"); addAchievementsControls(tab, "GameOptions_Achievements.", achievementsInfo); diff --git a/gui/launcher.cpp b/gui/launcher.cpp index e4d73d93705..9c3fa9e68ea 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -258,10 +258,13 @@ void LauncherDialog::updateListing() { U32StringArray l; ListWidget::ColorList colors; ThemeEngine::FontColor color; + int numEntries = ConfMan.getInt("gui_list_max_scan_entries"); // Retrieve a list of all games defined in the config file _domains.clear(); const ConfigManager::DomainMap &domains = ConfMan.getGameDomains(); + bool scanEntries = numEntries == -1 ? true : (domains.size() <= numEntries); + ConfigManager::DomainMap::const_iterator iter; for (iter = domains.begin(); iter != domains.end(); ++iter) { #ifdef __DS__ @@ -274,7 +277,6 @@ void LauncherDialog::updateListing() { String gameid(iter->_value.getVal("gameid")); String description(iter->_value.getVal("description")); - Common::FSNode path(iter->_value.getVal("path")); if (gameid.empty()) gameid = iter->_key; @@ -297,13 +299,17 @@ void LauncherDialog::updateListing() { pos++; color = ThemeEngine::kFontColorNormal; - if (!path.isDirectory()) { - color = ThemeEngine::kFontColorAlternate; - // If more conditions which grey out entries are added we should consider - // enabling this so that it is easy to spot why a certain game entry cannot - // be started. - // description += Common::String::format(" (%s)", _("Not found")); + if (scanEntries) { + Common::FSNode path(iter->_value.getVal("path")); + if (!path.isDirectory()) { + color = ThemeEngine::kFontColorAlternate; + // If more conditions which grey out entries are added we should consider + // enabling this so that it is easy to spot why a certain game entry cannot + // be started. + + // description += Common::String::format(" (%s)", _("Not found")); + } } l.insert_at(pos, description); @@ -469,14 +475,20 @@ void LauncherDialog::loadGame(int item) { EngineMan.upgradeTargetIfNecessary(target); // Look for the plugin - const Plugin *plugin = nullptr; - EngineMan.findTarget(target, &plugin); + const Plugin *metaEnginePlugin = nullptr; + const Plugin *enginePlugin = nullptr; + EngineMan.findTarget(target, &metaEnginePlugin); - if (plugin) { - const MetaEngine &metaEngine = plugin->get(); - if (metaEngine.hasFeature(MetaEngine::kSupportsListSaves) && - metaEngine.hasFeature(MetaEngine::kSupportsLoadingDuringStartup)) { - int slot = _loadDialog->runModalWithPluginAndTarget(plugin, target); + // If we found a relevant plugin, find the matching engine plugin. + if (metaEnginePlugin) { + enginePlugin = PluginMan.getEngineFromMetaEngine(metaEnginePlugin); + } + + if (enginePlugin) { + const MetaEngine &metaEngineConnect = enginePlugin->get(); + if (metaEngineConnect.hasFeature(MetaEngine::kSupportsListSaves) && + metaEngineConnect.hasFeature(MetaEngine::kSupportsLoadingDuringStartup)) { + int slot = _loadDialog->runModalWithPluginAndTarget(enginePlugin, target); if (slot >= 0) { ConfMan.setActiveDomain(_domains[item]); ConfMan.setInt("save_slot", slot, Common::ConfigManager::kTransientDomain); diff --git a/gui/saveload-dialog.h b/gui/saveload-dialog.h index aaea785b230..f0d986fbb31 100644 --- a/gui/saveload-dialog.h +++ b/gui/saveload-dialog.h @@ -110,16 +110,16 @@ protected: */ virtual void listSaves(); - const bool _saveMode; - const MetaEngine *_metaEngine; - bool _delSupport; - bool _metaInfoSupport; - bool _thumbnailSupport; - bool _saveDateSupport; - bool _playTimeSupport; - Common::String _target; + const bool _saveMode; + const MetaEngine *_metaEngine; + bool _delSupport; + bool _metaInfoSupport; + bool _thumbnailSupport; + bool _saveDateSupport; + bool _playTimeSupport; + Common::String _target; bool _dialogWasShown; - SaveStateList _saveList; + SaveStateList _saveList; #ifndef DISABLE_SAVELOADCHOOSER_GRID ButtonWidget *_listButton; diff --git a/gui/saveload.cpp b/gui/saveload.cpp index f37d3ed57dc..084bbc0f484 100644 --- a/gui/saveload.cpp +++ b/gui/saveload.cpp @@ -77,13 +77,23 @@ Common::String SaveLoadChooser::createDefaultSaveDescription(const int slot) con int SaveLoadChooser::runModalWithCurrentTarget() { const Plugin *plugin = EngineMan.findPlugin(ConfMan.get("engineid")); + const Plugin *enginePlugin = nullptr; if (!plugin) { error("SaveLoadChooser::runModalWithCurrentTarget(): Cannot find plugin"); + } else { + enginePlugin = PluginMan.getEngineFromMetaEngine(plugin); + + if (!enginePlugin) { + error("SaveLoadChooser::runModalWithCurrentTarget(): Couldn't match a Engine from the MetaEngine. \ + You will not be able to see savefiles until you have the necessary plugins."); + } } - return runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + return runModalWithPluginAndTarget(enginePlugin, ConfMan.getActiveDomainName()); } int SaveLoadChooser::runModalWithPluginAndTarget(const Plugin *plugin, const String &target) { + assert(plugin->getType() == PLUGIN_TYPE_ENGINE); + selectChooser(plugin->get()); if (!_impl) return -1; diff --git a/rules.mk b/rules.mk index b793ea480b1..a3bbec59776 100644 --- a/rules.mk +++ b/rules.mk @@ -3,6 +3,7 @@ # ############################################### +ifeq ($(LOAD_RULES_MK), 1) # Copy the list of objects to a new variable. The name of the new variable # contains the module name, a trick we use so we can keep multiple different @@ -103,3 +104,5 @@ ifdef SPLIT_DWARF endif .PHONY: clean-$(MODULE) $(MODULE) + +endif # LOAD_RULES_MK diff --git a/test/common/array.h b/test/common/array.h index bf0ff556398..f86d291ab2c 100644 --- a/test/common/array.h +++ b/test/common/array.h @@ -322,6 +322,16 @@ class ArrayTestSuite : public CxxTest::TestSuite Common::Array nonCopyable(1); } + void test_array_constructor_list() { +#ifdef USE_CXX11 + Common::Array array = {1, 42, 255}; + TS_ASSERT_EQUALS(array.size(), 3U); + TS_ASSERT_EQUALS(array[0], 1); + TS_ASSERT_EQUALS(array[1], 42); + TS_ASSERT_EQUALS(array[2], 255); +#endif + } + void test_array_constructor_count_copy_value() { Common::Array trivial(5, 1); TS_ASSERT_EQUALS(trivial.size(), 5U); diff --git a/video/flic_decoder.cpp b/video/flic_decoder.cpp index 72a8aa0c3dd..d9e79bc0700 100644 --- a/video/flic_decoder.cpp +++ b/video/flic_decoder.cpp @@ -158,6 +158,7 @@ Graphics::PixelFormat FlicDecoder::FlicVideoTrack::getPixelFormat() const { #define FLI_SETPAL 4 #define FLI_SS2 7 +#define FLI_BLACK 13 #define FLI_BRUN 15 #define FLI_COPY 16 #define PSTAMP 18 @@ -234,6 +235,11 @@ void FlicDecoder::FlicVideoTrack::handleFrame() { case FLI_SS2: decodeDeltaFLC(data); break; + case FLI_BLACK: + _surface->fillRect(Common::Rect(0, 0, getWidth(), getHeight()), 0); + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight())); + break; case FLI_BRUN: decodeByteRun(data); break;