From bd1fdd87eed48ba3ffcc413936d6a6a60a429a97 Mon Sep 17 00:00:00 2001 From: Przemysław Grzywacz Date: Sat, 4 May 2013 21:57:58 +0200 Subject: Client-side settings are now available from settings.xml --- AUTHORS | 1 + mana.cbp | 4 + mana.files | 4 + src/CMakeLists.txt | 4 + src/client.cpp | 20 ++-- src/net/manaserv/generalhandler.cpp | 10 -- src/net/tmwa/generalhandler.cpp | 14 +-- src/resources/attributes.cpp | 188 +++++++++++++++++------------------ src/resources/attributes.h | 13 ++- src/resources/emotedb.cpp | 116 ++++++++++------------ src/resources/emotedb.h | 9 +- src/resources/hairdb.cpp | 79 ++++----------- src/resources/hairdb.h | 12 ++- src/resources/monsterdb.cpp | 188 ++++++++++++++++++----------------- src/resources/monsterdb.h | 10 +- src/resources/npcdb.cpp | 71 ++++++-------- src/resources/npcdb.h | 11 ++- src/resources/settingsmanager.cpp | 191 ++++++++++++++++++++++++++++++++++++ src/resources/settingsmanager.h | 35 +++++++ src/resources/specialdb.cpp | 71 ++++++-------- src/resources/specialdb.h | 9 +- src/statuseffect.cpp | 82 +++++++--------- src/statuseffect.h | 9 +- src/units.cpp | 107 ++++++++++---------- src/units.h | 10 +- src/utils/path.cpp | 153 +++++++++++++++++++++++++++++ src/utils/path.h | 42 ++++++++ 27 files changed, 913 insertions(+), 550 deletions(-) create mode 100644 src/resources/settingsmanager.cpp create mode 100644 src/resources/settingsmanager.h create mode 100644 src/utils/path.cpp create mode 100644 src/utils/path.h diff --git a/AUTHORS b/AUTHORS index 031495a5..83a31805 100644 --- a/AUTHORS +++ b/AUTHORS @@ -42,6 +42,7 @@ Marcel W. Wysocki Mateusz Kaduk (Usiu) Matthias Hartmann Philipp Sehmisch (Crush) +Przemysław Grzywacz Roderic Morris (rodge) Rogier Polak Scott Ellis diff --git a/mana.cbp b/mana.cbp index f25a33c4..3d5345d7 100644 --- a/mana.cbp +++ b/mana.cbp @@ -552,6 +552,8 @@ + + @@ -598,6 +600,8 @@ + + diff --git a/mana.files b/mana.files index dbfddc00..16a0a9a6 100644 --- a/mana.files +++ b/mana.files @@ -499,6 +499,8 @@ src/resources/resource.cpp src/resources/resource.h src/resources/resourcemanager.cpp src/resources/resourcemanager.h +src/resources/settingsmanager.cpp +src/resources/settingsmanager.h src/resources/soundeffect.cpp src/resources/soundeffect.h src/resources/specialdb.cpp @@ -542,6 +544,8 @@ src/utils/mathutils.h src/utils/mkdir.cpp src/utils/mkdir.h src/utils/mutex.h +src/utils/path.cpp +src/utils/path.h src/utils/physfsrwops.c src/utils/physfsrwops.h src/utils/sha256.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 946f4ba6..6c0b3081 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -399,6 +399,8 @@ SET(SRCS resources/resource.h resources/resourcemanager.cpp resources/resourcemanager.h + resources/settingsmanager.cpp + resources/settingsmanager.h resources/soundeffect.h resources/soundeffect.cpp resources/specialdb.cpp @@ -418,6 +420,8 @@ SET(SRCS utils/dtor.h utils/gettext.h utils/mathutils.h + utils/path.cpp + utils/path.h utils/physfsrwops.c utils/physfsrwops.h utils/sha256.cpp diff --git a/src/client.cpp b/src/client.cpp index e6ab9191..0d2c4bca 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -75,6 +75,7 @@ #include "resources/resourcemanager.h" #include "resources/theme.h" #include "resources/userpalette.h" +#include "resources/settingsmanager.h" #include "utils/gettext.h" #include "utils/mkdir.h" @@ -452,13 +453,9 @@ Client::~Client() SDL_RemoveTimer(mSecondsCounterId); // Unload XML databases + SettingsManager::unload(); CharDB::unload(); - hairDB.unload(); - EmoteDB::unload(); delete itemDb; - MonsterDB::unload(); - NPCDB::unload(); - StatusEffect::unload(); // Before config.write() since it writes the shortcuts to the config delete itemShortcut; @@ -761,11 +758,16 @@ int Client::exec() // Read default paths file 'data/paths.xml' paths.init("paths.xml", true); + // TODO remove this as soon as inventoryhandler stops using this event Event::trigger(Event::ClientChannel, Event::LoadingDatabases); + // load game settings + + // Load XML databases + SettingsManager::load(); + CharDB::load(); - hairDB.load(); switch (Net::getNetworkType()) { case ServerInfo::TMWATHENA: @@ -790,12 +792,6 @@ int Client::exec() STATE_CHOOSE_SERVER); break; } - MonsterDB::load(); - SpecialDB::load(); - NPCDB::load(); - EmoteDB::load(); - StatusEffect::load(); - Units::loadUnits(); ActorSprite::load(); diff --git a/src/net/manaserv/generalhandler.cpp b/src/net/manaserv/generalhandler.cpp index c6b2af18..1e39410c 100644 --- a/src/net/manaserv/generalhandler.cpp +++ b/src/net/manaserv/generalhandler.cpp @@ -133,10 +133,6 @@ void GeneralHandler::reload() netToken.clear(); gameServer.clear(); chatServer.clear(); - - Attributes::unload(); - Attributes::load(); - Attributes::informItemDB(); } void GeneralHandler::unload() @@ -154,7 +150,6 @@ void GeneralHandler::unload() delete gameServerConnection; delete chatServerConnection; - Attributes::unload(); finalize(); } @@ -190,11 +185,6 @@ void GeneralHandler::event(Event::Channel channel, game->gameLoading(); } } - else if (event.getType() == Event::LoadingDatabases) - { - Attributes::load(); - Attributes::informItemDB(); - } } else if (channel == Event::GameChannel) { diff --git a/src/net/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp index 0ce16691..5e445eaf 100644 --- a/src/net/tmwa/generalhandler.cpp +++ b/src/net/tmwa/generalhandler.cpp @@ -186,17 +186,12 @@ void GeneralHandler::reload() static_cast(mLoginHandler.get())->clearWorlds(); static_cast(mCharHandler.get())->setCharCreateDialog(0); static_cast(mCharHandler.get())->setCharSelectDialog(0); - - Attributes::unload(); - Attributes::load(); } void GeneralHandler::unload() { if (mNetwork) mNetwork->clearHandlers(); - - Attributes::unload(); } void GeneralHandler::flushNetwork() @@ -226,14 +221,7 @@ void GeneralHandler::clearHandlers() void GeneralHandler::event(Event::Channel channel, const Event &event) { - if (channel == Event::ClientChannel) - { - if (event.getType() == Event::LoadingDatabases) - { - Attributes::load(); - } - } - else if (channel == Event::GameChannel) + if (channel == Event::GameChannel) { if (event.getType() == Event::GuiWindowsLoaded) { diff --git a/src/resources/attributes.cpp b/src/resources/attributes.cpp index c4c67fba..58bff6f1 100644 --- a/src/resources/attributes.cpp +++ b/src/resources/attributes.cpp @@ -29,7 +29,6 @@ #include "utils/gettext.h" #include "utils/stringutils.h" -#include "utils/xml.h" #include #include @@ -238,120 +237,121 @@ namespace Attributes { } } - void load() + void init() { - logger->log("Initializing attributes database..."); + if (attributes.size()) + unload(); + } - XML::Document doc(DEFAULT_ATTRIBUTESDB_FILE); - xmlNodePtr rootNode = doc.rootNode(); + /** + * Read attribute node + */ + void readAttributeNode(xmlNodePtr node, const std::string &filename) + { + int id = XML::getProperty(node, "id", 0); - if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "attributes")) + if (!id) { - logger->log("Attributes: Error while loading " - DEFAULT_ATTRIBUTESDB_FILE ". Using Built-ins."); - loadBuiltins(); - fillLabels(); + logger->log("Attributes: Invalid or missing stat ID in " + DEFAULT_ATTRIBUTESDB_FILE "!"); return; } + else if (attributes.find(id) != attributes.end()) + { + logger->log("Attributes: Redefinition of stat ID %d", id); + } + + std::string name = XML::getProperty(node, "name", ""); - for_each_xml_child_node(node, rootNode) + if (name.empty()) { - if (xmlStrEqual(node->name, BAD_CAST "attribute")) - { - int id = XML::getProperty(node, "id", 0); + logger->log("Attributes: Invalid or missing stat name in " + DEFAULT_ATTRIBUTESDB_FILE "!"); + return; + } + + // Create the attribute. + Attribute a; + a.id = id; + a.name = name; + a.description = XML::getProperty(node, "desc", ""); + a.modifiable = XML::getBoolProperty(node, "modifiable", false); + a.scope = XML::getProperty(node, "scope", "none"); + a.playerInfoId = getPlayerInfoIdFromAttrType( + XML::getProperty(node, "player-info", "")); + + attributes[id] = a; - if (!id) + unsigned int count = 0; + for_each_xml_child_node(effectNode, node) + { + if (!xmlStrEqual(effectNode->name, BAD_CAST "modifier")) + continue; + ++count; + std::string tag = XML::getProperty(effectNode, "tag", ""); + if (tag.empty()) + { + if (name.empty()) { - logger->log("Attributes: Invalid or missing stat ID in " - DEFAULT_ATTRIBUTESDB_FILE "!"); + logger->log("Attribute modifier in attribute %u:%s: " + "Empty name definition " + "on empty tag definition, skipping.", + a.id, a.name.c_str()); + --count; continue; } - else if (attributes.find(id) != attributes.end()) - { - logger->log("Attributes: Redefinition of stat ID %d", id); - } - - std::string name = XML::getProperty(node, "name", ""); + tag = name.substr(0, name.size() > 3 ? 3 : name.size()); + tag = toLower(tag) + toString(count); + } + std::string effect = XML::getProperty(effectNode, "effect", ""); + if (effect.empty()) + { if (name.empty()) { - logger->log("Attributes: Invalid or missing stat name in " - DEFAULT_ATTRIBUTESDB_FILE "!"); + logger->log("Attribute modifier in attribute %u:%s: " + "Empty name definition " + "on empty effect definition, skipping.", + a.id, a.name.c_str()); + --count; continue; } + else + effect = name + " %+f"; + } + tags.insert(std::make_pair(tag, effect)); + } + logger->log("Found %d tags for attribute %d.", count, id); - // Create the attribute. - Attribute a; - a.id = id; - a.name = name; - a.description = XML::getProperty(node, "desc", ""); - a.modifiable = XML::getBoolProperty(node, "modifiable", false); - a.scope = XML::getProperty(node, "scope", "none"); - a.playerInfoId = getPlayerInfoIdFromAttrType( - XML::getProperty(node, "player-info", "")); - - attributes[id] = a; - - unsigned int count = 0; - for_each_xml_child_node(effectNode, node) - { - if (!xmlStrEqual(effectNode->name, BAD_CAST "modifier")) - continue; - ++count; - std::string tag = XML::getProperty(effectNode, "tag", ""); - if (tag.empty()) - { - if (name.empty()) - { - logger->log("Attribute modifier in attribute %u:%s: " - "Empty name definition " - "on empty tag definition, skipping.", - a.id, a.name.c_str()); - --count; - continue; - } - tag = name.substr(0, name.size() > 3 ? 3 : name.size()); - tag = toLower(tag) + toString(count); - } - - std::string effect = XML::getProperty(effectNode, "effect", ""); - if (effect.empty()) - { - if (name.empty()) - { - logger->log("Attribute modifier in attribute %u:%s: " - "Empty name definition " - "on empty effect definition, skipping.", - a.id, a.name.c_str()); - --count; - continue; - } - else - effect = name + " %+f"; - } - tags.insert(std::make_pair(tag, effect)); - } - logger->log("Found %d tags for attribute %d.", count, id); - - }// End attribute - else if (xmlStrEqual(node->name, BAD_CAST "points")) - { - creationPoints = XML::getProperty(node, "start",DEFAULT_POINTS); - attributeMinimum = XML::getProperty(node, "minimum", - DEFAULT_MIN_PTS); - attributeMaximum = XML::getProperty(node, "maximum", - DEFAULT_MAX_PTS); - logger->log("Loaded points: start: %i, min: %i, max: %i.", - creationPoints, attributeMinimum, attributeMaximum); - } - else - { - continue; - } - } + } + + /** + * Read points node + */ + void readPointsNode(xmlNodePtr node, const std::string &filename) + { + creationPoints = XML::getProperty(node, "start",DEFAULT_POINTS); + attributeMinimum = XML::getProperty(node, "minimum", + DEFAULT_MIN_PTS); + attributeMaximum = XML::getProperty(node, "maximum", + DEFAULT_MAX_PTS); + logger->log("Loaded points: start: %i, min: %i, max: %i.", + creationPoints, attributeMinimum, attributeMaximum); + } + + /** + * Check if all the data loaded by readPointsNode and readAttributeNode is ok + */ + void checkStatus() + { logger->log("Found %d tags for %d attributes.", int(tags.size()), int(attributes.size())); + if (attributes.size() == 0) + { + loadBuiltins(); + } + fillLabels(); // Sanity checks on starting points diff --git a/src/resources/attributes.h b/src/resources/attributes.h index 7124ba94..41093af2 100644 --- a/src/resources/attributes.h +++ b/src/resources/attributes.h @@ -24,9 +24,18 @@ #include #include -namespace Attributes { +#include "utils/xml.h" - void load(); +namespace Attributes +{ + + void init(); + + void readAttributeNode(xmlNodePtr node, const std::string &filename); + + void readPointsNode(xmlNodePtr node, const std::string &filename); + + void checkStatus(); void unload(); diff --git a/src/resources/emotedb.cpp b/src/resources/emotedb.cpp index 00721ac4..04dd4bbb 100644 --- a/src/resources/emotedb.cpp +++ b/src/resources/emotedb.cpp @@ -1,7 +1,7 @@ /* * Emote database * Copyright (C) 2009 Aethyra Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -29,8 +29,6 @@ #include "resources/image.h" #include "resources/imageset.h" -#include "utils/xml.h" - namespace { Emotes mEmotes; @@ -39,7 +37,7 @@ namespace int mLastEmote = 0; } -void EmoteDB::load() +void EmoteDB::init() { if (mLoaded) unload(); @@ -51,74 +49,66 @@ void EmoteDB::load() mLastEmote = 0; - logger->log("Initializing emote database..."); +} + +void EmoteDB::readEmoteNode(xmlNodePtr node, const std::string &filename) +{ + int id = XML::getProperty(node, "id", -1); + if (id == -1) + { + logger->log("Emote Database: Emote with missing ID in %s!", filename.c_str()); + return; + } + + Emote *currentEmote = new Emote; + + currentEmote->name = XML::getProperty(node, "name", "unknown"); + currentEmote->effect = XML::getProperty(node, "effectid", -1); + + if (currentEmote->effect == -1) + { + logger->log("Emote Database: Warning: Emote %s has no attached effect in %s!", + currentEmote->name.c_str(), filename.c_str()); + delete currentEmote; + return; + } - XML::Document doc("emotes.xml"); - xmlNodePtr rootNode = doc.rootNode(); + const std::string imageName = XML::getProperty(node, "image", ""); + const int width = XML::getProperty(node, "width", 0); + const int height = XML::getProperty(node, "height", 0); - if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "emotes")) + if (imageName.empty() || width <= 0 || height <= 0) { - logger->log("Emote Database: Error while loading emotes.xml!"); + logger->log("Emote Database: Warning: Emote %s has bad imageset values in %s", + currentEmote->name.c_str(), filename.c_str()); + delete currentEmote; return; } - //iterate s - for_each_xml_child_node(emoteNode, rootNode) + ImageSet *is = ResourceManager::getInstance()->getImageSet(imageName, + width, + height); + if (!is || !(is->size() > 0)) + { + logger->log("Emote Database: Error loading imageset for emote %s in %s", + currentEmote->name.c_str(), filename.c_str()); + delete is; + delete currentEmote; + return; + } + else { - if (!xmlStrEqual(emoteNode->name, BAD_CAST "emote")) - continue; - - int id = XML::getProperty(emoteNode, "id", -1); - if (id == -1) - { - logger->log("Emote Database: Emote with missing ID in emotes.xml!"); - continue; - } - - Emote *currentEmote = new Emote; - - currentEmote->name = XML::getProperty(emoteNode, "name", "unknown"); - currentEmote->effect = XML::getProperty(emoteNode, "effectid", -1); - - if (currentEmote->effect == -1) - { - logger->log("Emote Database: Warning: Emote with no attached effect!"); - delete currentEmote; - continue; - } - - const std::string imageName = XML::getProperty(emoteNode, "image", ""); - const int width = XML::getProperty(emoteNode, "width", 0); - const int height = XML::getProperty(emoteNode, "height", 0); - - if (imageName.empty() || width <= 0 || height <= 0) - { - logger->log("Emote Database: Warning: Emote with bad imageset values"); - delete currentEmote; - continue; - } - - ImageSet *is = ResourceManager::getInstance()->getImageSet(imageName, - width, - height); - if (!is || !(is->size() > 0)) - { - logger->log("Emote Database: Error loading imageset"); - delete is; - delete currentEmote; - continue; - } - else - { - // For now we just use the first image in the animation - currentEmote->sprite = new ImageSprite(is->get(0)); - } - - mEmotes[id] = currentEmote; - if (id > mLastEmote) - mLastEmote = id; + // For now we just use the first image in the animation + currentEmote->sprite = new ImageSprite(is->get(0)); } + mEmotes[id] = currentEmote; + if (id > mLastEmote) + mLastEmote = id; +} + +void EmoteDB::checkStatus() +{ mLoaded = true; } diff --git a/src/resources/emotedb.h b/src/resources/emotedb.h index a1e991ec..33195d82 100644 --- a/src/resources/emotedb.h +++ b/src/resources/emotedb.h @@ -1,7 +1,7 @@ /* * Emote database * Copyright (C) 2009 Aethyra Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -25,6 +25,7 @@ #include #include #include +#include "utils/xml.h" class ImageSprite; @@ -42,7 +43,11 @@ typedef std::map Emotes; */ namespace EmoteDB { - void load(); + void init(); + + void readEmoteNode(xmlNodePtr node, const std::string &filename); + + void checkStatus(); void unload(); diff --git a/src/resources/hairdb.cpp b/src/resources/hairdb.cpp index 26ad966e..2e9747a2 100644 --- a/src/resources/hairdb.cpp +++ b/src/resources/hairdb.cpp @@ -1,7 +1,7 @@ /* * Hair database * Copyright (C) 2008 Aethyra Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -23,58 +23,32 @@ #include "log.h" -#include "utils/xml.h" - #include #define COLOR_WHITE "#ffffff" -#define HAIR_XML_FILE "hair.xml" -void HairDB::load() + +void HairDB::init() { if (mLoaded) unload(); // Default entry mHairColors[0] = COLOR_WHITE; +} - XML::Document *doc = new XML::Document(HAIR_XML_FILE); - xmlNodePtr root = doc->rootNode(); - - if (!root || (!xmlStrEqual(root->name, BAD_CAST "colors") - && !xmlStrEqual(root->name, BAD_CAST "hair"))) - { - logger->log("HairDb: Failed to find any old or new " - " nodes."); - delete doc; - mLoaded = true; - return; - } +void HairDB::readHairColorNode(xmlNodePtr node, const std::string &filename) +{ + int id = XML::getProperty(node, "id", 0); - // Old colors.xml file style. The hair style will be declared - // in the items.xml file. - if (xmlStrEqual(root->name, BAD_CAST "colors")) - { - loadHairColorsNode(root); - } - else if (xmlStrEqual(root->name, BAD_CAST "hair")) - { - // Loading new format: hair styles + colors. - for_each_xml_child_node(node, root) - { - if (xmlStrEqual(node->name, BAD_CAST "styles")) - { - loadHairStylesNode(root); - } - else if (xmlStrEqual(node->name, BAD_CAST "colors")) - { - loadHairColorsNode(node); - } - } - } + if (mHairColors.find(id) != mHairColors.end()) + logger->log("HairDb: Redefinition of color Id %d in %s", id, filename.c_str()); - delete doc; + mHairColors[id] = XML::getProperty(node, "value", COLOR_WHITE); +} +void HairDB::checkStatus() +{ mLoaded = true; } @@ -91,27 +65,6 @@ void HairDB::unload() mLoaded = false; } -void HairDB::loadHairColorsNode(xmlNodePtr colorsNode) -{ - for_each_xml_child_node(node, colorsNode) - { - if (xmlStrEqual(node->name, BAD_CAST "color")) - { - int id = XML::getProperty(node, "id", 0); - - if (mHairColors.find(id) != mHairColors.end()) - logger->log("HairDb: Redefinition of color Id %d", id); - - mHairColors[id] = XML::getProperty(node, "value", COLOR_WHITE); - } - } -} - -void HairDB::loadHairStylesNode(xmlNodePtr stylesNode) -{ - // TODO: Add support of the races.xml file. -} - void HairDB::addHairStyle(int id) { // TODO: Adapt the sprite handling with hair styles separated from items. @@ -128,8 +81,10 @@ void HairDB::addHairStyle(int id) const std::string &HairDB::getHairColor(int id) { if (!mLoaded) - load(); - + { + // no idea if this can happen, but that check existed before + logger->log("WARNING: HairDB::getHairColor() called before settings were loaded!"); + } ColorConstIterator it = mHairColors.find(id); if (it != mHairColors.end()) return it->second; diff --git a/src/resources/hairdb.h b/src/resources/hairdb.h index 700bd8b7..502d7c21 100644 --- a/src/resources/hairdb.h +++ b/src/resources/hairdb.h @@ -1,7 +1,7 @@ /* * Hair database * Copyright (C) 2008 Aethyra Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -26,6 +26,7 @@ #include #include +#include "utils/xml.h" /** * Hair information database. @@ -40,10 +41,11 @@ class HairDB ~HairDB() { unload(); } - /** - * Loads the color data from hair.xml. - */ - void load(); + void init(); + + void readHairColorNode(xmlNodePtr node, const std::string &filename); + + void checkStatus(); /** * Clear the color data diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp index 241cc053..8415b6ae 100644 --- a/src/resources/monsterdb.cpp +++ b/src/resources/monsterdb.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-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -29,131 +29,135 @@ #include "utils/dtor.h" #include "utils/gettext.h" -#include "utils/xml.h" #include "configuration.h" #define OLD_TMWATHENA_OFFSET 1002 + namespace { BeingInfos mMonsterInfos; bool mLoaded = false; + int mMonsterIdOffset; } -void MonsterDB::load() + +/** + * Initialize MonsterDB + * + * If it was initialized before, unload() will be called first. + */ +void MonsterDB::init() { if (mLoaded) unload(); - logger->log("Initializing monster database..."); + // This used to be read from offset attribute of monsters root tag, however + // I couldn't find any place it was used, so for now the default values are set + mMonsterIdOffset = Net::getNetworkType() == ServerInfo::TMWATHENA ? OLD_TMWATHENA_OFFSET : 0; +} - XML::Document doc("monsters.xml"); - xmlNodePtr rootNode = doc.rootNode(); +/** + * Read node from settings. + */ +void MonsterDB::readMonsterNode(xmlNodePtr node, const std::string &filename) +{ + BeingInfo *currentInfo = new BeingInfo; - if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "monsters")) - { - logger->error("Monster Database: Error while loading monster.xml!"); - } + currentInfo->setWalkMask(Map::BLOCKMASK_WALL + | Map::BLOCKMASK_CHARACTER + | Map::BLOCKMASK_MONSTER); + currentInfo->setBlockType(Map::BLOCKTYPE_MONSTER); + + currentInfo->setName(XML::getProperty(node, "name", _("unnamed"))); - int offset = XML::getProperty(rootNode, "offset", Net::getNetworkType() == - ServerInfo::TMWATHENA ? OLD_TMWATHENA_OFFSET : 0); + currentInfo->setTargetCursorSize(XML::getProperty(node, + "targetCursor", "medium")); - //iterate s - for_each_xml_child_node(monsterNode, rootNode) + SpriteDisplay display; + + //iterate s and s + for_each_xml_child_node(spriteNode, node) { - if (!xmlStrEqual(monsterNode->name, BAD_CAST "monster")) + if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) { - continue; + SpriteReference currentSprite; + currentSprite.sprite = (const char*)spriteNode->xmlChildrenNode->content; + currentSprite.variant = XML::getProperty(spriteNode, "variant", 0); + display.sprites.push_back(currentSprite); } - - BeingInfo *currentInfo = new BeingInfo; - - currentInfo->setWalkMask(Map::BLOCKMASK_WALL - | Map::BLOCKMASK_CHARACTER - | Map::BLOCKMASK_MONSTER); - currentInfo->setBlockType(Map::BLOCKTYPE_MONSTER); - - currentInfo->setName(XML::getProperty(monsterNode, "name", _("unnamed"))); - - currentInfo->setTargetCursorSize(XML::getProperty(monsterNode, - "targetCursor", "medium")); - - SpriteDisplay display; - - //iterate s and s - for_each_xml_child_node(spriteNode, monsterNode) + else if (xmlStrEqual(spriteNode->name, BAD_CAST "sound")) { - if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) + std::string event = XML::getProperty(spriteNode, "event", ""); + const char *soundFile; + soundFile = (const char*) spriteNode->xmlChildrenNode->content; + + if (event == "hit") + { + currentInfo->addSound(SOUND_EVENT_HIT, soundFile); + } + else if (event == "miss") { - SpriteReference currentSprite; - currentSprite.sprite = (const char*)spriteNode->xmlChildrenNode->content; - currentSprite.variant = XML::getProperty(spriteNode, "variant", 0); - display.sprites.push_back(currentSprite); + currentInfo->addSound(SOUND_EVENT_MISS, soundFile); } - else if (xmlStrEqual(spriteNode->name, BAD_CAST "sound")) + else if (event == "hurt") { - std::string event = XML::getProperty(spriteNode, "event", ""); - const char *filename; - filename = (const char*) spriteNode->xmlChildrenNode->content; - - if (event == "hit") - { - currentInfo->addSound(SOUND_EVENT_HIT, filename); - } - else if (event == "miss") - { - currentInfo->addSound(SOUND_EVENT_MISS, filename); - } - else if (event == "hurt") - { - currentInfo->addSound(SOUND_EVENT_HURT, filename); - } - else if (event == "die") - { - currentInfo->addSound(SOUND_EVENT_DIE, filename); - } - else - { - logger->log("MonsterDB: Warning, sound effect %s for " - "unknown event %s of monster %s", - filename, event.c_str(), - currentInfo->getName().c_str()); - } + currentInfo->addSound(SOUND_EVENT_HURT, soundFile); } - else if (xmlStrEqual(spriteNode->name, BAD_CAST "attack")) + else if (event == "die") { - const int id = XML::getProperty(spriteNode, "id", 0); - int effectId = XML::getProperty(spriteNode, "effect-id", -1); - int hitEffectId = - XML::getProperty(spriteNode, "hit-effect-id", - paths.getIntValue("hitEffectId")); - int criticalHitEffectId = - XML::getProperty(spriteNode, "critical-hit-effect-id", - paths.getIntValue("criticalHitEffectId")); - const std::string missileParticleFilename = - XML::getProperty(spriteNode, "missile-particle", ""); - - const std::string spriteAction = XML::getProperty(spriteNode, - "action", - "attack"); - - currentInfo->addAttack(id, spriteAction, effectId, - hitEffectId, criticalHitEffectId, - missileParticleFilename); + currentInfo->addSound(SOUND_EVENT_DIE, soundFile); } - else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx")) + else { - display.particles.push_back( - (const char*) spriteNode->xmlChildrenNode->content); + logger->log("MonsterDB: Warning, sound effect %s for " + "unknown event %s of monster %s in %s", + soundFile, event.c_str(), + currentInfo->getName().c_str(), + filename.c_str()); } } - currentInfo->setDisplay(display); - - mMonsterInfos[XML::getProperty(monsterNode, "id", 0) + offset] = currentInfo; + else if (xmlStrEqual(spriteNode->name, BAD_CAST "attack")) + { + const int id = XML::getProperty(spriteNode, "id", 0); + int effectId = XML::getProperty(spriteNode, "effect-id", -1); + int hitEffectId = + XML::getProperty(spriteNode, "hit-effect-id", + paths.getIntValue("hitEffectId")); + int criticalHitEffectId = + XML::getProperty(spriteNode, "critical-hit-effect-id", + paths.getIntValue("criticalHitEffectId")); + const std::string missileParticleFilename = + XML::getProperty(spriteNode, "missile-particle", ""); + + const std::string spriteAction = XML::getProperty(spriteNode, + "action", + "attack"); + + currentInfo->addAttack(id, spriteAction, effectId, + hitEffectId, criticalHitEffectId, + missileParticleFilename); + } + else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx")) + { + display.particles.push_back( + (const char*) spriteNode->xmlChildrenNode->content); + } } + currentInfo->setDisplay(display); + + mMonsterInfos[XML::getProperty(node, "id", 0) + mMonsterIdOffset] = currentInfo; - mLoaded = true; + +} + +/** + * Check if everything was loaded correctly + */ +void MonsterDB::checkStatus() +{ + // there is nothing to check for now } void MonsterDB::unload() diff --git a/src/resources/monsterdb.h b/src/resources/monsterdb.h index 8ea3afdf..5b2f3c2d 100644 --- a/src/resources/monsterdb.h +++ b/src/resources/monsterdb.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-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -22,6 +22,8 @@ #ifndef MONSTER_DB_H #define MONSTER_DB_H +#include "utils/xml.h" + class BeingInfo; /** @@ -29,7 +31,11 @@ class BeingInfo; */ namespace MonsterDB { - void load(); + void init(); + + void readMonsterNode(xmlNodePtr node, const std::string &filename); + + void checkStatus(); void unload(); diff --git a/src/resources/npcdb.cpp b/src/resources/npcdb.cpp index 45b36dfe..7d0f72b0 100644 --- a/src/resources/npcdb.cpp +++ b/src/resources/npcdb.cpp @@ -1,7 +1,7 @@ /* * The Mana Client * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -35,61 +35,52 @@ namespace bool mLoaded = false; } -void NPCDB::load() + +void NPCDB::init() { if (mLoaded) unload(); - logger->log("Initializing NPC database..."); - - XML::Document doc("npcs.xml"); - xmlNodePtr rootNode = doc.rootNode(); +} - if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "npcs")) +void NPCDB::readNPCNode(xmlNodePtr node, const std::string &filename) +{ + int id = XML::getProperty(node, "id", 0); + if (id == 0) { - logger->error("NPC Database: Error while loading npcs.xml!"); + logger->log("NPC Database: NPC with missing ID in %s", filename.c_str()); + return; } - //iterate s - for_each_xml_child_node(npcNode, rootNode) - { - if (!xmlStrEqual(npcNode->name, BAD_CAST "npc")) - continue; + BeingInfo *currentInfo = new BeingInfo; + + currentInfo->setTargetCursorSize(XML::getProperty(node, + "targetCursor", "medium")); - int id = XML::getProperty(npcNode, "id", 0); - if (id == 0) + SpriteDisplay display; + for_each_xml_child_node(spriteNode, node) + { + if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) { - logger->log("NPC Database: NPC with missing ID in npcs.xml!"); - continue; + SpriteReference currentSprite; + currentSprite.sprite = (const char*)spriteNode->xmlChildrenNode->content; + currentSprite.variant = XML::getProperty(spriteNode, "variant", 0); + display.sprites.push_back(currentSprite); } - - BeingInfo *currentInfo = new BeingInfo; - - currentInfo->setTargetCursorSize(XML::getProperty(npcNode, - "targetCursor", "medium")); - - SpriteDisplay display; - for_each_xml_child_node(spriteNode, npcNode) + else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx")) { - if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) - { - SpriteReference currentSprite; - currentSprite.sprite = (const char*)spriteNode->xmlChildrenNode->content; - currentSprite.variant = XML::getProperty(spriteNode, "variant", 0); - display.sprites.push_back(currentSprite); - } - else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx")) - { - std::string particlefx = (const char*)spriteNode->xmlChildrenNode->content; - display.particles.push_back(particlefx); - } + std::string particlefx = (const char*)spriteNode->xmlChildrenNode->content; + display.particles.push_back(particlefx); } + } - currentInfo->setDisplay(display); + currentInfo->setDisplay(display); - mNPCInfos[id] = currentInfo; - } + mNPCInfos[id] = currentInfo; +} +void NPCDB::checkStatus() +{ mLoaded = true; } diff --git a/src/resources/npcdb.h b/src/resources/npcdb.h index 16af7a5f..a3718a7b 100644 --- a/src/resources/npcdb.h +++ b/src/resources/npcdb.h @@ -1,7 +1,7 @@ /* * The Mana Client * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -22,6 +22,9 @@ #ifndef NPC_DB_H #define NPC_DB_H +#include +#include "utils/xml.h" + class BeingInfo; /** @@ -29,7 +32,11 @@ class BeingInfo; */ namespace NPCDB { - void load(); + void init(); + + void readNPCNode(xmlNodePtr node, const std::string &filename); + + void checkStatus(); void unload(); diff --git a/src/resources/settingsmanager.cpp b/src/resources/settingsmanager.cpp new file mode 100644 index 00000000..3cbb115c --- /dev/null +++ b/src/resources/settingsmanager.cpp @@ -0,0 +1,191 @@ +/* + * The Mana Server + * Copyright (C) 2013 The Mana World Development Team + * + * This file is part of The Mana Server. + * + * The Mana Server is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana Server. If not, see . + */ + +#include "resources/settingsmanager.h" + +#include "resources/attributes.h" +#include "resources/monsterdb.h" +#include "resources/hairdb.h" +#include "resources/specialdb.h" +#include "resources/npcdb.h" +#include "resources/emotedb.h" +#include "statuseffect.h" +#include "units.h" + +#include "net/manaserv/itemhandler.h" +#include "net/net.h" + +#include "utils/xml.h" +#include "utils/path.h" +#include "log.h" + +namespace SettingsManager +{ + std::string mSettingsFile; + std::set mIncludedFiles; + + static void loadFile(const std::string &filename); + + void load() + { + // initialize managers + Attributes::init(); + hairDB.init(); + MonsterDB::init(); + SpecialDB::init(); + NPCDB::init(); + EmoteDB::init(); + StatusEffect::init(); + Units::init(); + + // load stuff from settings + loadFile("settings.xml"); + + Attributes::checkStatus(); + hairDB.checkStatus(); + MonsterDB::checkStatus(); + SpecialDB::checkStatus(); + NPCDB::checkStatus(); + EmoteDB::checkStatus(); + StatusEffect::checkStatus(); + Units::checkStatus(); + + if (Net::getNetworkType() == ServerInfo::MANASERV) + { + Attributes::informItemDB(); + } + } + + void unload() + { + StatusEffect::unload(); + EmoteDB::unload(); + NPCDB::unload(); + SpecialDB::unload(); + MonsterDB::unload(); + hairDB.unload(); + Attributes::unload(); + } + + /** + * Loads a settings file. + */ + static void loadFile(const std::string &filename) + { + logger->log("Loading game settings from %s", filename.c_str()); + + XML::Document doc(filename); + xmlNodePtr node = doc.rootNode(); + + // add file to include set + mIncludedFiles.insert(filename); + + // FIXME: check root node's name when bjorn decides it's time + if (!node /*|| !xmlStrEqual(node->name, BAD_CAST "settings") */) + { + logger->log("Settings Manager: %s is not a valid settings file!", filename.c_str()); + return; + } + + + // go through every node + for_each_xml_child_node(childNode, node) + { + if (childNode->type != XML_ELEMENT_NODE) + continue; + + if (xmlStrEqual(childNode->name, BAD_CAST "include")) + { + // include an other file + const std::string includeFile = XML::getProperty(childNode, "file", std::string()); + + // check if file property was given + if (!includeFile.empty()) + { + // build absolute path path + const utils::splittedPath splittedPath = utils::splitFileNameAndPath(filename); + const std::string realIncludeFile = utils::cleanPath( + utils::joinPaths(splittedPath.path, includeFile)); + + // check if we're not entering a loop + if (mIncludedFiles.find(realIncludeFile) != mIncludedFiles.end()) + { + logger->log("Circular include loop detecting while including %s from %s", includeFile.c_str(), filename.c_str()); + } + else + { + // include that file + loadFile(realIncludeFile); + } + } + } + else if (xmlStrEqual(childNode->name, BAD_CAST "attribute")) + { + // map config + Attributes::readAttributeNode(childNode, filename); + } + else if (xmlStrEqual(childNode->name, BAD_CAST "points")) + { + Attributes::readPointsNode(childNode, filename); + } + else if (xmlStrEqual(childNode->name, BAD_CAST "color")) + { + hairDB.readHairColorNode(childNode, filename); + } + else if (xmlStrEqual(childNode->name, BAD_CAST "monster")) + { + MonsterDB::readMonsterNode(childNode, filename); + } + else if (xmlStrEqual(childNode->name, BAD_CAST "special-set")) + { + SpecialDB::readSpecialSetNode(childNode, filename); + } + else if (xmlStrEqual(childNode->name, BAD_CAST "npc")) + { + NPCDB::readNPCNode(childNode, filename); + } + else if (xmlStrEqual(childNode->name, BAD_CAST "emote")) + { + EmoteDB::readEmoteNode(childNode, filename); + } + else if (xmlStrEqual(childNode->name, BAD_CAST "status-effect") || xmlStrEqual(childNode->name, BAD_CAST "stun-effect")) + { + StatusEffect::readStatusEffectNode(childNode, filename); + } + else if (xmlStrEqual(childNode->name, BAD_CAST "unit")) + { + Units::readUnitNode(childNode, filename); + } + else + { + // compatibility stuff with older configs/games + if (xmlStrEqual(node->name, BAD_CAST "specials") && xmlStrEqual(childNode->name, BAD_CAST "set")) + { + // specials.xml:/specials/set + SpecialDB::readSpecialSetNode(childNode, filename); + } + } + } + + mIncludedFiles.erase(filename); + } + +} + diff --git a/src/resources/settingsmanager.h b/src/resources/settingsmanager.h new file mode 100644 index 00000000..25feb86b --- /dev/null +++ b/src/resources/settingsmanager.h @@ -0,0 +1,35 @@ +/* + * The Mana Client + * Copyright (C) 2013 The Mana Developers + * + * This file is part of The Mana Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SETTINGSMANAGER_HPP +#define SETTINGSMANAGER_HPP + +#include +#include +#include + +namespace SettingsManager +{ + void load(); + void unload(); +} + + +#endif // SETTINGSMANAGER_HPP diff --git a/src/resources/specialdb.cpp b/src/resources/specialdb.cpp index c75f4b1b..6601b586 100644 --- a/src/resources/specialdb.cpp +++ b/src/resources/specialdb.cpp @@ -1,6 +1,6 @@ /* * The Mana Client - * Copyright (C) 2010-2012 The Mana Developers + * Copyright (C) 2010-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -23,7 +23,6 @@ #include "log.h" #include "utils/dtor.h" -#include "utils/xml.h" namespace @@ -41,63 +40,51 @@ SpecialInfo::TargetMode SpecialDB::targetModeFromString(const std::string& str) return SpecialInfo::TARGET_BEING; } -void SpecialDB::load() + +void SpecialDB::init() { if (mLoaded) unload(); +} - logger->log("Initializing special database..."); - - XML::Document doc("specials.xml"); - xmlNodePtr root = doc.rootNode(); - - if (!root || !xmlStrEqual(root->name, BAD_CAST "specials")) - { - logger->log("Error loading specials file specials.xml"); - return; - } - - std::string setName; +void SpecialDB::readSpecialSetNode(xmlNodePtr node, const std::string &filename) +{ + std::string setName = XML::getProperty(node, "name", "Actions"); - for_each_xml_child_node(set, root) + for_each_xml_child_node(special, node) { - if (xmlStrEqual(set->name, BAD_CAST "set") || - xmlStrEqual(set->name, BAD_CAST "special-set")) + if (xmlStrEqual(special->name, BAD_CAST "special")) { - setName = XML::getProperty(set, "name", "Actions"); + SpecialInfo *info = new SpecialInfo(); + int id = XML::getProperty(special, "id", 0); + info->id = id; + info->set = setName; + info->name = XML::getProperty(special, "name", ""); + info->icon = XML::getProperty(special, "icon", ""); + + info->targetMode = targetModeFromString(XML::getProperty(special, "target", "being")); + info->rechargeable = XML::getBoolProperty(special, "rechargeable", true); + info->rechargeNeeded = 0; + info->rechargeCurrent = 0; - for_each_xml_child_node(special, set) + if (mSpecialInfos.find(id) != mSpecialInfos.end()) { - if (xmlStrEqual(special->name, BAD_CAST "special")) - { - SpecialInfo *info = new SpecialInfo(); - int id = XML::getProperty(special, "id", 0); - info->id = id; - info->set = setName; - info->name = XML::getProperty(special, "name", ""); - info->icon = XML::getProperty(special, "icon", ""); - - info->targetMode = targetModeFromString(XML::getProperty(special, "target", "being")); - - info->rechargeable = XML::getBoolProperty(special, "rechargeable", true); - info->rechargeNeeded = 0; - info->rechargeCurrent = 0; - - if (mSpecialInfos.find(id) != mSpecialInfos.end()) - { - logger->log("SpecialDB: Duplicate special ID %d (ignoring)", id); - } else { - mSpecialInfos[id] = info; - } - } + logger->log("SpecialDB: Duplicate special ID %d in %s, ignoring", id, filename.c_str()); + } else { + mSpecialInfos[id] = info; } } } +} + +void SpecialDB::checkStatus() +{ mLoaded = true; } + void SpecialDB::unload() { diff --git a/src/resources/specialdb.h b/src/resources/specialdb.h index dc1c26b6..f6987b71 100644 --- a/src/resources/specialdb.h +++ b/src/resources/specialdb.h @@ -1,6 +1,6 @@ /* * The Mana Client - * Copyright (C) 2010-2012 The Mana Developers + * Copyright (C) 2010-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -23,6 +23,7 @@ #include #include +#include "utils/xml.h" struct SpecialInfo { @@ -48,7 +49,11 @@ struct SpecialInfo */ namespace SpecialDB { - void load(); + void init(); + + void readSpecialSetNode(xmlNodePtr node, const std::string &filename); + + void checkStatus(); void unload(); diff --git a/src/statuseffect.cpp b/src/statuseffect.cpp index 659aeaf3..bdaaf566 100644 --- a/src/statuseffect.cpp +++ b/src/statuseffect.cpp @@ -1,7 +1,7 @@ /* * The Mana Client * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -25,8 +25,6 @@ #include "log.h" #include "sound.h" -#include "utils/xml.h" - #include "configuration.h" #include @@ -114,58 +112,52 @@ StatusEffect *StatusEffect::getStunEffect(int index, bool enabling) return stunEffects[enabling][index]; } -void StatusEffect::load() +void StatusEffect::init() { if (mLoaded) unload(); +} - XML::Document doc(STATUS_EFFECTS_FILE); - xmlNodePtr rootNode = doc.rootNode(); - - if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "status-effects")) +void StatusEffect::readStatusEffectNode(xmlNodePtr node, const std::string &filename) +{ + status_effect_map *the_map = NULL; + int index = atoi(XML::getProperty(node, "id", "-1").c_str()); + if (xmlStrEqual(node->name, BAD_CAST "status-effect")) { - logger->log("Error loading status effects file: " STATUS_EFFECTS_FILE); - return; + the_map = &statusEffects; + int block_index = atoi(XML::getProperty(node, "block-id", "-1").c_str()); + + if (index >= 0 && block_index >= 0) + blockEffectIndexMap[block_index] = index; } + else if (xmlStrEqual(node->name, BAD_CAST "stun-effect")) + the_map = &stunEffects; - for_each_xml_child_node(node, rootNode) + if (the_map) { - status_effect_map *the_map = NULL; - - int index = atoi(XML::getProperty(node, "id", "-1").c_str()); - - if (xmlStrEqual(node->name, BAD_CAST "status-effect")) - { - the_map = &statusEffects; - int block_index = atoi(XML::getProperty(node, "block-id", "-1").c_str()); - - if (index >= 0 && block_index >= 0) - blockEffectIndexMap[block_index] = index; + StatusEffect *startEffect = new StatusEffect; + StatusEffect *endEffect = new StatusEffect; + + startEffect->mMessage = XML::getProperty(node, "start-message", ""); + startEffect->mSFXEffect = XML::getProperty(node, "start-audio", ""); + startEffect->mParticleEffect = XML::getProperty(node, "start-particle", ""); + startEffect->mIcon = XML::getProperty(node, "icon", ""); + startEffect->mAction = XML::getProperty(node, "action", ""); + startEffect->mPersistentParticleEffect = (XML::getProperty(node, "persistent-particle-effect", "no")) != "no"; + + endEffect->mMessage = XML::getProperty(node, "end-message", ""); + endEffect->mSFXEffect = XML::getProperty(node, "end-audio", ""); + endEffect->mParticleEffect = XML::getProperty(node, "end-particle", ""); + + (*the_map)[1][index] = startEffect; + (*the_map)[0][index] = endEffect; + } - } - else if (xmlStrEqual(node->name, BAD_CAST "stun-effect")) - the_map = &stunEffects; +} - if (the_map) - { - StatusEffect *startEffect = new StatusEffect; - StatusEffect *endEffect = new StatusEffect; - - startEffect->mMessage = XML::getProperty(node, "start-message", ""); - startEffect->mSFXEffect = XML::getProperty(node, "start-audio", ""); - startEffect->mParticleEffect = XML::getProperty(node, "start-particle", ""); - startEffect->mIcon = XML::getProperty(node, "icon", ""); - startEffect->mAction = XML::getProperty(node, "action", ""); - startEffect->mPersistentParticleEffect = (XML::getProperty(node, "persistent-particle-effect", "no")) != "no"; - - endEffect->mMessage = XML::getProperty(node, "end-message", ""); - endEffect->mSFXEffect = XML::getProperty(node, "end-audio", ""); - endEffect->mParticleEffect = XML::getProperty(node, "end-particle", ""); - - (*the_map)[1][index] = startEffect; - (*the_map)[0][index] = endEffect; - } - } +void StatusEffect::checkStatus() +{ + mLoaded = true; } void unloadMap(std::map map) diff --git a/src/statuseffect.h b/src/statuseffect.h index 432f1c0e..5b1a7e23 100644 --- a/src/statuseffect.h +++ b/src/statuseffect.h @@ -1,7 +1,7 @@ /* * The Mana Client * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2012 The Mana Developers + * Copyright (C) 2009-2013 The Mana Developers * * This file is part of The Mana Client. * @@ -26,6 +26,7 @@ #include "animatedsprite.h" #include "resources/animation.h" +#include "utils/xml.h" class StatusEffect { @@ -94,7 +95,11 @@ public: */ static int blockEffectIndexToEffectIndex(int blocKIndex); - static void load(); + static void init(); + + static void readStatusEffectNode(xmlNodePtr node, const std::string &filename); + + static void checkStatus(); static void unload(); private: diff --git a/src/units.cpp b/src/units.cpp index 59181bde..1487eb21 100644 --- a/src/units.cpp +++ b/src/units.cpp @@ -50,7 +50,8 @@ enum UnitType { struct UnitDescription units[UNIT_END]; -void Units::loadUnits() + +void Units::init() { { // Setup default weight struct UnitDescription ud; @@ -90,72 +91,66 @@ void Units::loadUnits() units[UNIT_CURRENCY] = ud; } +} - XML::Document doc("units.xml"); - xmlNodePtr root = doc.rootNode(); +void Units::readUnitNode(xmlNodePtr node, const std::string &filename) +{ + struct UnitDescription ud; + int level = 1; + const std::string type = XML::getProperty(node, "type", ""); + ud.conversion = XML::getProperty(node, "conversion", 1); + ud.mix = XML::getProperty(node, "mix", "no") == "yes"; - if (!root || !xmlStrEqual(root->name, BAD_CAST "units")) - { - logger->log("Error loading unit definition file: units.xml"); - return; - } + struct UnitLevel bu; + bu.symbol = XML::getProperty(node, "base", "¤"); + bu.count = 1; + bu.round = XML::getProperty(node, "round", 2); + + ud.levels.push_back(bu); - for_each_xml_child_node(node, root) + for_each_xml_child_node(uLevel, node) { - if (xmlStrEqual(node->name, BAD_CAST "unit")) + if (xmlStrEqual(uLevel->name, BAD_CAST "level")) { - struct UnitDescription ud; - int level = 1; - const std::string type = XML::getProperty(node, "type", ""); - ud.conversion = XML::getProperty(node, "conversion", 1); - ud.mix = XML::getProperty(node, "mix", "no") == "yes"; - - struct UnitLevel bu; - bu.symbol = XML::getProperty(node, "base", "¤"); - bu.count = 1; - bu.round = XML::getProperty(node, "round", 2); + struct UnitLevel ul; + ul.symbol = XML::getProperty(uLevel, "symbol", + strprintf("¤%d",level)); + ul.count = XML::getProperty(uLevel, "count", -1); + ul.round = XML::getProperty(uLevel, "round", bu.round); - ud.levels.push_back(bu); - - for_each_xml_child_node(uLevel, node) + if (ul.count > 0) { - if (xmlStrEqual(uLevel->name, BAD_CAST "level")) - { - struct UnitLevel ul; - ul.symbol = XML::getProperty(uLevel, "symbol", - strprintf("¤%d",level)); - ul.count = XML::getProperty(uLevel, "count", -1); - ul.round = XML::getProperty(uLevel, "round", bu.round); - - if (ul.count > 0) - { - ud.levels.push_back(ul); - level++; - } - else - { - logger->log("Error bad unit count: %d for %s in %s", - ul.count, ul.symbol.c_str(), bu.symbol.c_str()); - } - } + ud.levels.push_back(ul); + level++; } - - // Add one more level for saftey - struct UnitLevel ll; - ll.symbol = ""; - ll.count = INT_MAX; - ll.round = 0; - - ud.levels.push_back(ll); - - if (type == "weight") - units[UNIT_WEIGHT] = ud; - else if (type == "currency") - units[UNIT_CURRENCY] = ud; else - logger->log("Error unknown unit type: %s", type.c_str()); + { + logger->log("Error bad unit count: %d for %s in %s", + ul.count, ul.symbol.c_str(), bu.symbol.c_str()); + } } } + + // Add one more level for saftey + struct UnitLevel ll; + ll.symbol = ""; + ll.count = INT_MAX; + ll.round = 0; + + ud.levels.push_back(ll); + + if (type == "weight") + units[UNIT_WEIGHT] = ud; + else if (type == "currency") + units[UNIT_CURRENCY] = ud; + else + logger->log("Error unknown unit type: %s in %s", type.c_str(), filename.c_str()); + +} + +void Units::checkStatus() +{ + } std::string formatUnit(int value, int type) diff --git a/src/units.h b/src/units.h index 1e923f33..96953b30 100644 --- a/src/units.h +++ b/src/units.h @@ -23,14 +23,16 @@ #define UNITS_H #include +#include "utils/xml.h" class Units { public: - /** - * Loads and parses the units.xml file (if found). - */ - static void loadUnits(); + static void init(); + + static void readUnitNode(xmlNodePtr node, const std::string &filename); + + static void checkStatus(); /** * Formats the given number in the correct currency format. diff --git a/src/utils/path.cpp b/src/utils/path.cpp new file mode 100644 index 00000000..95db40d3 --- /dev/null +++ b/src/utils/path.cpp @@ -0,0 +1,153 @@ +/* + * The Mana Server + * Copyright (C) 2013 The Mana World Development Team + * + * This file is part of The Mana Server. + * + * The Mana Server is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana Server. If not, see . + */ + +#include "utils/path.h" +#include + +namespace utils +{ + + /** + * Returns the filePath sub-part corresponding to the filename only. + * @return splittedPath: the file path ending with '/' or '\' + * and the file name alone. + */ + splittedPath splitFileNameAndPath(const std::string &fullFilePath) + { + // We'll reversed-search for '/' or'\' and extract the substrings + // corresponding to the filename and the path separately. + size_t slashPos = fullFilePath.find_last_of("/\\"); + + splittedPath splittedFilePath; + // Note the last slash is kept in the path name. + splittedFilePath.path = fullFilePath.substr(0, slashPos + 1); + splittedFilePath.file = fullFilePath.substr(slashPos + 1); + + return splittedFilePath; + } + + /** + * Join two path elements into one. + * + * This function helps build relative paths. + * + * Examples: + * + * /foo + bar = /foo/bar + * /foo/ + bar = /foo/bar + * /foo + /bar = /bar + * + * This will work for PhysFS paths. Windows style paths (prefixed with drive letters) won't work. + * + * @return Joined paths or path2 if path2 was an absolute path. + */ + std::string joinPaths(const std::string &path1, const std::string &path2) + { + if (path2.empty()) + return path1; + + if (path1.empty()) + return path2; + + // check if path2 is an absolute path that cannot be joined + if (path2[0] == '/' || path2[0] == '\\') + return path2; + + char p1end = path1[path1.size()-1]; + if (p1end == '/' || p1end == '\\') + { + return path1 + path2; + } + else + { + return path1 + "/" + path2; + } + } + + /** + * Removes relative elements from the path. + */ + std::string cleanPath(const std::string &path) + { + size_t prev, cur; + std::string part, result; + std::vector pathStack; + + prev = 0; + while (true) + { + cur = path.find_first_of("/\\", prev); + if (cur == std::string::npos) + { + // FIXME add everything from prev to the end + pathStack.push_back(path.substr(prev)); + break; + } + + part = path.substr(prev, cur - prev); + if (part == "..") + { + // go back one level + if (!pathStack.empty()) + { + pathStack.pop_back(); + } + } + else if (part == ".") + { + // do nothing + } + else if (part == "") + { + if (pathStack.empty() && cur == 0) + { + // handle first empty match before the root slash + pathStack.push_back(std::string()); + } + else + { + // empty match in the middle of the path should be ignored + } + } + else + { + // normal path element + pathStack.push_back(part); + } + + cur++; + prev = cur; + } + + // join the pathStack into a normal path + unsigned int i = 0; + for (i = 0; i < pathStack.size(); i++) + { + result += pathStack[i]; + if (i < pathStack.size() - 1) { + result += "/"; + } + } + + return result; + } + + +} diff --git a/src/utils/path.h b/src/utils/path.h new file mode 100644 index 00000000..2ad9e987 --- /dev/null +++ b/src/utils/path.h @@ -0,0 +1,42 @@ +/* + * The Mana Server + * Copyright (C) 2013 The Mana World Development Team + * + * This file is part of The Mana Server. + * + * The Mana Server is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana Server. If not, see . + */ + +#ifndef UTILS_PATH_H +#define UTILS_PATH_H + +#include + +namespace utils +{ + + struct splittedPath + { + std::string path; + std::string file; + }; + + splittedPath splitFileNameAndPath(const std::string &fullFilePath); + + std::string joinPaths(const std::string &path1, const std::string &path2); + + std::string cleanPath(const std::string &path); + +} +#endif // UTILS_PATH_H -- cgit v1.2.3-60-g2f50