diff options
author | Przemysław Grzywacz <nexather@gmail.com> | 2013-05-24 18:55:53 +0200 |
---|---|---|
committer | Przemysław Grzywacz <nexather@gmail.com> | 2013-05-24 18:55:53 +0200 |
commit | 05dc1666dc794ed6aa7f6568b768c652f8922c4e (patch) | |
tree | af83e22418e912e8eb8b2bc6b9595da344f461c1 | |
parent | 703cd73c0baa82d5f8ae3a1b390401f17de32f7a (diff) | |
parent | f9cd8a5d6b4460ffcb945979d1e8cd8ebadc9b8d (diff) | |
download | mana-05dc1666dc794ed6aa7f6568b768c652f8922c4e.tar.gz mana-05dc1666dc794ed6aa7f6568b768c652f8922c4e.tar.bz2 mana-05dc1666dc794ed6aa7f6568b768c652f8922c4e.tar.xz mana-05dc1666dc794ed6aa7f6568b768c652f8922c4e.zip |
Merge remote-tracking branch 'origin/master' into lpc2012 branch
38 files changed, 1110 insertions, 747 deletions
@@ -42,6 +42,7 @@ Marcel W. Wysocki <maci satgnu.org> Mateusz Kaduk (Usiu) <mateusz.kaduk gmail.com> Matthias Hartmann <hartmann.matthias gmail.com> Philipp Sehmisch (Crush) <tmw crushnet.org> +Przemysław Grzywacz <nexather gmail.com> Roderic Morris (rodge) <roderic ccs.neu.edu> Rogier Polak <rogier.l.a.polak gmail.com> Scott Ellis <quiche_on_a_leash hotmail.co.uk> diff --git a/docs/example.mana b/docs/example.mana index 9173efb0..a79471d4 100644 --- a/docs/example.mana +++ b/docs/example.mana @@ -13,7 +13,7 @@ filename / path as a command line parameter <option name="appShort" value="mana"/> <option name="appIcon" value="icons/mana.png"/> <option name="loginMusic" value="Magick - Real.ogg"/> - <option name="onlineServerList" value="http://manasource.org/serverlist.xml"/> + <option name="onlineServerList" value="http://www.manasource.org/serverlist.xml"/> <option name="defaultServer" value="testing.manasource.org"/> <option name="defaultPort" value="9601"/> <option name="defaultServerType" value="manaserv"/> @@ -396,8 +396,6 @@ <Unit filename="src\net\loginhandler.h" /> <Unit filename="src\net\manaserv\adminhandler.cpp" /> <Unit filename="src\net\manaserv\adminhandler.h" /> - <Unit filename="src\net\manaserv\attributes.cpp" /> - <Unit filename="src\net\manaserv\attributes.h" /> <Unit filename="src\net\manaserv\beinghandler.cpp" /> <Unit filename="src\net\manaserv\beinghandler.h" /> <Unit filename="src\net\manaserv\buysellhandler.cpp" /> @@ -524,6 +522,8 @@ <Unit filename="src\resources\ambientlayer.h" /> <Unit filename="src\resources\animation.cpp" /> <Unit filename="src\resources\animation.h" /> + <Unit filename="src\resources\attributes.cpp" /> + <Unit filename="src\resources\attributes.h" /> <Unit filename="src\resources\beinginfo.cpp" /> <Unit filename="src\resources\beinginfo.h" /> <Unit filename="src\resources\dye.cpp" /> @@ -554,6 +554,8 @@ <Unit filename="src\resources\resource.h" /> <Unit filename="src\resources\resourcemanager.cpp" /> <Unit filename="src\resources\resourcemanager.h" /> + <Unit filename="src\resources\settingsmanager.cpp" /> + <Unit filename="src\resources\settingsmanager.h" /> <Unit filename="src\resources\soundeffect.cpp" /> <Unit filename="src\resources\soundeffect.h" /> <Unit filename="src\resources\specialdb.cpp" /> @@ -600,6 +602,8 @@ <Unit filename="src\utils\physfsrwops.c"> <Option compilerVar="CC" /> </Unit> + <Unit filename="src\utils\path.cpp" /> + <Unit filename="src\utils\path.h" /> <Unit filename="src\utils\physfsrwops.h" /> <Unit filename="src\utils\sha256.cpp" /> <Unit filename="src\utils\sha256.h" /> @@ -501,6 +501,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 @@ -544,6 +546,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 8ce230ea..b40eab7b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -401,6 +401,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 @@ -420,6 +422,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/actorspritemanager.cpp b/src/actorspritemanager.cpp index 31b6d8f0..7da9fe10 100644 --- a/src/actorspritemanager.cpp +++ b/src/actorspritemanager.cpp @@ -138,7 +138,14 @@ FloorItem *ActorSpriteManager::createItem(int id, int itemId, const Vector &pos) return floorItem; } -void ActorSpriteManager::destroy(ActorSprite *actor) +void ActorSpriteManager::destroyActor(ActorSprite *actor) +{ + mActors.erase(actor); + mDeleteActors.erase(actor); + delete actor; +} + +void ActorSpriteManager::scheduleDelete(ActorSprite *actor) { if (!actor || actor == local_player) return; diff --git a/src/actorspritemanager.h b/src/actorspritemanager.h index 8ff9ff39..76364ea5 100644 --- a/src/actorspritemanager.h +++ b/src/actorspritemanager.h @@ -67,10 +67,15 @@ class ActorSpriteManager FloorItem *createItem(int id, int itemId, const Vector &position); /** + * Immediately destroys the given \a actor. + */ + void destroyActor(ActorSprite *actor); + + /** * Destroys the given ActorSprite at the end of * ActorSpriteManager::logic. */ - void destroy(ActorSprite *actor); + void scheduleDelete(ActorSprite *actor); /** * Returns a specific Being, by id; diff --git a/src/being.cpp b/src/being.cpp index 62081bb4..21d48ed2 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -892,7 +892,7 @@ void Being::logic() { if (getType() != PLAYER) - actorSpriteManager->destroy(this); + actorSpriteManager->scheduleDelete(this); } } diff --git a/src/client.cpp b/src/client.cpp index 88a2a523..1489a0dc 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; @@ -758,14 +755,15 @@ int Client::exec() false); } - // 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 XML databases CharDB::load(); - hairDB.load(); + + if (itemDb) + delete itemDb; + switch (Net::getNetworkType()) { case ServerInfo::TMWATHENA: @@ -779,23 +777,10 @@ int Client::exec() itemDb = 0; break; } - if (!itemDb || !itemDb->isLoaded()) - { - // Warn and return to login screen - errorMessage = - _("This server is missing needed world data. " - "Please contact the administrator(s)."); - showOkDialog(_("ItemDB: Error while loading " - ITEMS_DB_FILE "!"), errorMessage, - STATE_CHOOSE_SERVER); - break; - } - MonsterDB::load(); - SpecialDB::load(); - NPCDB::load(); - EmoteDB::load(); - StatusEffect::load(); - Units::loadUnits(); + assert(itemDb); + + // load settings.xml + SettingsManager::load(); ActorSprite::load(); diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index 9802224b..50510d15 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -424,7 +424,7 @@ void ServerDialog::downloadServerList() // Fall back to manasource.org when neither branding nor config set it if (listFile.empty()) - listFile = "http://manasource.org/serverlist.xml"; + listFile = "http://www.manasource.org/serverlist.xml"; mDownload = new Net::Download(this, listFile, &downloadUpdate); mDownload->setFile(mDir + "/serverlist.xml"); diff --git a/src/net/manaserv/beinghandler.cpp b/src/net/manaserv/beinghandler.cpp index 52f6dab4..61b4ef81 100644 --- a/src/net/manaserv/beinghandler.cpp +++ b/src/net/manaserv/beinghandler.cpp @@ -176,7 +176,7 @@ void BeingHandler::handleBeingLeaveMessage(MessageIn &msg) if (!being) return; - actorSpriteManager->destroy(being); + actorSpriteManager->destroyActor(being); } void BeingHandler::handleBeingsMoveMessage(MessageIn &msg) 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/manaserv/itemhandler.cpp b/src/net/manaserv/itemhandler.cpp index 4e29bb4f..de5b36fa 100644 --- a/src/net/manaserv/itemhandler.cpp +++ b/src/net/manaserv/itemhandler.cpp @@ -60,7 +60,7 @@ void ItemHandler::handleMessage(MessageIn &msg) } else if (FloorItem *item = actorSpriteManager->findItem(id)) { - actorSpriteManager->destroy(item); + actorSpriteManager->destroyActor(item); } } } break; diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp index fb01990a..12c97feb 100644 --- a/src/net/tmwa/beinghandler.cpp +++ b/src/net/tmwa/beinghandler.cpp @@ -327,7 +327,7 @@ void BeingHandler::handleMessage(MessageIn &msg) if (msg.readInt8() == 1) dstBeing->setAction(Being::DEAD); else - actorSpriteManager->destroy(dstBeing); + actorSpriteManager->destroyActor(dstBeing); break; 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<LoginHandler*>(mLoginHandler.get())->clearWorlds(); static_cast<CharServerHandler*>(mCharHandler.get())->setCharCreateDialog(0); static_cast<CharServerHandler*>(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/net/tmwa/itemhandler.cpp b/src/net/tmwa/itemhandler.cpp index f05bb899..6ad0ad4c 100644 --- a/src/net/tmwa/itemhandler.cpp +++ b/src/net/tmwa/itemhandler.cpp @@ -67,7 +67,7 @@ void ItemHandler::handleMessage(MessageIn &msg) case SMSG_ITEM_REMOVE: if (FloorItem *item = actorSpriteManager->findItem(msg.readInt32())) - actorSpriteManager->destroy(item); + actorSpriteManager->destroyActor(item); break; } } 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 <list> #include <map> @@ -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 <string> #include <vector> -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 <emote>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 <list> #include <map> #include <string> +#include "utils/xml.h" class ImageSprite; @@ -42,7 +43,11 @@ typedef std::map<int, Emote*> 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 <assert.h> #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 <colors> or new " - "<hair> 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 <map> #include <string> +#include "utils/xml.h" /** * Hair information database. @@ -40,10 +41,11 @@ class HairDB ~HairDB() { unload(); } - /** - * Loads the color data from <code>hair.xml</code>. - */ - void load(); + void init(); + + void readHairColorNode(xmlNodePtr node, const std::string &filename); + + void checkStatus(); /** * Clear the color data diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 4db7b085..8c1a8d15 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -31,7 +31,6 @@ #include "utils/dtor.h" #include "utils/gettext.h" #include "utils/stringutils.h" -#include "utils/xml.h" #include "configuration.h" #include <libxml/tree.h> @@ -189,18 +188,17 @@ void ItemDB::unload() mLoaded = false; } -void ItemDB::loadCommonRef(ItemInfo *itemInfo, xmlNodePtr node) +void ItemDB::loadCommonRef(ItemInfo *itemInfo, xmlNodePtr node, const std::string &filename) { int id = XML::getProperty(node, "id", 0); if (!id) { - logger->log("ItemDB: Invalid or missing item Id in " - ITEMS_DB_FILE "!"); + logger->log("ItemDB: Invalid or missing item Id in %s!", filename.c_str()); return; } else if (mItemInfos.find(id) != mItemInfos.end()) - logger->log("ItemDB: Redefinition of item Id %d", id); + logger->log("ItemDB: Redefinition of item Id %d in %s", id, filename.c_str()); int view = XML::getProperty(node, "view", 0); @@ -324,70 +322,59 @@ static char const *const fields[][2] = { "mp", N_("MP %+d") } }; -void TaItemDB::load() +void TaItemDB::init() { if (mLoaded) unload(); +} - logger->log("Initializing TmwAthena item database..."); +void TaItemDB::readItemNode(xmlNodePtr node, const std::string &filename) +{ + TaItemInfo *itemInfo = new TaItemInfo; - mUnknown = new TaItemInfo; - loadEmptyItemDefinition(); + loadCommonRef(itemInfo, node, filename); - XML::Document doc(ITEMS_DB_FILE); - xmlNodePtr rootNode = doc.rootNode(); + // Everything not unusable or usable is equippable by the Ta type system. + itemInfo->mEquippable = itemInfo->mType != ITEM_UNUSABLE + && itemInfo->mType != ITEM_USABLE; + itemInfo->mActivatable = itemInfo->mType == ITEM_USABLE; - if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "items")) + // Load nano description + std::vector<std::string> effect; + for (int i = 0; i < int(sizeof(fields) / sizeof(fields[0])); ++i) { - logger->error("ItemDB: Error while loading " ITEMS_DB_FILE "!"); - return; + int value = XML::getProperty(node, fields[i][0], 0); + if (!value) + continue; + effect.push_back(strprintf(gettext(fields[i][1]), value)); } - - for_each_xml_child_node(node, rootNode) + for (std::list<ItemStat>::iterator it = extraStats.begin(); + it != extraStats.end(); it++) { - if (!xmlStrEqual(node->name, BAD_CAST "item")) + int value = XML::getProperty(node, it->mTag.c_str(), 0); + if (!value) continue; + effect.push_back(strprintf(it->mFormat.c_str(), value)); + } + std::string temp = XML::getProperty(node, "effect", ""); + if (!temp.empty()) + effect.push_back(temp); - TaItemInfo *itemInfo = new TaItemInfo; - - loadCommonRef(itemInfo, node); - - // Everything not unusable or usable is equippable by the Ta type system. - itemInfo->mEquippable = itemInfo->mType != ITEM_UNUSABLE - && itemInfo->mType != ITEM_USABLE; - itemInfo->mActivatable = itemInfo->mType == ITEM_USABLE; - - // Load nano description - std::vector<std::string> effect; - for (int i = 0; i < int(sizeof(fields) / sizeof(fields[0])); ++i) - { - int value = XML::getProperty(node, fields[i][0], 0); - if (!value) - continue; - effect.push_back(strprintf(gettext(fields[i][1]), value)); - } - for (std::list<ItemStat>::iterator it = extraStats.begin(); - it != extraStats.end(); it++) - { - int value = XML::getProperty(node, it->mTag.c_str(), 0); - if (!value) - continue; - effect.push_back(strprintf(it->mFormat.c_str(), value)); - } - std::string temp = XML::getProperty(node, "effect", ""); - if (!temp.empty()) - effect.push_back(temp); + itemInfo->mEffect = effect; - itemInfo->mEffect = effect; + checkItemInfo(itemInfo); - checkItemInfo(itemInfo); + addItem(itemInfo); - addItem(itemInfo); + // Insert hairstyle id while letting the info as an item. + if (itemInfo->mType == ITEM_SPRITE_HAIR) + hairDB.addHairStyle(itemInfo->mId); +} - // Insert hairstyle id while letting the info as an item. - if (itemInfo->mType == ITEM_SPRITE_HAIR) - hairDB.addHairStyle(itemInfo->mId); - } +void TaItemDB::checkStatus() +{ + mUnknown = new TaItemInfo; + loadEmptyItemDefinition(); checkHairWeaponsRacesSpecialIds(); @@ -423,136 +410,125 @@ static void initTriggerTable() } } -void ManaServItemDB::load() +void ManaServItemDB::init() { if (mLoaded) unload(); // Initialize the trigger table for effect descriptions initTriggerTable(); +} - logger->log("Initializing ManaServ item database..."); - - mUnknown = new ManaServItemInfo; - loadEmptyItemDefinition(); +void ManaServItemDB::readItemNode(xmlNodePtr node, const std::string &filename) +{ + ManaServItemInfo *itemInfo = new ManaServItemInfo; - XML::Document doc(ITEMS_DB_FILE); - xmlNodePtr rootNode = doc.rootNode(); + loadCommonRef(itemInfo, node, filename); - if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "items")) - { - logger->log("ItemDB: Error while loading " ITEMS_DB_FILE "!"); - return; - } + // We default eqippable and activatable to false as their actual value will be set + // within the <equip> and <effect> sub-nodes.. + itemInfo->mActivatable = false; + itemInfo->mEquippable = false; - for_each_xml_child_node(node, rootNode) + // Load <equip>, and <effect> sub nodes. + std::vector<std::string> effect; + for_each_xml_child_node(itemChild, node) { - if (!xmlStrEqual(node->name, BAD_CAST "item")) - continue; - - ManaServItemInfo *itemInfo = new ManaServItemInfo; - - loadCommonRef(itemInfo, node); - - // We default eqippable and activatable to false as their actual value will be set - // within the <equip> and <effect> sub-nodes.. - itemInfo->mActivatable = false; - itemInfo->mEquippable = false; - - // Load <equip>, and <effect> sub nodes. - std::vector<std::string> effect; - for_each_xml_child_node(itemChild, node) + if (xmlStrEqual(itemChild->name, BAD_CAST "equip")) + { + // The fact that there is a way to equip is enough. + // Discard any details, but mark the item as equippable. + itemInfo->mEquippable = true; + } + else if (xmlStrEqual(itemChild->name, BAD_CAST "effect")) { - if (xmlStrEqual(itemChild->name, BAD_CAST "equip")) + std::string trigger = XML::getProperty( + itemChild, "trigger", ""); + if (trigger.empty()) { - // The fact that there is a way to equip is enough. - // Discard any details, but mark the item as equippable. - itemInfo->mEquippable = true; + logger->log("Found empty trigger effect label in %s, skipping.", filename.c_str()); + continue; } - else if (xmlStrEqual(itemChild->name, BAD_CAST "effect")) - { - std::string trigger = XML::getProperty( - itemChild, "trigger", ""); - if (trigger.empty()) - { - logger->log("Found empty trigger effect label, skipping."); - continue; - } - if (trigger == "activation") - itemInfo->mActivatable = true; + if (trigger == "activation") + itemInfo->mActivatable = true; - std::map<std::string, const char* >::const_iterator triggerLabel = - triggerTable.find(trigger); - if (triggerLabel == triggerTable.end()) - { - logger->log("Warning: unknown trigger %s in item %d!", - trigger.c_str(), itemInfo->mId); - continue; - } + std::map<std::string, const char* >::const_iterator triggerLabel = + triggerTable.find(trigger); + if (triggerLabel == triggerTable.end()) + { + logger->log("Warning: unknown trigger %s in item %d!", + trigger.c_str(), itemInfo->mId); + continue; + } - for_each_xml_child_node(effectChild, itemChild) + for_each_xml_child_node(effectChild, itemChild) + { + if (xmlStrEqual(effectChild->name, BAD_CAST "modifier")) { - if (xmlStrEqual(effectChild->name, BAD_CAST "modifier")) + std::string attribute = XML::getProperty( + effectChild, "attribute", ""); + double value = XML::getFloatProperty( + effectChild, "value", 0.0); + int duration = XML::getProperty( + effectChild, "duration", 0); + if (attribute.empty() || !value) { - std::string attribute = XML::getProperty( - effectChild, "attribute", ""); - double value = XML::getFloatProperty( - effectChild, "value", 0.0); - int duration = XML::getProperty( - effectChild, "duration", 0); - if (attribute.empty() || !value) - { - logger->log("Warning: incomplete modifier definition, skipping."); - continue; - } - std::list<ItemStat>::const_iterator - it = extraStats.begin(), - it_end = extraStats.end(); - while (it != it_end && !(*it == attribute)) - ++it; - if (it == extraStats.end()) - { - logger->log("Warning: unknown modifier tag %s, skipping.", attribute.c_str()); - continue; - } - effect.push_back( - strprintf(strprintf( - duration ? - strprintf("%%s%%s. This effect lasts %d ticks.", duration).c_str() - : "%s%s.", it->mFormat.c_str(), triggerLabel->second).c_str(), value)); + logger->log("Warning: incomplete modifier definition in %s, skipping.", filename.c_str()); + continue; } - else if (xmlStrEqual(effectChild->name, BAD_CAST "modifier")) - effect.push_back(strprintf("Provides an autoattack%s.", - triggerLabel->second)); - else if (xmlStrEqual(effectChild->name, BAD_CAST "consumes")) - effect.push_back(strprintf("This will be consumed%s.", - triggerLabel->second)); - else if (xmlStrEqual(effectChild->name, BAD_CAST "label")) - effect.push_back( - (const char*)effectChild->xmlChildrenNode->content); + std::list<ItemStat>::const_iterator + it = extraStats.begin(), + it_end = extraStats.end(); + while (it != it_end && !(*it == attribute)) + ++it; + if (it == extraStats.end()) + { + logger->log("Warning: unknown modifier tag %s in %s, skipping.", attribute.c_str(), filename.c_str()); + continue; + } + effect.push_back( + strprintf(strprintf( + duration ? + strprintf("%%s%%s. This effect lasts %d ticks.", duration).c_str() + : "%s%s.", it->mFormat.c_str(), triggerLabel->second).c_str(), value)); } + else if (xmlStrEqual(effectChild->name, BAD_CAST "modifier")) + effect.push_back(strprintf("Provides an autoattack%s.", + triggerLabel->second)); + else if (xmlStrEqual(effectChild->name, BAD_CAST "consumes")) + effect.push_back(strprintf("This will be consumed%s.", + triggerLabel->second)); + else if (xmlStrEqual(effectChild->name, BAD_CAST "label")) + effect.push_back( + (const char*)effectChild->xmlChildrenNode->content); } + } + + // FIXME: Load hair styles through the races.xml file + if (itemInfo->mType == ITEM_SPRITE_HAIR) + hairDB.addHairStyle(itemInfo->mId); - // FIXME: Load hair styles through the races.xml file - if (itemInfo->mType == ITEM_SPRITE_HAIR) - hairDB.addHairStyle(itemInfo->mId); + // Set Item Type based on subnodes info + // TODO: Improve it once the itemTypes are loaded through xml + itemInfo->mType = ITEM_UNUSABLE; + if (itemInfo->mActivatable) + itemInfo->mType = ITEM_USABLE; + else if (itemInfo->mEquippable) + itemInfo->mType = ITEM_EQUIPMENT_TORSO; + } // end for_each_xml_child_node(itemChild, node) - // Set Item Type based on subnodes info - // TODO: Improve it once the itemTypes are loaded through xml - itemInfo->mType = ITEM_UNUSABLE; - if (itemInfo->mActivatable) - itemInfo->mType = ITEM_USABLE; - else if (itemInfo->mEquippable) - itemInfo->mType = ITEM_EQUIPMENT_TORSO; - } // end for_each_xml_child_node(itemChild, node) + itemInfo->mEffect = effect; - itemInfo->mEffect = effect; + checkItemInfo(itemInfo); - checkItemInfo(itemInfo); + addItem(itemInfo); +} - addItem(itemInfo); - } +void ManaServItemDB::checkStatus() +{ + mUnknown = new ManaServItemInfo; + loadEmptyItemDefinition(); mLoaded = true; } diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h index d7859ad3..2f19339d 100644 --- a/src/resources/itemdb.h +++ b/src/resources/itemdb.h @@ -82,11 +82,6 @@ class ItemDB {} /** - * Loads the item data from <code>items.xml</code>. - */ - virtual void load() = 0; - - /** * Frees item data. */ virtual void unload(); @@ -102,12 +97,18 @@ class ItemDB const ItemInfo &get(int id); const ItemInfo &get(const std::string &name); + virtual void init() = 0; + + virtual void readItemNode(xmlNodePtr node, const std::string &filename) = 0; + + virtual void checkStatus() = 0; + protected: /** * Permits to load item definitions which are common * for each protocols to avoid code duplication. */ - void loadCommonRef(ItemInfo *itemInfo, xmlNodePtr node); + void loadCommonRef(ItemInfo *itemInfo, xmlNodePtr node, const std::string &filename); /** * Checks the items parameters consistency. @@ -164,16 +165,16 @@ class TaItemDB: public ItemDB { public: TaItemDB() : ItemDB() - { load(); } + { } ~TaItemDB() { unload(); } - /** - * Loads the item data from <code>items.xml</code>. - */ - void load(); + virtual void init(); + + virtual void readItemNode(xmlNodePtr node, const std::string &filename); + virtual void checkStatus(); private: /** * Check items id specific hard limits and log errors found. @@ -198,15 +199,16 @@ class ManaServItemDB: public ItemDB { public: ManaServItemDB() : ItemDB() - { load(); } + { } ~ManaServItemDB() { unload(); } - /** - * Loads the item data from <code>items.xml</code>. - */ - void load(); + virtual void init(); + + virtual void readItemNode(xmlNodePtr node, const std::string &filename); + + virtual void checkStatus(); private: void checkItemInfo(ItemInfo* itemInfo); 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 <monster> 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 <monster>s - for_each_xml_child_node(monsterNode, rootNode) + SpriteDisplay display; + + //iterate <sprite>s and <sound>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 <sprite>s and <sound>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 <npc>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 <string> +#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..940ebb59 --- /dev/null +++ b/src/resources/settingsmanager.cpp @@ -0,0 +1,212 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "resources/settingsmanager.h" + +#include "configuration.h" +#include "resources/attributes.h" +#include "resources/hairdb.h" +#include "resources/itemdb.h" +#include "resources/monsterdb.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 +{ + static std::string mSettingsFile; + static std::set<std::string> mIncludedFiles; + + static void loadFile(const std::string &filename); + + void load() + { + // initialize managers + paths.clear(); + Attributes::init(); + hairDB.init(); + itemDb->init(); + MonsterDB::init(); + SpecialDB::init(); + NPCDB::init(); + EmoteDB::init(); + StatusEffect::init(); + Units::init(); + + // load stuff from settings + loadFile("settings.xml"); + + Attributes::checkStatus(); + hairDB.checkStatus(); + itemDb->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(); + itemDb->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 "option")) + { + // options from paths.xml + std::string name = XML::getProperty(childNode, "name", std::string()); + std::string value = XML::getProperty(childNode, "value", std::string()); + + if (!name.empty()) + paths.setValue(name, value); + else + logger->log("Warning: option without a name found in %s", filename.c_str()); + } + 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 "item")) + { + itemDb->readItemNode(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 <http://www.gnu.org/licenses/>. + */ + +#ifndef SETTINGSMANAGER_HPP +#define SETTINGSMANAGER_HPP + +#include <string> +#include <list> +#include <set> + +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 <string> #include <map> +#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 <map> @@ -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<int, StatusEffect *> 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 <string> +#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 <http://www.gnu.org/licenses/>. + */ + +#include "utils/path.h" +#include <vector> + +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<std::string> 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef UTILS_PATH_H +#define UTILS_PATH_H + +#include <string> + +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 |