diff options
author | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2025-01-20 10:26:22 +0100 |
---|---|---|
committer | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2025-01-20 10:51:24 +0100 |
commit | db9b9f316d7bdcb9504092908bb18e82fc21de2f (patch) | |
tree | 3f7bb1577c5210a9523fd240556cf840665f3efb /src | |
parent | 0d1024b64155a05f45f247ad57d0f444db01c1e2 (diff) | |
download | mana-db9b9f316d7bdcb9504092908bb18e82fc21de2f.tar.gz mana-db9b9f316d7bdcb9504092908bb18e82fc21de2f.tar.bz2 mana-db9b9f316d7bdcb9504092908bb18e82fc21de2f.tar.xz mana-db9b9f316d7bdcb9504092908bb18e82fc21de2f.zip |
Made client config statically typed
This makes accessing the config values much faster, since it no longer
needs to do a lookup nor string conversion, which means we could remove
some needless copying of the values.
Overall it makes it easier to find out where settings are used and it
puts the defaults along with the declaration.
Options with default values are no longer saved to the config file. This
does not include unrecognized options, which are kept around to provide
some compatibility with older clients.
While most basic options have kept the same name, more complicated
settings like window geometry, shortcuts, outfits, etc. now have their
own XML elements. Older clients will ignore these and erase them when
saving the configuration.
Diffstat (limited to 'src')
79 files changed, 1184 insertions, 1184 deletions
diff --git a/src/being.cpp b/src/being.cpp index ef50d77e..821f7054 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -73,7 +73,7 @@ Being::Being(int id, Type type, int subtype, Map *map): mMoveSpeed = Net::getPlayerHandler()->getDefaultMoveSpeed(); if (getType() == PLAYER) - mShowName = config.getBoolValue("visiblenames"); + mShowName = config.visibleNames; if (getType() == PLAYER || getType() == NPC) setShowName(true); @@ -287,7 +287,7 @@ void Being::setSpeech(const std::string &text, int time) if (!mSpeech.empty()) mSpeechTimer.set(std::min(time, SPEECH_MAX_TIME)); - const int speech = config.getIntValue("speech"); + const int speech = config.speech; if (speech == TEXT_OVERHEAD) { delete mText; @@ -908,7 +908,7 @@ void Being::updateMovement() void Being::drawSpeech(int offsetX, int offsetY) { const int px = getPixelX() - offsetX; - const int speech = config.getIntValue("speech"); + const int speech = config.speech; // Draw speech above this being if (mSpeechTimer.passed()) @@ -979,7 +979,7 @@ void Being::showName() if (getType() == PLAYER) { - if (config.getBoolValue("showgender")) + if (config.showGender) { if (getGender() == Gender::FEMALE) mDisplayName += " \u2640"; @@ -997,7 +997,7 @@ void Being::showName() if (getType() == MONSTER) { - if (config.getBoolValue("showMonstersTakedDamage")) + if (config.showMonstersTakedDamage) { mDisplayName += ", " + toString(getDamageTaken()); } @@ -1234,7 +1234,7 @@ void Being::event(Event::Channel channel, const Event &event) { if (getType() == PLAYER && event.getString("option") == "visiblenames") { - setShowName(config.getBoolValue("visiblenames")); + setShowName(config.visibleNames); } } } diff --git a/src/chatlogger.cpp b/src/chatlogger.cpp index 331e322e..723d2e7b 100644 --- a/src/chatlogger.cpp +++ b/src/chatlogger.cpp @@ -154,8 +154,8 @@ void ChatLogger::writeTo(std::ofstream &file, const std::string &str) const void ChatLogger::setServerName(const std::string &serverName) { mServerName = serverName; - if (mServerName.empty()) - mServerName = config.getStringValue("MostUsedServerName0"); + if (mServerName.empty() && !config.servers.empty()) + mServerName = config.servers.front().hostname; if (mLogFile.is_open()) mLogFile.close(); diff --git a/src/client.cpp b/src/client.cpp index fba54c81..40f41b30 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -91,7 +91,7 @@ std::string errorMessage; LoginData loginData; -Configuration config; /**< XML file configuration reader */ +Config config; /**< Global settings (config.xml) */ Configuration branding; /**< XML branding information reader */ Configuration paths; /**< XML default paths information reader */ Logger *logger; /**< Log object */ @@ -179,7 +179,6 @@ Client::Client(const Options &options): // Set default values for configuration files branding.setDefaultValues(getBrandingDefaults()); paths.setDefaultValues(getPathsDefaults()); - config.setDefaultValues(getConfigDefaults()); // Load branding information if (!options.brandingPath.empty()) @@ -199,7 +198,7 @@ Client::Client(const Options &options): // Configure logger logger->setLogFile(mLocalDataDir + "/mana.log"); - logger->setLogToStandardOut(config.getBoolValue("logToStandardOut")); + logger->setLogToStandardOut(config.logToStandardOut); // Log the mana version logger->log("%s", FULL_VERSION); @@ -262,18 +261,18 @@ Client::Client(const Options &options): // Add the local data directory to PhysicsFS search path resman->addToSearchPath(mLocalDataDir, false); - bool useOpenGL = !mOptions.noOpenGL && config.getBoolValue("opengl"); + bool useOpenGL = !mOptions.noOpenGL && config.opengl; // Set up the transparency option for low CPU when not using OpenGL. - if (!useOpenGL && config.getBoolValue("disableTransparency")) + if (!useOpenGL && config.disableTransparency) Image::SDLdisableTransparency(); VideoSettings videoSettings; - videoSettings.windowMode = static_cast<WindowMode>(config.getIntValue("windowmode")); - videoSettings.width = config.getIntValue("screenwidth"); - videoSettings.height = config.getIntValue("screenheight"); - videoSettings.userScale = config.getIntValue("scale"); - videoSettings.vsync = config.getBoolValue("vsync"); + videoSettings.windowMode = config.windowMode; + videoSettings.width = config.screenWidth; + videoSettings.height = config.screenHeight; + videoSettings.userScale = config.scale; + videoSettings.vsync = config.vsync; videoSettings.openGL = useOpenGL; // Try to set the desired video mode and create the graphics context @@ -322,12 +321,12 @@ Client::Client(const Options &options): // Initialize sound engine try { - if (config.getBoolValue("sound")) + if (config.sound) sound.init(); - sound.setSfxVolume(config.getIntValue("sfxVolume")); - sound.setNotificationsVolume(config.getIntValue("notificationsVolume")); - sound.setMusicVolume(config.getIntValue("musicVolume")); + sound.setSfxVolume(config.sfxVolume); + sound.setNotificationsVolume(config.notificationsVolume); + sound.setMusicVolume(config.musicVolume); } catch (const char *err) { @@ -353,7 +352,7 @@ Client::Client(const Options &options): mCurrentServer.type = options.serverType; loginData.username = options.username; loginData.password = options.password; - loginData.remember = config.getBoolValue("remember"); + loginData.remember = config.remember; loginData.registerLogin = false; if (mCurrentServer.type == ServerType::UNKNOWN && mCurrentServer.port != 0) @@ -384,7 +383,7 @@ Client::Client(const Options &options): chatLogger->setServerName(mCurrentServer.hostname); if (loginData.username.empty() && loginData.remember) - loginData.username = config.getStringValue("username"); + loginData.username = config.username; if (mState != STATE_ERROR) mState = STATE_CHOOSE_SERVER; @@ -392,10 +391,6 @@ Client::Client(const Options &options): // Initialize seconds counter mSecondsCounterId = SDL_AddTimer(1000, nextSecond, nullptr); - listen(Event::ConfigChannel); - - mFpsLimit = config.getIntValue("fpslimit"); - // Initialize PlayerInfo PlayerInfo::init(); } @@ -428,7 +423,9 @@ Client::~Client() logger->log("Quitting"); delete userPalette; - config.write(); + XML::Writer writer(mConfigDir + "/config.xml"); + if (writer.isValid()) + serialize(writer, config); delete logger; @@ -489,7 +486,7 @@ int Client::exec() frame_count++; gui->draw(); graphics->updateScreen(); - mFpsManager.limitFps(mFpsLimit); + mFpsManager.limitFps(config.fpsLimit); } else { @@ -743,7 +740,7 @@ int Client::exec() mOptions.character, CharSelectDialog::Choose)) { ((CharSelectDialog*) mCurrentDialog)->selectByName( - config.getStringValue("lastCharacter"), + config.lastCharacter, mOptions.chooseDefault ? CharSelectDialog::Choose : CharSelectDialog::Focus); @@ -777,7 +774,7 @@ int Client::exec() case STATE_GAME: logger->log("Memorizing selected character %s", local_player->getName().c_str()); - config.setValue("lastCharacter", local_player->getName()); + config.lastCharacter = local_player->getName(); // Fade out logon-music here too to give the desired effect // of "flowing" into the game. @@ -963,16 +960,6 @@ void Client::showErrorDialog(const std::string &message, State state) showOkDialog(_("Error"), message, state); } -void Client::event(Event::Channel channel, const Event &event) -{ - if (channel == Event::ConfigChannel && - event.getType() == Event::ConfigOptionChanged && - event.getString("option") == "fpslimit") - { - mFpsLimit = config.getIntValue("fpslimit"); - } -} - void Client::action(const gcn::ActionEvent &event) { Window *window = nullptr; @@ -1102,33 +1089,15 @@ void Client::initHomeDir() void Client::initConfiguration() { // Fill configuration with defaults - config.setValue("updatehost", branding.getValue("defaultUpdateHost", - std::string())); - - // Checking if the configuration file exists... otherwise create it with - // default options. - FILE *configFile = nullptr; - std::string configPath; + config.updatehost = branding.getValue("defaultUpdateHost", std::string()); - configPath = mConfigDir + "/config.xml"; + const std::string configPath = mConfigDir + "/config.xml"; + XML::Document doc(configPath, false); - configFile = fopen(configPath.c_str(), "r"); - - // If we can't read it, it doesn't exist ! - if (!configFile) - { - // We reopen the file in write mode and we create it - configFile = fopen(configPath.c_str(), "wt"); - } - if (!configFile) - { - logger->log("Can't create %s. Using defaults.", configPath.c_str()); - } + if (doc.rootNode() && doc.rootNode().name() == "configuration") + deserialize(doc.rootNode(), config); else - { - fclose(configFile); - config.init(configPath); - } + logger->log("Couldn't read configuration file: %s", configPath.c_str()); } /** @@ -1139,7 +1108,7 @@ void Client::initUpdatesDir() { // If updatesHost is currently empty, fill it from config file if (mUpdateHost.empty()) - mUpdateHost = config.getStringValue("updatehost"); + mUpdateHost = config.updatehost; // Exit on empty update host. if (mUpdateHost.empty()) @@ -1217,17 +1186,16 @@ void Client::initScreenshotDir() mScreenshotDir = std::string(PHYSFS_getUserDir()) + "Desktop"; #endif - if (config.getBoolValue("useScreenshotDirectorySuffix")) + if (config.useScreenshotDirectorySuffix) { - std::string configScreenshotSuffix = - config.getValue("screenshotDirectorySuffix", - branding.getValue("appShort", "Mana")); + std::string screenshotSuffix = config.screenshotDirectorySuffix; + if (screenshotSuffix.empty()) + screenshotSuffix = branding.getValue("appShort", "Mana"); - if (!configScreenshotSuffix.empty()) + if (!screenshotSuffix.empty()) { - mScreenshotDir += "/" + configScreenshotSuffix; - config.setValue("screenshotDirectorySuffix", - configScreenshotSuffix); + mScreenshotDir += "/" + screenshotSuffix; + config.screenshotDirectorySuffix = screenshotSuffix; } } } @@ -1249,15 +1217,15 @@ void Client::accountLogin(LoginData *loginData) // TODO This is not the best place to save the config, but at least better // than the login gui window if (loginData->remember) - config.setValue("username", loginData->username); - config.setValue("remember", loginData->remember); + config.username = loginData->username; + config.remember = loginData->remember; } void Client::handleWindowSizeChanged(int width, int height) { // Store the new size in the configuration. - config.setValue("screenwidth", width); - config.setValue("screenheight", height); + config.screenWidth = width; + config.screenHeight = height; mVideo.windowSizeChanged(width, height); diff --git a/src/client.h b/src/client.h index a2371a1c..e7127ddc 100644 --- a/src/client.h +++ b/src/client.h @@ -22,7 +22,6 @@ #ifndef CLIENT_H #define CLIENT_H -#include "eventlistener.h" #include "video.h" #include "net/serverinfo.h" @@ -111,7 +110,7 @@ public: * The core part of the client. This class initializes all subsystems, runs * the event loop, and shuts everything down again. */ -class Client final : public EventListener, public gcn::ActionListener +class Client final : public gcn::ActionListener { public: /** @@ -187,7 +186,6 @@ public: static Video &getVideo() { return instance()->mVideo; } - void event(Event::Channel channel, const Event &event) override; void action(const gcn::ActionEvent &event) override; /** @@ -239,7 +237,6 @@ private: SDL_TimerID mSecondsCounterId = 0; - int mFpsLimit = 0; FpsManager mFpsManager; }; diff --git a/src/commandhandler.cpp b/src/commandhandler.cpp index 9100c9e3..75cca1ab 100644 --- a/src/commandhandler.cpp +++ b/src/commandhandler.cpp @@ -23,6 +23,7 @@ #include "actorspritemanager.h" #include "channelmanager.h" +#include "configuration.h" #include "game.h" #include "localplayer.h" #include "playerrelations.h" @@ -36,6 +37,12 @@ #include "utils/gettext.h" #include "utils/stringutils.h" +std::string booleanOptionInstructions(const char *command) +{ + return strprintf(_("Options to /%s are \"yes\", \"no\", \"true\", \"false\", \"1\", \"0\"."), + command); +} + CommandHandler::CommandHandler() {} @@ -452,8 +459,8 @@ void CommandHandler::handleToggle(const std::string &args, ChatTab *tab) { if (args.empty()) { - tab->chatLog(chatWindow->getReturnTogglesChat() ? - _("Return toggles chat.") : _("Message closes chat.")); + tab->chatLog(config.returnTogglesChat ? _("Return toggles chat.") + : _("Message closes chat.")); return; } @@ -463,14 +470,14 @@ void CommandHandler::handleToggle(const std::string &args, ChatTab *tab) { case 1: tab->chatLog(_("Return now toggles chat.")); - chatWindow->setReturnTogglesChat(true); + config.returnTogglesChat = true; return; case 0: tab->chatLog(_("Message now closes chat.")); - chatWindow->setReturnTogglesChat(false); + config.returnTogglesChat = false; return; case -1: - tab->chatLog(strprintf(BOOLEAN_OPTIONS, "toggle")); + tab->chatLog(booleanOptionInstructions("toggle")); } } @@ -496,7 +503,7 @@ void CommandHandler::handleShowIp(const std::string &args, ChatTab *tab) local_player->setShowIp(true); break; case -1: - tab->chatLog(strprintf(BOOLEAN_OPTIONS, "showip")); + tab->chatLog(booleanOptionInstructions("showip")); return; } diff --git a/src/commandhandler.h b/src/commandhandler.h index 2bf670c1..42f68b2f 100644 --- a/src/commandhandler.h +++ b/src/commandhandler.h @@ -28,8 +28,7 @@ class ChatTab; extern ChatTab *localChatTab; -#define BOOLEAN_OPTIONS _("Options to /%s are \"yes\", \"no\", \"true\", "\ -"\"false\", \"1\", \"0\".") +std::string booleanOptionInstructions(const char *command); /** * A class to parse and handle user commands diff --git a/src/configuration.cpp b/src/configuration.cpp index 5fc4eabd..ead228c4 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -1,7 +1,7 @@ /* * The Mana Client * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2024 The Mana Developers * * This file is part of The Mana Client. * @@ -33,16 +33,6 @@ void ConfigurationObject::setValue(const std::string &key, mOptions[key] = value; } -void Configuration::setValue(const std::string &key, const std::string &value) -{ - ConfigurationObject::setValue(key, value); - - // Notify listeners - Event event(Event::ConfigOptionChanged); - event.setString("option", key); - event.trigger(Event::ConfigChannel); -} - std::string ConfigurationObject::getValue(const std::string &key, const std::string &deflt) const { @@ -70,19 +60,8 @@ double ConfigurationObject::getValue(const std::string &key, return iter != mOptions.end() ? atof(iter->second.c_str()) : deflt; } -void ConfigurationObject::deleteList(std::list<ConfigurationObject*> &list) -{ - for (auto element : list) - delete element; - - list.clear(); -} - void ConfigurationObject::clear() { - for (auto &[_, list] : mContainerOptions) - deleteList(list); - mOptions.clear(); } @@ -212,33 +191,13 @@ void ConfigurationObject::initFromXML(XML::Node parent_node) for (auto node : parent_node.children()) { - if (node.name() == "list") + if (node.name() == "option") { - // List option handling. std::string name = node.getProperty("name", std::string()); - for (auto subnode : node.children()) - { - if (subnode.name() == name) - { - auto *cobj = new ConfigurationObject; - - cobj->initFromXML(subnode); // Recurse - - mContainerOptions[name].push_back(cobj); - } - } - - } - else if (node.name() == "option") - { - // Single option handling. - std::string name = node.getProperty("name", std::string()); - std::string value = node.getProperty("value", std::string()); - if (!name.empty()) - mOptions[name] = value; - } // Otherwise ignore + mOptions[name] = node.getProperty("value", std::string()); + } } } @@ -251,15 +210,15 @@ void Configuration::init(const std::string &filename, bool useResManager) else mConfigPath = filename; - if (!doc.rootNode()) + XML::Node rootNode = doc.rootNode(); + + if (!rootNode) { logger->log("Couldn't open configuration file: %s", filename.c_str()); return; } - XML::Node rootNode = doc.rootNode(); - - if (!rootNode || rootNode.name() != "configuration") + if (rootNode.name() != "configuration") { logger->log("Warning: No configuration file (%s)", filename.c_str()); return; @@ -268,57 +227,387 @@ void Configuration::init(const std::string &filename, bool useResManager) initFromXML(rootNode); } -void ConfigurationObject::writeToXML(XML::Writer &writer) const + +template<typename T> +struct Option +{ + Option(const char *name, const T &value, const T &defaultValue) + : name(name), value(value), defaultValue(defaultValue) + {} + + const char *name; + const T &value; + const T &defaultValue; +}; + +template<typename T> +static void serialize(XML::Writer &writer, const Option<T> &option) +{ + if (option.value == option.defaultValue) + return; + + writer.startElement("option"); + writer.addAttribute("name", option.name); + writer.addAttribute("value", option.value); + writer.endElement(); +} + +static void serialize(XML::Writer &writer, const ItemShortcutEntry &itemShortcut) +{ + writer.startElement("itemshortcut"); + writer.addAttribute("index", itemShortcut.index); + writer.addAttribute("id", itemShortcut.itemId); + writer.endElement(); +} + +static void serialize(XML::Writer &writer, const EmoteShortcutEntry &emoteShortcut) +{ + writer.startElement("emoteshortcut"); + writer.addAttribute("index", emoteShortcut.index); + writer.addAttribute("id", emoteShortcut.emoteId); + writer.endElement(); +} + +static void serialize(XML::Writer &writer, const Outfit &outfit) +{ + writer.startElement("outfit"); + writer.addAttribute("index", outfit.index); + writer.addAttribute("items", outfit.items); + writer.addAttribute("unequip", outfit.unequip); + writer.endElement(); +} + +static void serialize(XML::Writer &writer, const UserColor &color) +{ + if (!color.color.empty()) + writer.addAttribute("color", color.color); + + writer.addAttribute("gradient", color.gradient); + + if (color.delay) + writer.addAttribute("delay", *color.delay); +} + +static void serialize(XML::Writer &writer, const WindowState &state) { - for (auto &[name, value] : mOptions) + if (state.x) writer.addAttribute("x", *state.x); + if (state.y) writer.addAttribute("y", *state.y); + if (state.width) writer.addAttribute("width", *state.width); + if (state.height) writer.addAttribute("height", *state.height); + if (state.visible) writer.addAttribute("visible", *state.visible); + if (state.sticky) writer.addAttribute("sticky", *state.sticky); +} + +static const char *serverTypeToString(ServerType type) +{ + switch (type) { - writer.startElement("option"); - writer.addAttribute("name", name); - writer.addAttribute("value", value); - writer.endElement(); + case ServerType::TMWATHENA: + return "TmwAthena"; + case ServerType::MANASERV: + return "ManaServ"; + default: + return ""; } +} - for (auto &[name, list] : mContainerOptions) - { - writer.startElement("list"); - writer.addAttribute("name", name); +static void serialize(XML::Writer &writer, const ServerInfo &server) +{ + writer.startElement("server"); - // Recurse on all elements - for (auto element : list) - { - writer.startElement(name.c_str()); - element->writeToXML(writer); - writer.endElement(); - } + writer.addAttribute("name", server.name); + writer.addAttribute("type", serverTypeToString(server.type)); + + writer.startElement("connection"); + writer.addAttribute("hostname", server.hostname); + writer.addAttribute("port", server.port); + writer.endElement(); // connection + + if (!server.description.empty()) + { + writer.startElement("description"); + writer.writeText(server.description); + writer.endElement(); + } + if (!server.persistentIp) + { + writer.startElement("persistentIp"); + writer.writeText(server.persistentIp ? "1" : "0"); writer.endElement(); } + + writer.endElement(); // server +} + +template<typename T> +void serdeOptions(T option) +{ + option("OverlayDetail", &Config::overlayDetail); + option("speechBubblecolor", &Config::speechBubblecolor); + option("speechBubbleAlpha", &Config::speechBubbleAlpha); + option("speech", &Config::speech); + option("visiblenames", &Config::visibleNames); + option("showgender", &Config::showGender); + option("showMonstersTakedDamage", &Config::showMonstersTakedDamage); + option("showWarps", &Config::showWarps); + option("particleMaxCount", &Config::particleMaxCount); + option("particleFastPhysics", &Config::particleFastPhysics); + option("particleEmitterSkip", &Config::particleEmitterSkip); + option("particleeffects", &Config::particleEffects); + option("logToStandardOut", &Config::logToStandardOut); + option("opengl", &Config::opengl); + option("vsync", &Config::vsync); + option("windowmode", &Config::windowMode); + option("screenwidth", &Config::screenWidth); + option("screenheight", &Config::screenHeight); + option("scale", &Config::scale); + option("sound", &Config::sound); + option("sfxVolume", &Config::sfxVolume); + option("notificationsVolume", &Config::notificationsVolume); + option("musicVolume", &Config::musicVolume); + option("fpslimit", &Config::fpsLimit); + + option("remember", &Config::remember); + option("username", &Config::username); + option("lastCharacter", &Config::lastCharacter); + option("updatehost", &Config::updatehost); + option("screenshotDirectory", &Config::screenshotDirectory); + option("screenshotDirectorySuffix", &Config::screenshotDirectorySuffix); + option("useScreenshotDirectorySuffix", &Config::useScreenshotDirectorySuffix); + + option("EnableSync", &Config::enableSync); + + option("joystickEnabled", &Config::joystickEnabled); + option("upTolerance", &Config::upTolerance); + option("downTolerance", &Config::downTolerance); + option("leftTolerance", &Config::leftTolerance); + option("rightTolerance", &Config::rightTolerance); + + option("logNpcInGui", &Config::logNpcInGui); + option("download-music", &Config::downloadMusic); + option("guialpha", &Config::guiAlpha); + option("ChatLogLength", &Config::chatLogLength); + option("enableChatLog", &Config::enableChatLog); + option("whispertab", &Config::whisperTab); + option("customcursor", &Config::customCursor); + option("showownname", &Config::showOwnName); + option("showpickupparticle", &Config::showPickupParticle); + option("showpickupchat", &Config::showPickupChat); + option("showMinimap", &Config::showMinimap); + option("fontSize", &Config::fontSize); + option("ReturnToggles", &Config::returnTogglesChat); + option("ScrollLaziness", &Config::scrollLaziness); + option("ScrollRadius", &Config::scrollRadius); + option("ScrollCenterOffsetX", &Config::scrollCenterOffsetX); + option("ScrollCenterOffsetY", &Config::scrollCenterOffsetY); + option("onlineServerList", &Config::onlineServerList); + option("theme", &Config::theme); + option("disableTransparency", &Config::disableTransparency); + + option("persistent-player-list", &Config::persistentPlayerList); + option("player-ignore-strategy", &Config::playerIgnoreStrategy); + option("default-player-permissions", &Config::defaultPlayerPermissions); } -void Configuration::write() +void serialize(XML::Writer &writer, const Config &config) { - // Do not attempt to write to file that cannot be opened for writing - FILE *testFile = fopen(mConfigPath.c_str(), "w"); - if (!testFile) + const Config defaults; + auto serializeOption = [&](const char *name, auto member) { + serialize(writer, Option { name, config.*member, defaults.*member }); + }; + + writer.startElement("configuration"); + + serdeOptions(serializeOption); + + for (const auto &[name, value] : config.unknownOptions) + serialize(writer, Option { name.c_str(), value, std::string() }); + + for (const auto &[action, key] : config.keys) { - logger->log("Configuration::write() couldn't open %s for writing", - mConfigPath.c_str()); - return; + writer.startElement("key"); + writer.addAttribute("action", action); + writer.addAttribute("key", key); + writer.endElement(); } - fclose(testFile); + for (auto &itemShortcut : config.itemShortcuts) + serialize(writer, itemShortcut); + for (auto &emoteShortcut : config.emoteShortcuts) + serialize(writer, emoteShortcut); - XML::Writer writer(mConfigPath); + for (auto &outfit : config.outfits) + serialize(writer, outfit); - if (!writer.isValid()) + for (auto &[type, color] : config.colors) { - logger->log("Configuration::write() error while creating writer"); - return; + writer.startElement("color"); + writer.addAttribute("type", type); + + serialize(writer, color); + + writer.endElement(); } - logger->log("Configuration::write() writing configuration..."); + for (const auto &[name, state] : config.windows) + { + writer.startElement("window"); + writer.addAttribute("name", name); - writer.startElement("configuration"); - writeToXML(writer); + serialize(writer, state); + + writer.endElement(); // window + } + + for (const auto &server : config.servers) + { + if (server.save && server.isValid()) + serialize(writer, server); + } + + for (const auto &[name, relation] : config.players) + { + writer.startElement("player"); + writer.addAttribute("name", name); + writer.addAttribute("relation", static_cast<int>(relation)); + writer.endElement(); + } + + writer.endElement(); // configuration +} + +void deserialize(XML::Node node, ItemShortcutEntry &itemShortcut) +{ + node.attribute("index", itemShortcut.index); + node.attribute("id", itemShortcut.itemId); +} + +void deserialize(XML::Node node, EmoteShortcutEntry &emoteShortcut) +{ + node.attribute("index", emoteShortcut.index); + node.attribute("id", emoteShortcut.emoteId); +} + +void deserialize(XML::Node node, Outfit &outfit) +{ + node.attribute("index", outfit.index); + node.attribute("items", outfit.items); + node.attribute("unequip", outfit.unequip); +} + +void deserialize(XML::Node node, UserColor &color) +{ + node.attribute("color", color.color); + node.attribute("gradient", color.gradient); + node.attribute("delay", color.delay); +} + +void deserialize(XML::Node node, WindowState &state) +{ + node.attribute("x", state.x); + node.attribute("y", state.y); + node.attribute("width", state.width); + node.attribute("height", state.height); + node.attribute("visible", state.visible); + node.attribute("sticky", state.sticky); +} + +void deserialize(XML::Node node, ServerInfo &server) +{ + node.attribute("name", server.name); + + std::string type; + node.attribute("type", type); + server.type = ServerInfo::parseType(type); + + for (auto node : node.children()) { + if (node.name() == "connection") { + node.attribute("hostname", server.hostname); + node.attribute("port", server.port); + } else if (node.name() == "description") { + server.description = node.textContent(); + } else if (node.name() == "persistentIp") { + const std::string value { node.textContent() }; + server.persistentIp = getBoolFromString(value, server.persistentIp); + } + } +} + +void deserialize(XML::Node node, Config &config) +{ + std::map<std::string, std::string> options; + + for (auto node : node.children()) { + if (node.name() == "option") { + std::string name; + if (!node.attribute("name", name)) + continue; + node.attribute("value", options[name]); + } else if (node.name() == "list") { + // Backwards compatibility for old configuration files + for (auto node : node.children()) { + if (node.name() == "player") { + std::string playerName; + PlayerRelation relation = PlayerRelation::NEUTRAL; + + for (auto node : node.children()) { + if (node.name() == "option") { + std::string optionName; + + if (node.attribute("name", optionName)) { + if (optionName == "name") + node.attribute("value", playerName); + else if (optionName == "relation") + node.attribute("value", relation); + } + } + } + + if (!playerName.empty()) + config.players[playerName] = relation; + } + } + } else if (node.name() == "key") { + std::string action; + node.attribute("action", action); + if (!action.empty()) + node.attribute("key", config.keys[action]); + } else if (node.name() == "itemshortcut") { + deserialize(node, config.itemShortcuts.emplace_back()); + } else if (node.name() == "emoteshortcut") { + deserialize(node, config.emoteShortcuts.emplace_back()); + } else if (node.name() == "outfit") { + deserialize(node, config.outfits.emplace_back()); + } else if (node.name() == "color") { + std::string type; + node.attribute("type", type); + deserialize(node, config.colors[type]); + } else if (node.name() == "window") { + std::string name; + node.attribute("name", name); + deserialize(node, config.windows[name]); + } else if (node.name() == "player") { + std::string name; + node.attribute("name", name); + if (!name.empty()) + node.attribute("relation", config.players[name]); + } else if (node.name() == "server") { + deserialize(node, config.servers.emplace_back()); + } + } + + auto deserializeOption = [&](const char *name, auto member) { + auto it = options.find(name); + if (it == options.end()) + return; + + fromString(it->second.data(), config.*member); + options.erase(it); + }; + + serdeOptions(deserializeOption); + + config.unknownOptions = std::move(options); } diff --git a/src/configuration.h b/src/configuration.h index c6c115f6..69a211be 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -1,7 +1,7 @@ /* * The Mana Client * Copyright (C) 2004-2009 The Mana World Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2024 The Mana Developers * * This file is part of The Mana Client. * @@ -22,51 +22,20 @@ #ifndef CONFIGURATION_H #define CONFIGURATION_H +#include "being.h" #include "defaults.h" +#include "playerrelations.h" +#include "video.h" -#include "utils/stringutils.h" #include "utils/xml.h" +#include "net/serverinfo.h" + #include <cassert> -#include <list> #include <map> +#include <optional> #include <string> - -class ConfigurationObject; - -/** - * Configuration list manager interface; responsible for - * serializing/deserializing configuration choices in containers. - * - * \param T Type of the container elements to serialise - * \param CONT Type of the container we (de)serialise - */ -template <class T, class CONT> -class ConfigurationListManager -{ - public: - /** - * Writes a value into a configuration object - * - * \param value The value to write out - * \param obj The configuation object to write to - * \return obj, or otherwise NULL to indicate that this option should - * be skipped - */ - virtual ConfigurationObject *writeConfigItem(const T &value, - ConfigurationObject *obj) = 0; - - /** - * Reads a value from a configuration object - * - * \param obj The configuration object to read from - * \param container The container to insert the object to - */ - virtual CONT readConfigItem(ConfigurationObject *obj, - CONT container) = 0; - - virtual ~ConfigurationListManager() = default; -}; +#include <vector> /** * Configuration object, mapping values to names and possibly containing @@ -87,8 +56,7 @@ class ConfigurationObject * \param key Option identifier. * \param value Value. */ - virtual void setValue(const std::string &key, - const std::string &value); + void setValue(const std::string &key, const std::string &value); /** * Gets a value as string. @@ -110,74 +78,10 @@ class ConfigurationObject */ void clear(); - /** - * Serialises a container into a list of configuration options - * - * \tparam IT Iterator type over CONT - * \tparam T Elements that IT iterates over - * \tparam CONT The associated container type - * - * \param name Name of the list the elements should be stored under - * \param begin Iterator start - * \param end Iterator end - * \param manager An object capable of serialising T items - */ - template <class IT, class T, class CONT> - void setList(const std::string &name, IT begin, IT end, - ConfigurationListManager<T, CONT> &manager) - { - auto *nextobj = new ConfigurationObject; - std::list<ConfigurationObject *> &list = mContainerOptions[name]; - deleteList(list); - - for (IT it = begin; it != end; it++) - { - ConfigurationObject *wrobj = manager.writeConfigItem(*it, nextobj); - if (wrobj) - { // wrote something - assert (wrobj == nextobj); - nextobj = new ConfigurationObject; - list.push_back(wrobj); - } - else - { - nextobj->clear(); // you never know... - } - } - - delete nextobj; - } - - /** - * Serialises a container into a list of configuration options - * - * \tparam IT Iterator type over CONT - * \tparam T Elements that IT iterates over - * \tparam CONT The associated container type - * - * \param name Name of the list the elements should be read from under - * \param empty Initial (empty) container to write to - * \param manager An object capable of deserialising items into CONT - */ - template<class T, class CONT> - CONT getList(const std::string &name, CONT empty, ConfigurationListManager<T, CONT> &manager) - { - CONT container = empty; - - for (auto obj : mContainerOptions[name]) - container = manager.readConfigItem(obj, container); - - return container; - } - protected: void initFromXML(XML::Node node); - void writeToXML(XML::Writer &writer) const; - - void deleteList(std::list<ConfigurationObject *> &list); std::map<std::string, std::string> mOptions; - std::map<std::string, std::list<ConfigurationObject *>> mContainerOptions; }; /** @@ -208,31 +112,6 @@ class Configuration : public ConfigurationObject void setDefaultValues(DefaultsData *defaultsData); /** - * Writes the current settings back to the config file. - */ - void write(); - - void setValue(const std::string &key, const std::string &value) override; - - void setValue(const std::string &key, const char *value) - { setValue(key, std::string(value)); } - - void setValue(const std::string &key, float value) - { setValue(key, toString(value)); } - - void setValue(const std::string &key, double value) - { setValue(key, toString(value)); } - - void setValue(const std::string &key, int value) - { setValue(key, toString(value)); } - - void setValue(const std::string &key, unsigned value) - { setValue(key, toString(value)); } - - void setValue(const std::string &key, bool value) - { setValue(key, value ? "1" : "0"); } - - /** * returns a value corresponding to the given key. * The default value returned in based on fallbacks registry. * @see defaults.h @@ -257,8 +136,129 @@ class Configuration : public ConfigurationObject DefaultsData *mDefaultsData = nullptr; /**< Defaults of value for a given key */ }; +struct ItemShortcutEntry +{ + int index; + int itemId; +}; + +struct EmoteShortcutEntry +{ + int index; + int emoteId; +}; + +struct Outfit +{ + int index; + std::string items; + bool unequip; +}; + +struct UserColor +{ + std::string color; + int gradient; + std::optional<int> delay; +}; + +struct WindowState +{ + std::optional<int> x; + std::optional<int> y; + std::optional<int> width; + std::optional<int> height; + std::optional<bool> visible; + std::optional<bool> sticky; +}; + +struct Config +{ + int overlayDetail = 2; + std::string speechBubblecolor = "000000"; + float speechBubbleAlpha = 1.0f; + Being::Speech speech = Being::TEXT_OVERHEAD; + bool visibleNames = true; + bool showGender = false; + bool showMonstersTakedDamage = false; + bool showWarps = true; + int particleMaxCount = 3000; + int particleFastPhysics = 0; + int particleEmitterSkip = 1; + bool particleEffects = true; + bool logToStandardOut = false; + bool opengl = false; + bool vsync = true; + WindowMode windowMode = WindowMode::Windowed; + int screenWidth = defaultScreenWidth; + int screenHeight = defaultScreenHeight; + int scale = 0; + bool sound = true; + int sfxVolume = 100; + int notificationsVolume = 100; + int musicVolume = 60; + int fpsLimit = 0; + + bool remember = true; + std::string username; + std::string lastCharacter; + std::string updatehost; + std::string afkMessage; + std::string screenshotDirectory; + std::string screenshotDirectorySuffix; + bool useScreenshotDirectorySuffix = true; + + bool enableSync = false; + + bool joystickEnabled = false; + int upTolerance = 100; + int downTolerance = 100; + int leftTolerance = 100; + int rightTolerance = 100; + + bool logNpcInGui = true; + bool downloadMusic = false; + float guiAlpha = 0.8f; + int chatLogLength = 128; + bool enableChatLog = false; + bool whisperTab = true; + bool customCursor = true; + bool showOwnName = false; + bool showPickupParticle = true; + bool showPickupChat = false; + bool showMinimap = true; + int fontSize = 12; + bool returnTogglesChat = false; + int scrollLaziness = 16; + int scrollRadius = 0; + int scrollCenterOffsetX = 0; + int scrollCenterOffsetY = 0; + std::string onlineServerList; + std::string theme; + bool disableTransparency = false; + + bool persistentPlayerList = true; + std::string playerIgnoreStrategy = DEFAULT_IGNORE_STRATEGY; + unsigned defaultPlayerPermissions = PlayerPermissions::DEFAULT; + + std::map<std::string, std::string> keys; + std::vector<ItemShortcutEntry> itemShortcuts; + std::vector<EmoteShortcutEntry> emoteShortcuts; + std::vector<Outfit> outfits; + std::map<std::string, UserColor> colors; + std::map<std::string, WindowState> windows; + std::map<std::string, PlayerRelation> players; + ServerInfos servers; + + // For compatibility with old configuration files or different clients + std::map<std::string, std::string> unknownOptions; +}; + +void serialize(XML::Writer &writer, const Config &config); +void deserialize(XML::Node node, Config &config); + +extern Config config; extern Configuration branding; -extern Configuration config; extern Configuration paths; #endif diff --git a/src/defaults.cpp b/src/defaults.cpp index b17ba350..dff06bbb 100644 --- a/src/defaults.cpp +++ b/src/defaults.cpp @@ -20,7 +20,6 @@ #include "defaults.h" -#include "being.h" #include "client.h" VariableData *createData(int defData) @@ -59,70 +58,6 @@ void AddDEF(DefaultsData *defaultsData, const char *key, T value) defaultsData->insert(std::make_pair(key, createData(value))); } -DefaultsData* getConfigDefaults() -{ - auto* configData = new DefaultsData; - // Init main config defaults - AddDEF(configData, "OverlayDetail", 2); - AddDEF(configData, "speechBubblecolor", "000000"); - AddDEF(configData, "speechBubbleAlpha", 1.0f); - AddDEF(configData, "MostUsedServerName0", "server.themanaworld.org"); - AddDEF(configData, "visiblenames", true); - AddDEF(configData, "speech", Being::TEXT_OVERHEAD); - AddDEF(configData, "showgender", false); - AddDEF(configData, "showMonstersTakedDamage", false); - AddDEF(configData, "particleMaxCount", 3000); - AddDEF(configData, "particleFastPhysics", 0); - AddDEF(configData, "particleEmitterSkip", 1); - AddDEF(configData, "particleeffects", true); - AddDEF(configData, "logToStandardOut", false); - AddDEF(configData, "opengl", false); - AddDEF(configData, "windowmode", static_cast<int>(WindowMode::Windowed)); - AddDEF(configData, "screenwidth", defaultScreenWidth); - AddDEF(configData, "screenheight", defaultScreenHeight); - AddDEF(configData, "scale", 0); - AddDEF(configData, "vsync", true); - AddDEF(configData, "sound", true); - AddDEF(configData, "sfxVolume", 100); - AddDEF(configData, "notificationsVolume", 100); - AddDEF(configData, "musicVolume", 60); - AddDEF(configData, "remember", true); - AddDEF(configData, "username", ""); - AddDEF(configData, "lastCharacter", ""); - AddDEF(configData, "fpslimit", 0); - AddDEF(configData, "updatehost", ""); - AddDEF(configData, "screenshotDirectory", ""); - AddDEF(configData, "useScreenshotDirectorySuffix", true); - AddDEF(configData, "screenshotDirectorySuffix", ""); - AddDEF(configData, "EnableSync", false); - AddDEF(configData, "joystickEnabled", false); - AddDEF(configData, "upTolerance", 100); - AddDEF(configData, "downTolerance", 100); - AddDEF(configData, "leftTolerance", 100); - AddDEF(configData, "rightTolerance", 100); - AddDEF(configData, "logNpcInGui", true); - AddDEF(configData, "download-music", false); - AddDEF(configData, "guialpha", 0.8f); - AddDEF(configData, "ChatLogLength", 128); - AddDEF(configData, "enableChatLog", false); - AddDEF(configData, "whispertab", true); - AddDEF(configData, "customcursor", true); - AddDEF(configData, "showownname", false); - AddDEF(configData, "showpickupparticle", true); - AddDEF(configData, "showpickupchat", false); - AddDEF(configData, "fontSize", 12); - AddDEF(configData, "ReturnToggles", false); - AddDEF(configData, "ScrollLaziness", 16); - AddDEF(configData, "ScrollRadius", 0); - AddDEF(configData, "ScrollCenterOffsetX", 0); - AddDEF(configData, "ScrollCenterOffsetY", 0); - AddDEF(configData, "onlineServerList", ""); - AddDEF(configData, "theme", ""); - AddDEF(configData, "disableTransparency", false); - - return configData; -} - DefaultsData* getBrandingDefaults() { auto *brandingData = new DefaultsData; diff --git a/src/defaults.h b/src/defaults.h index a9532459..a588a543 100644 --- a/src/defaults.h +++ b/src/defaults.h @@ -27,7 +27,6 @@ using DefaultsData = std::map<std::string, VariableData *>; -DefaultsData* getConfigDefaults(); DefaultsData* getBrandingDefaults(); DefaultsData* getPathsDefaults(); diff --git a/src/emoteshortcut.cpp b/src/emoteshortcut.cpp index 69692437..cd80dea6 100644 --- a/src/emoteshortcut.cpp +++ b/src/emoteshortcut.cpp @@ -24,8 +24,6 @@ #include "configuration.h" #include "localplayer.h" -#include "utils/stringutils.h" - EmoteShortcut *emoteShortcut; EmoteShortcut::EmoteShortcut() @@ -41,16 +39,23 @@ EmoteShortcut::~EmoteShortcut() void EmoteShortcut::load() { for (int i = 0; i < SHORTCUT_EMOTES; i++) + mEmotes[i] = i + 1; + + for (auto &shortcut : config.emoteShortcuts) { - mEmotes[i] = (int) config.getValue("emoteshortcut" + toString(i), i + 1); + if (shortcut.index >= 0 && shortcut.index < SHORTCUT_EMOTES) + mEmotes[shortcut.index] = shortcut.emoteId; } } void EmoteShortcut::save() { + config.emoteShortcuts.clear(); + for (int i = 0; i < SHORTCUT_EMOTES; i++) { - config.setValue("emoteshortcut" + toString(i), mEmotes[i]); + if (mEmotes[i] != i + 1) + config.emoteShortcuts.push_back({ i, mEmotes[i] }); } } diff --git a/src/event.h b/src/event.h index 868aabab..9867c8aa 100644 --- a/src/event.h +++ b/src/event.h @@ -64,7 +64,7 @@ public: Close, CloseAll, CloseDialog, - ConfigOptionChanged, + ConfigOptionChanged, // todo: replace with more specific events Constructed, LoadingDatabases, Destroyed, diff --git a/src/game.cpp b/src/game.cpp index 96935981..c8b295bb 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -415,7 +415,7 @@ void Game::handleInput() if (setupWindow->isVisible() && keyboard.getNewKeyIndex() > KeyboardConfig::KEY_NO_VALUE) { - keyboard.setNewKey((int) event.key.keysym.sym); + keyboard.setNewKey(event.key.keysym.sym); keyboard.callbackNewKey(); keyboard.setNewKeyIndex(KeyboardConfig::KEY_NO_VALUE); return; diff --git a/src/gui/chatwindow.cpp b/src/gui/chatwindow.cpp index b4b03450..453baea2 100644 --- a/src/gui/chatwindow.cpp +++ b/src/gui/chatwindow.cpp @@ -123,14 +123,11 @@ ChatWindow::ChatWindow(): mChatInput->setHistory(mHistory); mChatInput->setAutoComplete(mAutoComplete); - mReturnToggles = config.getBoolValue("ReturnToggles"); - mRecorder = new Recorder(this); } ChatWindow::~ChatWindow() { - config.setValue("ReturnToggles", mReturnToggles); delete mRecorder; removeAllWhispers(); delete mItemLinkHandler; @@ -197,7 +194,7 @@ void ChatWindow::action(const gcn::ActionEvent &event) mChatInput->setText(std::string()); } - if (message.empty() || !mReturnToggles) + if (message.empty() || !config.returnTogglesChat) { // Remove focus and hide input mFocusHandler->focusNone(); @@ -469,7 +466,7 @@ void ChatWindow::whisper(const std::string &nick, if (i != mWhispers.end()) tab = i->second; - else if (config.getBoolValue("whispertab")) + else if (config.whisperTab) tab = addWhisperTab(nick); if (tab) diff --git a/src/gui/chatwindow.h b/src/gui/chatwindow.h index 9b46d7ad..59ab6d99 100644 --- a/src/gui/chatwindow.h +++ b/src/gui/chatwindow.h @@ -152,10 +152,10 @@ class ChatWindow : public Window, /** Override to reset mTmpVisible */ void setVisible(bool visible) override; - void mousePressed(gcn::MouseEvent &event) override; - void mouseDragged(gcn::MouseEvent &event) override; + void mousePressed(gcn::MouseEvent &event) override; + void mouseDragged(gcn::MouseEvent &event) override; - void event(Event::Channel channel, const Event &event) override; + void event(Event::Channel channel, const Event &event) override; /** * Scrolls the chat window @@ -173,9 +173,6 @@ class ChatWindow : public Window, */ void setRecordingFile(const std::string &msg); - bool getReturnTogglesChat() const { return mReturnToggles; } - void setReturnTogglesChat(bool toggles) { mReturnToggles = toggles; } - void doPresent(); void whisper(const std::string &nick, const std::string &mes, @@ -216,9 +213,6 @@ class ChatWindow : public Window, /** Manage whisper tabs */ std::map<const std::string, ChatTab *> mWhispers; - - bool mReturnToggles; /**< Marks whether <Return> toggles the chat log - or not */ }; extern ChatWindow *chatWindow; diff --git a/src/gui/customserverdialog.cpp b/src/gui/customserverdialog.cpp index c4fadca9..c7c03b1a 100644 --- a/src/gui/customserverdialog.cpp +++ b/src/gui/customserverdialog.cpp @@ -20,8 +20,6 @@ #include "gui/customserverdialog.h" -#include "configuration.h" - #include "gui/okdialog.h" #include "gui/sdlinput.h" #include "gui/serverdialog.h" diff --git a/src/gui/customserverdialog.h b/src/gui/customserverdialog.h index 59c1d2cc..8b0af4c8 100644 --- a/src/gui/customserverdialog.h +++ b/src/gui/customserverdialog.h @@ -30,8 +30,6 @@ class TypeListModel; #include "gui/widgets/window.h" -#include "net/serverinfo.h" - #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> #include <guichan/listmodel.hpp> diff --git a/src/gui/emotepopup.cpp b/src/gui/emotepopup.cpp index 8a85aca3..589d5087 100644 --- a/src/gui/emotepopup.cpp +++ b/src/gui/emotepopup.cpp @@ -22,10 +22,10 @@ #include "gui/emotepopup.h" -#include "imagesprite.h" #include "configuration.h" #include "emoteshortcut.h" #include "graphics.h" +#include "imagesprite.h" #include "log.h" #include "resources/emotedb.h" @@ -46,7 +46,7 @@ EmotePopup::EmotePopup() if (!mSelectionImage) logger->error("Unable to load selection.png"); - mSelectionImage->setAlpha(config.getFloatValue("guialpha")); + mSelectionImage->setAlpha(config.guiAlpha); addMouseListener(this); recalculateSize(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 2ff697c7..39314fcf 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -81,7 +81,7 @@ Gui::Gui(Graphics *graphics) ResourceManager *resman = ResourceManager::getInstance(); // Set global font - const int fontSize = config.getValue("fontSize", 11); + const int fontSize = config.fontSize; std::string fontFile = branding.getValue("font", "fonts/dejavusans.ttf"); std::string path = resman->getPath(fontFile); @@ -131,7 +131,7 @@ Gui::Gui(Graphics *graphics) gcn::Widget::setGlobalFont(mGuiFont); // Initialize mouse cursor and listen for changes to the option - setUseCustomCursor(config.getBoolValue("customcursor")); + setUseCustomCursor(config.customCursor); listen(Event::ConfigChannel); } @@ -179,7 +179,7 @@ void Gui::event(Event::Channel channel, const Event &event) if (event.getType() == Event::ConfigOptionChanged && event.getString("option") == "customcursor") { - setUseCustomCursor(config.getBoolValue("customcursor")); + setUseCustomCursor(config.customCursor); } } } diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index cb38fba6..f5206eda 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -26,7 +26,6 @@ #include "configuration.h" #include "graphics.h" #include "localplayer.h" -#include "log.h" #include "map.h" #include "gui/setup.h" @@ -39,13 +38,10 @@ #include <guichan/font.hpp> -bool Minimap::mShow = true; - Minimap::Minimap(): Window(_("Map")) { setWindowName("Minimap"); - mShow = config.getValue(getWindowName() + "Show", true); setDefaultSize(5, 25, 100, 100); // set this to false as the minimap window size is changed //depending on the map size @@ -59,13 +55,11 @@ Minimap::Minimap(): setSticky(false); loadWindowState(); - setVisible(mShow, isSticky()); + setVisible(config.showMinimap, isSticky()); } Minimap::~Minimap() -{ - config.setValue(getWindowName() + "Show", mShow); -} +{} void Minimap::setMap(Map *map) { @@ -122,7 +116,7 @@ void Minimap::setMap(Map *map) setDefaultSize(getX(), getY(), getWidth(), getHeight()); resetToDefaultSize(); - if (mShow) + if (config.showMinimap) setVisible(true); } else @@ -135,7 +129,7 @@ void Minimap::setMap(Map *map) void Minimap::toggle() { setVisible(!isVisible(), isSticky()); - mShow = isVisible(); + config.showMinimap = isVisible(); } void Minimap::draw(gcn::Graphics *graphics) diff --git a/src/gui/minimap.h b/src/gui/minimap.h index 6e80a3c1..8212f5b7 100644 --- a/src/gui/minimap.h +++ b/src/gui/minimap.h @@ -64,7 +64,6 @@ class Minimap : public Window ResourceRef<Image> mMapImage; float mWidthProportion = 0.5; float mHeightProportion = 0.5; - static bool mShow; }; extern Minimap *minimap; diff --git a/src/gui/ministatuswindow.cpp b/src/gui/ministatuswindow.cpp index e22172bc..598cb722 100644 --- a/src/gui/ministatuswindow.cpp +++ b/src/gui/ministatuswindow.cpp @@ -86,7 +86,9 @@ MiniStatusWindow::MiniStatusWindow(): setContentSize(mXpBar->getX() + mXpBar->getWidth(), mXpBar->getY() + mXpBar->getHeight()); - setVisible((bool) config.getValue(getPopupName() + "Visible", true)); + auto stateIt = config.windows.find(getPopupName()); + setVisible(stateIt != config.windows.end() ? stateIt->second.visible.value_or(true) + : true); mTextPopup = new TextPopup(); diff --git a/src/gui/npcdialog.cpp b/src/gui/npcdialog.cpp index 33b512f0..18b3ff1b 100644 --- a/src/gui/npcdialog.cpp +++ b/src/gui/npcdialog.cpp @@ -71,7 +71,6 @@ NpcDialog::DialogList NpcDialog::instances; NpcDialog::NpcDialog(int npcId) : Window(_("NPC")) , mNpcId(npcId) - , mLogInteraction(config.getBoolValue("logNpcInGui")) , mItemLinkHandler(std::make_unique<ItemLinkHandler>(this)) { // Basic Window Setup @@ -141,7 +140,6 @@ NpcDialog::NpcDialog(int npcId) setVisible(true); requestFocus(); - listen(Event::ConfigChannel); PlayerInfo::setNPCInteractionCount(PlayerInfo::getNPCInteractionCount() + 1); } @@ -175,7 +173,7 @@ void NpcDialog::setText(const std::vector<std::string> &text) void NpcDialog::addText(const std::string &text, bool save) { - if (save || mLogInteraction) + if (save || config.logNpcInGui) { mNewText.push_back(text); mTextBox->addRow(text); @@ -244,7 +242,7 @@ void NpcDialog::action(const gcn::ActionEvent &event) mNewText.clear(); } - if (!mLogInteraction) + if (!config.logNpcInGui) setText({}); } else if (event.getId() == "reset") @@ -378,18 +376,6 @@ void NpcDialog::setVisible(bool visible) } } -void NpcDialog::event(Event::Channel channel, const Event &event) -{ - if (channel != Event::ConfigChannel) - return; - - if (event.getType() == Event::ConfigOptionChanged && - event.getString("option") == "logNpcInGui") - { - mLogInteraction = config.getBoolValue("logNpcInGui"); - } -} - void NpcDialog::mouseClicked(gcn::MouseEvent &mouseEvent) { if (mouseEvent.getSource() == mItemList && @@ -457,7 +443,7 @@ void NpcDialog::buildLayout() } else if (mInputState != NPC_INPUT_NONE) { - if (!mLogInteraction) + if (!config.logNpcInGui) setText(mNewText); mNextButton->setCaption(CAPTION_SUBMIT); diff --git a/src/gui/npcdialog.h b/src/gui/npcdialog.h index 42485766..f2b50370 100644 --- a/src/gui/npcdialog.h +++ b/src/gui/npcdialog.h @@ -22,8 +22,6 @@ #ifndef NPCDIALOG_H #define NPCDIALOG_H -#include "eventlistener.h" - #include "gui/widgets/window.h" #include <guichan/actionlistener.hpp> @@ -48,8 +46,7 @@ class Button; */ class NpcDialog final : public Window, public gcn::ActionListener, - public gcn::ListModel, - public EventListener + public gcn::ListModel { public: NpcDialog(int npcId); @@ -143,8 +140,6 @@ class NpcDialog final : public Window, void setVisible(bool visible) override; - void event(Event::Channel channel, const Event &event) override; - void mouseClicked(gcn::MouseEvent &mouseEvent) override; /** @@ -170,7 +165,6 @@ class NpcDialog final : public Window, void buildLayout(); int mNpcId; - bool mLogInteraction; int mDefaultInt = 0; std::string mDefaultString; diff --git a/src/gui/outfitwindow.cpp b/src/gui/outfitwindow.cpp index 77de4b3a..b5033d70 100644 --- a/src/gui/outfitwindow.cpp +++ b/src/gui/outfitwindow.cpp @@ -50,8 +50,7 @@ OutfitWindow::OutfitWindow(): mNextButton = new Button(_(">"), "next", this); mCurrentLabel = new Label(strprintf(_("Outfit: %d"), 1)); mCurrentLabel->setAlignment(gcn::Graphics::CENTER); - mUnequipCheck = new CheckBox(_("Unequip first"), - config.getValue("OutfitUnequip0", true)); + mUnequipCheck = new CheckBox(_("Unequip first")); mUnequipCheck->setActionEventId("unequip"); mUnequipCheck->addActionListener(this); @@ -68,6 +67,8 @@ OutfitWindow::OutfitWindow(): loadWindowState(); load(); + + mUnequipCheck->setSelected(mOutfits[mCurrentOutfit].unequip); } OutfitWindow::~OutfitWindow() @@ -77,34 +78,48 @@ OutfitWindow::~OutfitWindow() void OutfitWindow::load() { - memset(mItems, -1, sizeof(mItems)); for (int o = 0; o < OUTFITS_COUNT; o++) + memset(mOutfits[o].items, -1, sizeof(mOutfits[o].items)); + + for (auto &outfit : config.outfits) { - std::string outfit = config.getValue("Outfit" + toString(o), "-1"); + if (outfit.index < 0 || outfit.index >= OUTFITS_COUNT) + continue; + std::string buf; - std::stringstream ss(outfit); + std::stringstream ss(outfit.items); for (size_t i = 0; (ss >> buf) && i < OUTFIT_ITEM_COUNT; i++) { - mItems[o][i] = atoi(buf.c_str()); + mOutfits[outfit.index].items[i] = atoi(buf.c_str()); } - mItemsUnequip[o] = config.getValue("OutfitUnequip" + toString(o), true); + mOutfits[outfit.index].unequip = outfit.unequip; } } void OutfitWindow::save() { + config.outfits.clear(); + std::string outfitStr; for (int o = 0; o < OUTFITS_COUNT; o++) { + auto &items = mOutfits[o].items; + bool emptyOutfit = true; + for (int i = 0; i < OUTFIT_ITEM_COUNT; i++) { - outfitStr += mItems[o][i] ? toString(mItems[o][i]) : toString(-1); - if (i <8) outfitStr += " "; + if (!outfitStr.empty()) + outfitStr += " "; + + outfitStr += items[i] ? toString(items[i]) : toString(-1); + emptyOutfit &= items[i] <= 0; } - config.setValue("Outfit" + toString(o), outfitStr); - config.setValue("OutfitUnequip" + toString(o), mItemsUnequip[o]); + + if (!emptyOutfit) + config.outfits.push_back({ o, outfitStr, mOutfits[o].unequip }); + outfitStr.clear(); } } @@ -118,7 +133,7 @@ void OutfitWindow::action(const gcn::ActionEvent &event) else mCurrentOutfit = 0; mCurrentLabel->setCaption(strprintf(_("Outfit: %d"), mCurrentOutfit + 1)); - mUnequipCheck->setSelected(mItemsUnequip[mCurrentOutfit]); + mUnequipCheck->setSelected(mOutfits[mCurrentOutfit].unequip); } else if (event.getId() == "previous") { @@ -131,23 +146,23 @@ void OutfitWindow::action(const gcn::ActionEvent &event) mCurrentOutfit = OUTFITS_COUNT - 1; } mCurrentLabel->setCaption(strprintf(_("Outfit: %d"), mCurrentOutfit + 1)); - mUnequipCheck->setSelected(mItemsUnequip[mCurrentOutfit]); + mUnequipCheck->setSelected(mOutfits[mCurrentOutfit].unequip); } else if (event.getId() == "unequip") { - mItemsUnequip[mCurrentOutfit] = mUnequipCheck->isSelected(); + mOutfits[mCurrentOutfit].unequip = mUnequipCheck->isSelected(); } } void OutfitWindow::wearOutfit(int outfit) { - if (mItemsUnequip[outfit]) + if (mOutfits[outfit].unequip) unequipNotInOutfit(outfit); Item *item; for (int i = 0; i < OUTFIT_ITEM_COUNT; i++) { - item = PlayerInfo::getInventory()->findItem(mItems[outfit][i]); + item = PlayerInfo::getInventory()->findItem(mOutfits[outfit].items[i]); if (item && !item->isEquipped() && item->getQuantity()) { if (item->isEquippable()) @@ -160,7 +175,7 @@ void OutfitWindow::copyOutfit(int outfit) { for (int i = 0; i < OUTFIT_ITEM_COUNT; i++) { - mItems[mCurrentOutfit][i] = mItems[outfit][i]; + mOutfits[mCurrentOutfit].items[i] = mOutfits[outfit].items[i]; } } @@ -183,15 +198,15 @@ void OutfitWindow::draw(gcn::Graphics *graphics) ITEM_ICON_SIZE, ITEM_ICON_SIZE)); - if (mItems[mCurrentOutfit][i] < 0) + if (mOutfits[mCurrentOutfit].items[i] < 0) { continue; } Item *item = - PlayerInfo::getInventory()->findItem(mItems[mCurrentOutfit][i]); + PlayerInfo::getInventory()->findItem(mOutfits[mCurrentOutfit].items[i]); if (item) - { + { // Draw item icon. if (Image *image = item->getImage()) { @@ -199,6 +214,7 @@ void OutfitWindow::draw(gcn::Graphics *graphics) } } } + if (mItemMoved) { // Draw the item image being dragged by the cursor. @@ -216,6 +232,7 @@ void OutfitWindow::draw(gcn::Graphics *graphics) void OutfitWindow::mouseDragged(gcn::MouseEvent &event) { Window::mouseDragged(event); + if (event.getButton() == gcn::MouseEvent::LEFT) { if (!mItemMoved && mItemClicked) @@ -223,16 +240,18 @@ void OutfitWindow::mouseDragged(gcn::MouseEvent &event) const int index = getIndexFromGrid(event.getX(), event.getY()); if (index == -1) return; - const int itemId = mItems[mCurrentOutfit][index]; + + const int itemId = mOutfits[mCurrentOutfit].items[index]; if (itemId < 0) return; - Item *item = PlayerInfo::getInventory()->findItem(itemId); - if (item) + + if (Item *item = PlayerInfo::getInventory()->findItem(itemId)) { mItemMoved = item; - mItems[mCurrentOutfit][index] = -1; + mOutfits[mCurrentOutfit].items[index] = -1; } } + if (mItemMoved) { mCursorPosX = event.getX(); @@ -251,10 +270,10 @@ void OutfitWindow::mousePressed(gcn::MouseEvent &event) // Stores the selected item if there is one. if (isItemSelected()) { - mItems[mCurrentOutfit][index] = mItemSelected; + mOutfits[mCurrentOutfit].items[index] = mItemSelected; mItemSelected = -1; } - else if (mItems[mCurrentOutfit][index]) + else if (mOutfits[mCurrentOutfit].items[index]) { mItemClicked = true; } @@ -277,7 +296,7 @@ void OutfitWindow::mouseReleased(gcn::MouseEvent &event) } if (mItemMoved) { - mItems[mCurrentOutfit][index] = mItemMoved->getId(); + mOutfits[mCurrentOutfit].items[index] = mItemMoved->getId(); mItemMoved = nullptr; } if (mItemClicked) @@ -311,7 +330,7 @@ void OutfitWindow::unequipNotInOutfit(int outfit) bool found = false; for (int f = 0; f < OUTFIT_ITEM_COUNT; f++) { - if (inventory->getItem(i)->getId() == mItems[outfit][f]) + if (inventory->getItem(i)->getId() == mOutfits[outfit].items[f]) { found = true; break; @@ -319,9 +338,7 @@ void OutfitWindow::unequipNotInOutfit(int outfit) } if (!found) { - Item *item = inventory->getItem(i); - - if (item) + if (Item *item = inventory->getItem(i)) item->doEvent(Event::DoUnequip); } } diff --git a/src/gui/outfitwindow.h b/src/gui/outfitwindow.h index aa07e020..56e96795 100644 --- a/src/gui/outfitwindow.h +++ b/src/gui/outfitwindow.h @@ -78,8 +78,13 @@ class OutfitWindow : public Window, gcn::ActionListener void save(); - int mItems[OUTFITS_COUNT][OUTFIT_ITEM_COUNT]; - bool mItemsUnequip[OUTFITS_COUNT]; + struct Outfit + { + int items[OUTFIT_ITEM_COUNT]; + bool unequip = true; + }; + + Outfit mOutfits[OUTFITS_COUNT]; int mItemSelected = -1; int mCurrentOutfit = 0; diff --git a/src/gui/palette.h b/src/gui/palette.h index b81d8865..9de911d5 100644 --- a/src/gui/palette.h +++ b/src/gui/palette.h @@ -33,7 +33,7 @@ #include <vector> // Default Gradient Delay -#define GRADIENT_DELAY 40 +constexpr int GRADIENT_DELAY = 40; /** * Class controlling the game's color palette. diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index bb978a78..01b477da 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -52,19 +52,6 @@ static const int MAX_SERVERLIST = 6; -static std::string serverTypeToString(ServerType type) -{ - switch (type) - { - case ServerType::TMWATHENA: - return "TmwAthena"; - case ServerType::MANASERV: - return "ManaServ"; - default: - return std::string(); - } -} - ServersListModel::ServersListModel(ServerInfos *servers, ServerDialog *parent): mServers(servers), mVersionStrings(servers->size(), VersionString(0, std::string())), @@ -413,7 +400,7 @@ void ServerDialog::downloadServerList() std::string listFile = branding.getStringValue("onlineServerList"); if (listFile.empty()) - listFile = config.getStringValue("onlineServerList"); + listFile = config.onlineServerList; // Fall back to manasource.org when neither branding nor config set it if (listFile.empty()) @@ -533,38 +520,18 @@ void ServerDialog::loadServers() void ServerDialog::loadCustomServers() { - for (int i = 0; i < MAX_SERVERLIST; ++i) + for (auto &server : config.servers) { - const std::string index = toString(i); - const std::string nameKey = "MostUsedServerDescName" + index; - const std::string hostNameKey = "MostUsedServerName" + index; - const std::string typeKey = "MostUsedServerType" + index; - const std::string portKey = "MostUsedServerPort" + index; - const std::string descriptionKey = "MostUsedServerDescription" + index; - - ServerInfo server; - server.name = config.getValue(nameKey, std::string()); - server.hostname = config.getValue(hostNameKey, std::string()); - server.type = ServerInfo::parseType(config.getValue(typeKey, std::string())); - - const uint16_t defaultPort = ServerInfo::defaultPortForServerType(server.type); - server.port = static_cast<uint16_t>(config.getValue(portKey, defaultPort)); - server.description = config.getValue(descriptionKey, std::string()); - - // Stop on the first invalid server - if (!server.isValid()) - break; - - server.save = true; - - mServers.push_back(server); + if (server.isValid()) + { + server.save = true; + mServers.push_back(server); + } } } void ServerDialog::saveCustomServers(const ServerInfo ¤tServer, int index) { - ServerInfos::iterator it, it_end = mServers.end(); - // Make sure the current server is mentioned first if (currentServer.isValid()) { @@ -574,7 +541,7 @@ void ServerDialog::saveCustomServers(const ServerInfo ¤tServer, int index) } else { - for (it = mServers.begin(); it != it_end; ++it) + for (auto it = mServers.begin(), it_end = mServers.end(); it != it_end; ++it) { if (*it == currentServer) { @@ -586,35 +553,7 @@ void ServerDialog::saveCustomServers(const ServerInfo ¤tServer, int index) } } - int savedServerCount = 0; - - for (it = mServers.begin(), it_end = mServers.end(); - it != it_end && savedServerCount < MAX_SERVERLIST; ++it) - { - const ServerInfo &server = *it; - - // Only save servers that were loaded from settings - if (!(server.save && server.isValid())) - continue; - - const std::string index = toString(savedServerCount); - const std::string nameKey = "MostUsedServerDescName" + index; - const std::string hostNameKey = "MostUsedServerName" + index; - const std::string typeKey = "MostUsedServerType" + index; - const std::string portKey = "MostUsedServerPort" + index; - const std::string descriptionKey = "MostUsedServerDescription" + index; - - config.setValue(hostNameKey, toString(server.hostname)); - config.setValue(typeKey, serverTypeToString(server.type)); - config.setValue(portKey, toString(server.port)); - config.setValue(nameKey, server.name); - config.setValue(descriptionKey, server.description); - ++savedServerCount; - } - - // Insert an invalid entry at the end to make the loading stop there - if (savedServerCount < MAX_SERVERLIST) - config.setValue("MostUsedServerName" + toString(savedServerCount), std::string()); + config.servers = mServers; // Restore the correct description if (index < 0) diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp index 6d18e71f..f51bfcb6 100644 --- a/src/gui/setup_audio.cpp +++ b/src/gui/setup_audio.cpp @@ -34,11 +34,11 @@ #include "utils/gettext.h" Setup_Audio::Setup_Audio(): - mMusicVolume(config.getIntValue("musicVolume")), - mSfxVolume(config.getIntValue("sfxVolume")), - mNotificationsVolume(config.getIntValue("notificationsVolume")), - mSoundEnabled(config.getBoolValue("sound")), - mDownloadEnabled(config.getBoolValue("download-music")), + mMusicVolume(config.musicVolume), + mSfxVolume(config.sfxVolume), + mNotificationsVolume(config.notificationsVolume), + mSoundEnabled(config.sound), + mDownloadEnabled(config.downloadMusic), mSoundCheckBox(new CheckBox(_("Sound"), mSoundEnabled)), mDownloadMusicCheckBox(new CheckBox(_("Download music"), mDownloadEnabled)), mSfxSlider(new Slider(0, sound.getMaxVolume())), @@ -84,19 +84,19 @@ void Setup_Audio::apply() { mSoundEnabled = mSoundCheckBox->isSelected(); mDownloadEnabled = mDownloadMusicCheckBox->isSelected(); - mSfxVolume = config.getIntValue("sfxVolume"); - mNotificationsVolume = config.getIntValue("sfxVolume"); - mMusicVolume = config.getIntValue("musicVolume"); + mSfxVolume = config.sfxVolume; + mNotificationsVolume = config.sfxVolume; + mMusicVolume = config.musicVolume; - config.setValue("sound", mSoundEnabled); + config.sound = mSoundEnabled; // Display a message if user has selected to download music, // And if downloadmusic is not already enabled - if (mDownloadEnabled && !config.getBoolValue("download-music")) + if (mDownloadEnabled && !config.downloadMusic) { new OkDialog(_("Notice"),_("You may have to restart your client if you want to download new music")); } - config.setValue("download-music", mDownloadEnabled); + config.downloadMusic = mDownloadEnabled; if (mSoundEnabled) { @@ -127,10 +127,10 @@ void Setup_Audio::cancel() sound.setMusicVolume(mMusicVolume); mMusicSlider->setValue(mMusicVolume); - config.setValue("sound", mSoundEnabled); - config.setValue("download-music", mDownloadEnabled); - config.setValue("sfxVolume", mSfxVolume); - config.setValue("musicVolume", mMusicVolume); + config.sound = mSoundEnabled; + config.downloadMusic = mDownloadEnabled; + config.sfxVolume = mSfxVolume; + config.musicVolume = mMusicVolume; } void Setup_Audio::action(const gcn::ActionEvent &event) @@ -138,19 +138,19 @@ void Setup_Audio::action(const gcn::ActionEvent &event) if (event.getId() == "sfx") { int volume = (int) mSfxSlider->getValue(); - config.setValue("sfxVolume", volume); + config.sfxVolume = volume; sound.setSfxVolume(volume); } else if (event.getId() == "notifications") { int volume = (int) mNotificationsSlider->getValue(); - config.setValue("notificationsVolume", volume); + config.notificationsVolume = volume; sound.setNotificationsVolume(volume); } else if (event.getId() == "music") { int volume = (int) mMusicSlider->getValue(); - config.setValue("musicVolume", volume); + config.musicVolume = volume; sound.setMusicVolume(volume); } } diff --git a/src/gui/setup_interface.cpp b/src/gui/setup_interface.cpp index 3801861b..229898c7 100644 --- a/src/gui/setup_interface.cpp +++ b/src/gui/setup_interface.cpp @@ -77,14 +77,14 @@ static const char *speechModeToString(Being::Speech mode) } Setup_Interface::Setup_Interface(): - mShowMonsterDamageEnabled(config.getBoolValue("showMonstersTakedDamage")), - mVisibleNamesEnabled(config.getBoolValue("visiblenames")), - mNameEnabled(config.getBoolValue("showownname")), - mNPCLogEnabled(config.getBoolValue("logNpcInGui")), - mPickupChatEnabled(config.getBoolValue("showpickupchat")), - mPickupParticleEnabled(config.getBoolValue("showpickupparticle")), - mOpacity(config.getFloatValue("guialpha")), - mSpeechMode(static_cast<Being::Speech>(config.getIntValue("speech"))), + mShowMonsterDamageEnabled(config.showMonstersTakedDamage), + mVisibleNamesEnabled(config.visibleNames), + mNameEnabled(config.showOwnName), + mNPCLogEnabled(config.logNpcInGui), + mPickupChatEnabled(config.showPickupChat), + mPickupParticleEnabled(config.showPickupParticle), + mOpacity(config.guiAlpha), + mSpeechMode(config.speech), mVisibleNamesCheckBox(new CheckBox(_("Visible names"), mVisibleNamesEnabled)), mNameCheckBox(new CheckBox(_("Show own name"), mNameEnabled)), @@ -98,7 +98,7 @@ Setup_Interface::Setup_Interface(): mSpeechSlider(new Slider(0, 3)), mSpeechLabel(new Label(std::string())), mAlphaSlider(new Slider(0.2, 1.0)), - mFontSize(config.getIntValue("fontSize")) + mFontSize(config.fontSize) { setName(_("Interface")); @@ -117,7 +117,7 @@ Setup_Interface::Setup_Interface(): mAlphaSlider->setValue(mOpacity); mAlphaSlider->setWidth(90); - mAlphaSlider->setEnabled(!config.getBoolValue("disableTransparency")); + mAlphaSlider->setEnabled(!config.disableTransparency); // Set actions @@ -182,16 +182,16 @@ Setup_Interface::~Setup_Interface() void Setup_Interface::apply() { - config.setValue("fontSize", mFontSizeDropDown->getSelected() + 10); - - mShowMonsterDamageEnabled = config.getBoolValue("showMonstersTakedDamage"); - mVisibleNamesEnabled = config.getBoolValue("visiblenames"); - mNameEnabled = config.getBoolValue("showownname"); - mNPCLogEnabled = config.getBoolValue("logNpcInGui"); - mSpeechMode = static_cast<Being::Speech>(config.getIntValue("speech")); - mOpacity = config.getFloatValue("guialpha"); - mPickupChatEnabled = config.getBoolValue("showpickupchat"); - mPickupParticleEnabled = config.getBoolValue("showpickupparticle"); + config.fontSize = mFontSizeDropDown->getSelected() + 10; + + mShowMonsterDamageEnabled = config.showMonstersTakedDamage; + mVisibleNamesEnabled = config.visibleNames; + mNameEnabled = config.showOwnName; + mNPCLogEnabled = config.logNpcInGui; + mSpeechMode = config.speech; + mOpacity = config.guiAlpha; + mPickupChatEnabled = config.showPickupChat; + mPickupParticleEnabled = config.showPickupParticle; } void Setup_Interface::cancel() @@ -204,14 +204,14 @@ void Setup_Interface::cancel() mAlphaSlider->setValue(mOpacity); //mAlphaSlider->setEnabled(!mSDLTransparencyDisabled); - config.setValue("showMonstersTakedDamage", mShowMonsterDamageEnabled); - config.setValue("visiblenames", mVisibleNamesEnabled); - config.setValue("speech", mSpeechMode); - config.setValue("showownname", mNameEnabled); - config.setValue("logNpcInGui", mNPCLogEnabled); - config.setValue("guialpha", mOpacity); - config.setValue("showpickupchat", mPickupChatEnabled); - config.setValue("showpickupparticle", mPickupParticleEnabled); + config.showMonstersTakedDamage = mShowMonsterDamageEnabled; + config.visibleNames = mVisibleNamesEnabled; + config.speech = mSpeechMode; + config.showOwnName = mNameEnabled; + config.logNpcInGui = mNPCLogEnabled; + config.guiAlpha = mOpacity; + config.showPickupChat = mPickupChatEnabled; + config.showPickupParticle = mPickupParticleEnabled; } void Setup_Interface::action(const gcn::ActionEvent &event) @@ -220,38 +220,37 @@ void Setup_Interface::action(const gcn::ActionEvent &event) if (id == "guialpha") { - config.setValue("guialpha", mAlphaSlider->getValue()); + config.guiAlpha = mAlphaSlider->getValue(); } else if (id == "monsterdamage") { - config.setValue("showMonstersTakedDamage", mShowMonsterDamageCheckBox->isSelected()); + config.showMonstersTakedDamage = mShowMonsterDamageCheckBox->isSelected(); } else if (id == "visiblenames") { - config.setValue("visiblenames", mVisibleNamesCheckBox->isSelected()); + config.visibleNames = mVisibleNamesCheckBox->isSelected(); } else if (id == "pickupchat") { - config.setValue("showpickupchat", mPickupChatCheckBox->isSelected()); + config.showPickupChat = mPickupChatCheckBox->isSelected(); } else if (id == "pickupparticle") { - config.setValue("showpickupparticle", - mPickupParticleCheckBox->isSelected()); + config.showPickupParticle = mPickupParticleCheckBox->isSelected(); } else if (id == "speech") { auto val = (Being::Speech)mSpeechSlider->getValue(); mSpeechLabel->setCaption(speechModeToString(val)); mSpeechSlider->setValue(val); - config.setValue("speech", val); + config.speech = val; } else if (id == "showownname") { - config.setValue("showownname", mNameCheckBox->isSelected()); + config.showOwnName = mNameCheckBox->isSelected(); } else if (id == "lognpc") { - config.setValue("logNpcInGui", mNPCLogCheckBox->isSelected()); + config.logNpcInGui = mNPCLogCheckBox->isSelected(); } } diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp index 1109f06e..17e86ea9 100644 --- a/src/gui/setup_joystick.cpp +++ b/src/gui/setup_joystick.cpp @@ -39,7 +39,7 @@ Setup_Joystick::Setup_Joystick(): { setName(_("Joystick")); - mJoystickEnabled = config.getBoolValue("joystickEnabled"); + mJoystickEnabled = config.joystickEnabled; mJoystickCheckBox->setSelected(mJoystickEnabled); mJoystickCheckBox->addActionListener(this); @@ -90,7 +90,5 @@ void Setup_Joystick::cancel() void Setup_Joystick::apply() { - config.setValue("joystickEnabled", - joystick ? joystick->isEnabled() : false); + config.joystickEnabled = joystick && joystick->isEnabled(); } - diff --git a/src/gui/setup_keyboard.h b/src/gui/setup_keyboard.h index 1ecb5ea3..1c9d1733 100644 --- a/src/gui/setup_keyboard.h +++ b/src/gui/setup_keyboard.h @@ -29,8 +29,6 @@ #include <guichan/actionlistener.hpp> -#include <string> - class Setup_Keyboard : public SetupTab, public gcn::ActionListener { public: diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp index a771d7ae..501fc83a 100644 --- a/src/gui/setup_players.cpp +++ b/src/gui/setup_players.cpp @@ -201,9 +201,6 @@ public: #define ACTION_DELETE "delete" #define ACTION_TABLE "table" #define ACTION_STRATEGY "strategy" -#define ACTION_WHISPER_TAB "whisper tab" -#define ACTION_SHOW_GENDER "show gender" -#define ACTION_ENABLE_CHAT_LOG "enable log" Setup_Players::Setup_Players(): mPlayerTableTitleModel(new StaticTableModel(1, COLUMNS_NR)), @@ -216,12 +213,9 @@ Setup_Players::Setup_Players(): mDefaultWhisper(new CheckBox(_("Allow whispers"), player_relations.getDefault() & PlayerPermissions::WHISPER)), mDeleteButton(new Button(_("Delete"), ACTION_DELETE, this)), - mWhisperTab(config.getBoolValue("whispertab")), - mWhisperTabCheckBox(new CheckBox(_("Put all whispers in tabs"), mWhisperTab)), - mShowGender(config.getBoolValue("showgender")), - mShowGenderCheckBox(new CheckBox(_("Show gender"), mShowGender)), - mEnableChatLog(config.getBoolValue("enableChatLog")), - mEnableChatLogCheckBox(new CheckBox(_("Enable Chat log"), mEnableChatLog)) + mWhisperTabCheckBox(new CheckBox(_("Put all whispers in tabs"), config.whisperTab)), + mShowGenderCheckBox(new CheckBox(_("Show gender"), config.showGender)), + mEnableChatLogCheckBox(new CheckBox(_("Enable Chat log"), config.enableChatLog)) { setName(_("Players")); @@ -253,27 +247,18 @@ Setup_Players::Setup_Players(): mIgnoreActionChoicesBox->setActionEventId(ACTION_STRATEGY); mIgnoreActionChoicesBox->addActionListener(this); - int ignore_strategy_index = 0; // safe default + int ignoreStrategyIndex = 0; // safe default - if (player_relations.getPlayerIgnoreStrategy()) + if (auto ignoreStrategy = player_relations.getPlayerIgnoreStrategy()) { - ignore_strategy_index = player_relations.getPlayerIgnoreStrategyIndex( - player_relations.getPlayerIgnoreStrategy()->mShortName); - if (ignore_strategy_index < 0) - ignore_strategy_index = 0; + ignoreStrategyIndex = player_relations.getPlayerIgnoreStrategyIndex( + ignoreStrategy->mShortName); + if (ignoreStrategyIndex < 0) + ignoreStrategyIndex = 0; } - mIgnoreActionChoicesBox->setSelected(ignore_strategy_index); + mIgnoreActionChoicesBox->setSelected(ignoreStrategyIndex); mIgnoreActionChoicesBox->adjustHeight(); - mWhisperTabCheckBox->setActionEventId(ACTION_WHISPER_TAB); - mWhisperTabCheckBox->addActionListener(this); - - mShowGenderCheckBox->setActionEventId(ACTION_SHOW_GENDER); - mShowGenderCheckBox->addActionListener(this); - - mEnableChatLogCheckBox->setActionEventId(ACTION_ENABLE_CHAT_LOG); - mEnableChatLogCheckBox->addActionListener(this); - reset(); // Do the layout @@ -323,26 +308,22 @@ void Setup_Players::apply() PlayerPermissions::TRADE : 0) | (mDefaultWhisper->isSelected() ? PlayerPermissions::WHISPER : 0)); - config.setValue("whispertab", mWhisperTab); - bool showGender = config.getBoolValue("showgender"); + const bool showGenderChanged = config.showGender != mShowGenderCheckBox->isSelected(); - config.setValue("showgender", mShowGender); + config.whisperTab = mWhisperTabCheckBox->isSelected(); + config.showGender = mShowGenderCheckBox->isSelected(); + config.enableChatLog = mEnableChatLogCheckBox->isSelected(); - if (actorSpriteManager && mShowGender != showGender) + if (actorSpriteManager && showGenderChanged) actorSpriteManager->updatePlayerNames(); - - config.setValue("enableChatLog", mEnableChatLog); } void Setup_Players::cancel() { - mWhisperTab = config.getBoolValue("whispertab"); - mWhisperTabCheckBox->setSelected(mWhisperTab); - mShowGender = config.getBoolValue("showgender"); - mShowGenderCheckBox->setSelected(mShowGender); - mEnableChatLog = config.getBoolValue("enableChatLog"); - mEnableChatLogCheckBox->setSelected(mEnableChatLog); + mWhisperTabCheckBox->setSelected(config.whisperTab); + mShowGenderCheckBox->setSelected(config.showGender); + mEnableChatLogCheckBox->setSelected(config.enableChatLog); } void Setup_Players::action(const gcn::ActionEvent &event) @@ -380,18 +361,6 @@ void Setup_Players::action(const gcn::ActionEvent &event) player_relations.setPlayerIgnoreStrategy(s); } - else if (event.getId() == ACTION_WHISPER_TAB) - { - mWhisperTab = mWhisperTabCheckBox->isSelected(); - } - else if (event.getId() == ACTION_SHOW_GENDER) - { - mShowGender = mShowGenderCheckBox->isSelected(); - } - else if (event.getId() == ACTION_ENABLE_CHAT_LOG) - { - mEnableChatLog = mEnableChatLogCheckBox->isSelected(); - } } void Setup_Players::playerRelationsUpdated() diff --git a/src/gui/setup_players.h b/src/gui/setup_players.h index 758c646d..48a08e83 100644 --- a/src/gui/setup_players.h +++ b/src/gui/setup_players.h @@ -65,13 +65,8 @@ private: gcn::ListModel *mIgnoreActionChoicesModel; gcn::DropDown *mIgnoreActionChoicesBox; - bool mWhisperTab; gcn::CheckBox *mWhisperTabCheckBox; - - bool mShowGender; gcn::CheckBox *mShowGenderCheckBox; - - bool mEnableChatLog; gcn::CheckBox *mEnableChatLogCheckBox; }; diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index 5f7dc7b4..efa56cb8 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -186,7 +186,7 @@ private: static const char *overlayDetailToString(int detail) { if (detail == -1) - detail = config.getIntValue("OverlayDetail"); + detail = config.overlayDetail; switch (detail) { @@ -200,7 +200,7 @@ static const char *overlayDetailToString(int detail) static const char *particleDetailToString(int detail) { if (detail == -1) - detail = 3 - config.getIntValue("particleEmitterSkip"); + detail = 3 - config.particleEmitterSkip; switch (detail) { @@ -214,10 +214,10 @@ static const char *particleDetailToString(int detail) Setup_Video::Setup_Video(): mVideoSettings(Client::getVideo().settings()), - mCustomCursorEnabled(config.getBoolValue("customcursor")), - mParticleEffectsEnabled(config.getBoolValue("particleeffects")), - mFps(config.getIntValue("fpslimit")), - mSDLTransparencyDisabled(config.getBoolValue("disableTransparency")), + mCustomCursorEnabled(config.customCursor), + mParticleEffectsEnabled(config.particleEffects), + mFps(config.fpsLimit), + mSDLTransparencyDisabled(config.disableTransparency), mWindowModeListModel(new StringListModel({ _("Windowed"), _("Windowed Fullscreen"), _("Fullscreen") })), mResolutionListModel(new ResolutionListModel), mScaleListModel(new ScaleListModel(mVideoSettings)), @@ -231,10 +231,10 @@ Setup_Video::Setup_Video(): mFpsCheckBox(new CheckBox(_("FPS limit:"))), mFpsSlider(new Slider(10, 120)), mFpsLabel(new Label), - mOverlayDetail(config.getIntValue("OverlayDetail")), + mOverlayDetail(config.overlayDetail), mOverlayDetailSlider(new Slider(0, 2)), mOverlayDetailField(new Label), - mParticleDetail(3 - config.getIntValue("particleEmitterSkip")), + mParticleDetail(3 - config.particleEmitterSkip), mParticleDetailSlider(new Slider(0, 3)), mParticleDetailField(new Label), mDisableSDLTransparencyCheckBox( @@ -361,11 +361,11 @@ void Setup_Video::apply() if (video.apply(mVideoSettings)) { - config.setValue("windowmode", static_cast<int>(mVideoSettings.windowMode)); - config.setValue("scale", mVideoSettings.userScale); - config.setValue("vsync", mVideoSettings.vsync); - config.setValue("screenwidth", mVideoSettings.width); - config.setValue("screenheight", mVideoSettings.height); + config.windowMode = mVideoSettings.windowMode; + config.scale = mVideoSettings.userScale; + config.vsync = mVideoSettings.vsync; + config.screenWidth = mVideoSettings.width; + config.screenHeight = mVideoSettings.height; Client::instance()->checkGraphicsSize(); } @@ -377,7 +377,7 @@ void Setup_Video::apply() // OpenGL change if (mOpenGLCheckBox->isSelected() != mVideoSettings.openGL) { - config.setValue("opengl", mOpenGLCheckBox->isSelected()); + config.opengl = mOpenGLCheckBox->isSelected(); // OpenGL can currently only be changed by restarting, notify user. if (mOpenGLCheckBox->isSelected()) @@ -397,7 +397,7 @@ void Setup_Video::apply() // If LowCPU is enabled from a disabled state we warn the user else if (mDisableSDLTransparencyCheckBox->isSelected()) { - if (!config.getBoolValue("disableTransparency")) + if (!config.disableTransparency) { new OkDialog(_("Transparency disabled"), _("You must restart to apply changes.")); @@ -405,29 +405,28 @@ void Setup_Video::apply() } else { - if (config.getBoolValue("disableTransparency")) + if (config.disableTransparency) { new OkDialog(_("Transparency enabled"), _("You must restart to apply changes.")); } } - config.setValue("disableTransparency", - mDisableSDLTransparencyCheckBox->isSelected()); + config.disableTransparency = mDisableSDLTransparencyCheckBox->isSelected(); mFps = mFpsCheckBox->isSelected() ? (int) mFpsSlider->getValue() : 0; mFpsSlider->setEnabled(mFps > 0); // FPS change - config.setValue("fpslimit", mFps); + config.fpsLimit = mFps; // We sync old and new values at apply time - mVideoSettings.windowMode = static_cast<WindowMode>(config.getIntValue("windowmode")); - mVideoSettings.vsync = config.getBoolValue("vsync"); - mVideoSettings.openGL = config.getBoolValue("opengl"); - mCustomCursorEnabled = config.getBoolValue("customcursor"); - mParticleEffectsEnabled = config.getBoolValue("particleeffects"); - mOverlayDetail = config.getIntValue("OverlayDetail"); - mSDLTransparencyDisabled = config.getBoolValue("disableTransparency"); + mVideoSettings.windowMode = config.windowMode; + mVideoSettings.vsync = config.vsync; + mVideoSettings.openGL = config.opengl; + mCustomCursorEnabled = config.customCursor; + mParticleEffectsEnabled = config.particleEffects; + mOverlayDetail = config.overlayDetail; + mSDLTransparencyDisabled = config.disableTransparency; } void Setup_Video::cancel() @@ -452,12 +451,12 @@ void Setup_Video::cancel() mDisableSDLTransparencyCheckBox->setSelected(mSDLTransparencyDisabled); mDisableSDLTransparencyCheckBox->setEnabled(!mVideoSettings.openGL); - config.setValue("windowmode", static_cast<int>(mVideoSettings.windowMode)); + config.windowMode = mVideoSettings.windowMode; - config.setValue("customcursor", mCustomCursorEnabled); - config.setValue("particleeffects", mParticleEffectsEnabled); - config.setValue("opengl", mVideoSettings.openGL); - config.setValue("disableTransparency", mSDLTransparencyDisabled); + config.customCursor = mCustomCursorEnabled; + config.particleEffects = mParticleEffectsEnabled; + config.opengl = mVideoSettings.openGL; + config.disableTransparency = mSDLTransparencyDisabled; } void Setup_Video::action(const gcn::ActionEvent &event) @@ -490,12 +489,11 @@ void Setup_Video::action(const gcn::ActionEvent &event) } else if (id == "customcursor") { - config.setValue("customcursor", mCustomCursorCheckBox->isSelected()); + config.customCursor = mCustomCursorCheckBox->isSelected(); } else if (id == "particleeffects") { - config.setValue("particleeffects", - mParticleEffectsCheckBox->isSelected()); + config.particleEffects = mParticleEffectsCheckBox->isSelected(); Particle::enabled = mParticleEffectsCheckBox->isSelected(); if (Game::instance()) @@ -508,13 +506,13 @@ void Setup_Video::action(const gcn::ActionEvent &event) { int val = (int) mOverlayDetailSlider->getValue(); mOverlayDetailField->setCaption(overlayDetailToString(val)); - config.setValue("OverlayDetail", val); + config.overlayDetail = val; } else if (id == "particledetailslider") { int val = (int) mParticleDetailSlider->getValue(); mParticleDetailField->setCaption(particleDetailToString(val)); - config.setValue("particleEmitterSkip", 3 - val); + config.particleEmitterSkip = 3 - val; Particle::emitterSkip = 4 - val; } else if (id == "fpslimitcheckbox" || id == "fpslimitslider") diff --git a/src/gui/updaterwindow.cpp b/src/gui/updaterwindow.cpp index a92911b4..772df725 100644 --- a/src/gui/updaterwindow.cpp +++ b/src/gui/updaterwindow.cpp @@ -464,7 +464,7 @@ void UpdaterWindow::logic() const UpdateFile &thisFile = mUpdateFiles[mUpdateIndex]; if (!thisFile.required) { - if (!(thisFile.type == "music" && config.getBoolValue("download-music"))) + if (!(thisFile.type == "music" && config.downloadMusic)) { mUpdateIndex++; break; diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index 8fcca014..558ce0e6 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -49,11 +49,6 @@ Viewport::Viewport() setOpaque(false); addMouseListener(this); - mScrollLaziness = config.getIntValue("ScrollLaziness"); - mScrollRadius = config.getIntValue("ScrollRadius"); - mScrollCenterOffsetX = config.getIntValue("ScrollCenterOffsetX"); - mScrollCenterOffsetY = config.getIntValue("ScrollCenterOffsetY"); - mPopupMenu = new PopupMenu; mBeingPopup = new BeingPopup; @@ -95,8 +90,8 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) auto *graphics = static_cast<Graphics*>(gcnGraphics); // Calculate viewpoint - int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 2; - int midTileY = (graphics->getHeight() + mScrollCenterOffsetX) / 2; + int midTileX = (graphics->getWidth() + config.scrollCenterOffsetX) / 2; + int midTileY = (graphics->getHeight() + config.scrollCenterOffsetY) / 2; const Vector &playerPos = local_player->getPosition(); const int player_x = (int) playerPos.x - midTileX; @@ -105,34 +100,34 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) const float ticks = Time::deltaTimeMs() / static_cast<float>(MILLISECONDS_IN_A_TICK); float scrollFraction = 1.0f; - if (mScrollLaziness > 1) + if (config.scrollLaziness > 1) { - // mScrollLaziness defines the fraction of the desired camera movement + // settings.ScrollLaziness defines the fraction of the desired camera movement // that is applied every 10ms. To make this work independently of the // frame duration, we calculate the actual scroll fraction based on the // time delta. - scrollFraction = 1.0f - std::pow(1.0f - 1.0f / mScrollLaziness, ticks); + scrollFraction = 1.0f - std::pow(1.0f - 1.0f / config.scrollLaziness, ticks); } // Apply lazy scrolling - if (player_x > mPixelViewX + mScrollRadius) + if (player_x > mPixelViewX + config.scrollRadius) { - mPixelViewX += (player_x - mPixelViewX - mScrollRadius) * + mPixelViewX += (player_x - mPixelViewX - config.scrollRadius) * scrollFraction; } - if (player_x < mPixelViewX - mScrollRadius) + if (player_x < mPixelViewX - config.scrollRadius) { - mPixelViewX += (player_x - mPixelViewX + mScrollRadius) * + mPixelViewX += (player_x - mPixelViewX + config.scrollRadius) * scrollFraction; } - if (player_y > mPixelViewY + mScrollRadius) + if (player_y > mPixelViewY + config.scrollRadius) { - mPixelViewY += (player_y - mPixelViewY - mScrollRadius) * + mPixelViewY += (player_y - mPixelViewY - config.scrollRadius) * scrollFraction; } - if (player_y < mPixelViewY - mScrollRadius) + if (player_y < mPixelViewY - config.scrollRadius) { - mPixelViewY += (player_y - mPixelViewY + mScrollRadius) * + mPixelViewY += (player_y - mPixelViewY + config.scrollRadius) * scrollFraction; } @@ -624,14 +619,4 @@ void Viewport::event(Event::Channel channel, const Event &event) if (mHoverItem == actor) mHoverItem = nullptr; } - else if (channel == Event::ConfigChannel && - event.getType() == Event::ConfigOptionChanged) - { - const std::string &option = event.getString("option"); - if (option == "ScrollLaziness" || option == "ScrollRadius") - { - mScrollLaziness = config.getIntValue("ScrollLaziness"); - mScrollRadius = config.getIntValue("ScrollRadius"); - } - } } diff --git a/src/gui/viewport.h b/src/gui/viewport.h index ee7eb96f..b69a73b6 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -194,10 +194,6 @@ class Viewport : public WindowContainer, public gcn::MouseListener, Map *mMap = nullptr; /**< The current map. */ - int mScrollRadius; - int mScrollLaziness; - int mScrollCenterOffsetX; - int mScrollCenterOffsetY; int mMouseX = 0; /**< Current mouse position in pixels. */ int mMouseY = 0; /**< Current mouse position in pixels. */ float mPixelViewX = 0.0f; /**< Current viewpoint in pixels. */ diff --git a/src/gui/widgets/button.cpp b/src/gui/widgets/button.cpp index 5c691705..274f329b 100644 --- a/src/gui/widgets/button.cpp +++ b/src/gui/widgets/button.cpp @@ -191,7 +191,7 @@ Button::~Button() void Button::updateAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), + float alpha = std::max(config.guiAlpha, Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp index 7a840cc6..1584eb0a 100644 --- a/src/gui/widgets/chattab.cpp +++ b/src/gui/widgets/chattab.cpp @@ -52,7 +52,7 @@ ChatTab::ChatTab(const std::string &name) mTextOutput = new BrowserBox(BrowserBox::AUTO_WRAP); mTextOutput->setWrapIndent(15); - mTextOutput->setMaxRows(config.getIntValue("ChatLogLength")); + mTextOutput->setMaxRows(config.chatLogLength); mTextOutput->setLinkHandler(chatWindow->mItemLinkHandler); mScrollArea = new ScrollArea(mTextOutput); @@ -216,7 +216,7 @@ void ChatTab::chatLog(std::string line, Own own, bool ignoreRecord) line = lineColor + timeStr.str() + tmp.nick + tmp.text; - if (config.getBoolValue("enableChatLog") && !ignoreRecord) + if (config.enableChatLog && !ignoreRecord) saveToLogFile(line); // We look if the Vertical Scroll Bar is set at the max before diff --git a/src/gui/widgets/checkbox.cpp b/src/gui/widgets/checkbox.cpp index 0554bad6..274855fd 100644 --- a/src/gui/widgets/checkbox.cpp +++ b/src/gui/widgets/checkbox.cpp @@ -89,7 +89,7 @@ void CheckBox::draw(gcn::Graphics* graphics) void CheckBox::updateAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), + float alpha = std::max(config.guiAlpha, Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp index c548570d..8811eb8d 100644 --- a/src/gui/widgets/dropdown.cpp +++ b/src/gui/widgets/dropdown.cpp @@ -110,7 +110,7 @@ DropDown::~DropDown() void DropDown::updateAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), + float alpha = std::max(config.guiAlpha, Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) diff --git a/src/gui/widgets/emoteshortcutcontainer.cpp b/src/gui/widgets/emoteshortcutcontainer.cpp index c72d166f..8ecbc9bf 100644 --- a/src/gui/widgets/emoteshortcutcontainer.cpp +++ b/src/gui/widgets/emoteshortcutcontainer.cpp @@ -41,7 +41,7 @@ EmoteShortcutContainer::EmoteShortcutContainer() mBackgroundImg = Theme::getImageFromTheme("item_shortcut_bgr.png"); - mBackgroundImg->setAlpha(config.getFloatValue("guialpha")); + mBackgroundImg->setAlpha(config.guiAlpha); mMaxItems = std::min(EmoteDB::getEmoteCount(), MAX_ITEMS); @@ -56,9 +56,9 @@ EmoteShortcutContainer::~EmoteShortcutContainer() void EmoteShortcutContainer::draw(gcn::Graphics *graphics) { - if (config.getFloatValue("guialpha") != mAlpha) + if (config.guiAlpha != mAlpha) { - mAlpha = config.getFloatValue("guialpha"); + mAlpha = config.guiAlpha; mBackgroundImg->setAlpha(mAlpha); } diff --git a/src/gui/widgets/itemshortcutcontainer.cpp b/src/gui/widgets/itemshortcutcontainer.cpp index e6db7a0b..0b8f0c8c 100644 --- a/src/gui/widgets/itemshortcutcontainer.cpp +++ b/src/gui/widgets/itemshortcutcontainer.cpp @@ -48,7 +48,7 @@ ItemShortcutContainer::ItemShortcutContainer() mBackgroundImg = Theme::getImageFromTheme("item_shortcut_bgr.png"); mMaxItems = itemShortcut->getItemCount(); - mBackgroundImg->setAlpha(config.getFloatValue("guialpha")); + mBackgroundImg->setAlpha(config.guiAlpha); mBoxHeight = mBackgroundImg->getHeight(); mBoxWidth = mBackgroundImg->getWidth(); @@ -62,9 +62,9 @@ ItemShortcutContainer::~ItemShortcutContainer() void ItemShortcutContainer::draw(gcn::Graphics *graphics) { - if (config.getFloatValue("guialpha") != mAlpha) + if (config.guiAlpha != mAlpha) { - mAlpha = config.getFloatValue("guialpha"); + mAlpha = config.guiAlpha; mBackgroundImg->setAlpha(mAlpha); } diff --git a/src/gui/widgets/listbox.cpp b/src/gui/widgets/listbox.cpp index fc4d8a8e..55f0f422 100644 --- a/src/gui/widgets/listbox.cpp +++ b/src/gui/widgets/listbox.cpp @@ -41,7 +41,7 @@ ListBox::ListBox(gcn::ListModel *listModel): void ListBox::updateAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), + float alpha = std::max(config.guiAlpha, Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) diff --git a/src/gui/widgets/playerbox.cpp b/src/gui/widgets/playerbox.cpp index 671fad36..3bdd6bd1 100644 --- a/src/gui/widgets/playerbox.cpp +++ b/src/gui/widgets/playerbox.cpp @@ -59,7 +59,7 @@ PlayerBox::PlayerBox(const Being *being): } } - background.setAlpha(config.getFloatValue("guialpha")); + background.setAlpha(config.guiAlpha); textbox->decRef(); } @@ -90,9 +90,10 @@ void PlayerBox::draw(gcn::Graphics *graphics) mBeing->drawSpriteAt(static_cast<Graphics*>(graphics), x, y); } - if (config.getFloatValue("guialpha") != mAlpha) + if (config.guiAlpha != mAlpha) { - background.setAlpha(config.getFloatValue("guialpha")); + mAlpha = config.guiAlpha; + background.setAlpha(config.guiAlpha); } } diff --git a/src/gui/widgets/progressbar.cpp b/src/gui/widgets/progressbar.cpp index 523dde1c..9d41d1af 100644 --- a/src/gui/widgets/progressbar.cpp +++ b/src/gui/widgets/progressbar.cpp @@ -116,7 +116,7 @@ void ProgressBar::logic() void ProgressBar::updateAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), + float alpha = std::max(config.guiAlpha, Theme::instance()->getMinimumOpacity()); if (mAlpha != alpha) diff --git a/src/gui/widgets/radiobutton.cpp b/src/gui/widgets/radiobutton.cpp index bb96d77c..92cdacd1 100644 --- a/src/gui/widgets/radiobutton.cpp +++ b/src/gui/widgets/radiobutton.cpp @@ -76,9 +76,9 @@ RadioButton::~RadioButton() void RadioButton::drawBox(gcn::Graphics* graphics) { - if (config.getFloatValue("guialpha") != mAlpha) + if (config.guiAlpha != mAlpha) { - mAlpha = config.getFloatValue("guialpha"); + mAlpha = config.guiAlpha; radioNormal->setAlpha(mAlpha); radioChecked->setAlpha(mAlpha); radioDisabled->setAlpha(mAlpha); diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp index 1770fcb1..dd29a977 100644 --- a/src/gui/widgets/resizegrip.cpp +++ b/src/gui/widgets/resizegrip.cpp @@ -58,9 +58,9 @@ ResizeGrip::~ResizeGrip() void ResizeGrip::draw(gcn::Graphics *graphics) { - if (config.getFloatValue("guialpha") != mAlpha) + if (config.guiAlpha != mAlpha) { - mAlpha = config.getFloatValue("guialpha"); + mAlpha = config.guiAlpha; gripImage->setAlpha(mAlpha); } diff --git a/src/gui/widgets/scrollarea.cpp b/src/gui/widgets/scrollarea.cpp index 8e16b5b3..225a231d 100644 --- a/src/gui/widgets/scrollarea.cpp +++ b/src/gui/widgets/scrollarea.cpp @@ -100,7 +100,7 @@ void ScrollArea::init() a++; } } - background.setAlpha(config.getFloatValue("guialpha")); + background.setAlpha(config.guiAlpha); textbox->decRef(); @@ -128,8 +128,8 @@ void ScrollArea::init() } } - vMarker.setAlpha(config.getFloatValue("guialpha")); - vMarkerHi.setAlpha(config.getFloatValue("guialpha")); + vMarker.setAlpha(config.guiAlpha); + vMarkerHi.setAlpha(config.guiAlpha); vscroll->decRef(); vscrollHi->decRef(); @@ -203,8 +203,8 @@ void ScrollArea::logic() void ScrollArea::updateAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), - Theme::instance()->getMinimumOpacity()); + float alpha = std::max(config.guiAlpha, + Theme::instance()->getMinimumOpacity()); if (alpha != mAlpha) { diff --git a/src/gui/widgets/shoplistbox.cpp b/src/gui/widgets/shoplistbox.cpp index d0c79af2..31c733a6 100644 --- a/src/gui/widgets/shoplistbox.cpp +++ b/src/gui/widgets/shoplistbox.cpp @@ -36,8 +36,6 @@ #include <guichan/font.hpp> #include <guichan/listmodel.hpp> -float ShopListBox::mAlpha = 1.0; - ShopListBox::ShopListBox(gcn::ListModel *listModel): ListBox(listModel) { @@ -72,10 +70,7 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) if (!mListModel) return; - if (config.getFloatValue("guialpha") != mAlpha) - mAlpha = config.getFloatValue("guialpha"); - - const int alpha = (int)(mAlpha * 255.0f); + const int alpha = (int)(config.guiAlpha * 255.0f); const gcn::Color &highlightColor = Theme::getThemeColor(Theme::HIGHLIGHT, alpha); const gcn::Color &backgroundColor = diff --git a/src/gui/widgets/shoplistbox.h b/src/gui/widgets/shoplistbox.h index b5718ed3..4dbd756b 100644 --- a/src/gui/widgets/shoplistbox.h +++ b/src/gui/widgets/shoplistbox.h @@ -95,8 +95,6 @@ class ShopListBox : public ListBox unsigned int mRowHeight; /**< Row Height */ - static float mAlpha; - bool mPriceCheck; }; diff --git a/src/gui/widgets/slider.cpp b/src/gui/widgets/slider.cpp index fd21becf..a7ba37e8 100644 --- a/src/gui/widgets/slider.cpp +++ b/src/gui/widgets/slider.cpp @@ -123,7 +123,7 @@ void Slider::init() void Slider::updateAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), + float alpha = std::max(config.guiAlpha, Theme::instance()->getMinimumOpacity()); if (alpha != mAlpha) diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp index 08acd245..64f49eac 100644 --- a/src/gui/widgets/tab.cpp +++ b/src/gui/widgets/tab.cpp @@ -114,7 +114,7 @@ void Tab::init() void Tab::updateAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), + float alpha = std::max(config.guiAlpha, Theme::instance()->getMinimumOpacity()); // TODO We don't need to do this for every tab on every draw diff --git a/src/gui/widgets/table.cpp b/src/gui/widgets/table.cpp index a74fc09e..905bb166 100644 --- a/src/gui/widgets/table.cpp +++ b/src/gui/widgets/table.cpp @@ -269,8 +269,8 @@ void GuiTable::draw(gcn::Graphics* graphics) if (!mModel) return; - if (config.getFloatValue("guialpha") != mAlpha) - mAlpha = config.getFloatValue("guialpha"); + if (config.guiAlpha != mAlpha) + mAlpha = config.guiAlpha; if (mOpaque) { diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp index 3e1665d3..dd0adecd 100644 --- a/src/gui/widgets/textfield.cpp +++ b/src/gui/widgets/textfield.cpp @@ -69,7 +69,7 @@ TextField::TextField(const std::string &text, bool loseFocusOnTab): a++; } } - skin.setAlpha(config.getFloatValue("guialpha")); + skin.setAlpha(config.guiAlpha); textbox->decRef(); } @@ -87,7 +87,7 @@ TextField::~TextField() void TextField::updateAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), + float alpha = std::max(config.guiAlpha, Theme::instance()->getMinimumOpacity()); if (alpha != mAlpha) diff --git a/src/gui/widgets/textpreview.cpp b/src/gui/widgets/textpreview.cpp index 8b2c3a75..f9e85052 100644 --- a/src/gui/widgets/textpreview.cpp +++ b/src/gui/widgets/textpreview.cpp @@ -41,8 +41,8 @@ TextPreview::TextPreview(const std::string &text): void TextPreview::draw(gcn::Graphics* graphics) { - if (config.getFloatValue("guialpha") != mAlpha) - mAlpha = config.getFloatValue("guialpha"); + if (config.guiAlpha != mAlpha) + mAlpha = config.guiAlpha; int alpha = (int) (mAlpha * 255.0f); diff --git a/src/gui/widgets/window.cpp b/src/gui/widgets/window.cpp index 050e31da..8bf9d081 100644 --- a/src/gui/widgets/window.cpp +++ b/src/gui/widgets/window.cpp @@ -37,6 +37,9 @@ #include <guichan/exception.hpp> #include <guichan/focushandler.hpp> +#include <algorithm> +#include <cassert> + int Window::instances = 0; int Window::mouseResize = 0; @@ -503,33 +506,29 @@ void Window::mouseDragged(gcn::MouseEvent &event) void Window::loadWindowState() { - const std::string &name = mWindowName; - assert(!name.empty()); + assert(!mWindowName.empty()); + + constexpr WindowState defaultState; + auto s = config.windows.find(mWindowName); + const WindowState state = s == config.windows.end() ? defaultState + : s->second; - setPosition((int) config.getValue(name + "WinX", mDefaultX), - (int) config.getValue(name + "WinY", mDefaultY)); + setPosition(state.x.value_or(mDefaultX), + state.y.value_or(mDefaultY)); if (mSaveVisible) - setVisible((bool) config.getValue(name + "Visible", mDefaultVisible)); + setVisible(state.visible.value_or(mDefaultVisible)); if (mStickyButton) - setSticky((bool) config.getValue(name + "Sticky", isSticky())); + setSticky(state.sticky.value_or(isSticky())); if (mGrip) { - int width = (int) config.getValue(name + "WinWidth", mDefaultWidth); - int height = (int) config.getValue(name + "WinHeight", mDefaultHeight); - - if (getMinWidth() > width) - width = getMinWidth(); - else if (getMaxWidth() < width) - width = getMaxWidth(); - if (getMinHeight() > height) - height = getMinHeight(); - else if (getMaxHeight() < height) - height = getMaxHeight(); - - setSize(width, height); + const int width = state.width.value_or(mDefaultWidth); + const int height = state.height.value_or(mDefaultHeight); + + setSize(std::clamp(width, getMinWidth(), getMaxWidth()), + std::clamp(height, getMinHeight(), getMaxHeight())); } else { @@ -540,35 +539,29 @@ void Window::loadWindowState() ensureOnScreen(); } -void Window::saveWindowState() +void Window::saveWindowState() const { // Saving X, Y and Width and Height for resizables in the config - if (!mWindowName.empty() && mWindowName != "window") - { - config.setValue(mWindowName + "WinX", getX()); - config.setValue(mWindowName + "WinY", getY()); + if (mWindowName.empty()) + return; - if (mSaveVisible) - config.setValue(mWindowName + "Visible", isVisible()); + WindowState state; + state.x = getX(); + state.y = getY(); - if (mStickyButton) - config.setValue(mWindowName + "Sticky", isSticky()); + if (mSaveVisible) + state.visible = isVisible(); - if (mGrip) - { - if (getMinWidth() > getWidth()) - setWidth(getMinWidth()); - else if (getMaxWidth() < getWidth()) - setWidth(getMaxWidth()); - if (getMinHeight() > getHeight()) - setHeight(getMinHeight()); - else if (getMaxHeight() < getHeight()) - setHeight(getMaxHeight()); - - config.setValue(mWindowName + "WinWidth", getWidth()); - config.setValue(mWindowName + "WinHeight", getHeight()); - } + if (mStickyButton) + state.sticky = isSticky(); + + if (mGrip) + { + state.width = getWidth(); + state.height = getHeight(); } + + config.windows[mWindowName] = state; } void Window::setDefaultSize(int defaultX, int defaultY, @@ -701,7 +694,7 @@ int Window::getResizeHandles(gcn::MouseEvent &event) int Window::getGuiAlpha() { - float alpha = std::max(config.getFloatValue("guialpha"), + float alpha = std::max(config.guiAlpha, Theme::instance()->getMinimumOpacity()); return (int) (alpha * 255.0f); } diff --git a/src/gui/widgets/window.h b/src/gui/widgets/window.h index 975de335..bf6f363c 100644 --- a/src/gui/widgets/window.h +++ b/src/gui/widgets/window.h @@ -264,7 +264,7 @@ class Window : public gcn::Window, gcn::WidgetListener * Saves the window state so that when the window is reloaded, it'll * maintain its previous state and location. */ - void saveWindowState(); + void saveWindowState() const; /** * Set the default win pos and size. @@ -380,7 +380,7 @@ class Window : public gcn::Window, gcn::WidgetListener ResizeGrip *mGrip = nullptr; /**< Resize grip */ Window *mParent; /**< The parent window */ Layout *mLayout = nullptr; /**< Layout handler */ - std::string mWindowName = "window"; /**< Name of the window */ + std::string mWindowName; /**< Name of the window */ bool mShowTitle = true; /**< Window has a title bar */ bool mModal; /**< Window is modal */ bool mCloseButton = false; /**< Window has a close button */ diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp index 577f76ae..643a594f 100644 --- a/src/itemshortcut.cpp +++ b/src/itemshortcut.cpp @@ -19,15 +19,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "itemshortcut.h" + #include "configuration.h" #include "event.h" #include "inventory.h" #include "item.h" -#include "itemshortcut.h" #include "playerinfo.h" -#include "utils/stringutils.h" - ItemShortcut *itemShortcut; ItemShortcut::ItemShortcut(): @@ -44,40 +43,44 @@ ItemShortcut::~ItemShortcut() void ItemShortcut::load() { for (int i = 0; i < SHORTCUT_ITEMS; i++) - { - int itemId = (int) config.getValue("shortcut" + toString(i), -1); + mItems[i] = -1; - mItems[i] = itemId; + for (auto &shortcut : config.itemShortcuts) + { + if (shortcut.index >= 0 && shortcut.index < SHORTCUT_ITEMS) + mItems[shortcut.index] = shortcut.itemId; } } void ItemShortcut::save() { + config.itemShortcuts.clear(); + for (int i = 0; i < SHORTCUT_ITEMS; i++) { - const int itemId = mItems[i] ? mItems[i] : -1; - config.setValue("shortcut" + toString(i), itemId); + if (mItems[i] >= 0) + config.itemShortcuts.push_back({ i, mItems[i] }); } } void ItemShortcut::useItem(int index) { - if (mItems[index]) + if (!mItems[index]) + return; + + Item *item = PlayerInfo::getInventory()->findItem(mItems[index]); + if (item && item->getQuantity()) { - Item *item = PlayerInfo::getInventory()->findItem(mItems[index]); - if (item && item->getQuantity()) + if (item->isEquippable()) { - if (item->isEquippable()) - { - if (item->isEquipped()) - item->doEvent(Event::DoUnequip); - else - item->doEvent(Event::DoEquip); - } + if (item->isEquipped()) + item->doEvent(Event::DoUnequip); else - { - item->doEvent(Event::DoUse); - } + item->doEvent(Event::DoEquip); + } + else + { + item->doEvent(Event::DoUse); } } } diff --git a/src/joystick.cpp b/src/joystick.cpp index a1da181c..c6e106bf 100644 --- a/src/joystick.cpp +++ b/src/joystick.cpp @@ -19,8 +19,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "configuration.h" #include "joystick.h" + +#include "configuration.h" #include "log.h" #include <cassert> @@ -40,10 +41,14 @@ void Joystick::init() logger->log("- %s", SDL_JoystickNameForIndex(i)); } -Joystick::Joystick(int no): - mDirection(0), - mCalibrating(false), - mEnabled(false) +Joystick::Joystick(int no) + : mDirection(0) + , mUpTolerance(config.upTolerance) + , mDownTolerance(config.downTolerance) + , mLeftTolerance(config.leftTolerance) + , mRightTolerance(config.rightTolerance) + , mCalibrating(false) + , mEnabled(config.joystickEnabled) { assert(no < joystickCount); @@ -60,12 +65,6 @@ Joystick::Joystick(int no): logger->log("Balls: %i", SDL_JoystickNumBalls(mJoystick)); logger->log("Hats: %i", SDL_JoystickNumHats(mJoystick)); logger->log("Buttons: %i", SDL_JoystickNumButtons(mJoystick)); - - mEnabled = config.getBoolValue("joystickEnabled"); - mUpTolerance = config.getIntValue("upTolerance"); - mDownTolerance = config.getIntValue("downTolerance"); - mLeftTolerance = config.getIntValue("leftTolerance"); - mRightTolerance = config.getIntValue("rightTolerance"); } Joystick::~Joystick() @@ -134,10 +133,10 @@ void Joystick::doCalibration() void Joystick::finishCalibration() { - config.setValue("leftTolerance", mLeftTolerance); - config.setValue("rightTolerance", mRightTolerance); - config.setValue("upTolerance", mUpTolerance); - config.setValue("downTolerance", mDownTolerance); + config.leftTolerance = mLeftTolerance; + config.rightTolerance = mRightTolerance; + config.upTolerance = mUpTolerance; + config.downTolerance = mDownTolerance; mCalibrating = false; } diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp index a705197a..c4d7a26d 100644 --- a/src/keyboardconfig.cpp +++ b/src/keyboardconfig.cpp @@ -28,82 +28,80 @@ #include "utils/gettext.h" #include "utils/stringutils.h" -#include <SDL.h> - struct KeyData { const char *configField; - int defaultValue; + SDL_Keycode defaultValue; std::string caption; }; // keyData must be in same order as enum keyAction. static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = { - {"keyMoveUp", SDLK_UP, _("Move Up")}, - {"keyMoveDown", SDLK_DOWN, _("Move Down")}, - {"keyMoveLeft", SDLK_LEFT, _("Move Left")}, - {"keyMoveRight", SDLK_RIGHT, _("Move Right")}, - {"keyAttack", SDLK_LCTRL, _("Attack")}, - {"keyTargetAttack", SDLK_x, _("Target & Attack")}, - {"keySmilie", SDLK_LALT, _("Smilie")}, - {"keyTalk", SDLK_t, _("Talk")}, - {"keyTarget", SDLK_LSHIFT, _("Stop Attack")}, - {"keyTargetClosest", SDLK_a, _("Target Monster")}, - {"keyTargetNPC", SDLK_n, _("Target NPC")}, - {"keyTargetPlayer", SDLK_q, _("Target Player")}, - {"keyPickup", SDLK_z, _("Pickup")}, - {"keyHideWindows", SDLK_h, _("Hide Windows")}, - {"keyBeingSit", SDLK_s, _("Sit")}, - {"keyScreenshot", SDLK_p, _("Screenshot")}, - {"keyTrade", SDLK_r, _("Enable/Disable Trading")}, - {"keyShortcut1", SDLK_1, strprintf(_("Item Shortcut %d"), 1)}, - {"keyShortcut2", SDLK_2, strprintf(_("Item Shortcut %d"), 2)}, - {"keyShortcut3", SDLK_3, strprintf(_("Item Shortcut %d"), 3)}, - {"keyShortcut4", SDLK_4, strprintf(_("Item Shortcut %d"), 4)}, - {"keyShortcut5", SDLK_5, strprintf(_("Item Shortcut %d"), 5)}, - {"keyShortcut6", SDLK_6, strprintf(_("Item Shortcut %d"), 6)}, - {"keyShortcut7", SDLK_7, strprintf(_("Item Shortcut %d"), 7)}, - {"keyShortcut8", SDLK_8, strprintf(_("Item Shortcut %d"), 8)}, - {"keyShortcut9", SDLK_9, strprintf(_("Item Shortcut %d"), 9)}, - {"keyShortcut10", SDLK_0, strprintf(_("Item Shortcut %d"), 10)}, - {"keyShortcut11", SDLK_MINUS, strprintf(_("Item Shortcut %d"), 11)}, - {"keyShortcut12", SDLK_EQUALS, strprintf(_("Item Shortcut %d"), 12)}, - {"keyWindowHelp", SDLK_F1, _("Help Window")}, - {"keyWindowStatus", SDLK_F2, _("Status Window")}, - {"keyWindowInventory", SDLK_F3, _("Inventory Window")}, - {"keyWindowEquipment", SDLK_F4, _("Equipment Window")}, - {"keyWindowSkill", SDLK_F5, _("Skill Window")}, - {"keyWindowMinimap", SDLK_F6, _("Minimap Window")}, - {"keyWindowChat", SDLK_F7, _("Chat Window")}, - {"keyWindowShortcut", SDLK_F8, _("Item Shortcut Window")}, - {"keyWindowSetup", SDLK_F9, _("Setup Window")}, - {"keyWindowDebug", SDLK_F10, _("Debug Window")}, - {"keyWindowSocial", SDLK_F11, _("Social Window")}, - {"keyWindowEmoteBar", SDLK_F12, _("Emote Shortcut Window")}, - {"keyWindowOutfit", SDLK_o, _("Outfits Window")}, - {"keyWearOutfit", SDLK_RCTRL, _("Wear Outfit")}, - {"keyCopyOutfit", SDLK_RALT, _("Copy Outfit")}, - {"keyEmoteShortcut1", SDLK_1, strprintf(_("Emote Shortcut %d"), 1)}, - {"keyEmoteShortcut2", SDLK_2, strprintf(_("Emote Shortcut %d"), 2)}, - {"keyEmoteShortcut3", SDLK_3, strprintf(_("Emote Shortcut %d"), 3)}, - {"keyEmoteShortcut4", SDLK_4, strprintf(_("Emote Shortcut %d"), 4)}, - {"keyEmoteShortcut5", SDLK_5, strprintf(_("Emote Shortcut %d"), 5)}, - {"keyEmoteShortcut6", SDLK_6, strprintf(_("Emote Shortcut %d"), 6)}, - {"keyEmoteShortcut7", SDLK_7, strprintf(_("Emote Shortcut %d"), 7)}, - {"keyEmoteShortcut8", SDLK_8, strprintf(_("Emote Shortcut %d"), 8)}, - {"keyEmoteShortcut9", SDLK_9, strprintf(_("Emote Shortcut %d"), 9)}, - {"keyEmoteShortcut10", SDLK_0, strprintf(_("Emote Shortcut %d"), 10)}, - {"keyEmoteShortcut11", SDLK_MINUS, strprintf(_("Emote Shortcut %d"), 11)}, - {"keyEmoteShortcut12", SDLK_EQUALS, strprintf(_("Emote Shortcut %d"), 12)}, - {"keyChat", SDLK_RETURN, _("Toggle Chat")}, - {"keyChatScrollUp", SDLK_PAGEUP, _("Scroll Chat Up")}, - {"keyChatScrollDown", SDLK_PAGEDOWN, _("Scroll Chat Down")}, - {"keyChatPrevTab", SDLK_LEFTBRACKET, _("Previous Chat Tab")}, - {"keyChatNextTab", SDLK_RIGHTBRACKET, _("Next Chat Tab")}, - {"keyOK", SDLK_SPACE, _("Select OK")}, - {"keyQuit", SDLK_ESCAPE, _("Quit")}, - {"keyIgnoreInput1", SDLK_LGUI, _("Ignore input 1")}, - {"keyIgnoreInput2", SDLK_RGUI, _("Ignore input 2")} + { "MoveUp", SDLK_UP, _("Move Up") }, + { "MoveDown", SDLK_DOWN, _("Move Down") }, + { "MoveLeft", SDLK_LEFT, _("Move Left") }, + { "MoveRight", SDLK_RIGHT, _("Move Right") }, + { "Attack", SDLK_LCTRL, _("Attack") }, + { "TargetAttack", SDLK_x, _("Target & Attack") }, + { "Smilie", SDLK_LALT, _("Smilie") }, + { "Talk", SDLK_t, _("Talk") }, + { "Target", SDLK_LSHIFT, _("Stop Attack") }, + { "TargetClosest", SDLK_a, _("Target Monster") }, + { "TargetNPC", SDLK_n, _("Target NPC") }, + { "TargetPlayer", SDLK_q, _("Target Player") }, + { "Pickup", SDLK_z, _("Pickup") }, + { "HideWindows", SDLK_h, _("Hide Windows") }, + { "BeingSit", SDLK_s, _("Sit") }, + { "Screenshot", SDLK_p, _("Screenshot") }, + { "Trade", SDLK_r, _("Enable/Disable Trading") }, + { "Shortcut1", SDLK_1, strprintf(_("Item Shortcut %d"), 1) }, + { "Shortcut2", SDLK_2, strprintf(_("Item Shortcut %d"), 2) }, + { "Shortcut3", SDLK_3, strprintf(_("Item Shortcut %d"), 3) }, + { "Shortcut4", SDLK_4, strprintf(_("Item Shortcut %d"), 4) }, + { "Shortcut5", SDLK_5, strprintf(_("Item Shortcut %d"), 5) }, + { "Shortcut6", SDLK_6, strprintf(_("Item Shortcut %d"), 6) }, + { "Shortcut7", SDLK_7, strprintf(_("Item Shortcut %d"), 7) }, + { "Shortcut8", SDLK_8, strprintf(_("Item Shortcut %d"), 8) }, + { "Shortcut9", SDLK_9, strprintf(_("Item Shortcut %d"), 9) }, + { "Shortcut10", SDLK_0, strprintf(_("Item Shortcut %d"), 10) }, + { "Shortcut11", SDLK_MINUS, strprintf(_("Item Shortcut %d"), 11) }, + { "Shortcut12", SDLK_EQUALS, strprintf(_("Item Shortcut %d"), 12) }, + { "WindowHelp", SDLK_F1, _("Help Window") }, + { "WindowStatus", SDLK_F2, _("Status Window") }, + { "WindowInventory", SDLK_F3, _("Inventory Window") }, + { "WindowEquipment", SDLK_F4, _("Equipment Window") }, + { "WindowSkill", SDLK_F5, _("Skill Window") }, + { "WindowMinimap", SDLK_F6, _("Minimap Window") }, + { "WindowChat", SDLK_F7, _("Chat Window") }, + { "WindowShortcut", SDLK_F8, _("Item Shortcut Window") }, + { "WindowSetup", SDLK_F9, _("Setup Window") }, + { "WindowDebug", SDLK_F10, _("Debug Window") }, + { "WindowSocial", SDLK_F11, _("Social Window") }, + { "WindowEmoteBar", SDLK_F12, _("Emote Shortcut Window") }, + { "WindowOutfit", SDLK_o, _("Outfits Window") }, + { "WearOutfit", SDLK_RCTRL, _("Wear Outfit") }, + { "CopyOutfit", SDLK_RALT, _("Copy Outfit") }, + { "EmoteShortcut1", SDLK_1, strprintf(_("Emote Shortcut %d"), 1) }, + { "EmoteShortcut2", SDLK_2, strprintf(_("Emote Shortcut %d"), 2) }, + { "EmoteShortcut3", SDLK_3, strprintf(_("Emote Shortcut %d"), 3) }, + { "EmoteShortcut4", SDLK_4, strprintf(_("Emote Shortcut %d"), 4) }, + { "EmoteShortcut5", SDLK_5, strprintf(_("Emote Shortcut %d"), 5) }, + { "EmoteShortcut6", SDLK_6, strprintf(_("Emote Shortcut %d"), 6) }, + { "EmoteShortcut7", SDLK_7, strprintf(_("Emote Shortcut %d"), 7) }, + { "EmoteShortcut8", SDLK_8, strprintf(_("Emote Shortcut %d"), 8) }, + { "EmoteShortcut9", SDLK_9, strprintf(_("Emote Shortcut %d"), 9) }, + { "EmoteShortcut10", SDLK_0, strprintf(_("Emote Shortcut %d"), 10) }, + { "EmoteShortcut11", SDLK_MINUS, strprintf(_("Emote Shortcut %d"), 11) }, + { "EmoteShortcut12", SDLK_EQUALS, strprintf(_("Emote Shortcut %d"), 12) }, + { "Chat", SDLK_RETURN, _("Toggle Chat") }, + { "ChatScrollUp", SDLK_PAGEUP, _("Scroll Chat Up") }, + { "ChatScrollDown", SDLK_PAGEDOWN, _("Scroll Chat Down") }, + { "ChatPrevTab", SDLK_LEFTBRACKET, _("Previous Chat Tab") }, + { "ChatNextTab", SDLK_RIGHTBRACKET, _("Next Chat Tab") }, + { "OK", SDLK_SPACE, _("Select OK") }, + { "Quit", SDLK_ESCAPE, _("Quit") }, + { "IgnoreInput1", SDLK_LGUI, _("Ignore input 1") }, + { "IgnoreInput2", SDLK_RGUI, _("Ignore input 2") } }; void KeyboardConfig::init() @@ -112,7 +110,6 @@ void KeyboardConfig::init() { mKey[i].configField = keyData[i].configField; mKey[i].defaultValue = keyData[i].defaultValue; - mKey[i].caption = keyData[i].caption; mKey[i].value = KEY_NO_VALUE; } mNewKeyIndex = KEY_NO_VALUE; @@ -125,15 +122,31 @@ void KeyboardConfig::retrieve() { for (auto &key : mKey) { - key.value = (int) config.getValue(key.configField, key.defaultValue); + const auto keyIt = config.keys.find(key.configField); + if (keyIt != config.keys.end()) + { + key.value = SDL_GetKeyFromName(keyIt->second.c_str()); + + if (key.value == SDLK_UNKNOWN) + key.value = KEY_NO_VALUE; + } + else + { + key.value = key.defaultValue; + } } } void KeyboardConfig::store() { + config.keys.clear(); + for (auto &key : mKey) { - config.setValue(key.configField, key.value); + if (key.value == key.defaultValue) + continue; + + config.keys[key.configField] = SDL_GetKeyName(key.value); } } @@ -185,7 +198,7 @@ bool KeyboardConfig::hasConflicts() mBindError = strprintf(_("Conflict \"%s\" and \"%s\" keys. " "Resolve them, or gameplay may result" " in strange behaviour."), - mKey[i].caption.c_str(), mKey[j].caption.c_str()); + keyData[i].caption.c_str(), keyData[j].caption.c_str()); return true; } } @@ -199,7 +212,12 @@ void KeyboardConfig::callbackNewKey() mSetupKey->newKeyCallback(mNewKeyIndex); } -int KeyboardConfig::getKeyIndex(int keyValue) const +const std::string &KeyboardConfig::getKeyCaption(int index) const +{ + return keyData[index].caption; +} + +int KeyboardConfig::getKeyIndex(SDL_Keycode keyValue) const { for (int i = 0; i < KEY_TOTAL; i++) { @@ -212,7 +230,7 @@ int KeyboardConfig::getKeyIndex(int keyValue) const } -int KeyboardConfig::getKeyEmoteOffset(int keyValue) const +int KeyboardConfig::getKeyEmoteOffset(SDL_Keycode keyValue) const { for (int i = KEY_EMOTE_1; i <= KEY_EMOTE_12; i++) { diff --git a/src/keyboardconfig.h b/src/keyboardconfig.h index 03f39551..e2d91e29 100644 --- a/src/keyboardconfig.h +++ b/src/keyboardconfig.h @@ -26,6 +26,8 @@ #include <cstdint> #include <string> +#include <SDL.h> + /** * Each key represents a key function. Such as 'Move up', 'Attack' etc. */ @@ -33,8 +35,7 @@ struct KeyFunction { const char* configField; /** Field index that is in the config file. */ int defaultValue; /** The default key value used. */ - std::string caption; /** The caption value for the key function. */ - int value; /** The actual value that is used. */ + SDL_Keycode value; /** The actual value that is used. */ }; class Setup_Keyboard; @@ -93,18 +94,17 @@ class KeyboardConfig /** * Get the key caption, providing more meaning to the user. */ - const std::string &getKeyCaption(int index) const - { return mKey[index].caption; } + const std::string &getKeyCaption(int index) const; /** * Get the key function index by providing the keys value. */ - int getKeyIndex(int keyValue) const; + int getKeyIndex(SDL_Keycode keyValue) const; /** * Get the key function index for an emote by providing the offset value. */ - int getKeyEmoteOffset(int keyValue) const; + int getKeyEmoteOffset(SDL_Keycode keyValue) const; /** * Set the enable flag, which will stop the user from doing actions. @@ -121,7 +121,7 @@ class KeyboardConfig /** * Set the value of the new key. */ - void setNewKey(int value) + void setNewKey(SDL_Keycode value) { mKey[mNewKeyIndex].value = value; } /** diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 7dec601a..7e66632b 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -29,7 +29,6 @@ #include "map.h" #include "particle.h" #include "playerinfo.h" -#include "sound.h" #include "gui/gui.h" #include "gui/okdialog.h" @@ -63,7 +62,7 @@ LocalPlayer::LocalPlayer(int id, int subtype): mAwayListener = new AwayListener(); - setShowName(config.getValue("showownname", 1)); + setShowName(config.showOwnName); listen(Event::ConfigChannel); listen(Event::ActorSpriteChannel); @@ -870,11 +869,11 @@ void LocalPlayer::pickedUp(const ItemInfo &itemInfo, int amount, msg = N_("Item belongs to someone else."); break; default: msg = N_("Unknown problem picking up item."); break; } - if (config.getValue("showpickupchat", 1)) + if (config.showPickupChat) { serverNotice(_(msg)); } - if (mMap && config.getBoolValue("showpickupparticle")) + if (mMap && config.showPickupParticle) { // Show pickup notification addMessageToQueue(_(msg), UserPalette::PICKUP_INFO); @@ -882,7 +881,7 @@ void LocalPlayer::pickedUp(const ItemInfo &itemInfo, int amount, } else { - if (config.getBoolValue("showpickupchat")) + if (config.showPickupChat) { // TRANSLATORS: This sentence may be translated differently // for different grammatical numbers (singular, plural, ...) @@ -892,7 +891,7 @@ void LocalPlayer::pickedUp(const ItemInfo &itemInfo, int amount, amount, itemInfo.id, itemInfo.name.c_str())); } - if (mMap && config.getBoolValue("showpickupparticle")) + if (mMap && config.showPickupParticle) { // Show pickup notification std::string msg; @@ -1006,7 +1005,7 @@ void LocalPlayer::event(Event::Channel channel, const Event &event) if (event.getType() == Event::ConfigOptionChanged && event.getString("option") == "showownname") { - setShowName(config.getValue("showownname", 1)); + setShowName(config.showOwnName); } } @@ -1020,8 +1019,9 @@ void LocalPlayer::changeAwayMode() if (mAwayMode) { - mAwayDialog = new OkDialog(_("Away"), - config.getValue("afkMessage", "I am away from keyboard")); + auto msg = config.afkMessage.empty() ? _("I am away from keyboard") + : config.afkMessage; + mAwayDialog = new OkDialog(_("Away"), msg); mAwayDialog->addActionListener(mAwayListener); } @@ -1031,33 +1031,31 @@ void LocalPlayer::changeAwayMode() void LocalPlayer::setAway(const std::string &message) { if (!message.empty()) - config.setValue("afkMessage", message); + config.afkMessage = message; changeAwayMode(); } void LocalPlayer::afkRespond(ChatTab *tab, const std::string &nick) { - if (mAwayMode) - { - if (mAfkTimer.passed()) - { - std::string msg = "*AFK*: " - + config.getValue("afkMessage", "I am away from keyboard"); + if (!mAwayMode || !mAfkTimer.passed()) + return; - Net::getChatHandler()->privateMessage(nick, msg); - if (!tab) - { - localChatTab->chatLog(getName() + " : " + msg, - ACT_WHISPER, false); - } - else - { - tab->chatLog(getName(), msg); - } + auto msg = config.afkMessage.empty() ? _("I am away from keyboard") + : config.afkMessage; + msg = strprintf(_("*AFK*: %s"), msg.c_str()); - mAfkTimer.set(AWAY_MESSAGE_TIMEOUT); - } + Net::getChatHandler()->privateMessage(nick, msg); + if (!tab) + { + localChatTab->chatLog(getName() + " : " + msg, + ACT_WHISPER, false); } + else + { + tab->chatLog(getName(), msg); + } + + mAfkTimer.set(AWAY_MESSAGE_TIMEOUT); } void AwayListener::action(const gcn::ActionEvent &event) diff --git a/src/map.cpp b/src/map.cpp index 5d7fa053..929d66f8 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -40,6 +40,7 @@ #include "utils/dtor.h" #include "utils/stringutils.h" +#include <cassert> #include <queue> #include <climits> @@ -326,7 +327,7 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY) // Draw backgrounds drawAmbientLayers(graphics, BACKGROUND_LAYERS, scrollX, scrollY, - config.getIntValue("OverlayDetail")); + config.overlayDetail); // draw the game world for (auto &layer : mLayers) @@ -365,7 +366,7 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY) } drawAmbientLayers(graphics, FOREGROUND_LAYERS, scrollX, scrollY, - config.getIntValue("OverlayDetail")); + config.overlayDetail); } void Map::drawCollision(Graphics *graphics, int scrollX, int scrollY, @@ -961,7 +962,7 @@ void Map::addParticleEffect(const std::string &effectFile, int x, int y, int w, void Map::initializeParticleEffects(Particle *particleEngine) { - if (config.getBoolValue("particleeffects")) + if (config.particleEffects) { for (auto &particleEffect : particleEffects) { diff --git a/src/net/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp index d8923caa..e1b1a9ea 100644 --- a/src/net/tmwa/generalhandler.cpp +++ b/src/net/tmwa/generalhandler.cpp @@ -43,7 +43,6 @@ #include "net/tmwa/itemhandler.h" #include "net/tmwa/loginhandler.h" #include "net/tmwa/messagein.h" -#include "net/tmwa/messageout.h" #include "net/tmwa/network.h" #include "net/tmwa/npchandler.h" #include "net/tmwa/partyhandler.h" @@ -73,7 +72,7 @@ extern Party *taParty; GeneralHandler::GeneralHandler(): mAdminHandler(new AdminHandler), - mBeingHandler(new BeingHandler(config.getBoolValue("EnableSync"))), + mBeingHandler(new BeingHandler(config.enableSync)), mBuySellHandler(new BuySellHandler), mCharHandler(new CharServerHandler), mChatHandler(new ChatHandler), diff --git a/src/net/tmwa/gui/partytab.cpp b/src/net/tmwa/gui/partytab.cpp index 24a8cc3e..418e0843 100644 --- a/src/net/tmwa/gui/partytab.cpp +++ b/src/net/tmwa/gui/partytab.cpp @@ -147,7 +147,7 @@ bool PartyTab::handleCommand(const std::string &type, const std::string &args) Net::getPartyHandler()->setShareItems(PARTY_SHARE_NO); break; case -1: - chatLog(strprintf(BOOLEAN_OPTIONS, "item")); + chatLog(booleanOptionInstructions("item")); } } else if (type == "exp") @@ -182,7 +182,7 @@ bool PartyTab::handleCommand(const std::string &type, const std::string &args) Net::getPartyHandler()->setShareExperience(PARTY_SHARE_NO); break; case -1: - chatLog(strprintf(BOOLEAN_OPTIONS, "exp")); + chatLog(booleanOptionInstructions("exp")); } } else diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp index e4a1815f..f6f6ef41 100644 --- a/src/net/tmwa/playerhandler.cpp +++ b/src/net/tmwa/playerhandler.cpp @@ -322,9 +322,9 @@ void PlayerHandler::handleMessage(MessageIn &msg) if (newMoney > oldMoney) { std::string money = Units::formatCurrency(newMoney - oldMoney); - if (config.getBoolValue("showpickupchat")) + if (config.showPickupChat) serverNotice(strprintf(_("You picked up %s."), money.c_str())); - if (config.getBoolValue("showpickupparticle")) + if (config.showPickupParticle) local_player->addMessageToQueue(money, UserPalette::PICKUP_INFO); } } diff --git a/src/particle.cpp b/src/particle.cpp index aa195c28..754cc43b 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -70,10 +70,10 @@ Particle::~Particle() void Particle::setupEngine() { - Particle::maxCount = config.getIntValue("particleMaxCount"); - Particle::fastPhysics = config.getIntValue("particleFastPhysics"); - Particle::emitterSkip = config.getIntValue("particleEmitterSkip") + 1; - Particle::enabled = config.getBoolValue("particleeffects"); + Particle::maxCount = config.particleMaxCount; + Particle::fastPhysics = config.particleFastPhysics; + Particle::emitterSkip = config.particleEmitterSkip + 1; + Particle::enabled = config.particleEffects; disableAutoDelete(); logger->log("Particle engine set up"); } diff --git a/src/playerrelations.cpp b/src/playerrelations.cpp index 22396009..bec1d081 100644 --- a/src/playerrelations.cpp +++ b/src/playerrelations.cpp @@ -29,57 +29,11 @@ #include "utils/dtor.h" #include "utils/gettext.h" -#define PLAYER_IGNORE_STRATEGY_NOP "nop" -#define DEFAULT_IGNORE_STRATEGY PLAYER_IGNORE_STRATEGY_NOP - -#define NAME "name" // constant for xml serialisation -#define RELATION "relation" // constant for xml serialisation - -// (De)serialisation class -class PlayerConfSerialiser : public ConfigurationListManager<std::pair<std::string, PlayerRelation>, - std::map<std::string, PlayerRelation> *> -{ - ConfigurationObject *writeConfigItem(const std::pair<std::string, PlayerRelation> &value, - ConfigurationObject *cobj) override - { - cobj->setValue(NAME, value.first); - cobj->setValue(RELATION, toString(static_cast<int>(value.second))); - - return cobj; - } - - std::map<std::string, PlayerRelation> * - readConfigItem(ConfigurationObject *cobj, - std::map<std::string, PlayerRelation> *container) override - { - std::string name = cobj->getValue(NAME, std::string()); - if (name.empty()) - return container; - - int v = cobj->getValue(RELATION, static_cast<int>(PlayerRelation::NEUTRAL)); - (*container)[name] = static_cast<PlayerRelation>(v); - - return container; - } -}; - - - PlayerRelationsManager::~PlayerRelationsManager() { delete_all(mIgnoreStrategies); } -void PlayerRelationsManager::clear() -{ - mRelations.clear(); - signalUpdate(); -} - -#define PERSIST_IGNORE_LIST "persistent-player-list" -#define PLAYER_IGNORE_STRATEGY "player-ignore-strategy" -#define DEFAULT_PERMISSIONS "default-player-permissions" - int PlayerRelationsManager::getPlayerIgnoreStrategyIndex(const std::string &name) { std::vector<PlayerIgnoreStrategy *> &strategies = getPlayerIgnoreStrategies(); @@ -92,43 +46,22 @@ int PlayerRelationsManager::getPlayerIgnoreStrategyIndex(const std::string &name void PlayerRelationsManager::init() { - mPersistIgnores = config.getValue(PERSIST_IGNORE_LIST, 1); - mDefaultPermissions = config.getValue(DEFAULT_PERMISSIONS, mDefaultPermissions); - std::string ignore_strategy_name = config.getValue(PLAYER_IGNORE_STRATEGY, DEFAULT_IGNORE_STRATEGY); - int ignore_strategy_index = getPlayerIgnoreStrategyIndex(ignore_strategy_name); - if (ignore_strategy_index >= 0) - setPlayerIgnoreStrategy(getPlayerIgnoreStrategies()[ignore_strategy_index]); - - mRelations.clear(); + int index = getPlayerIgnoreStrategyIndex(config.playerIgnoreStrategy); + if (index >= 0) + setPlayerIgnoreStrategy(getPlayerIgnoreStrategies()[index]); // Ignores are always saved to the config file, but might not be loaded - if (mPersistIgnores) - { - PlayerConfSerialiser player_conf_serialiser; - config.getList<std::pair<std::string, PlayerRelation>, - std::map<std::string, PlayerRelation> *> - ("player", &mRelations, player_conf_serialiser); - } + if (config.persistentPlayerList) + mRelations = config.players; signalUpdate(); } void PlayerRelationsManager::store() { - PlayerConfSerialiser player_conf_serialiser; - config.setList<std::map<std::string, PlayerRelation>::const_iterator, - std::pair<std::string, PlayerRelation>, - std::map<std::string, PlayerRelation> *> - ("player", - mRelations.begin(), mRelations.end(), - player_conf_serialiser); - - config.setValue(DEFAULT_PERMISSIONS, mDefaultPermissions); - config.setValue(PERSIST_IGNORE_LIST, mPersistIgnores); - config.setValue(PLAYER_IGNORE_STRATEGY, - (mIgnoreStrategy)? mIgnoreStrategy->mShortName : DEFAULT_IGNORE_STRATEGY); - - config.write(); + config.playerIgnoreStrategy = mIgnoreStrategy ? mIgnoreStrategy->mShortName + : DEFAULT_IGNORE_STRATEGY; + config.players = mRelations; } void PlayerRelationsManager::signalUpdate() @@ -143,7 +76,7 @@ unsigned int PlayerRelationsManager::checkPermissionSilently( const std::string &playerName, unsigned int flags) { - unsigned int permissions = mDefaultPermissions; + unsigned int permissions = config.defaultPlayerPermissions; switch (getRelation(playerName)) { @@ -238,12 +171,12 @@ PlayerRelation PlayerRelationsManager::getRelation(const std::string &name) cons unsigned int PlayerRelationsManager::getDefault() const { - return mDefaultPermissions; + return config.defaultPlayerPermissions; } void PlayerRelationsManager::setDefault(unsigned int permissions) { - mDefaultPermissions = permissions; + config.defaultPlayerPermissions = permissions; signalUpdate(); } @@ -258,7 +191,7 @@ public: PIS_nothing() { mDescription = _("Completely ignore"); - mShortName = PLAYER_IGNORE_STRATEGY_NOP; + mShortName = "nop"; } void ignore(Being *being, unsigned int flags) override diff --git a/src/playerrelations.h b/src/playerrelations.h index 2a43675e..38452c2f 100644 --- a/src/playerrelations.h +++ b/src/playerrelations.h @@ -52,6 +52,8 @@ struct PlayerPermissions }; }; +static constexpr const char *DEFAULT_IGNORE_STRATEGY = "nop"; + /** * Ignore strategy: describes how we should handle ignores. */ @@ -178,23 +180,6 @@ public: */ std::vector<std::string> getPlayers() const; - /** - * Removes all recorded player info. - */ - void clear(); - - /** - * Do we persist our `ignore' setup? - */ - bool getPersistIgnores() const { return mPersistIgnores; } - - /** - * Change the `ignore persist' flag. - * - * @param value Whether to persist ignores - */ - void setPersistIgnores(bool value) { mPersistIgnores = value; } - void addListener(PlayerRelationsListener *listener) { mListeners.push_back(listener); @@ -208,9 +193,6 @@ public: private: void signalUpdate(); - bool mPersistIgnores = false; // If NOT set, we delete the ignored data upon reloading - unsigned int mDefaultPermissions = PlayerPermissions::DEFAULT; - PlayerIgnoreStrategy *mIgnoreStrategy = nullptr; std::map<std::string, PlayerRelation> mRelations; std::list<PlayerRelationsListener *> mListeners; diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index 3279ba77..b5a5e258 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -193,7 +193,7 @@ Map *MapReader::readMap(XML::Node node, const std::string &path) } else if (objType == "WARP") { - if (config.getValue("showWarps", 1)) + if (config.showWarps) { map->addParticleEffect( paths.getStringValue("particles") @@ -502,7 +502,7 @@ static Tileset *readTileset(XML::Node node, const std::string &path, Tileset *set = nullptr; std::string pathDir(path); - if (node.hasProperty("source")) + if (node.hasAttribute("source")) { std::string filename = node.getProperty("source", std::string()); filename = resolveRelativePath(path, filename); diff --git a/src/resources/settingsmanager.cpp b/src/resources/settingsmanager.cpp index 99798ab0..8966f976 100644 --- a/src/resources/settingsmanager.cpp +++ b/src/resources/settingsmanager.cpp @@ -123,7 +123,7 @@ namespace SettingsManager if (node.name() == "monsters") { - if (node.hasProperty("offset")) + if (node.hasAttribute("offset")) { MonsterDB::setMonsterIdOffset(node.getProperty("offset", 0)); } diff --git a/src/resources/theme.cpp b/src/resources/theme.cpp index 29157240..1f7322a6 100644 --- a/src/resources/theme.cpp +++ b/src/resources/theme.cpp @@ -74,7 +74,7 @@ Skin::~Skin() void Skin::updateAlpha(float minimumOpacityAllowed) { const float alpha = std::max(minimumOpacityAllowed, - config.getFloatValue("guialpha")); + config.guiAlpha); mBorder.setAlpha(alpha); @@ -339,7 +339,7 @@ void Theme::prepareThemePath() instance(); // Try theme from settings - if (!tryThemePath(config.getStringValue("theme"))) + if (!tryThemePath(config.theme)) // Try theme from branding if (!tryThemePath(branding.getStringValue("theme"))) // Use default diff --git a/src/resources/userpalette.cpp b/src/resources/userpalette.cpp index 12e4d5bc..55935d8c 100644 --- a/src/resources/userpalette.cpp +++ b/src/resources/userpalette.cpp @@ -27,52 +27,27 @@ #include "utils/gettext.h" #include "utils/stringutils.h" -static const std::string ColorTypeNames[] = { - "ColorBeing", - "ColorPlayer", - "ColorSelf", - "ColorGM", - "ColorNPC", - "ColorMonster", - "ColorParty", - "ColorGuild", - "ColorParticle", - "ColorExperience", - "ColorPickup", - "ColorHitPlayerMonster", - "ColorHitMonsterPlayer", - "ColorHitCritical", - "ColorHitLocalPlayerMonster", - "ColorHitLocalPlayerCritical", - "ColorHitLocalPlayerMiss", - "ColorMiss" +static constexpr const char *ColorTypeNames[] = { + "Being", + "Player", + "Self", + "GM", + "NPC", + "Monster", + "Party", + "Guild", + "Particle", + "Experience", + "Pickup", + "HitPlayerMonster", + "HitMonsterPlayer", + "HitCritical", + "HitLocalPlayerMonster", + "HitLocalPlayerCritical", + "HitLocalPlayerMiss", + "Miss" }; -std::string UserPalette::getConfigName(const std::string &typeName) -{ - std::string res = "Color" + typeName; - - int pos = 5; - for (size_t i = 0; i < typeName.length(); i++) - { - if (i == 0 || typeName[i] == '_') - { - if (i > 0) - i++; - - res[pos] = typeName[i]; - } - else - { - res[pos] = tolower(typeName[i]); - } - pos++; - } - res.erase(pos, res.length() - pos); - - return res; -} - UserPalette::UserPalette(): Palette(USER_COLOR_LAST) { @@ -110,20 +85,20 @@ UserPalette::UserPalette(): UserPalette::~UserPalette() { + config.colors.clear(); + + // TODO: Don't write out colors when they have the default value for (auto &color : mColors) { - const std::string &configName = ColorTypeNames[color.type]; - config.setValue(configName + "Gradient", color.committedGrad); + auto &configColor = config.colors[ColorTypeNames[color.type]]; - if (color.grad != STATIC) - config.setValue(configName + "Delay", color.delay); + configColor.gradient = color.committedGrad; + + if (color.grad != STATIC && color.delay != GRADIENT_DELAY) + configColor.delay = color.delay; if (color.grad == STATIC || color.grad == PULSE) - { - char buffer[20]; - snprintf(buffer, 20, "0x%06x", color.getRGB()); - config.setValue(configName, std::string(buffer)); - } + configColor.color = strprintf("0x%06x", color.getRGB()); } } @@ -215,23 +190,19 @@ int UserPalette::getColorTypeAt(int i) return mColors[i].type; } -void UserPalette::addColor(int type, int rgb, Palette::GradientType grad, +void UserPalette::addColor(int type, unsigned rgb, GradientType grad, const std::string &text, int delay) { - const std::string &configName = ColorTypeNames[type]; - char buffer[20]; - snprintf(buffer, 20, "0x%06x", rgb); - const std::string rgbString = config.getValue(configName, - std::string(buffer)); - unsigned int rgbValue = 0; - if (rgbString.length() == 8 && rgbString[0] == '0' && rgbString[1] == 'x') - rgbValue = atox(rgbString); - else - rgbValue = atoi(rgbString.c_str()); - gcn::Color trueCol = rgbValue; - grad = (GradientType) config.getValue(configName + "Gradient", grad); - delay = (int) config.getValue(configName + "Delay", delay); - mColors[type].set(type, trueCol, grad, delay); + auto colorIt = config.colors.find(ColorTypeNames[type]); + if (colorIt != config.colors.end()) + { + const UserColor &userColor = colorIt->second; + rgb = atox(userColor.color); + grad = static_cast<GradientType>(userColor.gradient); + delay = userColor.delay.value_or(GRADIENT_DELAY); + } + + mColors[type].set(type, gcn::Color(rgb), grad, delay); mColors[type].text = text; if (grad != STATIC) diff --git a/src/resources/userpalette.h b/src/resources/userpalette.h index 6eba44b2..946a4725 100644 --- a/src/resources/userpalette.h +++ b/src/resources/userpalette.h @@ -175,24 +175,12 @@ class UserPalette : public Palette, public gcn::ListModel void commit(bool commitNonStatic); /** - * Prefixes the given string with "Color", lowercases all letters but - * the first and all following a '_'. All '_'s will be removed. - * - * E.g.: HIT_PLAYER_MONSTER -> HitPlayerMonster - * - * @param typeName string to transform - * - * @return the transformed string - */ - static std::string getConfigName(const std::string &typeName); - - /** * Initialise color * * @param rgb default color if not found in config * @param text identifier of color */ - void addColor(int type, int rgb, GradientType grad, + void addColor(int type, unsigned int rgb, GradientType grad, const std::string &text, int delay = GRADIENT_DELAY); }; diff --git a/src/text.cpp b/src/text.cpp index 26124666..e3776410 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -54,7 +54,7 @@ Text::Text(const std::string &text, int x, int y, { textManager = new TextManager; Image *sbImage = Theme::getImageFromTheme("bubble.png|W:#" - + config.getStringValue("speechBubblecolor")); + + config.speechBubblecolor); mBubble.grid[0] = sbImage->getSubImage(0, 0, 5, 5); mBubble.grid[1] = sbImage->getSubImage(5, 0, 5, 5); mBubble.grid[2] = sbImage->getSubImage(10, 0, 5, 5); @@ -65,9 +65,8 @@ Text::Text(const std::string &text, int x, int y, mBubble.grid[7] = sbImage->getSubImage(5, 10, 5, 5); mBubble.grid[8] = sbImage->getSubImage(10, 10, 5, 5); mBubbleArrow = sbImage->getSubImage(0, 15, 15, 10); - const float bubbleAlpha = config.getFloatValue("speechBubbleAlpha"); - mBubble.setAlpha(bubbleAlpha); - mBubbleArrow->setAlpha(bubbleAlpha); + mBubble.setAlpha(config.speechBubbleAlpha); + mBubbleArrow->setAlpha(config.speechBubbleAlpha); sbImage->decRef(); } ++mInstances; diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h index d6c45474..e7ff1332 100644 --- a/src/utils/stringutils.h +++ b/src/utils/stringutils.h @@ -22,8 +22,9 @@ #ifndef UTILS_STRINGUTILS_H #define UTILS_STRINGUTILS_H -#include <string> +#include <optional> #include <sstream> +#include <string> #include <vector> /** @@ -144,6 +145,55 @@ std::string findSameSubstring(const std::string &str1, */ bool getBoolFromString(std::string text, bool def = false); +inline void fromString(const char *str, std::string &value) +{ + value = str; +} + +inline void fromString(const char *str, int &value) +{ + value = atoi(str); +} + +inline void fromString(const char *str, unsigned &value) +{ + value = strtoul(str, nullptr, 10); +} + +inline void fromString(const char *str, unsigned short &value) +{ + value = static_cast<unsigned short>(strtoul(str, nullptr, 10)); +} + +inline void fromString(const char *str, float &value) +{ + value = strtof(str, nullptr); +} + +inline void fromString(const char *str, double &value) +{ + value = atof(str); +} + +inline void fromString(const char *str, bool &value) +{ + value = getBoolFromString(str); +} + +template<typename Enum, std::enable_if_t<std::is_enum_v<Enum>, bool> = true> +inline void fromString(const char *str, Enum &value) +{ + value = static_cast<Enum>(atoi(str)); +} + +template<typename T> +inline void fromString(const char *str, std::optional<T> &value) +{ + T v; + fromString(str, v); + value = v; +} + /** * Returns the most approaching string of base from candidates. */ diff --git a/src/utils/xml.h b/src/utils/xml.h index 95f7be99..13c06988 100644 --- a/src/utils/xml.h +++ b/src/utils/xml.h @@ -47,7 +47,10 @@ namespace XML std::string_view name() const { return (const char *) node->name; } std::string_view textContent() const; - bool hasProperty(const char *name) const; + template<typename T> + bool attribute(const char *name, T &value); + + bool hasAttribute(const char *name) const; int getProperty(const char *name, int def) const; double getFloatProperty(const char *name, double def) const; std::string getProperty(const char *name, const std::string &def) const; @@ -98,45 +101,58 @@ namespace XML return {}; } - inline bool Node::hasProperty(const char *name) const + inline const char *Node::attribute(const char *name) const { - return xmlHasProp(node, BAD_CAST name) != nullptr; + if (node->type != XML_ELEMENT_NODE) + return nullptr; + + for (xmlAttrPtr prop = node->properties; prop; prop = prop->next) { + if (xmlStrEqual(prop->name, BAD_CAST name)) { + if (prop->children) + return reinterpret_cast<const char*>(prop->children->content); + else + return nullptr; + } + } + return nullptr; } - inline int Node::getProperty(const char *name, int def) const + template<typename T> + inline bool Node::attribute(const char *name, T &value) { - int ret = def; - - if (xmlChar *prop = xmlGetProp(node, BAD_CAST name)) + if (const char *str = attribute(name)) { - ret = atol((char*)prop); - xmlFree(prop); + fromString(str, value); + return true; } + return false; + } + inline bool Node::hasAttribute(const char *name) const + { + return attribute(name) != nullptr; + } + + inline int Node::getProperty(const char *name, int def) const + { + int ret = def; + if (const char *str = attribute(name)) + fromString(str, ret); return ret; } inline double Node::getFloatProperty(const char *name, double def) const { double ret = def; - - if (xmlChar *prop = xmlGetProp(node, BAD_CAST name)) - { - ret = atof((char*)prop); - xmlFree(prop); - } - + if (const char *str = attribute(name)) + fromString(str, ret); return ret; } inline std::string Node::getProperty(const char *name, const std::string &def) const { - if (xmlChar *prop = xmlGetProp(node, BAD_CAST name)) - { - std::string val = (char*)prop; - xmlFree(prop); - return val; - } + if (const char *str = attribute(name)) + return str; return def; } @@ -144,12 +160,8 @@ namespace XML inline bool Node::getBoolProperty(const char *name, bool def) const { bool ret = def; - - if (xmlChar *prop = xmlGetProp(node, BAD_CAST name)) - { - ret = getBoolFromString((char*) prop, def); - xmlFree(prop); - } + if (const char *str = attribute(name)) + ret = getBoolFromString(str, def); return ret; } |