summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Makefile.am3
-rw-r--r--src/being.cpp26
-rw-r--r--src/being.h4
-rw-r--r--src/gui/emotecontainer.cpp29
-rw-r--r--src/gui/emotecontainer.h6
-rw-r--r--src/gui/emoteshortcutcontainer.cpp42
-rw-r--r--src/gui/emoteshortcutcontainer.h7
-rw-r--r--src/gui/emotewindow.cpp10
-rw-r--r--src/gui/emotewindow.h2
-rw-r--r--src/main.cpp7
-rw-r--r--src/npc.cpp3
-rw-r--r--src/npc.h3
-rw-r--r--src/resources/emotedb.cpp148
-rw-r--r--src/resources/emotedb.h62
-rw-r--r--src/resources/npcdb.cpp2
17 files changed, 301 insertions, 56 deletions
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a3a9f01c..534bdd70 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -39,6 +39,7 @@ src/gui/updatewindow.cpp
src/net/playerhandler.cpp
src/net/tradehandler.cpp
src/resources/colordb.cpp
+src/resources/emotedb.cpp
src/resources/itemdb.cpp
src/resources/monsterdb.cpp
src/resources/npcdb.cpp
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 657d8e6b..dbdd64b6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -233,6 +233,8 @@ SET(SRCS
resources/colordb.h
resources/dye.cpp
resources/dye.h
+ resources/emotedb.cpp
+ resources/emotedb.h
resources/image.cpp
resources/image.h
resources/imageloader.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index a54bb5c8..5c519832 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -131,7 +131,6 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \
gui/speechbubble.h \
gui/status.cpp \
gui/status.h \
- gui/table.h \
gui/table.cpp \
gui/table.h \
gui/table_model.cpp \
@@ -200,6 +199,8 @@ aethyra_SOURCES = gui/widgets/dropdown.cpp \
resources/colordb.h \
resources/dye.cpp \
resources/dye.h \
+ resources/emotedb.cpp \
+ resources/emotedb.h \
resources/image.cpp \
resources/image.h \
resources/imageloader.cpp \
diff --git a/src/being.cpp b/src/being.cpp
index 69da1182..883344d8 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -35,6 +35,7 @@
#include "sound.h"
#include "text.h"
+#include "resources/emotedb.h"
#include "resources/imageset.h"
#include "resources/itemdb.h"
#include "resources/iteminfo.h"
@@ -50,7 +51,7 @@
int Being::instances = 0;
int Being::mNumberOfHairstyles = 1;
-ImageSet *Being::emotionSet = NULL;
+std::vector<AnimatedSprite*> Being::emotionSet;
static const int X_SPEECH_OFFSET = 18;
static const int Y_SPEECH_OFFSET = 60;
@@ -87,10 +88,18 @@ Being::Being(int id, int job, Map *map):
if (instances == 0)
{
- // Load the emotion set
- ResourceManager *rm = ResourceManager::getInstance();
- emotionSet = rm->getImageSet("graphics/sprites/emotions.png", 30, 32);
- if (!emotionSet) logger->error(_("Unable to load emotions"));
+ // Setup emote sprites
+ for (int i = 0; i <= EmoteDB::getLast(); i++)
+ {
+ EmoteInfo info = EmoteDB::get(i);
+
+ if (info.sprites != EmoteDB::getUnknown().sprites)
+ {
+ std::string file = "graphics/sprites/" + info.sprites.front()->sprite;
+ int variant = info.sprites.front()->variant;
+ emotionSet.push_back(AnimatedSprite::load(file, variant));
+ }
+ }
// Hairstyles are encoded as negative numbers. Count how far negative we can go.
int hairstyles = 1;
@@ -117,8 +126,7 @@ Being::~Being()
if (instances == 0)
{
- emotionSet->decRef();
- emotionSet = NULL;
+ delete_all(emotionSet);
}
delete mSpeechBubble;
@@ -448,8 +456,8 @@ void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
const int py = mPy + offsetY - 60;
const int emotionIndex = mEmotion - 1;
- if (emotionIndex >= 0 && emotionIndex < (int) emotionSet->size())
- graphics->drawImage(emotionSet->get(emotionIndex), px, py);
+ if (emotionIndex >= 0 && emotionIndex < EmoteDB::getLast())
+ emotionSet[emotionIndex]->draw(graphics, px, py);
}
void Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY)
diff --git a/src/being.h b/src/being.h
index 54c9d717..4534b1ea 100644
--- a/src/being.h
+++ b/src/being.h
@@ -431,8 +431,8 @@ class Being : public Sprite
// Speech Bubble components
SpeechBubble *mSpeechBubble;
- static int instances; /**< Number of Being instances */
- static ImageSet *emotionSet; /**< Emoticons used by beings */
+ static int instances; /**< Number of Being instances */
+ static std::vector<AnimatedSprite*> emotionSet; /**< Emoticons used by beings */
};
#endif
diff --git a/src/gui/emotecontainer.cpp b/src/gui/emotecontainer.cpp
index c3e20c41..691211ca 100644
--- a/src/gui/emotecontainer.cpp
+++ b/src/gui/emotecontainer.cpp
@@ -25,14 +25,17 @@
#include "emotecontainer.h"
#include "emoteshortcut.h"
+#include "../animatedsprite.h"
#include "../configuration.h"
#include "../graphics.h"
#include "../log.h"
+#include "../resources/emotedb.h"
#include "../resources/image.h"
#include "../resources/iteminfo.h"
#include "../resources/resourcemanager.h"
+#include "../utils/dtor.h"
#include "../utils/gettext.h"
#include "../utils/tostring.h"
@@ -46,15 +49,25 @@ EmoteContainer::EmoteContainer():
{
ResourceManager *resman = ResourceManager::getInstance();
- mEmoteImg = resman->getImageSet("graphics/sprites/emotions.png", 30, 32);
- if (!mEmoteImg) logger->error(_("Unable to load emotions"));
+ // Setup emote sprites
+ for (int i = 0; i <= EmoteDB::getLast(); i++)
+ {
+ EmoteInfo info = EmoteDB::get(i);
+
+ if (info.sprites != EmoteDB::getUnknown().sprites)
+ {
+ std::string file = "graphics/sprites/" + info.sprites.front()->sprite;
+ int variant = info.sprites.front()->variant;
+ mEmoteImg.push_back(AnimatedSprite::load(file, variant));
+ }
+ }
mSelImg = resman->getImage("graphics/gui/selection.png");
if (!mSelImg) logger->error(_("Unable to load selection.png"));
mSelImg->setAlpha(config.getValue("guialpha", 0.8));
- mMaxEmote = mEmoteImg->size();
+ mMaxEmote = EmoteDB::getLast() + 1;
addMouseListener(this);
addWidgetListener(this);
@@ -62,11 +75,8 @@ EmoteContainer::EmoteContainer():
EmoteContainer::~EmoteContainer()
{
- if (mEmoteImg)
- {
- mEmoteImg->decRef();
- mEmoteImg = NULL;
- }
+ delete_all(mEmoteImg);
+
if (!mSelImg)
{
mSelImg->decRef();
@@ -90,8 +100,7 @@ void EmoteContainer::draw(gcn::Graphics *graphics)
int emoteY = ((i) / columns) * gridHeight;
// Draw emote icon
- static_cast<Graphics*>(graphics)->drawImage(
- mEmoteImg->get(i), emoteX, emoteY);
+ mEmoteImg[i]->draw(static_cast<Graphics*>(graphics), emoteX, emoteY);
// Draw selection image below selected item
if (mSelectedEmoteIndex == i)
diff --git a/src/gui/emotecontainer.h b/src/gui/emotecontainer.h
index 2a115f0b..2231e01a 100644
--- a/src/gui/emotecontainer.h
+++ b/src/gui/emotecontainer.h
@@ -23,6 +23,7 @@
#define _AETHYRA_EMOTECONTAINER_H__
#include <list>
+#include <vector>
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
@@ -30,8 +31,7 @@
#include "../guichanfwd.h"
-#include "../resources/imageset.h"
-
+class AnimatedSprite;
class Image;
namespace gcn {
@@ -123,7 +123,7 @@ class EmoteContainer : public gcn::Widget,
*/
void distributeValueChangedEvent(void);
- ImageSet *mEmoteImg;
+ std::vector<AnimatedSprite*> mEmoteImg;
Image *mSelImg;
int mSelectedEmoteIndex;
diff --git a/src/gui/emoteshortcutcontainer.cpp b/src/gui/emoteshortcutcontainer.cpp
index de9f8bab..edaa8602 100644
--- a/src/gui/emoteshortcutcontainer.cpp
+++ b/src/gui/emoteshortcutcontainer.cpp
@@ -21,6 +21,7 @@
#include "emoteshortcutcontainer.h"
+#include "../animatedsprite.h"
#include "../emoteshortcut.h"
#include "../graphics.h"
#include "../inventory.h"
@@ -30,12 +31,16 @@
#include "../localplayer.h"
#include "../log.h"
+#include "../resources/emotedb.h"
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
+#include "../utils/dtor.h"
#include "../utils/gettext.h"
#include "../utils/tostring.h"
+static const int MAX_ITEMS = 12;
+
EmoteShortcutContainer::EmoteShortcutContainer():
mEmoteClicked(false),
mEmoteMoved(0)
@@ -48,10 +53,21 @@ EmoteShortcutContainer::EmoteShortcutContainer():
ResourceManager *resman = ResourceManager::getInstance();
mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png");
- mEmoteImg = resman->getImageSet("graphics/sprites/emotions.png", 30, 32);
- if (!mEmoteImg) logger->error(_("Unable to load emotions"));
- mMaxItems = emoteShortcut->getEmoteCount();
+ // Setup emote sprites
+ for (int i = 0; i <= EmoteDB::getLast(); i++)
+ {
+ EmoteInfo info = EmoteDB::get(i);
+
+ if (info.sprites != EmoteDB::getUnknown().sprites)
+ {
+ std::string file = "graphics/sprites/" + info.sprites.front()->sprite;
+ int variant = info.sprites.front()->variant;
+ mEmoteImg.push_back(AnimatedSprite::load(file, variant));
+ }
+ }
+
+ mMaxItems = MAX_ITEMS;
mBoxHeight = mBackgroundImg->getHeight();
mBoxWidth = mBackgroundImg->getWidth();
@@ -60,11 +76,8 @@ EmoteShortcutContainer::EmoteShortcutContainer():
EmoteShortcutContainer::~EmoteShortcutContainer()
{
mBackgroundImg->decRef();
- if (mEmoteImg)
- {
- mEmoteImg->decRef();
- mEmoteImg=NULL;
- }
+
+ delete_all(mEmoteImg);
}
void EmoteShortcutContainer::draw(gcn::Graphics *graphics)
@@ -88,21 +101,20 @@ void EmoteShortcutContainer::draw(gcn::Graphics *graphics)
if (emoteShortcut->getEmote(i))
{
- static_cast<Graphics*>(graphics)->drawImage(
- mEmoteImg->get(emoteShortcut->getEmote(i) - 1), emoteX + 2, emoteY + 10);
+ mEmoteImg[emoteShortcut->getEmote(i) - 1]->draw(g, emoteX + 2, emoteY + 10);
}
}
if (mEmoteMoved)
{
// Draw the emote image being dragged by the cursor.
- Image* image = mEmoteImg->get(mEmoteMoved-1);
- if (image)
+ AnimatedSprite* sprite = mEmoteImg[mEmoteMoved - 1];
+ if (sprite)
{
- const int tPosX = mCursorPosX - (image->getWidth() / 2);
- const int tPosY = mCursorPosY - (image->getHeight() / 2);
+ const int tPosX = mCursorPosX - (sprite->getWidth() / 2);
+ const int tPosY = mCursorPosY - (sprite->getHeight() / 2);
- g->drawImage(image, tPosX, tPosY);
+ sprite->draw(g, tPosX, tPosY);
}
}
}
diff --git a/src/gui/emoteshortcutcontainer.h b/src/gui/emoteshortcutcontainer.h
index 5b3f61cd..f8a07dcc 100644
--- a/src/gui/emoteshortcutcontainer.h
+++ b/src/gui/emoteshortcutcontainer.h
@@ -22,6 +22,8 @@
#ifndef _AETHYRA_EMOTESHORTCUTCONTAINER_H__
#define _AETHYRA_EMOTESHORTCUTCONTAINER_H__
+#include <vector>
+
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
#include <guichan/widgetlistener.hpp>
@@ -30,8 +32,7 @@
#include "../guichanfwd.h"
-#include "../resources/imageset.h"
-
+class AnimatedSprite;
class Image;
/**
@@ -73,7 +74,7 @@ class EmoteShortcutContainer : public ShortcutContainer
void mouseReleased(gcn::MouseEvent &event);
private:
- ImageSet *mEmoteImg;
+ std::vector<AnimatedSprite*> mEmoteImg;
bool mEmoteClicked;
int mEmoteMoved;
diff --git a/src/gui/emotewindow.cpp b/src/gui/emotewindow.cpp
index af9648ef..9639d9b6 100644
--- a/src/gui/emotewindow.cpp
+++ b/src/gui/emotewindow.cpp
@@ -48,13 +48,13 @@ EmoteWindow::EmoteWindow():
mEmotes = new EmoteContainer();
mEmotes->addSelectionListener(this);
- mInvenScroll = new ScrollArea(mEmotes);
- mInvenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mEmoteScroll = new ScrollArea(mEmotes);
+ mEmoteScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
draw();
add(mUseButton);
- add(mInvenScroll);
+ add(mEmoteScroll);
mUseButton->setSize(60, mUseButton->getHeight());
@@ -80,8 +80,8 @@ void EmoteWindow::draw()
mUseButton->setPosition(8, height - 8 - mUseButton->getHeight());
- mInvenScroll->setSize(width - 16, mUseButton->getY() - 18);
- mInvenScroll->setPosition(8, 10);
+ mEmoteScroll->setSize(width - 16, mUseButton->getY() - 18);
+ mEmoteScroll->setPosition(8, 10);
setMinHeight(130);
}
diff --git a/src/gui/emotewindow.h b/src/gui/emotewindow.h
index dbe4efd7..a996db99 100644
--- a/src/gui/emotewindow.h
+++ b/src/gui/emotewindow.h
@@ -70,7 +70,7 @@ class EmoteWindow : public Window, gcn::ActionListener,
EmoteContainer *mEmotes;
gcn::Button *mUseButton;
- gcn::ScrollArea *mInvenScroll;
+ gcn::ScrollArea *mEmoteScroll;
};
extern EmoteWindow *emoteWindow;
diff --git a/src/main.cpp b/src/main.cpp
index 61b90b12..a1109092 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -74,6 +74,7 @@
#include "net/network.h"
#include "resources/colordb.h"
+#include "resources/emotedb.h"
#include "resources/image.h"
#include "resources/itemdb.h"
#include "resources/monsterdb.h"
@@ -402,7 +403,7 @@ void init_engine(const Options &options)
// Initialize the item shortcuts.
itemShortcut = new ItemShortcut();
-
+
// Initialize the emote shortcuts.
emoteShortcut = new EmoteShortcut();
@@ -437,7 +438,6 @@ void exit_engine()
{
// Before config.write() since it writes the shortcuts to the config
delete itemShortcut;
-
delete emoteShortcut;
config.write();
@@ -453,6 +453,7 @@ void exit_engine()
// Unload XML databases
ColorDB::unload();
+ EmoteDB::unload();
ItemDB::unload();
MonsterDB::unload();
NPCDB::unload();
@@ -903,6 +904,8 @@ int main(int argc, char *argv[])
ItemDB::load();
MonsterDB::load();
NPCDB::load();
+ EmoteDB::load();
+
state = CHAR_CONNECT_STATE;
break;
diff --git a/src/npc.cpp b/src/npc.cpp
index a2fb7d38..a9aa216c 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -105,8 +105,7 @@ void NPC::setSprite(int slot, int id, std::string color)
Being::setSprite(slot, id, color);
}
-Being::Type
-NPC::getType() const
+Being::Type NPC::getType() const
{
return Being::NPC;
}
diff --git a/src/npc.h b/src/npc.h
index 6e150e2b..af1dfc66 100644
--- a/src/npc.h
+++ b/src/npc.h
@@ -39,8 +39,7 @@ class NPC : public Player
void setGender(Gender gender);
void setSprite(int slot, int id, std::string color);
- virtual Type
- getType() const;
+ virtual Type getType() const;
void talk();
void nextDialog();
diff --git a/src/resources/emotedb.cpp b/src/resources/emotedb.cpp
new file mode 100644
index 00000000..03096eff
--- /dev/null
+++ b/src/resources/emotedb.cpp
@@ -0,0 +1,148 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra 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.
+ *
+ * Aethyra 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 Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "emotedb.h"
+#include "resourcemanager.h"
+
+#include "../log.h"
+
+#include "../utils/dtor.h"
+#include "../utils/gettext.h"
+#include "../utils/xml.h"
+
+namespace
+{
+ EmoteInfos mEmoteInfos;
+ EmoteInfo mUnknown;
+ bool mLoaded = false;
+ int mLastEmote = 0;
+}
+
+void EmoteDB::load()
+{
+ if (mLoaded)
+ return;
+
+ mLastEmote = 0;
+
+ EmoteSprite *unknownSprite = new EmoteSprite;
+ unknownSprite->sprite = "error.xml";
+ unknownSprite->name = "unknown";
+ unknownSprite->variant = 0;
+ mUnknown.sprites.push_back(unknownSprite);
+
+ logger->log(_("Initializing emote database..."));
+
+ XML::Document doc("emotes.xml");
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "emotes"))
+ {
+ logger->log(_("Emote Database: Error while loading emotes.xml!"));
+ return;
+ }
+
+ //iterate <emote>s
+ for_each_xml_child_node(emoteNode, rootNode)
+ {
+ 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;
+ }
+
+ EmoteInfo *currentInfo = new EmoteInfo;
+
+ for_each_xml_child_node(spriteNode, emoteNode)
+ {
+ if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
+ {
+ EmoteSprite *currentSprite = new EmoteSprite;
+ currentSprite->sprite = (const char*) spriteNode->xmlChildrenNode->content;
+ currentSprite->variant = XML::getProperty(spriteNode, "variant", 0);
+ currentInfo->sprites.push_back(currentSprite);
+ }
+ else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx"))
+ {
+ std::string particlefx = (const char*) spriteNode->xmlChildrenNode->content;
+ currentInfo->particles.push_back(particlefx);
+ }
+ }
+ mEmoteInfos[id] = currentInfo;
+ if (id > mLastEmote) mLastEmote = id;
+ }
+
+ mLoaded = true;
+}
+
+void EmoteDB::unload()
+{
+ for ( EmoteInfosIterator i = mEmoteInfos.begin();
+ i != mEmoteInfos.end();
+ i++)
+ {
+ while (!i->second->sprites.empty())
+ {
+ delete i->second->sprites.front();
+ i->second->sprites.pop_front();
+ }
+ delete i->second;
+ }
+
+ mEmoteInfos.clear();
+
+ while (!mUnknown.sprites.empty())
+ {
+ delete mUnknown.sprites.front();
+ mUnknown.sprites.pop_front();
+ }
+
+ mLoaded = false;
+}
+
+const EmoteInfo& EmoteDB::get(int id)
+{
+ EmoteInfosIterator i = mEmoteInfos.find(id);
+
+ if (i == mEmoteInfos.end())
+ {
+ logger->log(_("EmoteDB: Warning, unknown emote ID %d requested"), id);
+ return mUnknown;
+ }
+ else
+ {
+ return *(i->second);
+ }
+}
+
+const EmoteInfo& EmoteDB::getUnknown()
+{
+ return mUnknown;
+}
+
+const int& EmoteDB::getLast()
+{
+ return mLastEmote;
+}
diff --git a/src/resources/emotedb.h b/src/resources/emotedb.h
new file mode 100644
index 00000000..9e904cc1
--- /dev/null
+++ b/src/resources/emotedb.h
@@ -0,0 +1,62 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra 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.
+ *
+ * Aethyra 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 Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _AETHYRA_EMOTE_DB_H
+#define _AETHYRA_EMOTE_DB_H
+
+#include <list>
+#include <map>
+#include <string>
+
+struct EmoteSprite
+{
+ std::string sprite;
+ std::string name;
+ int variant;
+};
+
+struct EmoteInfo
+{
+ std::list<EmoteSprite*> sprites;
+ std::list<std::string> particles;
+};
+
+typedef std::map<int, EmoteInfo*> EmoteInfos;
+
+/**
+ * Emote information database.
+ */
+namespace EmoteDB
+{
+ void load();
+
+ void unload();
+
+ const EmoteInfo& get(int id);
+
+ const EmoteInfo& getUnknown();
+
+ const int& getLast();
+
+ typedef EmoteInfos::iterator EmoteInfosIterator;
+}
+
+#endif
diff --git a/src/resources/npcdb.cpp b/src/resources/npcdb.cpp
index bfa22214..0908d67d 100644
--- a/src/resources/npcdb.cpp
+++ b/src/resources/npcdb.cpp
@@ -55,7 +55,7 @@ void NPCDB::load()
logger->error(_("NPC Database: Error while loading npcs.xml!"));
}
- //iterate <monster>s
+ //iterate <npc>s
for_each_xml_child_node(npcNode, rootNode)
{
if (!xmlStrEqual(npcNode->name, BAD_CAST "npc"))