diff options
-rw-r--r-- | TODO | 35 | ||||
-rw-r--r-- | base/engine.cpp | 10 | ||||
-rw-r--r-- | base/gameDetector.cpp | 429 | ||||
-rw-r--r-- | base/gameDetector.h | 64 | ||||
-rw-r--r-- | base/main.cpp | 59 | ||||
-rw-r--r-- | common/config-file.cpp | 240 | ||||
-rw-r--r-- | common/config-file.h | 70 | ||||
-rw-r--r-- | common/config-manager.cpp | 370 | ||||
-rw-r--r-- | common/config-manager.h | 127 | ||||
-rw-r--r-- | common/module.mk | 2 | ||||
-rw-r--r-- | common/singleton.h | 57 | ||||
-rw-r--r-- | gui/launcher.cpp | 74 | ||||
-rw-r--r-- | gui/options.cpp | 30 | ||||
-rw-r--r-- | gui/options.h | 2 | ||||
-rw-r--r-- | queen/queen.cpp | 5 | ||||
-rw-r--r-- | queen/queen.h | 1 | ||||
-rw-r--r-- | scumm/dialogs.cpp | 14 | ||||
-rw-r--r-- | scumm/saveload.cpp | 2 | ||||
-rw-r--r-- | scumm/scummvm.cpp | 60 | ||||
-rw-r--r-- | scumm/sound.cpp | 2 | ||||
-rw-r--r-- | simon/simon.cpp | 18 | ||||
-rw-r--r-- | sky/sky.cpp | 24 | ||||
-rw-r--r-- | sword2/sword2.cpp | 8 |
23 files changed, 904 insertions, 799 deletions
@@ -6,18 +6,16 @@ General * Revise the way "quit" is handled. Maybe add a global variable "g_quit" which we set when the application should be quit (e.g. when an EVENT_QUIT is received). This is useful if multiple levels of event loops have to be ended -* gameDetector.cpp is quite messy. Also, it makes providing native GUI front - ends for ScummVM unnecessarily cumbersome (think of systems which don't - even have a command line, like classic MacOS). It would be nice to better - separate the command line parsing from any GUI and also from the storage - for the user settings (this ties into my proposed config system changes; - ideally, we should be able to drop almost all of the member variables - in the game detector, in favor of getting all these directly from the - config system). * fix the Map<> template, make it more robust; maybe use a red-black tree? * add iterators to List<> template and make use of them * allow for return-to-launcher instead of a normal "quit" ? - +* turn g_pluginManager into a proper singleton +* improve the argv (command line args) parser +* extend the Plugin API to provide for "game detection": instead of the + TargetSettings::detectname "hack" to detect files, provide a callback + in each Plugin which given a FSList returns a list of candidate targets. + This way, a plugin can implement tests more elaborate than filename + checking, e.g. it could actually peek into the files. GUI === @@ -41,18 +39,7 @@ Audio Config ====== -* The config system could stand an overhaul * Preserve comments in config file somehow -* Add two virtual domains (for command line settings and user overrides); - while we currently do something like this already, our implementation is - a big ugly hack (no offense meant) and has some cumbersome problems. For - example, currently to query a config value, one would have to search up to - four domains manually (user override, command line, game specific, global - application domain, in that order). Ideally all this should be hidden - inside the config system. If you are interested in this, I can elaborate -* Add a way to distinguish if a given key is present at all. That is, it - would be nice if one could distinguish between an explicit "fullscreen=false" - and the absence of any fullscreen config. * Add a 'notification' system. E.g. the SoundMixer could request to be notified whenever the value of the "volume" config option changes. In other words, instead of a "pull" approach (where each subsystem has to check whether any @@ -61,6 +48,12 @@ Config setting is changed, the code doing so has to updated the SoundMixer etc. That's cumbersome, and error prone. Would be much nicer if updating the volume config value automatically notifies the SoundMixer, iMuse etc. +* Change backends to directly access the config manager +* During the config rewrite, some command line switches were disabled. + Gotta decide what to do about each of them: reimplement, remove, replace? + In particular: -w and -l (those were kind of oddball switches, IMHO); + also -z should be split into two seperate functions (see TODO comment in + GameDetector::list_games()) SCUMM ===== @@ -89,6 +82,8 @@ SCUMM 2a) If 1) succeeded, file SF.net CVS file rename request 2b) If 2) failed, do brute force file rename (cp && cvs add && cvs rm) 3) Adjust Makefile and project files to use the new name +* Possible implement a new resource manager, which then also could be shared + by ScummEX. [Jamieson has some ideas about this and might work on it| Broken Sword 2 ============== diff --git a/base/engine.cpp b/base/engine.cpp index 9eb5ab8e42..567def93cd 100644 --- a/base/engine.cpp +++ b/base/engine.cpp @@ -24,7 +24,7 @@ #endif #include "base/engine.h" #include "base/gameDetector.h" -#include "common/config-file.h" +#include "common/config-manager.h" #include "common/timer.h" #include "sound/mixer.h" @@ -36,7 +36,7 @@ Engine::Engine(GameDetector *detector, OSystem *syst) g_engine = this; _mixer = detector->createMixer(); - _gameDataPath = detector->_gameDataPath; + _gameDataPath = strdup(ConfMan.get("path").c_str()); // FIXME - leak. Just conver to a String? _timer = g_timer; } @@ -61,11 +61,7 @@ const char *Engine::getSavePath() const { // If SCUMMVM_SAVEPATH was not specified, try to use game specific savepath from config if (!dir || dir[0] == 0) - dir = g_config->get("savepath"); - - // If SCUMMVM_SAVEPATH was not specified, try to use general path from config - if (!dir || dir[0] == 0) - dir = g_config->get("savepath", "scummvm"); + dir = ConfMan.get("savepath").c_str(); // If no save path was specified, use no directory prefix if (dir == NULL) diff --git a/base/gameDetector.cpp b/base/gameDetector.cpp index 7c73715da1..36ee551b89 100644 --- a/base/gameDetector.cpp +++ b/base/gameDetector.cpp @@ -27,7 +27,7 @@ #include "base/gameDetector.h" #include "base/plugins.h" -#include "common/config-file.h" +#include "common/config-manager.h" #include "common/scaler.h" // Only for gfx_modes #include "sound/mididrv.h" @@ -69,20 +69,26 @@ static const char USAGE_STRING[] = " -m<num> - Set music volume to <num> (0-255)\n" " -o<num> - Set master volume to <num> (0-255)\n" " -s<num> - Set sfx volume to <num> (0-255)\n" +#ifndef DISABLE_SCUMM " -t<num> - Set music tempo (50-200, default 100%%)\n" +#endif "\n" " -n - No subtitles for speech\n" +#ifndef DISABLE_SCUMM " -y - Set text speed (default: 60)\n" +#endif "\n" +/* FIXME / TODO: config rewrite " -l<file> - Load config file instead of default\n" #if defined(UNIX) " -w[file] - Write to config file [~/.scummvmrc]\n" #else " -w[file] - Write to config file [scummvm.ini]\n" #endif +*/ " -v - Show version info and exit\n" " -h - Display this text and exit\n" - " -z - Display list of games\n" + " -z - Display list of supported games\n" "\n" " -b<num> - Pass number to the boot script (boot param)\n" " -d[num] - Enable debug output (debug level [0])\n" @@ -143,13 +149,13 @@ static const struct GraphicsMode gfx_modes[] = { {0, 0, 0} }; -struct Language { +struct LanguageDescription { const char *name; const char *description; - int id; + Language id; }; -static const struct Language languages[] = { +static const struct LanguageDescription languages[] = { {"en", "English", EN_USA}, {"de", "German", DE_DEU}, {"fr", "French", FR_FRA}, @@ -162,162 +168,105 @@ static const struct Language languages[] = { {"gb", "English", EN_GRB}, {"se", "Swedish", SE_SWE}, {"hb", "Hebrew", HB_HEB}, - {0, 0, 0} + {0, 0, UNK_LANG} }; - GameDetector::GameDetector() { - _fullScreen = false; - _aspectRatio = false; - - _master_volume = kDefaultMasterVolume; - _music_volume = kDefaultMusicVolume; - _sfx_volume = kDefaultSFXVolume; - _amiga = false; - _platform = 0; - _language = 0; - -#ifndef DISABLE_SCUMM - _demo_mode = false; -#endif - -#ifndef DISABLE_SKY - _floppyIntro = false; -#endif - - _talkSpeed = 60; - _debugMode = 0; - _debugLevel = 0; - _dumpScripts = 0; - _noSubtitles = false; - _bootParam = 0; - - _gameDataPath = 0; - _gameTempo = 0; - _midi_driver = MD_AUTO; - _game.features = 0; - _plugin = 0; - - _multi_midi = false; - _native_mt32 = false; - _cdrom = 0; - _joystick_num = 0; - _save_slot = 0; - - _saveconfig = false; - _confirmExit = false; - + // Graphics + ConfMan.registerDefault("fullscreen", false); + ConfMan.registerDefault("aspect_ratio", false); #ifndef _WIN32_WCE - _gfx_mode = GFX_DOUBLESIZE; + ConfMan.registerDefault("gfx_mode", "2x"); #else - _gfx_mode = GFX_NORMAL; + ConfMan.registerDefault("gfx_mode", "normal"); #endif - _default_gfx_mode = true; -} - -void GameDetector::updateconfig() { - const char *val; - - _amiga = g_config->getBool("amiga", _amiga); - _platform = g_config->getInt("platform", _platform); + // Sound & Music + ConfMan.registerDefault("master_volume", kDefaultMasterVolume); + ConfMan.registerDefault("music_volume", kDefaultMusicVolume); + ConfMan.registerDefault("sfx_volume", kDefaultSFXVolume); - _save_slot = g_config->getInt("save_slot", _save_slot); + ConfMan.registerDefault("multi_midi", false); + ConfMan.registerDefault("native_mt32", false); +// ConfMan.registerDefault("music_driver", ???); - _joystick_num = g_config->getInt("joystick_num", _joystick_num); + ConfMan.registerDefault("cdrom", 0); - _cdrom = g_config->getInt("cdrom", _cdrom); + // Game specifc + ConfMan.registerDefault("path", ""); - _bootParam = g_config->getInt("boot_param", _bootParam); - - if ((val = g_config->get("music_driver"))) - if (!parseMusicDriver(val)) { - printf("Error in the config file: invalid music_driver.\n"); - printf(USAGE_STRING); - exit(-1); - } - - _fullScreen = g_config->getBool("fullscreen", _fullScreen); - _aspectRatio = g_config->getBool("aspect_ratio", _aspectRatio); - - if ((val = g_config->get("gfx_mode"))) - if ((_gfx_mode = parseGraphicsMode(val)) == -1) { - printf("Error in the config file: invalid gfx_mode.\n"); - printf(USAGE_STRING); - exit(-1); - } - -#ifndef DISABLE_SKY - _floppyIntro = g_config->getBool("floppy_intro", _floppyIntro); -#endif + ConfMan.registerDefault("amiga", false); + ConfMan.registerDefault("platform", kPlatformPC); + ConfMan.registerDefault("language", "en"); + ConfMan.registerDefault("nosubtitles", false); + ConfMan.registerDefault("boot_param", 0); + ConfMan.registerDefault("save_slot", -1); #ifndef DISABLE_SCUMM - _demo_mode = g_config->getBool("demo_mode", _demo_mode); + ConfMan.registerDefault("demo_mode", false); + ConfMan.registerDefault("talkspeed", 60); + ConfMan.registerDefault("tempo", 0); #endif - if ((val = g_config->get("language"))) - if ((_language = parseLanguage(val)) == -1) { - printf("Error in the config file: invalid language.\n"); - printf(USAGE_STRING); - exit(-1); - } - - _master_volume = g_config->getInt("master_volume", _master_volume); - - _music_volume = g_config->getInt("music_volume", _music_volume); - - _noSubtitles = g_config->getBool("nosubtitles", _noSubtitles ? true : false); - - if ((val = g_config->get("path"))) - _gameDataPath = strdup(val); - - _sfx_volume = g_config->getInt("sfx_volume", _sfx_volume); - - _debugLevel = g_config->getInt("debuglevel", _debugLevel); - if (_debugLevel) - _debugMode = true; +#ifndef DISABLE_SKY + ConfMan.registerDefault("floppy_intro", false); +#endif - // We use strtol for the tempo to allow it to be specified in hex. - if ((val = g_config->get("tempo"))) - _gameTempo = strtol(val, NULL, 0); + // Miscellaneous + ConfMan.registerDefault("debuglevel", 0); + ConfMan.registerDefault("joystick_num", -1); + ConfMan.registerDefault("confirm_exit", false); - _talkSpeed = g_config->getInt("talkspeed", _talkSpeed); + _debugMode = false; + _dumpScripts = false; + _midi_driver = MD_AUTO; - _confirmExit = g_config->getBool("confirm_exit", _confirmExit ? true : false); + _saveconfig = false; - _multi_midi = g_config->getBool ("multi_midi", _multi_midi); - _native_mt32 = g_config->getBool ("native_mt32", _native_mt32); + _game.features = 0; + _plugin = 0; } void GameDetector::list_games() { + // FIXME / TODO: config rewrite + // Right now this lists all known built-in targets; and also for each of + // those it tells the user if the target is "configured". + // To me this seems like an ill mix of two different functionalities. + // IMHO we should split this into two seperate commands/options: + // 1) List all built-in gameids (e.g. monkey, atlantis, ...) similiar to + // what this code does, but without the "Config" column. + // 2) List all available (configured) targets, including those with custom + // names, e.g. "monkey-mac", "skycd-demo", ... const PluginList &plugins = g_pluginManager->getPlugins(); const TargetSettings *v; - const char *config; - printf("Game Full Title Config\n" - "---------------- ------------------------------------------------------ -------\n"); + printf("Game Full Title \n" + "---------------- ------------------------------------------------------\n"); PluginList::ConstIterator iter = plugins.begin(); for (iter = plugins.begin(); iter != plugins.end(); ++iter) { v = (*iter)->getTargets(); while (v->targetName && v->description) { - config = (g_config->has_domain(v->targetName)) ? "Yes" : ""; +#if 1 + printf("%-17s%-56s\n", v->targetName, v->description); +#else + const char *config = (g_config->has_domain(v->targetName)) ? "Yes" : ""; printf("%-17s%-56s%s\n", v->targetName, v->description, config); +#endif v++; } } } -const TargetSettings *GameDetector::findTarget(const char *targetName, const Plugin **plugin) const { +const TargetSettings *GameDetector::findTarget(const String &targetName, const Plugin **plugin) const { // Find the TargetSettings for this target - assert(targetName); const TargetSettings *target; const PluginList &plugins = g_pluginManager->getPlugins(); PluginList::ConstIterator iter = plugins.begin(); for (iter = plugins.begin(); iter != plugins.end(); ++iter) { - target = (*iter)->findTarget(targetName); + target = (*iter)->findTarget(targetName.c_str()); if (target) { if (plugin) *plugin = *iter; @@ -334,12 +283,15 @@ void GameDetector::parseCommandLine(int argc, char **argv) { char *option = NULL; char c; bool long_option_value; - _save_slot = -1; - _joystick_num = -1; - // Parse the arguments - // into a transient "_COMMAND_LINE" config comain. - g_config->set_domain ("_COMMAND_LINE"); + // Iterate over all comman line arguments, backwards. + // FIXME: Looping backwards has a major problem: Consider this example + // invocation: "scummvm -g 1x". It should work exactly like "scummvm -g1x" + // but it doesn't! Instead of starting the launcher with the 1x sacler + // in effect, it will give an error about target 1x being unknown. + // This can be fixed by forward iterating the args. Of course doing that + // essentially means we have to rewrite the whole command line parser, + // but that seems like a good idea anyway. for (i = argc - 1; i >= 1; i--) { s = argv[i]; @@ -349,20 +301,19 @@ void GameDetector::parseCommandLine(int argc, char **argv) { switch (tolower(c)) { case 'b': HANDLE_OPTION(); - _bootParam = atoi(option); + ConfMan.set("boot_param", (int)strtol(option, 0, 10)); break; case 'c': HANDLE_OPTION(); - _cdrom = atoi(option); - g_config->setInt("cdrom", _cdrom); + ConfMan.set("cdrom", (int)strtol(option, 0, 10)); break; case 'd': _debugMode = true; HANDLE_OPT_OPTION(); if (option != NULL) - _debugLevel = atoi(option); - if (_debugLevel) { - printf("Debuglevel (from command line): %d\n", _debugLevel); + ConfMan.set("debuglevel", (int)strtol(option, 0, 10)); + if (ConfMan.getInt("debuglevel")) { + printf("Debuglevel (from command line): %d\n", ConfMan.getInt("debuglevel")); } else { printf("Debuglevel (from command line): 0 - Engine only\n"); } @@ -373,37 +324,31 @@ void GameDetector::parseCommandLine(int argc, char **argv) { // maybe print a message like: // "'option' is not a supported music driver on this machine. // Available driver: ..." - if (!parseMusicDriver(option)) + if (parseMusicDriver(option) < 0) goto ShowHelpAndExit; - g_config->set("music_driver", option); + ConfMan.set("music_driver", option); break; case 'f': CHECK_OPTION(); - _fullScreen = (c == 'f'); - g_config->setBool("fullscreen", _fullScreen); - g_config->setBool("fullscreen", _fullScreen, "scummvm"); + ConfMan.set("fullscreen", (c == 'f')); break; - case 'g': + case 'g':{ HANDLE_OPTION(); - _gfx_mode = parseGraphicsMode(option); + int _gfx_mode = parseGraphicsMode(option); // TODO: Instead of just showing the generic help text, // maybe print a message like: // "'option' is not a supported graphic mode on this machine. // Available graphic modes: ..." if (_gfx_mode == -1) goto ShowHelpAndExit; - g_config->set("gfx_mode", option); - g_config->set("gfx_mode", option, "scummvm"); - break; + ConfMan.set("gfx_mode", option); + break;} // case 'h': reserved for help case 'j': - _joystick_num = 0; HANDLE_OPT_OPTION(); - if (option != NULL) { - _joystick_num = atoi(option); - g_config->setInt("joystick_num", _joystick_num); - } + ConfMan.set("joystick_num", (option != NULL) ? (int)strtol(option, 0, 10) : 0); break; +/* FIXME / TODO: config rewrite case 'l': HANDLE_OPTION(); { @@ -414,47 +359,43 @@ void GameDetector::parseCommandLine(int argc, char **argv) { break; } break; +*/ case 'm': HANDLE_OPTION(); - _music_volume = atoi(option); - g_config->setInt("music_volume", _music_volume); + ConfMan.set("music_volume", (int)strtol(option, 0, 10)); break; case 'n': CHECK_OPTION(); - _noSubtitles = (c == 'n'); - g_config->setBool("nosubtitles", _noSubtitles ? true : false); + ConfMan.set("nosubtitles", (c == 'n')); break; case 'o': HANDLE_OPTION(); - _master_volume = atoi(option); - g_config->setInt("master_volume", _master_volume); + ConfMan.set("master_volume", (int)strtol(option, 0, 10)); break; case 'p': HANDLE_OPTION(); - _gameDataPath = option; - g_config->set("path", _gameDataPath); + // TODO: Verify path is valid + ConfMan.set("path", option); break; case 'q': HANDLE_OPTION(); - _language = parseLanguage(option); - if (_language == -1) + if (parseLanguage(option) == UNK_LANG) goto ShowHelpAndExit; - g_config->set("language", option); - break; - case 'r': - HANDLE_OPTION(); - // Ignore -r for now, to ensure backward compatibility. + ConfMan.set("language", option); break; case 's': HANDLE_OPTION(); - _sfx_volume = atoi(option); - g_config->setInt("sfx_volume", _sfx_volume); + ConfMan.set("sfx_volume", (int)strtol(option, 0, 10)); break; +#ifndef DISABLE_SCUMM case 't': HANDLE_OPTION(); - _gameTempo = strtol(option, 0, 0); - g_config->set("tempo", option); + // Use the special value '0' for the base in (int)strtol. + // Doing that makes it possible to enter hex values + // as "0x1234", but also decimal values ("123"). + ConfMan.set("tempo", (int)strtol(option, 0, 0)); break; +#endif case 'u': CHECK_OPTION(); _dumpScripts = true; @@ -462,7 +403,9 @@ void GameDetector::parseCommandLine(int argc, char **argv) { case 'v': CHECK_OPTION(); printf("%s\n", gScummVMFullVersion); - exit(1); + exit(0); + break; +/* FIXME / TODO: config rewrite case 'w': _saveconfig = true; g_config->set_writing(true); @@ -470,19 +413,17 @@ void GameDetector::parseCommandLine(int argc, char **argv) { if (option != NULL) g_config->set_filename(option); break; +*/ case 'x': - _save_slot = 0; HANDLE_OPT_OPTION(); - if (option != NULL) { - _save_slot = atoi(option); - g_config->setInt("save_slot", _save_slot); - } + ConfMan.set("save_slot", (option != NULL) ? (int)strtol(option, 0, 10) : 0); break; +#ifndef DISABLE_SCUMM case 'y': HANDLE_OPTION(); - _talkSpeed = atoi(option); - g_config->setInt("talkspeed", _talkSpeed); + ConfMan.set("talkspeed", (int)strtol(option, 0, 10)); break; +#endif case 'z': CHECK_OPTION(); list_games(); @@ -491,16 +432,11 @@ void GameDetector::parseCommandLine(int argc, char **argv) { // Long options. Let the fun begin! if (!strncmp(s, "platform=", 9)) { s += 9; - if (!strcmp (s, "amiga")) - _platform = 1; - else if (!strcmp (s, "atari-st")) - _platform = 2; - else if (!strcmp (s, "macintosh")) - _platform = 3; - else + int platform = parsePlatform(s); + if (platform == kPlatformUnknown) goto ShowHelpAndExit; - g_config->setInt ("platform", _platform); + ConfMan.set("platform", platform); break; } @@ -511,28 +447,21 @@ void GameDetector::parseCommandLine(int argc, char **argv) { long_option_value = true; if (!strcmp (s, "multi-midi")) { - _multi_midi = long_option_value; - g_config->setBool ("multi_midi", _multi_midi); + ConfMan.set("multi_midi", long_option_value); } else if (!strcmp (s, "native-mt32")) { - _native_mt32 = long_option_value; - g_config->setBool ("native_mt32", _native_mt32); + ConfMan.set("native_mt32", long_option_value); } else if (!strcmp (s, "aspect-ratio")) { - _aspectRatio = long_option_value; - g_config->setBool ("aspect_ratio", _aspectRatio); + ConfMan.set("aspect_ratio", long_option_value); } else if (!strcmp (s, "fullscreen")) { - _fullScreen = long_option_value; - g_config->setBool("fullscreen", _fullScreen); - g_config->setBool("fullscreen", _fullScreen, "scummvm"); + ConfMan.set("fullscreen", long_option_value); #ifndef DISABLE_SCUMM } else if (!strcmp (s, "demo-mode")) { - _demo_mode = long_option_value; - g_config->setBool ("demo_mode", _demo_mode); + ConfMan.set("demo_mode", long_option_value); #endif #ifndef DISABLE_SKY } else if (!strcmp (s, "floppy-intro")) { - _floppyIntro = long_option_value; - g_config->setBool ("floppy_intro", _floppyIntro); + ConfMan.set("floppy_intro", long_option_value); #endif } else { goto ShowHelpAndExit; @@ -553,8 +482,10 @@ void GameDetector::parseCommandLine(int argc, char **argv) { } } +/* FIXME / TODO: config rewrite if (!_gameFileName.isEmpty()) - g_config->flush(); + ConfMan.flushToDisk(); +*/ return; @@ -565,29 +496,14 @@ ShowHelpAndExit: void GameDetector::setGame(const String &name) { _gameFileName = name; - g_config->set_domain(name); - g_config->rename_domain(name, "game-specific"); - g_config->rename_domain("game-specific", name); - updateconfig(); - - // The command line and launcher options - // override config file global and game-specific options. - g_config->set_domain("_COMMAND_LINE"); - updateconfig(); - g_config->set_domain("_USER_OVERRIDES"); - updateconfig(); - g_config->delete_domain("_COMMAND_LINE"); - g_config->delete_domain("_USER_OVERRIDES"); - g_config->set_domain(name); - if (_debugMode) - printf("Debuglevel (from config): %d\n", _debugLevel); + ConfMan.setActiveDomain(name); } -int GameDetector::parseGraphicsMode(const char *s) { +int GameDetector::parseGraphicsMode(const String &str) { + const char *s = str.c_str(); const GraphicsMode *gm = gfx_modes; - while(gm->name) { + while (gm->name) { if (!scumm_stricmp(gm->name, s)) { - _default_gfx_mode = false; return gm->id; } gm++; @@ -596,50 +512,65 @@ int GameDetector::parseGraphicsMode(const char *s) { return -1; } -int GameDetector::parseLanguage(const char *s) { - const Language *l = languages; - while(l->name) { +Language GameDetector::parseLanguage(const String &str) { + const char *s = str.c_str(); + const LanguageDescription *l = languages; + while (l->name) { if (!scumm_stricmp(l->name, s)) return l->id; l++; } - return -1; + return UNK_LANG; +} + +Platform GameDetector::parsePlatform(const String &str) { + const char *s = str.c_str(); + if (!scumm_stricmp(s, "pc")) + return kPlatformPC; + else if (!scumm_stricmp(s, "amiga") || !scumm_stricmp(s, "1")) + return kPlatformAmiga; + else if (!scumm_stricmp(s, "atari-st") || !scumm_stricmp(s, "atari") || !scumm_stricmp(s, "2")) + return kPlatformAtariST; + else if (!scumm_stricmp(s, "macintosh") || !scumm_stricmp(s, "mac") || !scumm_stricmp(s, "3")) + return kPlatformMacintosh; + else + return kPlatformUnknown; } -bool GameDetector::parseMusicDriver(const char *s) { +int GameDetector::parseMusicDriver(const String &str) { + const char *s = str.c_str(); const MidiDriverDescription *md = getAvailableMidiDrivers(); while (md->name) { if (!scumm_stricmp(md->name, s)) { - _midi_driver = md->id; - return true; + return md->id; } md++; } - return false; + return -1; } bool GameDetector::detectGame() { const TargetSettings *target; - const char *realGame, *basename; - _gameText.clear(); + String realGame; - realGame = g_config->get("gameid"); - if (!realGame) - realGame = _gameFileName.c_str(); - printf("Looking for %s\n", realGame); + if (ConfMan.hasKey("gameid")) + realGame = ConfMan.get("gameid"); + else + realGame = _gameFileName; + printf("Looking for %s\n", realGame.c_str()); target = findTarget(realGame, &_plugin); if (target) { _game = *target; - if ((basename = g_config->get("basename"))) { + if (ConfMan.hasKey("basename")) { // FIXME: What is this good for? - _game.targetName = basename; + // FIXME: This leaks now! + _game.targetName = strdup(ConfMan.get("basename").c_str()); } - _gameText = _game.description; printf("Trying to start game '%s'\n", _game.description); return true; } else { @@ -648,15 +579,6 @@ bool GameDetector::detectGame() { } } -const Common::String& GameDetector::getGameName() { - if (_gameText.isEmpty()) { - _gameText = "Unknown game: \""; - _gameText += _gameFileName; - _gameText += "\""; - } - return _gameText; -} - bool GameDetector::detectMain() { if (_gameFileName.isEmpty()) { warning("No game was specified..."); @@ -672,7 +594,8 @@ bool GameDetector::detectMain() { * and the game is one of those that want adlib as * default, OR if the game is an older game that doesn't * support anything else anyway. */ - if (_midi_driver == MD_AUTO) { + _midi_driver = parseMusicDriver(ConfMan.get("music_driver")); + if (_midi_driver == MD_AUTO || _midi_driver < 0) { if (_game.midi & MDT_PREFER_NATIVE) _midi_driver = getMidiDriverType(); else @@ -691,21 +614,17 @@ bool GameDetector::detectMain() { if ((_midi_driver == MD_PCSPK || _midi_driver == MD_PCJR) && !(_game.midi & MDT_PCSPK)) _midi_driver = MD_NULL; - if (!_gameDataPath) { + String gameDataPath(ConfMan.get("path")); + if (gameDataPath.isEmpty()) { warning("No path was provided. Assuming the data files are in the current directory"); - _gameDataPath = strdup(""); #ifndef __PALM_OS__ // add last slash also in File::fopenNoCase, so this is not needed - } else if (_gameDataPath[strlen(_gameDataPath)-1] != '/' + } else if (gameDataPath.lastChar() != '/' #ifdef __MORPHOS__ - && _gameDataPath[strlen(_gameDataPath)-1] != ':' + && gameDataPath.lastChar() != ':' #endif - && _gameDataPath[strlen(_gameDataPath)-1] != '\\') { - char slashless[1024]; /* Append slash to path */ - strcpy(slashless, _gameDataPath); - - // need to allocate 2 extra bytes, one for the "/" and one for the NULL terminator - _gameDataPath = (char *)malloc((strlen(slashless) + 2) * sizeof(char)); - sprintf(_gameDataPath, "%s/", slashless); + && gameDataPath.lastChar() != '\\') { + gameDataPath += '/'; + ConfMan.set("path", gameDataPath); #endif } @@ -713,6 +632,8 @@ bool GameDetector::detectMain() { } OSystem *GameDetector::createSystem() { + int _gfx_mode = parseGraphicsMode(ConfMan.get("gfx_mode")); // FIXME: Get rid of this again! + #if defined(USE_NULL_DRIVER) return OSystem_NULL_create(); #elif defined(__DC__) @@ -720,18 +641,18 @@ OSystem *GameDetector::createSystem() { #elif defined(X11_BACKEND) return OSystem_X11_create(); #elif defined(__MORPHOS__) - return OSystem_MorphOS_create(_gfx_mode, _fullScreen); + return OSystem_MorphOS_create(_gfx_mode, ConfMan.getBool("fullscreen")); #elif defined(_WIN32_WCE) return OSystem_WINCE3_create(); #elif defined(MACOS_CARBON) - return OSystem_MAC_create(_gfx_mode, _fullScreen); + return OSystem_MAC_create(_gfx_mode, ConfMan.getBool("fullscreen")); #elif defined(__GP32__) // ph0x return OSystem_GP32_create(GFX_NORMAL, true); #elif defined(__PALM_OS__) //chrilith - return OSystem_PALMOS_create(_gfx_mode, _fullScreen); + return OSystem_PALMOS_create(_gfx_mode, ConfMan.getBool("fullscreen")); #else /* SDL is the default driver for now */ - return OSystem_SDL_create(_gfx_mode, _fullScreen, _aspectRatio, _joystick_num); + return OSystem_SDL_create(_gfx_mode, ConfMan.getBool("fullscreen"), ConfMan.getBool("aspect_ratio"), ConfMan.getBool("joystick_num")); #endif } diff --git a/base/gameDetector.h b/base/gameDetector.h index a78288e437..7f96ecf4e4 100644 --- a/base/gameDetector.h +++ b/base/gameDetector.h @@ -51,7 +51,8 @@ enum { * @note The order and mappings of the values 0..8 are *required* to stay the * way they are now, as scripts in COMI rely on them. So don't touch them. */ -enum { +enum Language { + UNK_LANG = -1, // Use default language (i.e. none specified) EN_USA = 0, DE_DEU = 1, FR_FRA = 2, @@ -66,6 +67,14 @@ enum { HB_HEB = 20 }; +enum Platform { + kPlatformUnknown = -1, + kPlatformPC = 0, + kPlatformAmiga = 1, + kPlatformAtariST = 2, + kPlatformMacintosh = 3 +}; + enum MidiDriverType { MDT_NONE = 0, MDT_PCSPK = 1, // MD_PCSPK and MD_PCJR @@ -92,69 +101,36 @@ public: void parseCommandLine(int argc, char **argv); bool detectMain(); - void setGame(const String &name); - const String& getGameName(void); String _gameFileName; TargetSettings _game; const Plugin *_plugin; - bool _fullScreen; - bool _aspectRatio; - - int _master_volume; - int _music_volume; - int _sfx_volume; - bool _amiga; - int _platform; - int _language; - - bool _demo_mode; - bool _floppyIntro; - - uint16 _talkSpeed; - uint16 _debugMode; - uint16 _debugLevel; + bool _debugMode; bool _dumpScripts; - bool _noSubtitles; - uint16 _bootParam; + bool _saveconfig; - char *_gameDataPath; - int _gameTempo; int _midi_driver; - int _gfx_mode; - bool _default_gfx_mode; - - bool _multi_midi; - bool _native_mt32; - - int _cdrom; - int _joystick_num; - int _save_slot; - - bool _saveconfig; - bool _confirmExit; - public: OSystem *createSystem(); Engine *createEngine(OSystem *system); SoundMixer *createMixer(); MidiDriver *createMidi(); - int getMidiDriverType(); + int getMidiDriverType(); // FIXME: Try to get rid of this, only Sky frontend uses it - int parseGraphicsMode(const char *s); - void updateconfig(); + void setGame(const String &name); + + static int parseGraphicsMode(const String &s); // Used in main() + static int parseMusicDriver(const String &s); + static Language parseLanguage(const String &s); + static Platform parsePlatform(const String &s); - const TargetSettings *findTarget(const char *targetName, const Plugin **plugin = NULL) const; + const TargetSettings *findTarget(const String &targetName, const Plugin **plugin = NULL) const; protected: - String _gameText; - bool detectGame(void); - bool parseMusicDriver(const char *s); - int parseLanguage(const char *s); void list_games(); }; diff --git a/base/main.cpp b/base/main.cpp index 98fd8413f5..1ebd405899 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -32,7 +32,7 @@ #include "base/engine.h" #include "base/gameDetector.h" #include "base/plugins.h" -#include "common/config-file.h" +#include "common/config-manager.h" #include "common/scaler.h" // For GFX_NORMAL #include "common/timer.h" #include "gui/newgui.h" @@ -83,7 +83,6 @@ const char *gScummVMBuildDate = __DATE__ " " __TIME__; const char *gScummVMFullVersion = "ScummVM 0.5.4cvs (" __DATE__ " " __TIME__ ")"; -Config *g_config = 0; NewGui *g_gui = 0; OSystem *g_system = 0; @@ -109,20 +108,6 @@ extern "C" int main(int argc, char *argv[]); #endif #if defined(UNIX) -#include <sys/param.h> -#ifndef MAXPATHLEN -#define MAXPATHLEN 256 -#endif -#ifdef MACOSX -#define DEFAULT_CONFIG_FILE "Library/Preferences/ScummVM Preferences" -#else -#define DEFAULT_CONFIG_FILE ".scummvmrc" -#endif -#else -#define DEFAULT_CONFIG_FILE "scummvm.ini" -#endif - -#if defined(UNIX) #include <signal.h> #ifndef SCUMM_NEED_ALIGNMENT @@ -211,23 +196,6 @@ int main(int argc, char *argv[]) { #if defined(UNIX) /* On Unix, do a quick endian / alignement check before starting */ do_memory_test(); - - char scummhome[MAXPATHLEN]; - if(getenv("HOME") != NULL) - sprintf(scummhome,"%s/%s", getenv("HOME"), DEFAULT_CONFIG_FILE); - else strcpy(scummhome,DEFAULT_CONFIG_FILE); -#else - char scummhome[256]; - #if defined (WIN32) && !defined(_WIN32_WCE) - GetWindowsDirectory(scummhome, 256); - strcat(scummhome, "\\"); - strcat(scummhome, DEFAULT_CONFIG_FILE); - #elif defined(__PALM_OS__) - strcpy(scummhome,"/PALM/Programs/ScummVM/"); - strcat(scummhome, DEFAULT_CONFIG_FILE); - #else - strcpy(scummhome, DEFAULT_CONFIG_FILE); - #endif #endif // Code copied from SDL_main @@ -265,9 +233,8 @@ int main(int argc, char *argv[]) { #endif //defined(WIN32) && defined(USE_CONSOLE) - // Read the config file - g_config = new Config(scummhome, "scummvm"); - g_config->set("versioninfo", gScummVMVersion); + // Update the config file + ConfMan.set("versioninfo", gScummVMVersion, "scummvm"); // Load the plugins g_pluginManager = new PluginManager(); @@ -276,7 +243,6 @@ int main(int argc, char *argv[]) { // Parse the command line information GameDetector detector; detector._saveconfig = false; - detector.updateconfig(); detector.parseCommandLine(argc, argv); // Create the system object @@ -301,30 +267,30 @@ int main(int argc, char *argv[]) { if (detector.detectMain()) { // Set the window caption to the game name - prop.caption = g_config->get("description", detector._gameFileName); + prop.caption = ConfMan.get("description", detector._gameFileName).c_str(); if (prop.caption == NULL) - prop.caption = detector.getGameName().c_str(); - system->property(OSystem::PROP_SET_WINDOW_CAPTION, &prop); + prop.caption = detector._gameFileName.c_str(); + if (prop.caption != NULL) + system->property(OSystem::PROP_SET_WINDOW_CAPTION, &prop); // FIXME: It seem not logical that we first might set the gfx mode to // 1x, and then immediately after might override it again. We probably // should combine both checks into one. // See if the game should default to 1x scaler - if ((detector._default_gfx_mode) && + if (!ConfMan.hasKey("gfx_mode", detector._gameFileName) && (detector._game.features & GF_DEFAULT_TO_1X_SCALER)) { prop.gfx_mode = GFX_NORMAL; system->property(OSystem::PROP_SET_GFX_MODE, &prop); - } - + } else // Override global scaler with any game-specific define - if (g_config->get("gfx_mode")) { - prop.gfx_mode = detector.parseGraphicsMode(g_config->get("gfx_mode")); + if (ConfMan.hasKey("gfx_mode")) { + prop.gfx_mode = detector.parseGraphicsMode(ConfMan.get("gfx_mode")); system->property(OSystem::PROP_SET_GFX_MODE, &prop); } // Override global fullscreen setting with any game-specific define - if (g_config->getBool("fullscreen", false)) { + if (ConfMan.getBool("fullscreen")) { if (!system->property(OSystem::PROP_GET_FULLSCREEN, 0)) system->property(OSystem::PROP_TOGGLE_FULLSCREEN, 0); } @@ -344,7 +310,6 @@ int main(int argc, char *argv[]) { } delete g_gui; - delete g_config; // ...and quit (the return 0 should never be reached) system->quit(); diff --git a/common/config-file.cpp b/common/config-file.cpp deleted file mode 100644 index 4b66e70981..0000000000 --- a/common/config-file.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2003 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - * - */ - -#include "stdafx.h" -#include "common/config-file.h" -#include "base/engine.h" // for debug() - -#define MAXLINELEN 256 - -static char *ltrim(char *t) { - while (*t == ' ') - t++; - return t; -} - -static char *rtrim(char *t) { - int l = strlen(t) - 1; - while (l >= 0 && t[l] == ' ') - t[l--] = 0; - return t; -} - -// The config-class itself. - -Config::Config (const String &cfg, const String &d) - : filename(cfg), defaultDomain(d), willwrite(false) { - FILE *cfg_file; - char t[MAXLINELEN]; - - if (!(cfg_file = fopen(filename.c_str(), "r"))) { - debug(1, "Unable to open configuration file: %s.\n", filename.c_str()); - } else { - while (!feof(cfg_file)) { - if (!fgets(t, MAXLINELEN, cfg_file)) - continue; - if (t[0] != '#') { - if (t[0] == '[') { - // It's a new domain which begins here. - char *p = strchr(t, ']'); - if (!p) { - debug(1, "Config file buggy: no ] at the end of the domain name.\n"); - } else { - *p = 0; - set_domain(t + 1); - } - } else { - // It's a new key in the domain. - if (defaultDomain.isEmpty()) { - debug(1, "Config file buggy: we have a key without a domain first.\n"); - } - char *p = strchr(t, '\n'); - if (p) - *p = 0; - p = strchr(t, '\r'); - if (p) - *p = 0; - - if (!(p = strchr(t, '='))) { - if (strlen(t)) - debug(1, "Config file buggy: there is junk: %s\n", t); - } else { - char *key, *value; - *p = 0; - key = ltrim(rtrim(t)); - value = ltrim(p + 1); - set(key, value); - } - } - } - } - set_domain(d); - fclose(cfg_file); - } -} - -const char *Config::get(const String &key, const String &d) const { - String domain; - - if (d.isEmpty()) - domain = defaultDomain; - else - domain = d; - - domain.toLowercase(); - if (domains.contains(domain) && domains[domain].contains(key)) - return domains[domain][key].c_str(); - - return 0; -} - -const int Config::getInt(const String &key, int def, const String &d) const { - const char *value = get(key, d); - - if (value) - return atoi(value); - return def; -} - -const bool Config::getBool(const String &key, bool def, const String &d) const { - const char *value = get(key, d); - - if (value) - return !scumm_stricmp(value, "true"); - return def; -} - -void Config::set(const String &key, const String &value, const String &d) { - String domain(d); - - if (domain.isEmpty()) - domain = defaultDomain; - - domain.toLowercase(); - domains[domain][key] = value; -} - -void Config::setInt(const String &key, int value_i, const String &d) { - char value[MAXLINELEN]; - sprintf(value, "%i", value_i); - set(key, String(value), d); -} - -void Config::setBool(const String &key, bool value_b, const String &d) { - String value(value_b ? "true" : "false"); - set(key, value, d); -} - -void Config::set_domain(const String &d) { - defaultDomain = d; - defaultDomain.toLowercase(); -} - -bool Config::has_domain(const String &d) const { - String temp(d); - temp.toLowercase(); - return domains.contains(temp); -} - -void Config::flush() const { - FILE *cfg_file; - - if (!willwrite) - return; - - if (!(cfg_file = fopen(filename.c_str(), "w"))) { - debug(1, "Unable to write configuration file: %s.\n", filename.c_str()); - } else { - DomainMap::ConstIterator d; - for (d = domains.begin(); d != domains.end(); ++d) { - fprintf(cfg_file, "[%s]\n", d->_key.c_str()); - - const StringMap &data = d->_value; - StringMap::ConstIterator x; - for (x = data.begin(); x != data.end(); ++x) { - const String &value = x->_value; - if (!value.isEmpty()) - fprintf(cfg_file, "%s=%s\n", x->_key.c_str(), value.c_str()); - } - fprintf(cfg_file, "\n"); - } - fclose(cfg_file); - } -} - -void Config::rename_domain(const String &oldD, const String &newD) { - String oldDomain(oldD); - String newDomain(newD); - oldDomain.toLowercase(); - newDomain.toLowercase(); - - if (oldDomain == newDomain) - return; - - StringMap &oldHash = domains[oldDomain]; - StringMap &newHash = domains[newDomain]; - - newHash.merge(oldHash); - - domains.remove(oldDomain); -} - -void Config::delete_domain(const String &d) { - String domain(d); - domain.toLowercase(); - domains.remove(d); -} - -void Config::set_filename(const String &f) { - filename = f; -} - -void Config::merge_config(const Config &c) { - DomainMap::ConstIterator d, end(c.domains.end()); - for (d = c.domains.begin(); d != end; ++d) { - domains[d->_key].merge(d->_value); - } -} - -void Config::set_writing(bool w) { - willwrite = w; -} - -const int Config::count_domains() { - int count = 0; - DomainMap::ConstIterator d, end(domains.end()); - for (d = domains.begin(); d != end; ++d) - count++; - - return count; -} - -Common::StringList Config::get_domains() { - StringList domainNames; - DomainMap::ConstIterator d, end(domains.end()); - for (d = domains.begin(); d != end; ++d) { - domainNames.push_back(d->_key); - } - - return domainNames; -} - diff --git a/common/config-file.h b/common/config-file.h deleted file mode 100644 index bfec3e8465..0000000000 --- a/common/config-file.h +++ /dev/null @@ -1,70 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001 Ludvig Strigeus - * Copyright (C) 2001-2003 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - * - */ - -#ifndef CONFIG_FILE_H -#define CONFIG_FILE_H - -#include "common/list.h" -#include "common/map.h" -#include "common/str.h" -#include "common/util.h" - -class Config { -public: - typedef Common::String String; - typedef Common::StringList StringList; - typedef Common::StringMap StringMap; - typedef Common::Map<String, StringMap> DomainMap; - - Config (const String & = String("config.cfg"), const String & = String("default")); - const char *get(const String &key, const String &dom = String()) const; - const int getInt(const String &key, int def = 0, const String &dom = String()) const; - const bool getBool(const String &key, bool def = false, const String &dom = String()) const; - - void set(const String &key, const String &value, const String &dom = String()); - void setInt(const String &key, int value, const String &dom = String()); - void setBool(const String &key, bool value, const String &dom = String()); - - void set_domain(const String &d); - void flush() const; - void rename_domain(const String &oldD, const String &newD); - void delete_domain(const String &d); - bool has_domain(const String &d) const; - void set_filename(const String &); - void merge_config(const Config &); - void set_writing(bool); - - const int count_domains(); - StringList get_domains(); - -protected: - DomainMap domains; - String filename; - String defaultDomain; - - bool willwrite; -}; - -// The global config object -extern Config *g_config; - -#endif diff --git a/common/config-manager.cpp b/common/config-manager.cpp new file mode 100644 index 0000000000..f90eefbbd3 --- /dev/null +++ b/common/config-manager.cpp @@ -0,0 +1,370 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "common/config-manager.h" + +#if defined(UNIX) +#include <sys/param.h> +#ifndef MAXPATHLEN +#define MAXPATHLEN 256 +#endif +#ifdef MACOSX +#define DEFAULT_CONFIG_FILE "Library/Preferences/ScummVM Preferences" +#else +#define DEFAULT_CONFIG_FILE ".scummvmrc" +#endif +#else +#define DEFAULT_CONFIG_FILE "scummvm.ini" +#endif + +#define MAXLINELEN 256 + +static char *ltrim(char *t) { + while (*t == ' ') + t++; + return t; +} + +static char *rtrim(char *t) { + int l = strlen(t) - 1; + while (l >= 0 && t[l] == ' ') + t[l--] = 0; + return t; +} + + +namespace Common { + +const String ConfigManager::kApplicationDomain("scummvm"); + +const String trueStr("true"); +const String falseStr("false"); + + +#pragma mark - + + +ConfigManager::ConfigManager() { + +#if defined(UNIX) + char configFile[MAXPATHLEN]; + if(getenv("HOME") != NULL) + sprintf(configFile,"%s/%s", getenv("HOME"), DEFAULT_CONFIG_FILE); + else strcpy(configFile,DEFAULT_CONFIG_FILE); +#else + char configFile[256]; + #if defined (WIN32) && !defined(_WIN32_WCE) + GetWindowsDirectory(configFile, 256); + strcat(configFile, "\\"); + strcat(configFile, DEFAULT_CONFIG_FILE); + #elif defined(__PALM_OS__) + strcpy(configFile,"/PALM/Programs/ScummVM/"); + strcat(configFile, DEFAULT_CONFIG_FILE); + #else + strcpy(configFile, DEFAULT_CONFIG_FILE); + #endif +#endif + + // Ensure the global domain(s) are setup. + _globalDomains.addKey(kApplicationDomain); +#ifdef _WIN32_WCE + // WinCE for some reasons uses additional global domains. + _globalDomains.addKey("wince"); + _globalDomains.addKey("smartfon-keys"); +#endif + + _filename = configFile; + loadFile(_filename); +} + +void ConfigManager::loadFile(const String &filename) { + FILE *cfg_file; + char t[MAXLINELEN]; + String domain; + + if (!(cfg_file = fopen(filename.c_str(), "r"))) { + debug(1, "Unable to open configuration file: %s.\n", filename.c_str()); + } else { + while (!feof(cfg_file)) { + if (!fgets(t, MAXLINELEN, cfg_file)) + continue; + if (t[0] != '#') { + if (t[0] == '[') { + // It's a new domain which begins here. + char *p = strchr(t, ']'); + if (!p) { + error("Config file buggy: no ] at the end of the domain name.\n"); + } else { + *p = 0; + // TODO: Some kind of domain name verification might be nice. + // E.g. restrict to only a-zA-Z0-9 and maybe -_ or so... + domain = t + 1; + } + } else { + // It's a new key in the domain. + if (domain.isEmpty()) { + error("Config file buggy: we have a key without a domain first.\n"); + } + char *p = strchr(t, '\n'); + if (p) + *p = 0; + p = strchr(t, '\r'); + if (p) + *p = 0; + + if (!(p = strchr(t, '='))) { + if (strlen(t)) + warning("Config file buggy: there is junk: %s\n", t); + } else { + *p = 0; + String key = ltrim(rtrim(t)); + String value = ltrim(p + 1); + set(key, value, domain); + } + } + } + } + fclose(cfg_file); + } +} + +void ConfigManager::flushToDisk() { + FILE *cfg_file; + +// TODO +// if (!willwrite) +// return; + + if (!(cfg_file = fopen(_filename.c_str(), "w"))) { + warning("Unable to write configuration file: %s.\n", _filename.c_str()); + } else { + DomainMap::ConstIterator d; + + // First write the global domains + for (d = _globalDomains.begin(); d != _globalDomains.end(); ++d) { + writeDomain(cfg_file, d->_key, d->_value); + } + + // Second, write the game domains + for (d = _gameDomains.begin(); d != _gameDomains.end(); ++d) { + writeDomain(cfg_file, d->_key, d->_value); + } + + fclose(cfg_file); + } +} + +void ConfigManager::writeDomain(FILE *file, const String &name, const Domain &domain) { + if (domain.isEmpty()) + return; // Don't bother writing empty domains. + + fprintf(file, "[%s]\n", name.c_str()); + + StringMap::ConstIterator x; + for (x = domain.begin(); x != domain.end(); ++x) { + const String &value = x->_value; + if (!value.isEmpty()) + fprintf(file, "%s=%s\n", x->_key.c_str(), value.c_str()); + } + fprintf(file, "\n"); +} + +#pragma mark - + + +bool ConfigManager::hasKey(const String &key) const { + // Search the domains in the following order: + // 1) Run time domain + // 2) Active game domain (if any) + // 3) All global domains + // The defaults domain is explicitly *not* checked. + +// if (_runtimeDomain.contain(key)) +// return true; + + if (!_activeDomain.isEmpty() && _gameDomains[_activeDomain].contains(key)) + return true; + + DomainMap::ConstIterator iter; + for (iter = _globalDomains.begin(); iter != _globalDomains.end(); ++iter) { + if (iter->_value.contains(key)) + return true; + } + + return false; +} + + +bool ConfigManager::hasKey(const String &key, const String &dom) const { + assert(!dom.isEmpty()); + + if (_gameDomains.contains(dom)) + return _gameDomains[dom].contains(key); + if (_globalDomains.contains(dom)) + return _globalDomains[dom].contains(key); + + return false; +} + + +#pragma mark - + + +const String & ConfigManager::get(const String &key) const { + // Search the domains in the following order: + // 1) Run time domain + // 2) Active game domain (if any) + // 3) All global domains + // 4) The defaults + +// if (_runtimeDomain.contain(key)) +// return true; + + if (!_activeDomain.isEmpty() && _gameDomains[_activeDomain].contains(key)) + return _gameDomains[_activeDomain][key]; + + DomainMap::ConstIterator iter; + for (iter = _globalDomains.begin(); iter != _globalDomains.end(); ++iter) { + if (iter->_value.contains(key)) + return iter->_value[key]; + } + + return _defaultsDomain.get(key); +} + +const String & ConfigManager::get(const String &key, const String &dom) const { + if (dom.isEmpty()) + return get(key); + + // TODO: How exactly should we handle the case were the domain 'dom' + // is not found, or were dom is found, but doesn't contain 'key' ? + // Right now we just return an empty string. But might want to print + // out a warning, or even error out? + if (_gameDomains.contains(dom)) + return _gameDomains[dom].get(key); + if (_globalDomains.contains(dom)) + return _globalDomains[dom].get(key); + + return String::emptyString; +} + +int ConfigManager::getInt(const String &key, const String &dom) const { + String value(get(key, dom)); + // Convert the string to an integer. + // TODO: We should perform some error checking. + long v = strtol(value.c_str(), 0, 10); + return (int)v; +} + +bool ConfigManager::getBool(const String &key, const String &dom) const { + String value(get(key, dom)); + // '1', 'true' and 'yes' are accepted as true values; everything else + // maps to value 'false'. + return (value == "true") || (value == "yes") || (value == "1"); +} + + +#pragma mark - + + +void ConfigManager::set(const String &key, const String &value) { +#if 0 + // TODO ?!? +// _runtimeDomain[key] = value; +#else + if (_activeDomain.isEmpty()) + _globalDomains[kApplicationDomain][key] = value; + else + _gameDomains[_activeDomain][key] = value; +#endif +} + +void ConfigManager::set(const String &key, const String &value, const String &dom) { + if (_globalDomains.contains(dom)) + _globalDomains[dom][key] = value; + else + _gameDomains[dom][key] = value; +} + +void ConfigManager::set(const String &key, const char *value, const String &dom) { + set(key, String(value), dom); +} + +void ConfigManager::set(const String &key, int value, const String &dom) { + char tmp[128]; + snprintf(tmp, sizeof(tmp), "%i", value); + set(key, String(tmp), dom); +} + +void ConfigManager::set(const String &key, bool value, const String &dom) { + set(key, value ? trueStr : falseStr, dom); +} + + +#pragma mark - + + +void ConfigManager::registerDefault(const String &key, const String &value) { + _defaultsDomain[key] = value; +} + +void ConfigManager::registerDefault(const String &key, const char *value) { + registerDefault(key, String(value)); +} + +void ConfigManager::registerDefault(const String &key, int value) { + char tmp[128]; + snprintf(tmp, sizeof(tmp), "%i", value); + registerDefault(key, tmp); +} + +void ConfigManager::registerDefault(const String &key, bool value) { + registerDefault(key, value ? trueStr : falseStr); +} + + +#pragma mark - + + +void ConfigManager::setActiveDomain(const String &domain) { + _activeDomain = domain; + _gameDomains.addKey(domain); +} + +void ConfigManager::removeGameDomain(const String &name) { + _gameDomains.remove(name); +} + +void ConfigManager::renameGameDomain(const String &oldName, const String &newName) { + if (oldName == newName) + return; + + _gameDomains[newName].merge(_gameDomains[oldName]); + + _gameDomains.remove(oldName); +} + +bool ConfigManager::hasGameDomain(const String &domain) const { + return _gameDomains.contains(domain); +} + +} // End of namespace Common diff --git a/common/config-manager.h b/common/config-manager.h new file mode 100644 index 0000000000..d4d368e761 --- /dev/null +++ b/common/config-manager.h @@ -0,0 +1,127 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef COMMON_CONFIG_H +#define COMMON_CONFIG_H + +#include "common/list.h" +#include "common/map.h" +#include "common/singleton.h" +#include "common/str.h" +#include "common/util.h" + +namespace Common { + +class File; + + +/** + * The (singleton) configuration manager, used to query & set configuration + * values using string keys. + * + * @todo Implement the callback based notification system (outline below) + * which sends out notifications to interested parties whenever the value + * of some specific (or any) configuration key changes. + */ +class ConfigManager : public Singleton<ConfigManager> { +public: + class Domain : public StringMap { +// friend class ConfigManager; + public: + const String &get(const String &key) const { + Node *node = findNode(_root, key); + return node ? node->_value : String::emptyString; + } +/* + void set(const String &key, const String &value); + void set(const String &key, int value); + void set(const String &key, bool value); +*/ + }; + + typedef Map<String, Domain> DomainMap; + + /** The name of the application domain (normally 'scummvm'). */ + static const String kApplicationDomain; + + bool hasKey(const String &key) const; + bool hasKey(const String &key, const String &dom) const; + + const String & get(const String &key) const; + const String & get(const String &key, const String &dom) const; + int getInt(const String &key, const String &dom = String::emptyString) const; + bool getBool(const String &key, const String &dom = String::emptyString) const; + + void set(const String &key, const String &value); + void set(const String &key, const String &value, const String &dom); + void set(const String &key, const char *value, const String &dom = String::emptyString); + void set(const String &key, int value, const String &dom = String::emptyString); + void set(const String &key, bool value, const String &dom = String::emptyString); + + void registerDefault(const String &key, const String &value); + void registerDefault(const String &key, const char *value); + void registerDefault(const String &key, int value); + void registerDefault(const String &key, bool value); +// ... + + void flushToDisk(); + + void setActiveDomain(const String &domain); + +// void addDomain(const String &name); + void removeGameDomain(const String &name); + void renameGameDomain(const String &oldName, const String &newName); + bool hasGameDomain(const String &domain) const; + const DomainMap & getGameDomains() const { return _gameDomains; } + +/* + TODO: Callback/change notification system + typedef void (*ConfigCallback)(const ConstString &key, void *refCon); + + void registerCallback(const ConstString &key, ConfigCallback cfgc, void *refCon) + void unregisterCallback(const ConstString &key, ConfigCallback cfgc) +*/ + +private: + friend class Singleton<ConfigManager>; + ConfigManager(); + + void loadFile(const String &filename); + void writeDomain(FILE *file, const String &name, const Domain &domain); + +// Domain _runtimeDomain; + DomainMap _gameDomains; + DomainMap _globalDomains; + Domain _defaultsDomain; + + List<Domain *> _searchOrder; + + String _activeDomain; + String _filename; +}; + +} // End of namespace Common + +/** Shortcut for accessing the configuration manager. */ +#define ConfMan Common::ConfigManager::instance() + +#endif diff --git a/common/module.mk b/common/module.mk index 4bb6e6e1e5..b55428edab 100644 --- a/common/module.mk +++ b/common/module.mk @@ -1,7 +1,7 @@ MODULE := common MODULE_OBJS := \ - common/config-file.o \ + common/config-manager.o \ common/file.o \ common/scaler.o \ common/str.o \ diff --git a/common/singleton.h b/common/singleton.h new file mode 100644 index 0000000000..be40b45f42 --- /dev/null +++ b/common/singleton.h @@ -0,0 +1,57 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef COMMON_SINGLETON_H +#define COMMON_SINGLETON_H + +namespace Common { + +/** + * Generic template base class for implementing the singleton design pattern. + */ +template <class T> +class Singleton +{ +public: + static T& instance() { + // TODO: We aren't thread safe. For now we ignore it since the + // only thing using this singleton template is the config manager, + // and that is first instantiated long before any threads. + // TODO: We don't leak, but the destruction order is nevertheless + // semi-random. If we use multiple singletons, the destruction + // order might become an issue. There are various approaches + // to solve that problem, but for now this is sufficient + static T singleton; + return singleton; + } +protected: + Singleton<T>() { } + ~Singleton<T>() { } + +private: + Singleton(const Singleton&); + Singleton& operator= (const Singleton&); +}; + +} // End of namespace Common + +#endif diff --git a/gui/launcher.cpp b/gui/launcher.cpp index 91866a8ad0..743e37bb09 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -32,11 +32,13 @@ #include "backends/fs/fs.h" +#include "base/engine.h" #include "base/gameDetector.h" #include "base/plugins.h" -#include "common/config-file.h" -#include "base/engine.h" +#include "common/config-manager.h" + +using Common::ConfigManager; enum { kStartCmd = 'STRT', @@ -83,7 +85,6 @@ public: virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); protected: - Config &_config; const String &_domain; EditTextWidget *_descriptionWidget; EditTextWidget *_domainWidget; @@ -92,10 +93,11 @@ protected: }; EditGameDialog::EditGameDialog(NewGui *gui, const String &domain, const TargetSettings *target) - : Dialog(gui, 8, 50, 320 - 2 * 8, 200 - 2 * 40), _config(*g_config), _domain(domain) { + : Dialog(gui, 8, 50, 320 - 2 * 8, 200 - 2 * 40), + _domain(domain) { // Determine the description string - String description(_config.get("description", _domain)); + String description(ConfMan.get("description", domain)); if (description.isEmpty()) { description = target->description; } @@ -116,18 +118,18 @@ EditGameDialog::EditGameDialog(NewGui *gui, const String &domain, const TargetSe new EditTextWidget(this, 50, 26, _w - 50 - 10, kLineHeight, description); // Path to game data (view only) - String path(_config.get("path", _domain)); + String path(ConfMan.get("path", _domain)); new StaticTextWidget(this, 10, 42, 40, kLineHeight, "Path: ", kTextAlignRight); new StaticTextWidget(this, 50, 42, _w - 50 - 10, kLineHeight, path, kTextAlignLeft); // Full screen checkbox _fullscreenCheckbox = new CheckboxWidget(this, 15, 62, 200, 16, "Use Fullscreen Mode", 0, 'F'); - _fullscreenCheckbox->setState(_config.getBool("fullscreen", false, _domain)); + _fullscreenCheckbox->setState(ConfMan.getBool("fullscreen", _domain)); // Display 'Amiga' checkbox, but only for Scumm games. if (isScumm) { _amigaCheckbox = new CheckboxWidget(this, 15, 82, 200, 16, "Amiga Version", 0, 'A'); - _amigaCheckbox->setState(_config.getBool("amiga", false, _domain)); + _amigaCheckbox->setState(ConfMan.getBool("amiga", _domain)); } else { _amigaCheckbox = 0; } @@ -142,17 +144,17 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat // Write back changes made to config object String newDomain(_domainWidget->getLabel()); if (newDomain != _domain) { - if (newDomain.isEmpty() || _config.has_domain(newDomain)) { + if (newDomain.isEmpty() || ConfMan.hasGameDomain(newDomain)) { MessageDialog alert(_gui, "This game ID is already taken. Please choose another one."); alert.runModal(); return; } - _config.rename_domain(_domain, newDomain); + ConfMan.renameGameDomain(_domain, newDomain); } - _config.set("description", _descriptionWidget->getLabel(), newDomain); + ConfMan.set("description", _descriptionWidget->getLabel(), newDomain); if (_amigaCheckbox) - _config.setBool("amiga", _amigaCheckbox->getState(), newDomain); - _config.setBool("fullscreen", _fullscreenCheckbox->getState(), newDomain); + ConfMan.set("amiga", _amigaCheckbox->getState(), newDomain); + ConfMan.set("fullscreen", _fullscreenCheckbox->getState(), newDomain); setResult(1); close(); } else { @@ -218,12 +220,16 @@ LauncherDialog::~LauncherDialog() { void LauncherDialog::open() { Dialog::open(); +/* FIXME / TODO: config rewrite g_config->set_writing(true); +*/ } void LauncherDialog::close() { - g_config->flush(); + ConfMan.flushToDisk(); +/* FIXME / TODO: config rewrite g_config->set_writing(false); +*/ Dialog::close(); } @@ -232,16 +238,16 @@ void LauncherDialog::updateListing() { // Retrieve a list of all games defined in the config file _domains.clear(); - StringList domains = g_config->get_domains(); - StringList::ConstIterator iter = domains.begin(); + const ConfigManager::DomainMap &domains = ConfMan.getGameDomains(); + ConfigManager::DomainMap::ConstIterator iter = domains.begin(); for (iter = domains.begin(); iter != domains.end(); ++iter) { - String name(g_config->get("gameid", *iter)); - String description(g_config->get("description", *iter)); + String name(iter->_value.get("gameid")); + String description(iter->_value.get("description")); if (name.isEmpty()) - name = *iter; + name = iter->_key; if (description.isEmpty()) { - const TargetSettings *v = _detector.findTarget(name.c_str()); + const TargetSettings *v = _detector.findTarget(name); if (v && v->description) description = v->description; } @@ -253,7 +259,7 @@ void LauncherDialog::updateListing() { while (pos < size && (description > l[pos])) pos++; l.insert_at(pos, description); - _domains.insert_at(pos, *iter); + _domains.insert_at(pos, iter->_key); } } @@ -372,18 +378,18 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat // Pick a domain name which does not yet exist (after all, we // are *adding* a game to the config, not replacing). String domain(v->targetName); - if (g_config->has_domain(domain)) { + if (ConfMan.hasGameDomain(domain)) { char suffix = 'a'; domain += suffix; - while (g_config->has_domain(domain)) { + while (ConfMan.hasGameDomain(domain)) { domain.deleteLastChar(); suffix++; domain += suffix; } - g_config->set("gameid", v->targetName, domain); - g_config->set("description", v->description, domain); + ConfMan.set("gameid", v->targetName, domain); + ConfMan.set("description", v->description, domain); } - g_config->set("path", dir->path(), domain); + ConfMan.set("path", dir->path(), domain); // Display edit dialog for the new entry EditGameDialog editDialog(_gui, domain, v); @@ -391,14 +397,14 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat // User pressed OK, so make changes permanent // Write config to disk - g_config->flush(); + ConfMan.flushToDisk(); // Update the ListWidget and force a redraw updateListing(); draw(); } else { // User aborted, remove the the new domain again - g_config->delete_domain(domain); + ConfMan.removeGameDomain(domain); } } } @@ -406,10 +412,10 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat case kRemoveGameCmd: // Remove the currently selected game from the list assert(item >= 0); - g_config->delete_domain(_domains[item]); + ConfMan.removeGameDomain(_domains[item]); // Write config to disk - g_config->flush(); + ConfMan.flushToDisk(); // Update the ListWidget and force a redraw updateListing(); @@ -423,15 +429,15 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat // This is useful because e.g. MonkeyVGA needs Adlib music to have decent // music support etc. assert(item >= 0); - const char *gameId = g_config->get("gameid", _domains[item]); - if (!gameId) - gameId = _domains[item].c_str(); + String gameId(ConfMan.get("gameid", _domains[item])); + if (gameId.isEmpty()) + gameId = _domains[item]; EditGameDialog editDialog(_gui, _domains[item], _detector.findTarget(gameId)); if (editDialog.runModal()) { // User pressed OK, so make changes permanent // Write config to disk - g_config->flush(); + ConfMan.flushToDisk(); // Update the ListWidget and force a redraw updateListing(); diff --git a/gui/options.cpp b/gui/options.cpp index 0e3bc0ea73..475e478ce5 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -27,7 +27,7 @@ #include "backends/fs/fs.h" #include "base/gameDetector.h" -#include "common/config-file.h" +#include "common/config-manager.h" #include "sound/mididrv.h" #if (!( defined(__DC__) || defined(__GP32__)) && !defined(_MSC_VER)) @@ -61,7 +61,7 @@ enum { }; GlobalOptionsDialog::GlobalOptionsDialog(NewGui *gui, GameDetector &detector) - : Dialog(gui, 10, 15, 320 - 2 * 10, 200 - 2 * 15), _detector(detector) { + : Dialog(gui, 10, 15, 320 - 2 * 10, 200 - 2 * 15) { // The GFX mode popup & a label // TODO - add an API to query the list of available GFX modes, and to get/set the mode new StaticTextWidget(this, 5, 10+1, 100, kLineHeight, "Graphics mode: ", kTextAlignRight); @@ -94,7 +94,7 @@ GlobalOptionsDialog::GlobalOptionsDialog(NewGui *gui, GameDetector &detector) const MidiDriverDescription *md = getAvailableMidiDrivers(); while (md->name) { _midiPopUp->appendEntry(md->description, md->id); - if (md->id == _detector._midi_driver) + if (md->id == detector._midi_driver) midiSelected = i; i++; md++; @@ -134,10 +134,9 @@ GlobalOptionsDialog::GlobalOptionsDialog(NewGui *gui, GameDetector &detector) _savePath = new StaticTextWidget(this, 105, 106, 180, kLineHeight, "/foo/bar", kTextAlignLeft); new ButtonWidget(this, 105, 120, 64, 16, "Choose...", kChooseSaveDirCmd, 0); -// TODO: set _savePath to the current save path, i.e. as obtained via - const char *dir = NULL; - dir = g_config->get("savepath", "scummvm"); - if (dir) { +// TODO: set _savePath to the current save path + Common::String dir(ConfMan.get("savepath")); + if (!dir.isEmpty()) { _savePath->setLabel(dir); } else { // Default to the current directory... @@ -164,9 +163,9 @@ GlobalOptionsDialog::~GlobalOptionsDialog() { void GlobalOptionsDialog::open() { Dialog::open(); - _soundVolumeMaster = _detector._master_volume; - _soundVolumeMusic = _detector._music_volume; - _soundVolumeSfx = _detector._sfx_volume; + _soundVolumeMaster = ConfMan.getInt("master_volume"); + _soundVolumeMusic = ConfMan.getInt("music_volume"); + _soundVolumeSfx = ConfMan.getInt("sfx_volume"); _masterVolumeSlider->setValue(_soundVolumeMaster); _musicVolumeSlider->setValue(_soundVolumeMusic); @@ -184,7 +183,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3 // User made his choice... FilesystemNode *dir = _browser->getResult(); _savePath->setLabel(dir->path()); - // TODO - we should check if the director is writeable before accepting it + // TODO - we should check if the directory is writeable before accepting it } break; case kMasterVolumeChanged: @@ -207,18 +206,17 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3 const MidiDriverDescription *md = getAvailableMidiDrivers(); for (; md->name; md++) { if (md->id == (int) data) { - g_config->set ("music_driver", md->name, "_USER_OVERRIDES"); + ConfMan.set("music_driver", md->name); break; } } } break; case kOKCmd: - // TODO Write back changes made to config object setResult(1); - _detector._master_volume = _soundVolumeMaster; - _detector._music_volume = _soundVolumeMusic; - _detector._sfx_volume = _soundVolumeSfx; + ConfMan.set("master_volume", _soundVolumeMaster); + ConfMan.set("music_volume", _soundVolumeMusic); + ConfMan.set("sfx_volume", _soundVolumeSfx); close(); break; default: diff --git a/gui/options.h b/gui/options.h index db25eee8a8..71f3011c8c 100644 --- a/gui/options.h +++ b/gui/options.h @@ -40,8 +40,6 @@ public: void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); protected: - GameDetector &_detector; - BrowserDialog *_browser; StaticTextWidget*_savePath; diff --git a/queen/queen.cpp b/queen/queen.cpp index 59dd9c8df4..ccb9ef6f9a 100644 --- a/queen/queen.cpp +++ b/queen/queen.cpp @@ -21,6 +21,7 @@ #include "stdafx.h" #include "queen/queen.h" +#include "common/config-manager.h" #include "common/file.h" #include "base/gameDetector.h" #include "base/plugins.h" @@ -60,10 +61,10 @@ QueenEngine::QueenEngine(GameDetector *detector, OSystem *syst) if (!_mixer->bindToSystem(syst)) warning("Sound initialisation failed."); - _mixer->setVolume(detector->_sfx_volume); + _mixer->setVolume(ConfMan.getInt("sfx_volume")); _debugMode = detector->_debugMode; - _debugLevel = detector->_debugLevel; + _debugLevel = ConfMan.getInt("debuglevel"); _detector = detector; _fastMode = 0; diff --git a/queen/queen.h b/queen/queen.h index 9eff963f79..2d2108f9a8 100644 --- a/queen/queen.h +++ b/queen/queen.h @@ -29,7 +29,6 @@ #include "sound/mixer.h" #include "queen/resource.h" #include "queen/logic.h" -#include "common/config-file.h" namespace Queen { diff --git a/scumm/dialogs.cpp b/scumm/dialogs.cpp index 51ee68aadb..94e59cdd08 100644 --- a/scumm/dialogs.cpp +++ b/scumm/dialogs.cpp @@ -34,7 +34,7 @@ #include "gui/newgui.h" #include "gui/ListWidget.h" -#include "common/config-file.h" +#include "common/config-manager.h" #ifdef _WIN32_WCE #include "gapi_keys.h" @@ -546,13 +546,13 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data _scumm->_mixer->setVolume(_soundVolumeSfx * _soundVolumeMaster / 255); _scumm->_mixer->setMusicVolume(_soundVolumeMusic); - g_config->setInt("master_volume", _soundVolumeMaster); - g_config->setInt("music_volume", _soundVolumeMusic); - g_config->setInt("sfx_volume", _soundVolumeSfx); + ConfMan.set("master_volume", _soundVolumeMaster); + ConfMan.set("music_volume", _soundVolumeMusic); + ConfMan.set("sfx_volume", _soundVolumeSfx); // Subtitles? _scumm->_noSubtitles = !subtitlesCheckbox->getState(); - g_config->setBool("nosubtitles", _scumm->_noSubtitles); + ConfMan.set("nosubtitles", _scumm->_noSubtitles); // Amiga version? if (amigaCheckbox->getState()) @@ -560,10 +560,10 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data else _scumm->setFeatures (_scumm->_features & (~GF_AMIGA)); - g_config->setBool("amiga", amigaCheckbox->getState()); + ConfMan.set("amiga", amigaCheckbox->getState()); // Finally flush the modified config - g_config->flush(); + ConfMan.flushToDisk(); } case kCancelCmd: close(); diff --git a/scumm/saveload.cpp b/scumm/saveload.cpp index b8adbc7a8c..a3d727bd7a 100644 --- a/scumm/saveload.cpp +++ b/scumm/saveload.cpp @@ -22,7 +22,7 @@ #include "stdafx.h" -#include "common/config-file.h" +#include "common/config-manager.h" #include "scumm/actor.h" #include "scumm/charset.h" diff --git a/scumm/scummvm.cpp b/scumm/scummvm.cpp index a7c7f2a665..b493a71257 100644 --- a/scumm/scummvm.cpp +++ b/scumm/scummvm.cpp @@ -25,7 +25,7 @@ #include "base/gameDetector.h" #include "base/plugins.h" -#include "common/config-file.h" +#include "common/config-manager.h" #include "gui/console.h" #include "gui/message.h" @@ -595,22 +595,22 @@ ScummEngine::ScummEngine(GameDetector *detector, OSystem *syst) g_debugger = new ScummDebugger; _debugMode = detector->_debugMode; - _debugLevel = detector->_debugLevel; + _debugLevel = ConfMan.getInt("debuglevel"); _dumpScripts = detector->_dumpScripts; - _bootParam = detector->_bootParam; + _bootParam = ConfMan.getInt("boot_param"); _exe_name = strdup(detector->_game.targetName); _game_name = strdup(detector->_gameFileName.c_str()); _gameId = detector->_game.id; _version = detector->_game.version; setFeatures(detector->_game.features); - _demoMode = detector->_demo_mode; - _noSubtitles = detector->_noSubtitles; - _confirmExit = detector->_confirmExit; - _defaultTalkDelay = detector->_talkSpeed; + _demoMode = ConfMan.getBool("demo_mode"); + _noSubtitles = ConfMan.getBool("nosubtitles"); + _confirmExit = ConfMan.getBool("confirm_exit"); + _defaultTalkDelay = ConfMan.getInt("talkspeed"); _midiDriver = detector->_midi_driver; - _native_mt32 = detector->_native_mt32; - _language = detector->_language; + _native_mt32 = ConfMan.getBool("native_mt32"); + _language = GameDetector::parseLanguage(ConfMan.get("language")); memset(&res, 0, sizeof(res)); _hexdumpScripts = false; _showStack = false; @@ -634,13 +634,13 @@ ScummEngine::ScummEngine(GameDetector *detector, OSystem *syst) _newgui = g_gui; _sound = new Sound(this); - _sound->_sound_volume_master = detector->_master_volume; - _sound->_sound_volume_sfx = detector->_sfx_volume; - _sound->_sound_volume_music = detector->_music_volume; + _sound->_sound_volume_master = ConfMan.getInt("master_volume"); + _sound->_sound_volume_sfx = ConfMan.getInt("music_volume"); + _sound->_sound_volume_music = ConfMan.getInt("sfx_volume"); /* Initialize backend */ syst->init_size(_screenWidth, _screenHeight); - prop.cd_num = detector->_cdrom; + prop.cd_num = ConfMan.getInt("cdrom"); if (prop.cd_num >= 0 && (_features & GF_AUDIOTRACKS)) syst->property(OSystem::PROP_OPEN_CD, &prop); @@ -681,16 +681,16 @@ ScummEngine::ScummEngine(GameDetector *detector, OSystem *syst) _musicEngine = new Player_V2(this, _midiDriver != MD_PCSPK); } else if (_version > 2) { MidiDriver *driver = detector->createMidi(); - if (driver && detector->_native_mt32) + if (driver && _native_mt32) driver->property (MidiDriver::PROP_CHANNEL_MASK, 0x03FE); _musicEngine = _imuse = IMuse::create(syst, _mixer, driver); if (_imuse) { - if (detector->_gameTempo != 0) - _imuse->property(IMuse::PROP_TEMPO_BASE, detector->_gameTempo); + if (ConfMan.hasKey("tempo")) + _imuse->property(IMuse::PROP_TEMPO_BASE, ConfMan.getInt("tempo")); _imuse->property(IMuse::PROP_OLD_ADLIB_INSTRUMENTS, (_features & GF_SMALL_HEADER) ? 1 : 0); - _imuse->property(IMuse::PROP_MULTI_MIDI, detector->_multi_midi && + _imuse->property(IMuse::PROP_MULTI_MIDI, ConfMan.getBool("multi_midi") && _midiDriver != MD_NULL && (detector->_game.midi & MDT_ADLIB)); - _imuse->property(IMuse::PROP_NATIVE_MT32, detector->_native_mt32); + _imuse->property(IMuse::PROP_NATIVE_MT32, _native_mt32); if (_features & GF_HUMONGOUS || _features & GF_FMTOWNS) { _imuse->property(IMuse::PROP_LIMIT_PLAYERS, 1); _imuse->property(IMuse::PROP_RECYCLE_PLAYERS, 1); @@ -703,8 +703,8 @@ ScummEngine::ScummEngine(GameDetector *detector, OSystem *syst) #endif // ph0x-hack // Load game from specified slot, if any - if (detector->_save_slot != -1) { - _saveLoadSlot = detector->_save_slot; + if (ConfMan.hasKey("save_slot")) { + _saveLoadSlot = ConfMan.getInt("save_slot"); _saveLoadFlag = 2; _saveLoadCompatible = false; } @@ -2647,20 +2647,24 @@ const TargetSettings *Engine_SCUMM_targetList() { Engine *Engine_SCUMM_create(GameDetector *detector, OSystem *syst) { Engine *engine; - if (detector->_amiga) - detector->_game.features |= GF_AMIGA; - - switch (detector->_platform) { - case 1: - if (!(detector->_game.features & GF_AMIGA)) + if (ConfMan.hasKey("amiga")) { + warning("Configuration key 'amiga' is deprecated. Use 'platform=amiga' instead"); + if (ConfMan.getBool("amiga")) detector->_game.features |= GF_AMIGA; + } + + switch (GameDetector::parsePlatform(ConfMan.get("platform"))) { + case kPlatformAmiga: + detector->_game.features |= GF_AMIGA; break; - case 2: + case kPlatformAtariST: detector->_game.features |= GF_ATARI_ST; break; - case 3: + case kPlatformMacintosh: detector->_game.features |= GF_MACINTOSH; break; + default: + break; } switch (detector->_game.version) { diff --git a/scumm/sound.cpp b/scumm/sound.cpp index 6dffa34457..fd55633bd1 100644 --- a/scumm/sound.cpp +++ b/scumm/sound.cpp @@ -28,7 +28,7 @@ #include "scumm/scumm.h" #include "scumm/sound.h" -#include "common/config-file.h" +#include "common/config-manager.h" #include "common/timer.h" #include "common/util.h" diff --git a/simon/simon.cpp b/simon/simon.cpp index bb4b25133d..9692c0ed29 100644 --- a/simon/simon.cpp +++ b/simon/simon.cpp @@ -24,7 +24,7 @@ #include "base/gameDetector.h" #include "base/plugins.h" -#include "common/config-file.h" +#include "common/config-manager.h" #include "common/file.h" #include "simon/simon.h" @@ -471,26 +471,26 @@ SimonEngine::SimonEngine(GameDetector *detector, OSystem *syst) if (!_mixer->bindToSystem(syst)) warning("Sound initialization failed. " "Features of the game that depend on sound synchronization will most likely break"); - set_volume(detector->_sfx_volume); + set_volume(ConfMan.getInt("sfx_volume")); // Setup midi driver MidiDriver *driver = detector->createMidi(); if (!driver) driver = MidiDriver_ADLIB_create(_mixer); - else if (detector->_native_mt32) - driver->property (MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + else if (ConfMan.getBool("native_mt32")) + driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); - midi.mapMT32toGM (!(_game & GF_SIMON2) && !detector->_native_mt32); + midi.mapMT32toGM (!(_game & GF_SIMON2) && !ConfMan.getBool("native_mt32")); midi.set_driver(driver); int ret = midi.open(); if (ret) warning ("MIDI Player init failed: \"%s\"", midi.getErrorName (ret)); - midi.set_volume(detector->_music_volume); + midi.set_volume(ConfMan.getInt("music_volume")); _debugMode = detector->_debugMode; - _debugLevel = detector->_debugLevel; - _language = detector->_language; - _noSubtitles = detector->_noSubtitles; + _debugLevel = ConfMan.getInt("debuglevel"); + _language = GameDetector::parseLanguage(ConfMan.get("language")); + _noSubtitles = ConfMan.getBool("nosubtitles"); _system->init_size(320, 200); diff --git a/sky/sky.cpp b/sky/sky.cpp index 8d7264f258..a987235d7d 100644 --- a/sky/sky.cpp +++ b/sky/sky.cpp @@ -24,6 +24,7 @@ #include "base/gameDetector.h" #include "base/plugins.h" +#include "common/config-manager.h" #include "common/file.h" #include "common/timer.h" @@ -103,13 +104,13 @@ SkyEngine::SkyEngine(GameDetector *detector, OSystem *syst) if (!_mixer->bindToSystem(syst)) warning("Sound initialisation failed."); - _mixer->setVolume(detector->_sfx_volume); //unnecessary? + _mixer->setVolume(ConfMan.getInt("sfx_volume")); //unnecessary? _debugMode = detector->_debugMode; - _debugLevel = detector->_debugLevel; + _debugLevel = ConfMan.getInt("debuglevel"); _detector = detector; - _floppyIntro = detector->_floppyIntro; + _floppyIntro = ConfMan.getBool("floppy_intro"); _fastMode = 0; @@ -251,7 +252,7 @@ void SkyEngine::go() { void SkyEngine::initialise(void) { _skyDisk = new SkyDisk(_gameDataPath); - _skySound = new SkySound(_mixer, _skyDisk, _detector->_sfx_volume); + _skySound = new SkySound(_mixer, _skyDisk, ConfMan.getInt("sfx_volume")); _systemVars.gameVersion = _skyDisk->determineGameVersion(); @@ -260,14 +261,14 @@ void SkyEngine::initialise(void) { _skyMusic = new SkyAdlibMusic(_mixer, _skyDisk, _system); } else { _systemVars.systemFlags |= SF_ROLAND; - if (_detector->_native_mt32) + if (ConfMan.getBool("native_mt32")) _skyMusic = new SkyMT32Music(_detector->createMidi(), _skyDisk, _system); else _skyMusic = new SkyGmMusic(_detector->createMidi(), _skyDisk, _system); } if (isCDVersion()) { - if (_detector->_noSubtitles) + if (ConfMan.getBool("nosubtitles")) _systemVars.systemFlags |= SF_ALLOW_SPEECH; else _systemVars.systemFlags |= SF_ALLOW_SPEECH | SF_ALLOW_TEXT; @@ -296,10 +297,11 @@ void SkyEngine::initialise(void) { if (_systemVars.gameVersion == 288) SkyCompact::patchFor288(); - if (_detector->_language > 10) + int language = GameDetector::parseLanguage(ConfMan.get("language")); + if (language < 0 || language > 10) _systemVars.language = SKY_USA; else - _systemVars.language = _languageTable[_detector->_language]; + _systemVars.language = _languageTable[language]; if (!_skyDisk->fileExists(60600 + SkyEngine::_systemVars.language * 8)) { warning("The language you selected does not exist in your BASS version."); @@ -316,15 +318,15 @@ void SkyEngine::initialise(void) { } uint16 result = 0; - if (_detector->_save_slot >= 0) - result = _skyControl->quickXRestore(_detector->_save_slot); + if (ConfMan.hasKey("save_slot") && ConfMan.getInt("save_slot") >= 0) + result = _skyControl->quickXRestore(ConfMan.getInt("save_slot")); if (result == GAME_RESTORED) _quickLaunch = true; else _quickLaunch = false; - _skyMusic->setVolume(_detector->_music_volume >> 1); + _skyMusic->setVolume(ConfMan.getInt("music_volume") >> 1); } void SkyEngine::initItemList() { diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp index 214ffbbcf1..731850fae6 100644 --- a/sword2/sword2.cpp +++ b/sword2/sword2.cpp @@ -20,7 +20,7 @@ #include "stdafx.h" #include "base/gameDetector.h" #include "base/plugins.h" -#include "common/config-file.h" +#include "common/config-manager.h" #include "bs2/build_display.h" #include "bs2/console.h" #include "bs2/controls.h" @@ -105,9 +105,9 @@ Sword2Engine::Sword2Engine(GameDetector *detector, OSystem *syst) _features = detector->_game.features; _gameId = detector->_game.id; _game_name = strdup(detector->_gameFileName.c_str()); - _bootParam = detector->_bootParam; - _saveSlot = detector->_save_slot; - _debugLevel = detector->_debugLevel; + _bootParam = ConfMan.getInt("boot_param"); + _saveSlot = ConfMan.getInt("save_slot"); + _debugLevel = ConfMan.getInt("debuglevel"); // Setup mixer if (!_mixer->bindToSystem(syst)) |