summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt19
-rw-r--r--src/Makefile.am19
-rw-r--r--src/action.cpp66
-rw-r--r--src/action.h (renamed from src/resources/itemmanager.h)34
-rw-r--r--src/animatedsprite.cpp430
-rw-r--r--src/animatedsprite.h131
-rw-r--r--src/animation.cpp127
-rw-r--r--src/animation.h97
-rw-r--r--src/base64.cpp63
-rw-r--r--src/base64.h11
-rw-r--r--src/being.cpp87
-rw-r--r--src/being.h36
-rw-r--r--src/beingmanager.cpp24
-rw-r--r--src/engine.cpp147
-rw-r--r--src/engine.h14
-rw-r--r--src/floor_item.cpp4
-rw-r--r--src/floor_item.h10
-rw-r--r--src/game.cpp94
-rw-r--r--src/graphics.cpp3
-rw-r--r--src/gui/buy.cpp4
-rw-r--r--src/gui/char_select.cpp51
-rw-r--r--src/gui/char_select.h11
-rw-r--r--src/gui/confirm_dialog.cpp1
-rw-r--r--src/gui/confirm_dialog.h2
-rw-r--r--src/gui/debugwindow.cpp10
-rw-r--r--src/gui/gui.cpp152
-rw-r--r--src/gui/gui.h38
-rw-r--r--src/gui/inventorywindow.cpp3
-rw-r--r--src/gui/item_amount.cpp3
-rw-r--r--src/gui/login.cpp1
-rw-r--r--src/gui/ok_dialog.cpp1
-rw-r--r--src/gui/ok_dialog.h2
-rw-r--r--src/gui/passwordfield.h4
-rw-r--r--src/gui/playerbox.cpp37
-rw-r--r--src/gui/playerbox.h24
-rw-r--r--src/gui/popupmenu.cpp4
-rw-r--r--src/gui/register.cpp1
-rw-r--r--src/gui/sell.cpp5
-rw-r--r--src/gui/serverdialog.cpp1
-rw-r--r--src/gui/serverdialog.h2
-rw-r--r--src/gui/setup_joystick.cpp2
-rw-r--r--src/gui/shop.cpp6
-rw-r--r--src/gui/textfield.h1
-rw-r--r--src/gui/trade.cpp36
-rw-r--r--src/gui/updatewindow.cpp2
-rw-r--r--src/gui/viewport.cpp392
-rw-r--r--src/gui/viewport.h145
-rw-r--r--src/gui/window.cpp3
-rw-r--r--src/gui/window.h3
-rw-r--r--src/gui/windowcontainer.h3
-rw-r--r--src/item.h4
-rw-r--r--src/localplayer.cpp36
-rw-r--r--src/localplayer.h10
-rw-r--r--src/log.cpp23
-rw-r--r--src/main.cpp51
-rw-r--r--src/map.cpp53
-rw-r--r--src/map.h12
-rw-r--r--src/monster.cpp39
-rw-r--r--src/monster.h2
-rw-r--r--src/net/beinghandler.cpp83
-rw-r--r--src/net/inventoryhandler.cpp2
-rw-r--r--src/net/npchandler.cpp10
-rw-r--r--src/net/playerhandler.cpp18
-rw-r--r--src/net/skillhandler.cpp4
-rw-r--r--src/npc.cpp17
-rw-r--r--src/npc.h8
-rw-r--r--src/openglgraphics.cpp3
-rw-r--r--src/player.cpp109
-rw-r--r--src/player.h18
-rw-r--r--src/resources/equipmentdb.cpp158
-rw-r--r--src/resources/equipmentdb.h52
-rw-r--r--src/resources/equipmentinfo.h52
-rw-r--r--src/resources/image.cpp10
-rw-r--r--src/resources/itemdb.cpp (renamed from src/resources/itemmanager.cpp)343
-rw-r--r--src/resources/itemdb.h53
-rw-r--r--src/resources/iteminfo.h12
-rw-r--r--src/resources/mapreader.cpp32
-rw-r--r--src/resources/monsterdb.cpp151
-rw-r--r--src/resources/monsterdb.h45
-rw-r--r--src/resources/monsterinfo.cpp70
-rw-r--r--src/resources/monsterinfo.h74
-rw-r--r--src/resources/resourcemanager.cpp61
-rw-r--r--src/resources/resourcemanager.h17
-rw-r--r--src/resources/soundeffect.cpp19
-rw-r--r--src/resources/spritedef.cpp381
-rw-r--r--src/resources/spritedef.h158
-rw-r--r--src/resources/spriteset.h6
-rw-r--r--src/sound.cpp6
-rw-r--r--src/sound.h4
-rw-r--r--src/sprite.h2
-rw-r--r--src/utils/wingettimeofday.h111
-rw-r--r--src/utils/xml.cpp54
-rw-r--r--src/utils/xml.h46
93 files changed, 3095 insertions, 1690 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4fd8d880..e0b93382 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -155,6 +155,8 @@ SET(SRCS
gui/vbox.h
gui/windowcontainer.cpp
gui/windowcontainer.h
+ gui/viewport.cpp
+ gui/viewport.h
gui/window.cpp
gui/window.h
gui/widgets/dropdown.cpp
@@ -216,17 +218,24 @@ SET(SRCS
resources/ambientoverlay.h
resources/buddylist.cpp
resources/buddylist.h
+ resources/equipmentdb.cpp
+ resources/equipmentdb.h
+ resources/equipmentinfo.h
resources/image.cpp
resources/image.h
resources/imagewriter.cpp
resources/imagewriter.h
resources/iteminfo.cpp
+ resources/itemdb.cpp
+ resources/itemdb.h
resources/iteminfo.h
- resources/itemmanager.cpp
- resources/itemmanager.h
resources/mapreader.cpp
resources/mapreader.h
resources/music.cpp
+ resources/monsterdb.h
+ resources/monsterdb.cpp
+ resources/monsterinfo.h
+ resources/monsterinfo.cpp
resources/music.h
resources/openglsdlimageloader.cpp
resources/openglsdlimageloader.h
@@ -239,9 +248,15 @@ SET(SRCS
resources/soundeffect.cpp
resources/soundeffect.h
resources/spriteset.cpp
+ resources/spritedef.h
+ resources/spritedef.cpp
resources/spriteset.h
utils/dtor.h
utils/tostring.h
+ utils/xml.cpp
+ utils/xml.h
+ action.cpp
+ action.h
animatedsprite.cpp
animatedsprite.h
animation.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index 23c57922..1628df18 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -110,6 +110,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \
gui/textfield.h \
gui/trade.cpp \
gui/trade.h \
+ gui/viewport.cpp \
+ gui/viewport.h \
gui/window.cpp \
gui/window.h \
gui/windowcontainer.cpp \
@@ -179,16 +181,23 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \
net/gameserver/player.h \
resources/ambientoverlay.cpp \
resources/ambientoverlay.h \
+ resources/equipmentdb.cpp \
+ resources/equipmentdb.h \
+ resources/equipmentinfo.h \
resources/image.cpp \
resources/image.h \
resources/imagewriter.cpp \
resources/imagewriter.h \
+ resources/itemdb.cpp \
+ resources/itemdb.h \
resources/iteminfo.h \
resources/iteminfo.cpp \
- resources/itemmanager.cpp \
- resources/itemmanager.h \
resources/mapreader.cpp \
resources/mapreader.h \
+ resources/monsterdb.h \
+ resources/monsterdb.cpp \
+ resources/monsterinfo.h \
+ resources/monsterinfo.cpp \
resources/music.h \
resources/music.cpp \
resources/openglsdlimageloader.h \
@@ -201,12 +210,18 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \
resources/sdlimageloader.cpp \
resources/soundeffect.h \
resources/soundeffect.cpp \
+ resources/spritedef.h \
+ resources/spritedef.cpp \
resources/spriteset.h \
resources/spriteset.cpp \
resources/buddylist.h \
resources/buddylist.cpp \
utils/dtor.h \
utils/tostring.h \
+ utils/xml.cpp \
+ utils/xml.h \
+ action.cpp \
+ action.h \
animatedsprite.cpp \
animatedsprite.h \
animation.cpp \
diff --git a/src/action.cpp b/src/action.cpp
new file mode 100644
index 00000000..148ea105
--- /dev/null
+++ b/src/action.cpp
@@ -0,0 +1,66 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "action.h"
+
+#include <algorithm>
+
+#include "animation.h"
+#include "utils/dtor.h"
+
+
+Action::Action()
+{
+}
+
+Action::~Action()
+{
+ std::for_each(mAnimations.begin(), mAnimations.end(),
+ make_dtor(mAnimations));
+}
+
+Animation*
+Action::getAnimation(int direction) const
+{
+ Animations::const_iterator i = mAnimations.find(direction);
+
+ // When the direction isn't defined, try the default
+ if (i == mAnimations.end())
+ {
+ i = mAnimations.find(0);
+ }
+
+ return (i == mAnimations.end()) ? NULL : i->second;
+}
+
+void
+Action::setAnimation(int direction, Animation *animation)
+{
+ // Set first direction as default direction
+ if (mAnimations.empty())
+ {
+ mAnimations[0] = animation;
+ }
+
+ mAnimations[direction] = animation;
+}
diff --git a/src/resources/itemmanager.h b/src/action.h
index b1f2b95c..8d5e8d11 100644
--- a/src/resources/itemmanager.h
+++ b/src/action.h
@@ -21,39 +21,41 @@
* $Id$
*/
-#ifndef _TMW_ITEM_MANAGER_H
-#define _TMW_ITEM_MANAGER_H
-
-#include "iteminfo.h"
+#ifndef _TMW_ACTION_H
+#define _TMW_ACTION_H
#include <map>
+#include <libxml/tree.h>
+
+class Animation;
+
/**
- * Defines a class to load items database.
+ * An action consists of several animations, one for each direction.
*/
-class ItemManager
+class Action
{
public:
/**
* Constructor.
*/
- ItemManager();
+ Action();
/**
* Destructor.
*/
- ~ItemManager();
+ ~Action();
- const ItemInfo& getItemInfo(int id);
+ void
+ setAnimation(int direction, Animation *animation);
+
+ Animation*
+ getAnimation(int direction) const;
protected:
- // Items database
- typedef std::map<int, ItemInfo*> ItemInfos;
- typedef ItemInfos::iterator ItemInfoIterator;
- ItemInfos mItemInfos;
- ItemInfo mUnknown;
+ typedef std::map<int, Animation*> Animations;
+ typedef Animations::iterator AnimationIterator;
+ Animations mAnimations;
};
-extern ItemManager *itemDb;
-
#endif
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp
index 3815f04a..46369c80 100644
--- a/src/animatedsprite.cpp
+++ b/src/animatedsprite.cpp
@@ -24,401 +24,177 @@
#include "animatedsprite.h"
#include "animation.h"
+#include "action.h"
#include "graphics.h"
#include "log.h"
#include "resources/resourcemanager.h"
#include "resources/spriteset.h"
+#include "resources/image.h"
-AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant):
- mAction(NULL),
+#include "utils/xml.h"
+
+#include <cassert>
+
+AnimatedSprite::AnimatedSprite(SpriteDef *sprite):
mDirection(DIRECTION_DOWN),
mLastTime(0),
- mSpeed(1.0f),
- mAnimationFile(animationFile)
+ mFrameIndex(0),
+ mFrameTime(0),
+ mSprite(sprite),
+ mAction(0),
+ mAnimation(0),
+ mFrame(0)
{
- int size;
- ResourceManager *resman = ResourceManager::getInstance();
- char *data = (char*)resman->loadFile(animationFile.c_str(), size);
-
- if (!data) {
- logger->error("Animation: Could not find " + animationFile + "!");
- }
-
- xmlDocPtr doc = xmlParseMemory(data, size);
- free(data);
-
- if (!doc) {
- logger->error(
- "Animation: Error while parsing animation definition file!");
- }
-
- xmlNodePtr node = xmlDocGetRootElement(doc);
- if (!node || !xmlStrEqual(node->name, BAD_CAST "sprite")) {
- logger->error(
- "Animation: this is not a valid animation definition file!");
- }
-
- // Get the variant
- int variant_num = getProperty(node, "variants", 0);
- int variant_offset = getProperty(node, "variant_offset", 0);
-
- if (variant_num > 0 && variant < variant_num ) {
- variant_offset *= variant;
- } else {
- variant_offset = 0;
- }
+ assert(mSprite);
- for (node = node->xmlChildrenNode; node != NULL; node = node->next)
- {
- if (xmlStrEqual(node->name, BAD_CAST "imageset"))
- {
- int width = getProperty(node, "width", 0);
- int height = getProperty(node, "height", 0);
- std::string name = getProperty(node, "name", "");
- std::string imageSrc = getProperty(node, "src", "");
-
- Spriteset *spriteset =
- resman->getSpriteset(imageSrc, width, height);
-
- if (!spriteset) {
- logger->error("Couldn't load spriteset!");
- }
-
- mSpritesets[name] = spriteset;
- }
- // get action
- else if (xmlStrEqual(node->name, BAD_CAST "action"))
- {
- std::string actionName = getProperty(node, "name", "");
- std::string imageset = getProperty(node, "imageset", "");
-
- if (mSpritesets.find(imageset) == mSpritesets.end()) {
- logger->log("Warning: imageset \"%s\" not defined in %s",
- imageset.c_str(),
- animationFile.c_str());
-
- // skip loading animations
- continue;
- }
-
-
- SpriteAction actionType = makeSpriteAction(actionName);
- if (actionType == ACTION_INVALID)
- {
- logger->log("Warning: Unknown action \"%s\" defined in %s",
- actionName.c_str(),
- animationFile.c_str());
- continue;
- }
- Action *action = new Action();
- action->setSpriteset(mSpritesets[imageset]);
- mActions[actionType] = action;
-
- // When first action set it as default direction
- if (mActions.empty())
- {
- mActions[ACTION_DEFAULT] = action;
- }
-
-
- // get animations
- for (xmlNodePtr animationNode = node->xmlChildrenNode;
- animationNode != NULL;
- animationNode = animationNode->next)
- {
- // We're only interested in animations
- if (!xmlStrEqual(animationNode->name, BAD_CAST "animation"))
- continue;
-
- std::string directionName = getProperty(animationNode, "direction", "");
-
- SpriteDirection directionType = makeSpriteDirection(directionName);
- if (directionType == DIRECTION_INVALID)
- {
- logger->log("Warning: Unknown direction \"%s\" defined for action %s in %s",
- directionName.c_str(),
- actionName.c_str(),
- animationFile.c_str());
- continue;
- }
-
- Animation *animation = new Animation();
- action->setAnimation(directionType, animation);
-
- // Get animation phases
- for (xmlNodePtr phaseNode = animationNode->xmlChildrenNode;
- phaseNode != NULL;
- phaseNode = phaseNode->next)
- {
- int delay = getProperty(phaseNode, "delay", 0);
-
- if (xmlStrEqual(phaseNode->name, BAD_CAST "frame"))
- {
- int index = getProperty(phaseNode, "index", -1);
- int offsetX = getProperty(phaseNode, "offsetX", 0);
- int offsetY = getProperty(phaseNode, "offsetY", 0);
-
- offsetY -= mSpritesets[imageset]->getHeight() - 32;
- offsetX -= mSpritesets[imageset]->getWidth() / 2 - 16;
- animation->addPhase(index + variant_offset, delay,
- offsetX, offsetY);
- }
- else if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence"))
- {
- int start = getProperty(phaseNode, "start", 0);
- int end = getProperty(phaseNode, "end", 0);
- int offsetY = -mSpritesets[imageset]->getHeight() + 32;
- int offsetX = -mSpritesets[imageset]->getWidth() / 2 + 16;
- while (end >= start)
- {
- animation->addPhase(start + variant_offset,
- delay, offsetX, offsetY);
- start++;
- }
- }
- else if (xmlStrEqual(phaseNode->name, BAD_CAST "end"))
- {
- animation->addTerminator();
- };
- } // for phaseNode
- } // for animationNode
- } // if "<imageset>" else if "<action>"
- } // for node
-
- // Complete missing actions
- substituteAction(ACTION_STAND, ACTION_DEFAULT);
- substituteAction(ACTION_WALK, ACTION_STAND);
- substituteAction(ACTION_WALK, ACTION_RUN);
- substituteAction(ACTION_ATTACK, ACTION_STAND);
- substituteAction(ACTION_ATTACK_SWING, ACTION_ATTACK);
- substituteAction(ACTION_ATTACK_STAB, ACTION_ATTACK_SWING);
- substituteAction(ACTION_ATTACK_BOW, ACTION_ATTACK_STAB);
- substituteAction(ACTION_ATTACK_THROW, ACTION_ATTACK_SWING);
- substituteAction(ACTION_CAST_MAGIC, ACTION_ATTACK_SWING);
- substituteAction(ACTION_USE_ITEM, ACTION_CAST_MAGIC);
- substituteAction(ACTION_SIT, ACTION_STAND);
- substituteAction(ACTION_SLEEP, ACTION_SIT);
- substituteAction(ACTION_HURT, ACTION_STAND);
- substituteAction(ACTION_DEAD, ACTION_HURT);
+ // Take possession of the sprite
+ mSprite->incRef();
// Play the stand animation by default
play(ACTION_STAND);
-
- xmlFreeDoc(doc);
-}
-
-int
-AnimatedSprite::getProperty(xmlNodePtr node, const char* name, int def)
-{
- int &ret = def;
-
- xmlChar *prop = xmlGetProp(node, BAD_CAST name);
- if (prop) {
- ret = atoi((char*)prop);
- xmlFree(prop);
- }
-
- return ret;
}
-std::string
-AnimatedSprite::getProperty(xmlNodePtr node, const char* name,
- const std::string& def)
+AnimatedSprite::AnimatedSprite(const std::string& filename, int variant):
+ mDirection(DIRECTION_DOWN),
+ mLastTime(0),
+ mFrameIndex(0),
+ mFrameTime(0),
+ mAnimation(0),
+ mFrame(0)
{
- xmlChar *prop = xmlGetProp(node, BAD_CAST name);
- if (prop) {
- std::string val = (char*)prop;
- xmlFree(prop);
- return val;
- }
-
- return def;
-}
+ ResourceManager *resman = ResourceManager::getInstance();
+ mSprite = resman->getSprite(filename, variant);
+ assert(mSprite);
-void
-AnimatedSprite::substituteAction(SpriteAction complete,
- SpriteAction with)
-{
- if (mActions.find(complete) == mActions.end())
- {
- ActionIterator i = mActions.find(with);
- if (i != mActions.end()) {
- mActions[complete] = i->second;
- }
- }
+ // Play the stand animation by default
+ play(ACTION_STAND);
}
AnimatedSprite::~AnimatedSprite()
{
- for (SpritesetIterator i = mSpritesets.begin(); i != mSpritesets.end(); ++i)
- {
- i->second->decRef();
- }
- mSpritesets.clear();
+ mSprite->decRef();
}
void
AnimatedSprite::reset()
{
- // Reset all defined actions (because of aliases some will be resetted
- // multiple times, but this doesn't matter)
- for (ActionIterator i = mActions.begin(); i != mActions.end(); ++i)
- {
- if (i->second)
- {
- i->second->reset();
- }
- }
+ mFrameIndex = 0;
+ mFrameTime = 0;
+ mLastTime = 0;
}
void
-AnimatedSprite::play(SpriteAction action)
+AnimatedSprite::play(SpriteAction spriteAction)
{
- ActionIterator i = mActions.find(action);
-
- if (i == mActions.end())
+ Action *action = mSprite->getAction(spriteAction);
+ if (!action)
{
- //logger->log("Warning: no action %u defined for \"%s\"!",
- // action, mAnimationFile.c_str());
- mAction = NULL;
return;
}
- if (mAction != i->second)
+ mAction = action;
+ Animation *animation = mAction->getAnimation(mDirection);
+
+ if (animation && animation != mAnimation && animation->getLength() > 0)
{
- mAction = i->second;
- //mAction->reset();
+ mAnimation = animation;
+ mFrame = mAnimation->getFrame(0);
+
+ reset();
}
}
void
AnimatedSprite::update(int time)
{
- bool notFinished = true;
// Avoid freaking out at first frame or when tick_time overflows
if (time < mLastTime || mLastTime == 0)
+ {
mLastTime = time;
+ }
// If not enough time has passed yet, do nothing
- if (time > mLastTime && mAction)
+ if (time <= mLastTime || !mAnimation)
{
- Animation *animation = mAction->getAnimation(mDirection);
- if (animation != NULL) {
- notFinished = animation->update((unsigned int)(time - mLastTime));}
- mLastTime = time;
+ return;
}
- if (!notFinished)
+ unsigned int dt = time - mLastTime;
+ mLastTime = time;
+
+ if (!updateCurrentAnimation(dt))
{
+ // Animation finished, reset to default
play(ACTION_STAND);
}
}
bool
-AnimatedSprite::draw(Graphics* graphics, Sint32 posX, Sint32 posY) const
+AnimatedSprite::updateCurrentAnimation(unsigned int time)
{
- if (!mAction)
+ if (!mFrame || Animation::isTerminator(*mFrame))
+ {
return false;
+ }
- Animation *animation = mAction->getAnimation(mDirection);
- if (animation == NULL) return false;
+ mFrameTime += time;
- int phase = animation->getCurrentPhase();
- if (phase < 0)
- return false;
+ while (mFrameTime > mFrame->delay && mFrame->delay > 0)
+ {
+ mFrameTime -= mFrame->delay;
+ mFrameIndex++;
- Spriteset *spriteset = mAction->getSpriteset();
- Image *image = spriteset->get(phase);
- Sint32 offsetX = animation->getOffsetX();
- Sint32 offsetY = animation->getOffsetY();
- return graphics->drawImage(image, posX + offsetX, posY + offsetY);
-}
+ if (mFrameIndex == mAnimation->getLength())
+ {
+ mFrameIndex = 0;
+ }
-int
-AnimatedSprite::getWidth() const
-{
- return mAction ? mAction->getSpriteset()->getWidth() : 0;
-}
+ mFrame = mAnimation->getFrame(mFrameIndex);
-int
-AnimatedSprite::getHeight() const
-{
- return mAction ? mAction->getSpriteset()->getHeight() : 0;
+ if (Animation::isTerminator(*mFrame))
+ {
+ mAnimation = 0;
+ mFrame = 0;
+ return false;
+ }
+ }
+
+ return true;
}
-SpriteAction
-AnimatedSprite::makeSpriteAction(const std::string& action)
+bool
+AnimatedSprite::draw(Graphics* graphics, int posX, int posY) const
{
- if (action == "" || action == "default") {
- return ACTION_DEFAULT;
- }
- if (action == "stand") {
- return ACTION_STAND;
- }
- else if (action == "walk") {
- return ACTION_WALK;
- }
- else if (action == "run") {
- return ACTION_RUN;
- }
- else if (action == "attack") {
- return ACTION_ATTACK;
- }
- else if (action == "attack_swing") {
- return ACTION_ATTACK_SWING;
- }
- else if (action == "attack_stab") {
- return ACTION_ATTACK_STAB;
- }
- else if (action == "attack_bow") {
- return ACTION_ATTACK_BOW;
- }
- else if (action == "attack_throw") {
- return ACTION_ATTACK_THROW;
- }
- else if (action == "cast_magic") {
- return ACTION_CAST_MAGIC;
- }
- else if (action == "use_item") {
- return ACTION_USE_ITEM;
- }
- else if (action == "sit") {
- return ACTION_SIT;
- }
- else if (action == "sleep") {
- return ACTION_SLEEP;
- }
- else if (action == "hurt") {
- return ACTION_HURT;
- }
- else if (action == "dead") {
- return ACTION_DEAD;
- }
- else {
- return ACTION_INVALID;
+ if (!mFrame || !mFrame->image)
+ {
+ return false;
}
+
+ return graphics->drawImage(mFrame->image,
+ posX + mFrame->offsetX,
+ posY + mFrame->offsetY);
}
-SpriteDirection
-AnimatedSprite::makeSpriteDirection(const std::string& direction)
+void
+AnimatedSprite::setDirection(SpriteDirection direction)
{
- if (direction == "" || direction == "default") {
- return DIRECTION_DEFAULT;
- }
- else if (direction == "up") {
- return DIRECTION_UP;
- }
- else if (direction == "left") {
- return DIRECTION_LEFT;
- }
- else if (direction == "right") {
- return DIRECTION_RIGHT;
- }
- else if (direction == "down") {
- return DIRECTION_DOWN;
+ if (mDirection != direction)
+ {
+ mDirection = direction;
+
+ if (!mAction)
+ {
+ return;
+ }
+
+ Animation *animation = mAction->getAnimation(mDirection);
+
+ if (animation && animation != mAnimation && animation->getLength() > 0)
+ {
+ mAnimation = animation;
+ mFrame = mAnimation->getFrame(0);
+ reset();
+ }
}
- else {
- return DIRECTION_INVALID;
- };
}
diff --git a/src/animatedsprite.h b/src/animatedsprite.h
index bda612ab..4e485f14 100644
--- a/src/animatedsprite.h
+++ b/src/animatedsprite.h
@@ -24,56 +24,34 @@
#ifndef _TMW_ANIMATEDSPRITE_H
#define _TMW_ANIMATEDSPRITE_H
+#include "resources/spritedef.h"
+
#include <map>
#include <string>
-#include <SDL_types.h>
-
-#include <libxml/tree.h>
-class Action;
class Graphics;
-class Spriteset;
-
-enum SpriteAction
-{
- ACTION_DEFAULT = 0,
- ACTION_STAND,
- ACTION_WALK,
- ACTION_RUN,
- ACTION_ATTACK,
- ACTION_ATTACK_SWING,
- ACTION_ATTACK_STAB,
- ACTION_ATTACK_BOW,
- ACTION_ATTACK_THROW,
- ACTION_CAST_MAGIC,
- ACTION_USE_ITEM,
- ACTION_SIT,
- ACTION_SLEEP,
- ACTION_HURT,
- ACTION_DEAD,
- ACTION_INVALID
-};
-
-enum SpriteDirection
-{
- DIRECTION_DEFAULT = 0,
- DIRECTION_DOWN,
- DIRECTION_UP,
- DIRECTION_LEFT,
- DIRECTION_RIGHT,
- DIRECTION_INVALID
-};
+struct AnimationPhase;
/**
- * Defines a class to load an animation.
+ * Animates a sprite by adding playback state.
*/
class AnimatedSprite
{
public:
/**
* Constructor.
+ * @param sprite the sprite to animate
*/
- AnimatedSprite(const std::string& animationFile, int variant);
+ AnimatedSprite(SpriteDef *sprite);
+
+ /**
+ * A convenience constructor, which will request the sprite to animate
+ * from the resource manager.
+ *
+ * @param filename the file of the sprite to animate
+ * @param variant the sprite variant
+ */
+ AnimatedSprite(const std::string& filename, int variant = 0);
/**
* Destructor.
@@ -81,8 +59,7 @@ class AnimatedSprite
~AnimatedSprite();
/**
- * Resets the animated sprite. This is used to synchronize several
- * animated sprites.
+ * Resets the animated sprite.
*/
void
reset();
@@ -97,84 +74,36 @@ class AnimatedSprite
* Inform the animation of the passed time so that it can output the
* correct animation phase.
*/
- void update(int time);
+ void
+ update(int time);
/**
* Draw the current animation phase at the coordinates given in screen
* pixels.
*/
bool
- draw(Graphics* graphics, Sint32 posX, Sint32 posY) const;
-
- /**
- * gets the width in pixels of the current animation phase.
- */
- int
- getWidth() const;
-
- /**
- * gets the height in pixels of the current animation phase.
- */
- int
- getHeight() const;
+ draw(Graphics* graphics, int posX, int posY) const;
/**
* Sets the direction.
*/
void
- setDirection(SpriteDirection direction)
- {
- mDirection = direction;
- }
+ setDirection(SpriteDirection direction);
private:
- /**
- * When there are no animations defined for the action "complete", its
- * animations become a copy of those of the action "with".
- */
- void
- substituteAction(SpriteAction complete, SpriteAction with);
-
- /**
- * Gets an integer property from an xmlNodePtr.
- *
- * TODO: Same function is present in MapReader. Should probably be
- * TODO: shared in a static utility class.
- */
- static int
- getProperty(xmlNodePtr node, const char *name, int def);
-
- /**
- * Gets a string property from an xmlNodePtr.
- */
- static std::string
- getProperty(xmlNodePtr node, const char *name, const std::string &def);
-
- /**
- * Converts a string into a SpriteAction enum.
- */
- static SpriteAction
- makeSpriteAction(const std::string &action);
-
- /**
- * Converts a string into a SpriteDirection enum.
- */
- static SpriteDirection
- makeSpriteDirection(const std::string &direction);
-
+ bool
+ updateCurrentAnimation(unsigned int dt);
- typedef std::map<std::string, Spriteset*> Spritesets;
- typedef Spritesets::iterator SpritesetIterator;
+ SpriteDirection mDirection; /**< The sprite direction. */
+ int mLastTime; /**< The last time update was called. */
- typedef std::map<SpriteAction, Action*> Actions;
- typedef Actions::iterator ActionIterator;
+ unsigned int mFrameIndex; /**< The index of the current frame. */
+ unsigned int mFrameTime; /**< The time since start of frame. */
- Spritesets mSpritesets;
- Actions mActions;
- Action *mAction;
- SpriteDirection mDirection;
- int mLastTime;
- float mSpeed;
+ SpriteDef *mSprite; /**< The sprite definition. */
+ Action *mAction; /**< The currently active action. */
+ Animation *mAnimation; /**< The currently active animation. */
+ AnimationPhase *mFrame; /**< The currently active frame. */
std::string mAnimationFile;
};
diff --git a/src/animation.cpp b/src/animation.cpp
index 98a4abb8..67fdae11 100644
--- a/src/animation.cpp
+++ b/src/animation.cpp
@@ -27,138 +27,29 @@
#include "utils/dtor.h"
-Animation::Animation()
+Animation::Animation():
+ mDuration(0)
{
- reset();
}
void
-Animation::reset()
+Animation::addPhase(Image *image, unsigned int delay, int offsetX, int offsetY)
{
- mTime = 0;
- iCurrentPhase = mAnimationPhases.begin();
-}
-
-
-bool
-Animation::update(unsigned int time)
-{
- mTime += time;
- if (mAnimationPhases.empty())
- return true;
- if (isTerminator(*iCurrentPhase))
- return false;
-
- unsigned int delay = iCurrentPhase->delay;
-
- while (mTime > delay)
- {
- if (!delay)
- return true;
- mTime -= delay;
- iCurrentPhase++;
- if (iCurrentPhase == mAnimationPhases.end())
- {
- iCurrentPhase = mAnimationPhases.begin();
- }
- if (isTerminator(*iCurrentPhase))
- return false;
- delay = iCurrentPhase->delay;
- }
- return true;
-}
-
-
-int
-Animation::getCurrentPhase() const
-{
- return mAnimationPhases.empty() ? -1 : iCurrentPhase->image;
-}
-
-
-void
-Animation::addPhase(int image, unsigned int delay, int offsetX, int offsetY)
-{
- //add new phase to animation list
- AnimationPhase newPhase = { image, delay, offsetX, offsetY};
+ // Add new phase to animation list
+ AnimationPhase newPhase = { image, delay, offsetX, offsetY };
mAnimationPhases.push_back(newPhase);
- //reset animation circle
- iCurrentPhase = mAnimationPhases.begin();
+ mDuration += delay;
}
void
Animation::addTerminator()
{
- AnimationPhase terminator = { -1, 0, 0, 0};
- mAnimationPhases.push_back(terminator);
- iCurrentPhase = mAnimationPhases.begin();
+ addPhase(NULL, 0, 0, 0);
}
bool
-Animation::isTerminator(AnimationPhase candidate)
-{
- return (candidate.image < 0);
-}
-
-int
-Animation::getLength()
-{
- if (mAnimationPhases.empty())
- return 0;
-
- std::list<AnimationPhase>::iterator i;
- int length = 0;
- for (i = mAnimationPhases.begin(); i != mAnimationPhases.end(); i++)
- {
- length += i->delay;
- }
- return length;
-}
-
-Action::Action():
- mSpriteset(NULL)
-{
-}
-
-Action::~Action()
-{
- std::for_each(mAnimations.begin(), mAnimations.end(), make_dtor(mAnimations));
- mAnimations.clear();
-}
-
-Animation*
-Action::getAnimation(int direction) const
-{
- Animations::const_iterator i = mAnimations.find(direction);
-
- // When the direction isn't defined, try the default
- if (i == mAnimations.end())
- {
- i = mAnimations.find(0);
- }
-
- return (i == mAnimations.end()) ? NULL : i->second;
-}
-
-void
-Action::setAnimation(int direction, Animation *animation)
-{
- // Set first direction as default direction
- if (mAnimations.empty())
- {
- mAnimations[0] = animation;
- }
-
- mAnimations[direction] = animation;
-}
-
-void
-Action::reset()
+Animation::isTerminator(const AnimationPhase candidate)
{
- for (AnimationIterator i = mAnimations.begin();
- i != mAnimations.end(); ++i)
- {
- i->second->reset();
- }
+ return (candidate.image == NULL);
}
diff --git a/src/animation.h b/src/animation.h
index 605d8cb1..85e950d7 100644
--- a/src/animation.h
+++ b/src/animation.h
@@ -24,8 +24,7 @@
#ifndef _TMW_ANIMATION_H
#define _TMW_ANIMATION_H
-#include <list>
-#include <map>
+#include <vector>
#include <libxml/tree.h>
@@ -34,10 +33,12 @@ class Spriteset;
/**
* A single frame in an animation, with a delay and an offset.
+ *
+ * TODO: Rename this struct to Frame
*/
struct AnimationPhase
{
- int image;
+ Image *image;
unsigned int delay;
int offsetX;
int offsetY;
@@ -56,105 +57,45 @@ class Animation
Animation();
/**
- * Restarts the animation from the first frame.
- */
- void
- reset();
-
- /**
* Appends a new animation at the end of the sequence
*/
void
- addPhase(int image, unsigned int delay, int offsetX, int offsetY);
+ addPhase(Image *image, unsigned int delay, int offsetX, int offsetY);
/**
* Appends an animation terminator that states that the animation
- * should not loop
+ * should not loop.
*/
void
addTerminator();
/**
- * Updates animation phase.
- * true indicates a still running animation while false indicates a
- * finished animation
+ * Returns the frame at the specified index.
*/
- bool
- update(unsigned int time);
-
- int
- getCurrentPhase() const;
+ AnimationPhase*
+ getFrame(int index) { return &(mAnimationPhases[index]); }
/**
- * Returns the x offset of the current frame.
+ * Returns the length of this animation in frames.
*/
- int
- getOffsetX() const { return iCurrentPhase->offsetX; };
+ unsigned int
+ getLength() const { return mAnimationPhases.size(); }
/**
- * Returns the y offset of the current frame.
+ * Returns the duration of this animation.
*/
int
- getOffsetY() const { return iCurrentPhase->offsetY; };
+ getDuration() const { return mDuration; }
/**
- * Returns the length of this animation.
+ * Determines whether the given animation frame is a terminator.
*/
- int
- getLength();
-
- protected:
- static bool isTerminator(AnimationPhase);
- std::list<AnimationPhase> mAnimationPhases;
- std::list<AnimationPhase>::iterator iCurrentPhase;
- unsigned int mTime;
-};
-
-/**
- * An action consists of several animations, one for each direction.
- */
-class Action
-{
- public:
- /**
- * Constructor.
- */
- Action();
-
- /**
- * Destructor.
- */
- ~Action();
-
- /**
- * Sets the spriteset used by this action.
- */
- void
- setSpriteset(Spriteset *spriteset) { mSpriteset = spriteset; }
-
- /**
- * Returns the spriteset used by this action.
- */
- Spriteset*
- getSpriteset() const { return mSpriteset; }
-
- void
- setAnimation(int direction, Animation *animation);
-
- /**
- * Resets all animations associated with this action.
- */
- void
- reset();
-
- Animation*
- getAnimation(int direction) const;
+ static bool
+ isTerminator(const AnimationPhase phase);
protected:
- Spriteset *mSpriteset;
- typedef std::map<int, Animation*> Animations;
- typedef Animations::iterator AnimationIterator;
- Animations mAnimations;
+ std::vector<AnimationPhase> mAnimationPhases;
+ int mDuration;
};
#endif
diff --git a/src/base64.cpp b/src/base64.cpp
index 6d503a53..9a8f6356 100644
--- a/src/base64.cpp
+++ b/src/base64.cpp
@@ -1,16 +1,27 @@
/*
+----------------------------------------------------------------------+
- | PHP version 4.0 |
+ | PHP HTML Embedded Scripting Language Version 3.0 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group |
+ | Copyright (c) 1997-2000 PHP Development Team (See Credits file) |
+----------------------------------------------------------------------+
- | This source file is subject to version 2.02 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available at through the world-wide-web at |
- | http://www.php.net/license/2_02.txt. |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
+ | This program is free software; you can redistribute it and/or modify |
+ | it under the terms of one of the following licenses: |
+ | |
+ | A) the GNU General Public License as published by the Free Software |
+ | Foundation; either version 2 of the License, or (at your option) |
+ | any later version. |
+ | |
+ | B) the PHP License as published by the PHP Development Team and |
+ | included in the distribution in the file: LICENSE |
+ | |
+ | 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 both licenses referred to here. |
+ | If you did not, or have any questions about PHP licensing, please |
+ | contact core@php.net. |
+----------------------------------------------------------------------+
| Author: Jim Winstead (jimw@php.net) |
+----------------------------------------------------------------------+
@@ -32,8 +43,8 @@ static char base64_table[] =
};
static char base64_pad = '=';
-unsigned char *php_base64_encode(const unsigned char *str, int length, int *ret_length) {
- const unsigned char *current = str;
+unsigned char *php3_base64_encode(const unsigned char *string, int length, int *ret_length) {
+ const unsigned char *current = string;
int i = 0;
unsigned char *result = (unsigned char *)malloc(((length + 3 - length % 3) * 4 / 3 + 1) * sizeof(char));
@@ -69,27 +80,13 @@ unsigned char *php_base64_encode(const unsigned char *str, int length, int *ret_
}
/* as above, but backwards. :) */
-unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_length) {
- const unsigned char *current = str;
+unsigned char *php3_base64_decode(const unsigned char *string, int length, int *ret_length) {
+ const unsigned char *current = string;
int ch, i = 0, j = 0, k;
- /* this sucks for threaded environments */
- static short reverse_table[256];
- static int table_built;
- unsigned char *result;
-
- if (++table_built == 1) {
- char *chp;
- for(ch = 0; ch < 256; ch++) {
- chp = strchr(base64_table, ch);
- if(chp) {
- reverse_table[ch] = chp - base64_table;
- } else {
- reverse_table[ch] = -1;
- }
- }
- }
+ char *chp;
+
+ unsigned char *result = (unsigned char *)malloc(length + 1);
- result = (unsigned char *)malloc(length + 1);
if (result == NULL) {
return NULL;
}
@@ -107,8 +104,9 @@ unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_
if (ch == ' ') ch = '+';
- ch = reverse_table[ch];
- if (ch < 0) continue;
+ chp = strchr(base64_table, ch);
+ if (chp == NULL) continue;
+ ch = chp - base64_table;
switch(i % 4) {
case 0:
@@ -149,4 +147,3 @@ unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_
result[k] = '\0';
return result;
}
-
diff --git a/src/base64.h b/src/base64.h
index 5b275c45..ff20ac53 100644
--- a/src/base64.h
+++ b/src/base64.h
@@ -31,14 +31,7 @@
#ifndef _TMW_BASE64_H
#define _TMW_BASE64_H
-extern unsigned char *php_base64_encode(const unsigned char *, int, int *);
-extern unsigned char *php_base64_decode(const unsigned char *, int, int *);
+extern unsigned char *php3_base64_encode(const unsigned char *, int, int *);
+extern unsigned char *php3_base64_decode(const unsigned char *, int, int *);
#endif /* _TMW_BASE64_H */
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- */
diff --git a/src/being.cpp b/src/being.cpp
index 50a2dc35..9cd0af0d 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -49,7 +49,7 @@ PATH_NODE::PATH_NODE(Uint16 iX, Uint16 iY):
Being::Being(Uint16 id, Uint16 job, Map *map):
mJob(job),
- mX(0), mY(0), mDirection(DOWN),
+ mX(0), mY(0),
mAction(STAND),
mWalkTime(0),
mEmotion(0), mEmotionTime(0),
@@ -60,12 +60,15 @@ Being::Being(Uint16 id, Uint16 job, Map *map):
mWeapon(0),
mWalkSpeed(150),
mSpeedModifier(1024),
+ mDirection(DOWN),
mMap(NULL),
mHairStyle(0), mHairColor(0),
mSpeechTime(0),
mDamageTime(0),
mShowSpeech(false), mShowDamage(false),
- mSprites(VECTOREND_SPRITE, NULL)
+ mPx(0), mPy(0),
+ mSprites(VECTOREND_SPRITE, NULL),
+ mEquipmentSpriteIDs(VECTOREND_SPRITE, 0)
{
setMap(map);
}
@@ -110,9 +113,7 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY)
p1 = mMap->findPath(srcX / 32, srcY / 32, dstX / 32, dstY / 32);
if (p1.empty())
{
- // No path? Better teleport.
- mX = dstX;
- mY = dstY;
+ // No path, but don't teleport since it could be user input.
setPath(p1);
return;
}
@@ -189,9 +190,8 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY)
if (bestRating < 0)
{
- // Unable to reach the path? Better teleport.
- mX = srcX;
- mY = srcY;
+ // Unable to reach the path? Still, don't teleport since it could be
+ // user input instead of server command.
setPath(p1);
delete[] p1_dist;
return;
@@ -263,8 +263,9 @@ Being::setHairStyle(Uint16 style)
}
void
-Being::setVisibleEquipment(Uint8 slot, Uint8 id)
+Being::setVisibleEquipment(Uint8 slot, int id)
{
+ mEquipmentSpriteIDs[slot] = id;
}
void
@@ -304,7 +305,7 @@ Being::setMap(Map *map)
void
Being::setAction(Uint8 action)
{
- SpriteAction currentAction = ACTION_STAND;
+ SpriteAction currentAction = ACTION_INVALID;
switch (action)
{
case WALK:
@@ -314,37 +315,21 @@ Being::setAction(Uint8 action)
currentAction = ACTION_SIT;
break;
case ATTACK:
- if (getType() == MONSTER)
+ switch (getWeapon())
{
- currentAction = ACTION_DEAD;
+ case 3:
+ currentAction = ACTION_ATTACK;
+ break;
+ case 2:
+ currentAction = ACTION_ATTACK_BOW;
+ break;
+ case 1:
+ currentAction = ACTION_ATTACK_STAB;
+ break;
+ case 0:
+ currentAction = ACTION_ATTACK;
+ break;
}
- else {
- switch (getWeapon())
- {
- case 3:
- currentAction = ACTION_ATTACK;
- break;
- case 2:
- currentAction = ACTION_ATTACK_BOW;
- break;
- case 1:
- currentAction = ACTION_ATTACK_STAB;
- break;
- case 0:
- currentAction = ACTION_ATTACK;
- break;
- }
- for (int i = 0; i < VECTOREND_SPRITE; i++)
- {
- if (mSprites[i])
- {
- mSprites[i]->reset();
- }
- }
- };
- break;
- case MONSTER_ATTACK:
- currentAction = ACTION_ATTACK;
for (int i = 0; i < VECTOREND_SPRITE; i++)
{
if (mSprites[i])
@@ -353,25 +338,33 @@ Being::setAction(Uint8 action)
}
}
break;
+ case HURT:
+ //currentAction = ACTION_HURT; // Buggy: makes the player stop
+ // attacking and unable to attack
+ // again until he moves
+ break;
case DEAD:
currentAction = ACTION_DEAD;
break;
- default:
+ case STAND:
currentAction = ACTION_STAND;
break;
}
- for (int i = 0; i < VECTOREND_SPRITE; i++)
+ if (currentAction != ACTION_INVALID)
{
- if (mSprites[i])
+ for (int i = 0; i < VECTOREND_SPRITE; i++)
{
- mSprites[i]->play(currentAction);
+ if (mSprites[i])
+ {
+ mSprites[i]->play(currentAction);
+ }
}
+ mAction = action;
}
-
- mAction = action;
}
+
void
Being::setDirection(Uint8 direction)
{
@@ -487,7 +480,7 @@ Being::logic()
}
void
-Being::draw(Graphics *graphics, int offsetX, int offsetY)
+Being::draw(Graphics *graphics, int offsetX, int offsetY) const
{
int px = mPx + offsetX;
int py = mPy + offsetY;
@@ -528,7 +521,7 @@ Being::drawSpeech(Graphics *graphics, Sint32 offsetX, Sint32 offsetY)
}
// Draw damage above this being
- if (mShowDamage)
+ if (mShowDamage && get_elapsed_time(mDamageTime) > 250)
{
// Selecting the right color
if (mDamage == "miss")
diff --git a/src/being.h b/src/being.h
index 2804b20b..c95cd191 100644
--- a/src/being.h
+++ b/src/being.h
@@ -68,14 +68,12 @@ class Being : public Sprite
};
enum Action {
- STAND = 0,
- WALK = 1,
- MONSTER_ATTACK = 5,
- SIT = 7,
- DEAD = 8,
- ATTACK = 9,
- MONSTER_DEAD = 9,
- HIT = 17
+ STAND,
+ WALK,
+ ATTACK,
+ SIT,
+ DEAD,
+ HURT
};
enum Sprite {
@@ -101,7 +99,6 @@ class Being : public Sprite
std::string mName; /**< Name of character */
Uint16 mJob; /**< Job (player job, npc, monster, ) */
Uint16 mX, mY; /**< Pixel coordinates (tile center) */
- Uint8 mDirection; /**< Facing direction */
Uint8 mAction; /**< Action the being is performing */
Uint16 mWalkTime;
Uint8 mEmotion; /**< Currently showing emotion */
@@ -199,7 +196,7 @@ class Being : public Sprite
* Sets visible equipments for this being.
*/
virtual void
- setVisibleEquipment(Uint8 slot, Uint8 id);
+ setVisibleEquipment(Uint8 slot, int id);
/**
* Sets the sex for this being.
@@ -216,7 +213,7 @@ class Being : public Sprite
/**
* Makes this being take the next step of his path.
*/
- void
+ virtual void
nextStep();
/**
@@ -301,7 +298,13 @@ class Being : public Sprite
/**
* Sets the current action.
*/
- void setAction(Uint8 action);
+ virtual void
+ setAction(Uint8 action);
+
+ /**
+ * Returns the current direction.
+ */
+ Uint8 getDirection() const { return mDirection; }
/**
* Sets the current direction.
@@ -314,7 +317,7 @@ class Being : public Sprite
* @see Sprite::draw(Graphics, int, int)
*/
virtual void
- draw(Graphics *graphics, Sint32 offsetX, Sint32 offsetY);
+ draw(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) const;
/**
* Returns the pixel X coordinate.
@@ -343,7 +346,6 @@ class Being : public Sprite
getYOffset() const { return getOffset(mStepY); }
std::auto_ptr<Equipment> mEquipment;
- int mVisibleEquipment[6]; /**< Visible equipments */
protected:
/**
@@ -363,6 +365,7 @@ class Being : public Sprite
Uint16 mWeapon; /**< Weapon picture id */
Uint16 mWalkSpeed; /**< Walking speed */
Uint16 mSpeedModifier; /**< Modifier to keep course on sync (1024 = normal speed) */
+ Uint8 mDirection; /**< Facing direction */
Map *mMap; /**< Map on which this being resides */
SpriteIterator mSpriteIterator;
@@ -376,11 +379,14 @@ class Being : public Sprite
Sint32 mPx, mPy; /**< Pixel coordinates */
std::vector<AnimatedSprite*> mSprites;
+ std::vector<int> mEquipmentSpriteIDs;
private:
+ int
+ getOffset(int step) const;
+
Sint16 mStepX, mStepY;
Uint16 mStepTime;
- int getOffset(int) const;
};
#endif
diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp
index 923283b5..14b4ea7e 100644
--- a/src/beingmanager.cpp
+++ b/src/beingmanager.cpp
@@ -38,7 +38,7 @@ class FindBeingFunctor
Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0);
return (being->mX / 32 == x &&
(being->mY / 32 == y || being->mY / 32 == other_y) &&
- being->mAction != Being::MONSTER_DEAD &&
+ being->mAction != Being::DEAD &&
(type == Being::UNKNOWN || being->getType() == type));
}
@@ -64,14 +64,7 @@ Being* BeingManager::createBeing(Uint16 id, Uint16 job)
Being *being;
if (job < 10)
- {
being = new Player(id, job, mMap);
- // XXX Convert for new server
- /*
- MessageOut outMsg(0x0094);
- outMsg.writeLong(id);
- */
- }
else if (job >= 100 & job < 200)
being = new NPC(id, job, mMap);
else if (job >= 1000 && job < 1200)
@@ -79,6 +72,17 @@ Being* BeingManager::createBeing(Uint16 id, Uint16 job)
else
being = new Being(id, job, mMap);
+ // Player or NPC
+ if (job < 200)
+ {
+ // XXX Convert for new server
+ /*
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(0x0094);
+ outMsg.writeInt32(id);//readLong(2));
+ */
+ }
+
mBeings.push_back(being);
return being;
@@ -127,7 +131,8 @@ void BeingManager::logic()
being->logic();
- /*if (being->mAction == Being::MONSTER_DEAD && being->mFrame >= 20)
+ /*
+ if (being->mAction == Being::DEAD && being->mFrame >= 20)
{
delete being;
i = mBeings.erase(i);
@@ -168,7 +173,6 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
if ((being->getType() == type || type == Being::UNKNOWN)
&& (d < dist || closestBeing == NULL) // it is closer
&& being->mAction != Being::DEAD // no dead beings
- && being->mAction != Being::MONSTER_DEAD
)
{
dist = d;
diff --git a/src/engine.cpp b/src/engine.cpp
index 231313c4..30f0097e 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -39,9 +39,10 @@
#include "gui/gui.h"
#include "gui/minimap.h"
+#include "gui/viewport.h"
-#include "resources/itemmanager.h"
#include "resources/mapreader.h"
+#include "resources/monsterdb.h"
#include "resources/resourcemanager.h"
#include "resources/spriteset.h"
@@ -51,16 +52,12 @@
extern Minimap *minimap;
char itemCurrenyQ[10] = "0";
-int camera_x, camera_y;
-
-ItemManager *itemDb; /**< Item database object */
Spriteset *emotionset;
Spriteset *npcset;
std::vector<Spriteset *> weaponset;
Engine::Engine():
- mShowDebugPath(false),
mCurrentMap(NULL)
{
// Load the sprite sets
@@ -82,9 +79,6 @@ Engine::Engine():
if (!npcset) logger->error("Unable to load NPC spriteset!");
if (!emotionset) logger->error("Unable to load emotions spriteset!");
-
- // Initialize item manager
- itemDb = new ItemManager();
}
Engine::~Engine()
@@ -96,8 +90,6 @@ Engine::~Engine()
std::for_each(weaponset.begin(), weaponset.end(),
std::mem_fun(&Spriteset::decRef));
weaponset.clear();
-
- delete itemDb;
}
void Engine::changeMap(const std::string &mapPath)
@@ -125,6 +117,7 @@ void Engine::changeMap(const std::string &mapPath)
}
minimap->setMapImage(mapImage);
beingManager->setMap(newMap);
+ viewport->setMap(newMap);
// Start playing new music file when necessary
std::string oldMusic = "";
@@ -152,139 +145,5 @@ void Engine::logic()
void Engine::draw(Graphics *graphics)
{
- int midTileX = graphics->getWidth() / 2;
- int midTileY = graphics->getHeight() / 2;
- static int lastTick = tick_time;
-
- int player_x = player_node->mX - midTileX + player_node->getXOffset();
- int player_y = player_node->mY - midTileY + player_node->getYOffset();
-
- scrollLaziness = (int)config.getValue("ScrollLaziness", 32);
- scrollRadius = (int)config.getValue("ScrollRadius", 32);
-
- if (scrollLaziness < 1)
- scrollLaziness = 1; //avoids division by zero
-
- //apply lazy scrolling
- int nbTicks = get_elapsed_time(lastTick) / 10;
- lastTick += nbTicks;
- for (; nbTicks > 0; --nbTicks)
- {
- if (player_x > view_x + scrollRadius)
- {
- view_x += (player_x - view_x - scrollRadius) / scrollLaziness;
- }
- if (player_x < view_x - scrollRadius)
- {
- view_x += (player_x - view_x + scrollRadius) / scrollLaziness;
- }
- if (player_y > view_y + scrollRadius)
- {
- view_y += (player_y - view_y - scrollRadius) / scrollLaziness;
- }
- if (player_y < view_y - scrollRadius)
- {
- view_y += (player_y - view_y + scrollRadius) / scrollLaziness;
- }
- }
-
- //auto center when player is off screen
- if ( player_x - view_x > graphics->getWidth() / 2
- || view_x - player_x > graphics->getWidth() / 2
- || view_y - player_y > graphics->getHeight() / 2
- || player_y - view_y > graphics->getHeight() / 2
- )
- {
- view_x = player_x;
- view_y = player_y;
- };
-
- if (mCurrentMap) {
- if (view_x < 0) {
- view_x = 0;
- }
- if (view_y < 0) {
- view_y = 0;
- }
- if (view_x > mCurrentMap->getWidth() * 32 - midTileX) {
- view_x = mCurrentMap->getWidth() * 32 - midTileX;
- }
- if (view_y > mCurrentMap->getHeight() * 32 - midTileY) {
- view_y = mCurrentMap->getHeight() * 32 - midTileY;
- }
- }
-
- camera_x = (int)view_x;
- camera_y = (int)view_y;
-
- // Draw tiles and sprites
- if (mCurrentMap != NULL)
- {
- mCurrentMap->draw(graphics, camera_x, camera_y, 0);
- mCurrentMap->draw(graphics, camera_x, camera_y, 1);
- mCurrentMap->draw(graphics, camera_x, camera_y, 2);
- mCurrentMap->drawOverlay( graphics,
- view_x,
- view_y,
- (int)config.getValue("OverlayDetail", 2)
- );
- }
- else
- {
- // When no map is loaded, draw a replacement background
- graphics->setColor(gcn::Color(128, 128, 128));
- graphics->fillRectangle(gcn::Rectangle(0, 0,
- graphics->getWidth(), graphics->getHeight()));
- }
-
- // Find a path from the player to the mouse, and draw it. This is for debug
- // purposes.
- if (mShowDebugPath && mCurrentMap != NULL)
- {
- // Get the current mouse position
- int mouseX, mouseY;
- SDL_GetMouseState(&mouseX, &mouseY);
-
- int mouseTileX = (mouseX + camera_x) / 32;
- int mouseTileY = (mouseY + camera_y) / 32;
-
- Path debugPath = mCurrentMap->findPath(
- player_node->mX / 32, player_node->mY / 32,
- mouseTileX, mouseTileY);
-
- graphics->setColor(gcn::Color(255, 0, 0));
- for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++)
- {
- int squareX = i->x * 32 - camera_x + 12;
- int squareY = i->y * 32 - camera_y + 12;
-
- graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
- graphics->drawText(
- toString(mCurrentMap->getMetaTile(i->x, i->y)->Gcost),
- squareX + 4, squareY + 12, gcn::Graphics::CENTER);
- }
- }
-
- // Draw player nickname, speech, and emotion sprite as needed
- Beings &beings = beingManager->getAll();
- for (BeingIterator i = beings.begin(); i != beings.end(); i++)
- {
- (*i)->drawSpeech(graphics, -camera_x, -camera_y);
- (*i)->drawName(graphics, -camera_x, -camera_y);
- (*i)->drawEmotion(graphics, -camera_x, -camera_y);
- }
-
- // Draw target marker if needed
- Being *target;
- if ((target = player_node->getTarget()))
- {
- graphics->setFont(speechFont);
- graphics->setColor(gcn::Color(255, 255, 255));
- int dy = (target->getType() == Being::PLAYER) ? 90 : 52;
-
- graphics->drawText("[TARGET]", target->getPixelX() - camera_x + 15,
- target->getPixelY() - camera_y - dy, gcn::Graphics::CENTER);
- }
-
gui->draw();
}
diff --git a/src/engine.h b/src/engine.h
index e8ef7e33..62e82a49 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -26,8 +26,6 @@
#include <iosfwd>
-extern int camera_x, camera_y;
-
class Graphics;
class Map;
@@ -67,20 +65,8 @@ class Engine
*/
void draw(Graphics *graphics);
- /**
- * Toggles whether the path debug graphics are shown
- */
- void toggleDebugPath() { mShowDebugPath = !mShowDebugPath; };
-
private:
- bool mShowDebugPath;
-
Map *mCurrentMap;
-
- int scrollRadius;
- int scrollLaziness;
- float view_x; // current viewpoint in pixels
- float view_y; // current viewpoint in pixels
};
extern Engine *engine;
diff --git a/src/floor_item.cpp b/src/floor_item.cpp
index 9a179a21..f33f7eb4 100644
--- a/src/floor_item.cpp
+++ b/src/floor_item.cpp
@@ -25,7 +25,7 @@
#include "map.h"
-#include "resources/itemmanager.h"
+#include "resources/itemdb.h"
#include "resources/iteminfo.h"
#include "resources/spriteset.h"
@@ -42,7 +42,7 @@ FloorItem::FloorItem(unsigned int id,
mMap(map)
{
// Retrieve item image from item info
- mImage = itemDb->getItemInfo(itemId).getImage();
+ mImage = ItemDB::get(itemId).getImage();
// Add ourselves to the map
mSpriteIterator = mMap->addSprite(this);
diff --git a/src/floor_item.h b/src/floor_item.h
index 386d0759..36f81585 100644
--- a/src/floor_item.h
+++ b/src/floor_item.h
@@ -53,25 +53,25 @@ class FloorItem : public Sprite
* Returns instance id of this item.
*/
unsigned int
- getId() { return mId; }
+ getId() const { return mId; }
/**
* Returns the item id.
*/
unsigned int
- getItemId() { return mItemId; }
+ getItemId() const { return mItemId; }
/**
* Returns the x coordinate.
*/
unsigned short
- getX() { return mX; }
+ getX() const { return mX; }
/**
* Returns the y coordinate.
*/
unsigned short
- getY() { return mY; }
+ getY() const { return mY; }
/**
* Returns the pixel y coordinate.
@@ -87,7 +87,7 @@ class FloorItem : public Sprite
* @see Sprite::draw(Graphics, int, int)
*/
void
- draw(Graphics *graphics, int offsetX, int offsetY)
+ draw(Graphics *graphics, int offsetX, int offsetY) const
{
graphics->drawImage(mImage,
mX * 32 + offsetX,
diff --git a/src/game.cpp b/src/game.cpp
index 5052f2ce..15298ec6 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -29,6 +29,7 @@
#include <string>
#include <guichan/sdl/sdlinput.hpp>
+#include <guichan/exception.hpp>
#include "beingmanager.h"
#include "configuration.h"
@@ -42,23 +43,25 @@
#include "gui/buy.h"
#include "gui/buysell.h"
-#include "gui/chargedialog.h"
+//#include "gui/chargedialog.h"
#include "gui/chat.h"
#include "gui/confirm_dialog.h"
+#include "gui/debugwindow.h"
#include "gui/equipmentwindow.h"
+#include "gui/gui.h"
#include "gui/help.h"
#include "gui/inventorywindow.h"
+#include "gui/menuwindow.h"
#include "gui/minimap.h"
+#include "gui/ministatus.h"
#include "gui/npclistdialog.h"
#include "gui/npc_text.h"
#include "gui/sell.h"
#include "gui/setup.h"
#include "gui/skill.h"
-#include "gui/menuwindow.h"
#include "gui/status.h"
-#include "gui/ministatus.h"
#include "gui/trade.h"
-#include "gui/debugwindow.h"
+#include "gui/viewport.h"
#include "net/beinghandler.h"
#include "net/buysellhandler.h"
@@ -85,7 +88,7 @@ bool done = false;
volatile int tick_time;
volatile int fps = 0, frame = 0;
Engine *engine = NULL;
-Joystick *joystick;
+Joystick *joystick = NULL;
extern Window *weightNotice;
extern Window *deathNotice;
@@ -106,7 +109,7 @@ SkillDialog *skillDialog;
Setup* setupWindow;
Minimap *minimap;
EquipmentWindow *equipmentWindow;
-ChargeDialog *chargeDialog;
+//ChargeDialog *chargeDialog;
TradeWindow *tradeWindow;
//BuddyWindow *buddyWindow;
HelpWindow *helpWindow;
@@ -182,47 +185,23 @@ void createGuiWindows()
setupWindow = new Setup();
minimap = new Minimap();
equipmentWindow = new EquipmentWindow(player_node->mEquipment.get());
- chargeDialog = new ChargeDialog();
+ //chargeDialog = new ChargeDialog();
tradeWindow = new TradeWindow;
//buddyWindow = new BuddyWindow();
helpWindow = new HelpWindow();
debugWindow = new DebugWindow();
// Initialize window positions
- int screenW = graphics->getWidth();
- int screenH = graphics->getHeight();
-
- chargeDialog->setPosition(
- screenW - 5 - chargeDialog->getWidth(),
- screenH - chargeDialog->getHeight() - 15);
+ //chargeDialog->setPosition(
+ // graphics->getWidth() - 5 - chargeDialog->getWidth(),
+ // graphics->getHeight() - chargeDialog->getHeight() - 15);
- /*buddyWindow->setPosition(10,
- minimap->getHeight() + 30);*/
+ //buddyWindow->setPosition(10, minimap->getHeight() + 30);
// Set initial window visibility
-// chatWindow->setSticky(true);
-// miniStatusWindow->setSticky(true);
-// menuWindow->setSticky(true);
-
chatWindow->setVisible(true);
miniStatusWindow->setVisible(true);
- statusWindow->setVisible(false);
menuWindow->setVisible(true);
- buyDialog->setVisible(false);
- sellDialog->setVisible(false);
- buySellDialog->setVisible(false);
- inventoryWindow->setVisible(false);
- npcTextDialog->setVisible(false);
- npcListDialog->setVisible(false);
- skillDialog->setVisible(false);
- //newSkillWindow->setVisible(false);
- setupWindow->setVisible(false);
- equipmentWindow->setVisible(false);
- chargeDialog->setVisible(false);
- tradeWindow->setVisible(false);
- //buddyWindow->setVisible(false);
- helpWindow->setVisible(false);
- debugWindow->setVisible(false);
}
/**
@@ -244,7 +223,7 @@ void destroyGuiWindows()
delete setupWindow;
delete minimap;
delete equipmentWindow;
- delete chargeDialog;
+ //delete chargeDialog;
//delete newSkillWindow;
delete tradeWindow;
//delete buddyWindow;
@@ -511,13 +490,13 @@ void Game::handleInput()
// If none below the player, try the tile in front of
// the player
if (!item) {
- if (player_node->mDirection & Being::UP)
+ if (player_node->getDirection() & Being::UP)
y--;
- if (player_node->mDirection & Being::DOWN)
+ if (player_node->getDirection() & Being::DOWN)
y++;
- if (player_node->mDirection & Being::LEFT)
+ if (player_node->getDirection() & Being::LEFT)
x--;
- if (player_node->mDirection & Being::RIGHT)
+ if (player_node->getDirection() & Being::RIGHT)
x++;
item = floorItemManager->findByCoordinates(x, y);
@@ -584,7 +563,7 @@ void Game::handleInput()
case SDLK_f:
// Find path to mouse (debug purpose)
- engine->toggleDebugPath();
+ viewport->toggleDebugPath();
used = true;
break;
}
@@ -621,8 +600,17 @@ void Game::handleInput()
}
// Push input to GUI when not used
- if (!used) {
- guiInput->pushInput(event);
+ if (!used)
+ {
+ try
+ {
+ guiInput->pushInput(event);
+ }
+ catch (gcn::Exception e)
+ {
+ const char* err = e.getMessage().c_str();
+ logger->log("Warning: guichan input exception: %s", err);
+ }
}
} // End while
@@ -633,35 +621,35 @@ void Game::handleInput()
!chatWindow->isFocused())
{
Uint16 x = player_node->mX / 32, y = player_node->mY / 32;
- unsigned char Direction = 0;
+ unsigned char direction = 0;
// Translate pressed keys to movement and direction
if (keys[SDLK_UP] || keys[SDLK_KP8] ||
keys[SDLK_KP7] || keys[SDLK_KP9] ||
joystick && joystick->isUp())
{
- Direction |= Being::UP;
+ direction |= Being::UP;
}
else if (keys[SDLK_DOWN] || keys[SDLK_KP2] ||
keys[SDLK_KP1] || keys[SDLK_KP3] ||
joystick && joystick->isDown())
{
- Direction |= Being::DOWN;
+ direction |= Being::DOWN;
}
if (keys[SDLK_LEFT] || keys[SDLK_KP4] ||
keys[SDLK_KP1] || keys[SDLK_KP7] ||
joystick && joystick->isLeft())
{
- Direction |= Being::LEFT;
+ direction |= Being::LEFT;
}
else if (keys[SDLK_RIGHT] || keys[SDLK_KP6] ||
keys[SDLK_KP3] || keys[SDLK_KP9] ||
joystick && joystick->isRight())
{
- Direction |= Being::RIGHT;
+ direction |= Being::RIGHT;
}
- player_node->walk(Direction);
+ player_node->walk(direction);
// Attacking monsters
if (keys[SDLK_LCTRL] || keys[SDLK_RCTRL] ||
@@ -675,13 +663,13 @@ void Game::handleInput()
{
Uint16 targetX = x, targetY = y;
- if (player_node->mDirection & Being::UP)
+ if (player_node->getDirection() & Being::UP)
targetY--;
- if (player_node->mDirection & Being::DOWN)
+ if (player_node->getDirection() & Being::DOWN)
targetY++;
- if (player_node->mDirection & Being::LEFT)
+ if (player_node->getDirection() & Being::LEFT)
targetX--;
- if (player_node->mDirection & Being::RIGHT)
+ if (player_node->getDirection() & Being::RIGHT)
targetX++;
// Attack priority is: Monster, Player, auto target
diff --git a/src/graphics.cpp b/src/graphics.cpp
index 065c0a46..f007470a 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -39,6 +39,9 @@ Graphics::~Graphics()
bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
{
+ logger->log("Setting video mode %dx%d %s",
+ w, h, fs ? "fullscreen" : "windowed");
+
int displayFlags = SDL_ANYFORMAT;
mFullscreen = fs;
diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp
index b681b683..9fcf752b 100644
--- a/src/gui/buy.cpp
+++ b/src/gui/buy.cpp
@@ -32,7 +32,7 @@
#include "../npc.h"
-#include "../resources/itemmanager.h"
+#include "../resources/itemdb.h"
#include "../utils/tostring.h"
@@ -266,7 +266,7 @@ void BuyDialog::selectionChanged(const SelectionEvent &event)
if (selectedItem > -1)
{
const ItemInfo &info =
- itemDb->getItemInfo(mShopItems->at(selectedItem).id);
+ ItemDB::get(mShopItems->at(selectedItem).id);
mItemDescLabel->setCaption("Description: " + info.getDescription());
mItemEffectLabel->setCaption("Effect: " + info.getEffect());
diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp
index d825db31..3cb42078 100644
--- a/src/gui/char_select.cpp
+++ b/src/gui/char_select.cpp
@@ -83,7 +83,7 @@ CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo):
mNameLabel = new gcn::Label("Name");
mLevelLabel = new gcn::Label("Level");
mMoneyLabel = new gcn::Label("Money");
- mPlayerBox = new PlayerBox(0);
+ mPlayerBox = new PlayerBox();
int w = 195;
int h = 220;
@@ -116,8 +116,9 @@ CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo):
add(mLevelLabel);
add(mMoneyLabel);
- mSelectButton->requestFocus();
setLocationRelativeTo(getParent());
+ setVisible(true);
+ mSelectButton->requestFocus();
updatePlayerInfo();
}
@@ -171,7 +172,8 @@ void CharSelectDialog::updatePlayerInfo()
{
LocalPlayer *pi = mCharInfo->getEntry();
- if (pi) {
+ if (pi)
+ {
mNameLabel->setCaption(pi->getName());
mLevelLabel->setCaption("Lvl: " + toString(pi->mLevel));
mMoneyLabel->setCaption("Money: " + toString(pi->mMoney));
@@ -181,22 +183,17 @@ void CharSelectDialog::updatePlayerInfo()
mDelCharButton->setEnabled(true);
mSelectButton->setEnabled(true);
}
- mPlayerBox->mHairStyle = pi->getHairStyle();
- mPlayerBox->mHairColor = pi->getHairColor();
- mPlayerBox->mSex = pi->getSex();
- mPlayerBox->mShowPlayer = true;
- } else {
+ }
+ else {
mNameLabel->setCaption("Name");
mLevelLabel->setCaption("Level");
mMoneyLabel->setCaption("Money");
mNewCharButton->setEnabled(true);
mDelCharButton->setEnabled(false);
mSelectButton->setEnabled(false);
-
- mPlayerBox->mHairStyle = 0;
- mPlayerBox->mHairColor = 0;
- mPlayerBox->mShowPlayer = false;
}
+
+ mPlayerBox->setPlayer(pi);
}
void CharSelectDialog::attemptCharDelete()
@@ -240,6 +237,10 @@ std::string CharSelectDialog::getName()
CharCreateDialog::CharCreateDialog(Window *parent, int slot):
Window("Create Character", true, parent), mSlot(slot)
{
+ mPlayer = new Player(0, 0, NULL);
+ mPlayer->setHairStyle(rand() % NR_HAIR_STYLES + 1);
+ mPlayer->setHairColor(rand() % NR_HAIR_COLORS + 1);
+
mNameField = new TextField("");
mNameLabel = new gcn::Label("Name:");
mNextHairColorButton = new Button(">", "nextcolor", this);
@@ -250,8 +251,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot):
mHairStyleLabel = new gcn::Label("Hair Style:");
mCreateButton = new Button("Create", "create", this);
mCancelButton = new Button("Cancel", "cancel", this);
- mPlayerBox = new PlayerBox(0);
- mPlayerBox->mShowPlayer = true;
+ mPlayerBox = new PlayerBox(mPlayer);
mNameField->setEventId("create");
@@ -290,6 +290,12 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot):
add(mCancelButton);
setLocationRelativeTo(getParent());
+ setVisible(true);
+}
+
+CharCreateDialog::~CharCreateDialog()
+{
+ delete mPlayer;
}
void CharCreateDialog::action(const std::string &eventId, gcn::Widget *widget)
@@ -299,7 +305,9 @@ void CharCreateDialog::action(const std::string &eventId, gcn::Widget *widget)
// Attempt to create the character
mCreateButton->setEnabled(false);
Net::AccountServer::Account::createCharacter(
- getName(), mPlayerBox->mHairStyle, mPlayerBox->mHairColor,
+ getName(),
+ mPlayer->getHairStyle(),
+ mPlayer->getHairColor(),
0, // gender
10, // STR
10, // AGI
@@ -318,20 +326,19 @@ void CharCreateDialog::action(const std::string &eventId, gcn::Widget *widget)
scheduleDelete();
}
else if (eventId == "nextcolor") {
- mPlayerBox->mHairColor++;
+ mPlayer->setHairColor(mPlayer->getHairColor() % NR_HAIR_COLORS + 1);
}
else if (eventId == "prevcolor") {
- mPlayerBox->mHairColor += NR_HAIR_COLORS - 1;
+ int prevColor = mPlayer->getHairColor() + NR_HAIR_COLORS - 2;
+ mPlayer->setHairColor(prevColor % NR_HAIR_COLORS + 1);
}
else if (eventId == "nextstyle") {
- mPlayerBox->mHairStyle++;
+ mPlayer->setHairStyle(mPlayer->getHairStyle() % NR_HAIR_STYLES + 1);
}
else if (eventId == "prevstyle") {
- mPlayerBox->mHairStyle += NR_HAIR_STYLES - 1;
+ int prevStyle = mPlayer->getHairStyle() + NR_HAIR_STYLES - 2;
+ mPlayer->setHairStyle(prevStyle % NR_HAIR_STYLES + 1);
}
-
- mPlayerBox->mHairColor %= NR_HAIR_COLORS;
- mPlayerBox->mHairStyle %= NR_HAIR_STYLES;
}
std::string CharCreateDialog::getName()
diff --git a/src/gui/char_select.h b/src/gui/char_select.h
index 6d9d1a83..9d2d77da 100644
--- a/src/gui/char_select.h
+++ b/src/gui/char_select.h
@@ -31,6 +31,7 @@
#include <guichan/actionlistener.hpp>
+class Player;
class LocalPlayer;
class PlayerBox;
@@ -48,7 +49,7 @@ class CharSelectDialog : public Window, public gcn::ActionListener
*/
CharSelectDialog(LockedArray<LocalPlayer*> *charInfo);
- void action(const std::string& eventId, gcn::Widget* widget);
+ void action(const std::string &eventId, gcn::Widget *widget);
void updatePlayerInfo();
@@ -103,7 +104,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener
*/
CharCreateDialog(Window *parent, int slot);
- void action(const std::string& eventId, gcn::Widget* widget);
+ /**
+ * Destructor.
+ */
+ ~CharCreateDialog();
+
+ void action(const std::string &eventId, gcn::Widget *widget);
std::string getName();
@@ -119,6 +125,7 @@ class CharCreateDialog : public Window, public gcn::ActionListener
gcn::Button *mCreateButton;
gcn::Button *mCancelButton;
+ Player *mPlayer;
PlayerBox *mPlayerBox;
int mSlot;
diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp
index ed2f8680..5a70544f 100644
--- a/src/gui/confirm_dialog.cpp
+++ b/src/gui/confirm_dialog.cpp
@@ -61,6 +61,7 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg,
setLocationRelativeTo(getParent());
getParent()->moveToTop(this);
}
+ setVisible(true);
yesButton->requestFocus();
}
diff --git a/src/gui/confirm_dialog.h b/src/gui/confirm_dialog.h
index 1c206b03..771ecc36 100644
--- a/src/gui/confirm_dialog.h
+++ b/src/gui/confirm_dialog.h
@@ -47,7 +47,7 @@ class ConfirmDialog : public Window, public gcn::ActionListener {
/**
* Called when receiving actions from the widgets.
*/
- void action(const std::string& eventId, gcn::Widget* widget);
+ void action(const std::string &eventId, gcn::Widget *widget);
};
#endif
diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp
index d467d4d3..f8a4154e 100644
--- a/src/gui/debugwindow.cpp
+++ b/src/gui/debugwindow.cpp
@@ -72,15 +72,15 @@ DebugWindow::logic()
// Get the current mouse position
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
- int mouseTileX = mouseX / 32 + camera_x;
- int mouseTileY = mouseY / 32 + camera_y;
+ //int mouseTileX = mouseX / 32 + camera_x;
+ //int mouseTileY = mouseY / 32 + camera_y;
mFPSLabel->setCaption("[" + toString(fps) + " FPS");
mFPSLabel->adjustSize();
- mTileMouseLabel->setCaption("[Mouse: " +
- toString(mouseTileX) + ", " + toString(mouseTileY) + "]");
- mTileMouseLabel->adjustSize();
+ //mTileMouseLabel->setCaption("[Mouse: " +
+ // toString(mouseTileX) + ", " + toString(mouseTileY) + "]");
+ //mTileMouseLabel->adjustSize();
Map *currentMap = engine->getCurrentMap();
if (currentMap != NULL)
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index 38b17781..fb7144a1 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -35,22 +35,14 @@
#endif
#include "focushandler.h"
-#include "popupmenu.h"
#include "window.h"
#include "windowcontainer.h"
+#include "viewport.h"
-#include "../being.h"
-#include "../beingmanager.h"
#include "../configlistener.h"
#include "../configuration.h"
-#include "../engine.h"
-#include "../flooritemmanager.h"
#include "../graphics.h"
-#include "../localplayer.h"
#include "../log.h"
-#include "../main.h"
-#include "../map.h"
-#include "../npc.h"
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
@@ -61,7 +53,8 @@
// Guichan stuff
Gui *gui;
-gcn::SDLInput *guiInput; // GUI input
+Viewport *viewport; /**< Viewport on the map. */
+gcn::SDLInput *guiInput; /**< GUI input. */
// Fonts used in showing hits
gcn::Font *hitRedFont;
@@ -91,9 +84,9 @@ class GuiConfigListener : public ConfigListener
Gui::Gui(Graphics *graphics):
mHostImageLoader(NULL),
mMouseCursor(NULL),
- mCustomCursor(false),
- mPopupActive(false)
+ mCustomCursor(false)
{
+ logger->log("Initializing GUI...");
// Set graphics
setGraphics(graphics);
@@ -122,7 +115,6 @@ Gui::Gui(Graphics *graphics):
guiTop->setDimension(gcn::Rectangle(0, 0,
graphics->getWidth(), graphics->getHeight()));
guiTop->setOpaque(false);
- guiTop->addMouseListener(this);
Window::setWindowContainer(guiTop);
setTop(guiTop);
@@ -172,13 +164,15 @@ Gui::Gui(Graphics *graphics):
mConfigListener = new GuiConfigListener(this);
config.addListener("customcursor", mConfigListener);
- mPopup = new PopupMenu();
+ // Create the viewport
+ viewport = new Viewport();
+ viewport->setDimension(gcn::Rectangle(0, 0,
+ graphics->getWidth(), graphics->getHeight()));
+ guiTop->add(viewport);
}
Gui::~Gui()
{
- delete mPopup;
-
config.removeListener("customcursor", mConfigListener);
delete mConfigListener;
@@ -193,6 +187,7 @@ Gui::~Gui()
delete mGuiFont;
delete speechFont;
+ delete viewport;
delete mTop;
delete mImageLoader;
delete mHostImageLoader;
@@ -231,113 +226,6 @@ Gui::draw()
}
void
-Gui::mousePress(int mx, int my, int button)
-{
- // Mouse pressed on window container (basically, the map)
-
- // Are we in-game yet?
- if (state != STATE_GAME)
- return;
-
- // Check if we are alive and kickin'
- if (!player_node || player_node->mAction == Being::DEAD)
- return;
-
- // Check if we are busy
- if (current_npc)
- return;
-
- int tilex = (mx + camera_x) / 32;
- int tiley = (my + camera_y) / 32;
-
- // Right click might open a popup
- if (button == gcn::MouseInput::RIGHT)
- {
- Being *being;
- FloorItem *floorItem;
-
- if ((being = beingManager->findBeing(tilex, tiley)) &&
- being->getType() != Being::LOCALPLAYER)
- {
- showPopup(mx, my, being);
- return;
- }
- else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley)))
- {
- showPopup(mx, my, floorItem);
- return;
- }
- }
-
- // If a popup is active, just remove it
- if (mPopupActive)
- {
- mPopup->setVisible(false);
- mPopupActive = false;
- return;
- }
-
- // Left click can cause different actions
- if (button == gcn::MouseInput::LEFT)
- {
- Being *being;
- FloorItem *item;
-
- // Interact with some being
- if ((being = beingManager->findBeing(tilex, tiley)))
- {
- switch (being->getType())
- {
- case Being::NPC:
- dynamic_cast<NPC*>(being)->talk();
- break;
-
- case Being::MONSTER:
- case Being::PLAYER:
- if (being->mAction == Being::MONSTER_DEAD)
- break;
-
- player_node->attack(being, true);
- break;
-
- default:
- break;
- }
- }
- // Pick up some item
- else if ((item = floorItemManager->findByCoordinates(tilex, tiley)))
- {
- player_node->pickUp(item);
- }
- // Just walk around
- else if (engine->getCurrentMap() &&
- engine->getCurrentMap()->getWalk(tilex, tiley))
- {
- // XXX XXX XXX REALLY UGLY!
- Uint8 *keys = SDL_GetKeyState(NULL);
- if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]))
- {
- player_node->setDestination(mx + camera_x, my + camera_y);
- player_node->stopAttack();
- }
- }
- }
-
- if (button == gcn::MouseInput::MIDDLE)
- {
- // Find the being nearest to the clicked position
- Being *target = beingManager->findNearestLivingBeing(
- tilex, tiley,
- 20, Being::MONSTER);
-
- if (target)
- {
- player_node->setTarget(target);
- }
- }
-}
-
-void
Gui::setUseCustomCursor(bool customCursor)
{
if (customCursor != mCustomCursor)
@@ -369,21 +257,3 @@ Gui::setUseCustomCursor(bool customCursor)
}
}
}
-
-void Gui::showPopup(int x, int y, Item *item)
-{
- mPopup->showPopup(x, y, item);
- mPopupActive = true;
-}
-
-void Gui::showPopup(int x, int y, FloorItem *floorItem)
-{
- mPopup->showPopup(x, y, floorItem);
- mPopupActive = true;
-}
-
-void Gui::showPopup(int x, int y, Being *being)
-{
- mPopup->showPopup(x, y, being);
- mPopupActive = true;
-}
diff --git a/src/gui/gui.h b/src/gui/gui.h
index c4c47a88..caf27744 100644
--- a/src/gui/gui.h
+++ b/src/gui/gui.h
@@ -25,17 +25,13 @@
#define _TMW_GUI
#include <guichan/gui.hpp>
-#include <guichan/mouselistener.hpp>
#include "../guichanfwd.h"
-class Being;
-class FloorItem;
class GuiConfigListener;
class Graphics;
class Image;
-class Item;
-class PopupMenu;
+class Viewport;
/**
* \defgroup GUI Core GUI related classes (widgets)
@@ -50,7 +46,7 @@ class PopupMenu;
*
* \ingroup GUI
*/
-class Gui : public gcn::Gui, public gcn::MouseListener
+class Gui : public gcn::Gui
{
public:
/**
@@ -77,12 +73,6 @@ class Gui : public gcn::Gui, public gcn::MouseListener
draw();
/**
- * Handles mouse press on map.
- */
- void
- mousePress(int mx, int my, int button);
-
- /**
* Return game font
*/
gcn::Font*
@@ -94,37 +84,17 @@ class Gui : public gcn::Gui, public gcn::MouseListener
void
setUseCustomCursor(bool customCursor);
- /**
- * Shows a popup for an item
- * TODO Find some way to get rid of Item here
- */
- void showPopup(int x, int y, Item *item);
-
- /**
- * Shows a popup for a floor item
- * TODO Find some way to get rid of FloorItem here
- */
- void showPopup(int x, int y, FloorItem *floorItem);
-
- /**
- * Shows a popup for a being
- * TODO Find some way to get rid of Being here
- */
- void showPopup(int x, int y, Being *being);
-
private:
GuiConfigListener *mConfigListener;
gcn::ImageLoader *mHostImageLoader; /**< For loading images in GL */
gcn::ImageLoader *mImageLoader; /**< For loading images */
- gcn::Font *mGuiFont; /**< The global GUI font */
+ gcn::Font *mGuiFont; /**< The global GUI font */
Image *mMouseCursor; /**< Mouse cursor image */
bool mCustomCursor; /**< Show custom cursor */
-
- PopupMenu *mPopup; /**< Popup window */
- bool mPopupActive;
};
extern Gui *gui; /**< The GUI system */
+extern Viewport *viewport; /**< The viewport */
extern gcn::SDLInput *guiInput; /**< GUI input */
/**
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp
index 452b7c16..7f9ba3b9 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -34,6 +34,7 @@
#include "item_amount.h"
#include "itemcontainer.h"
#include "scrollarea.h"
+#include "viewport.h"
#include "../item.h"
#include "../localplayer.h"
@@ -169,7 +170,7 @@ void InventoryWindow::mouseClick(int x, int y, int button, int count)
*/
int mx = x + getX();
int my = y + getY();
- gui->showPopup(mx, my, item);
+ viewport->showPopup(mx, my, item);
}
}
diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp
index 30c899a8..5ebc0213 100644
--- a/src/gui/item_amount.cpp
+++ b/src/gui/item_amount.cpp
@@ -18,7 +18,7 @@
* along with The Mana World; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id $
+ * $Id$
*/
#include "item_amount.h"
@@ -87,6 +87,7 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item):
setContentSize(200, 80);
setLocationRelativeTo(getParentWindow());
+ setVisible(true);
}
void ItemAmountWindow::resetAmount()
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
index 1d9b6e1e..b8d4df2b 100644
--- a/src/gui/login.cpp
+++ b/src/gui/login.cpp
@@ -102,6 +102,7 @@ LoginDialog::LoginDialog(LoginData *loginData):
add(mRegisterButton);
setLocationRelativeTo(getParent());
+ setVisible(true);
if (mUserField->getText().empty()) {
mUserField->requestFocus();
diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp
index 906fd61f..4f9623d7 100644
--- a/src/gui/ok_dialog.cpp
+++ b/src/gui/ok_dialog.cpp
@@ -51,6 +51,7 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg,
add(okButton);
setLocationRelativeTo(getParent());
+ setVisible(true);
okButton->requestFocus();
}
diff --git a/src/gui/ok_dialog.h b/src/gui/ok_dialog.h
index 06f703cc..8ae08955 100644
--- a/src/gui/ok_dialog.h
+++ b/src/gui/ok_dialog.h
@@ -46,7 +46,7 @@ class OkDialog : public Window, public gcn::ActionListener {
/**
* Called when receiving actions from the widgets.
*/
- void action(const std::string& eventId, gcn::Widget* widget);
+ void action(const std::string &eventId, gcn::Widget *widget);
};
#endif
diff --git a/src/gui/passwordfield.h b/src/gui/passwordfield.h
index 15ca85c9..cae1f92e 100644
--- a/src/gui/passwordfield.h
+++ b/src/gui/passwordfield.h
@@ -21,8 +21,8 @@
* $Id$
*/
-#ifndef __PASSWORDFIELD_H__
-#define __PASSWORDFIELD_H__
+#ifndef _TMW_PASSWORDFIELD_H_
+#define _TMW_PASSWORDFIELD_H_
#include "textfield.h"
diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp
index 568c3350..5fbe79b7 100644
--- a/src/gui/playerbox.cpp
+++ b/src/gui/playerbox.cpp
@@ -23,7 +23,7 @@
#include "playerbox.h"
-#include "../being.h"
+#include "../player.h"
#include "../graphics.h"
#include "../resources/image.h"
@@ -32,17 +32,11 @@
#include "../utils/dtor.h"
-extern std::vector<Spriteset *> hairset;
-extern Spriteset *playerset[2];
-
int PlayerBox::instances = 0;
ImageRect PlayerBox::background;
-PlayerBox::PlayerBox(unsigned char sex):
- mHairColor(0),
- mHairStyle(0),
- mSex(sex),
- mShowPlayer(false)
+PlayerBox::PlayerBox(const Player *player):
+ mPlayer(player)
{
setBorderSize(2);
@@ -81,29 +75,18 @@ PlayerBox::~PlayerBox()
}
}
-void PlayerBox::draw(gcn::Graphics *graphics)
+void
+PlayerBox::draw(gcn::Graphics *graphics)
{
- if (!mShowPlayer) {
- return;
- }
-
- // Draw character
- dynamic_cast<Graphics*>(graphics)->drawImage(
- playerset[mSex]->get(0), 23, 12);
-
- // Draw his hair
- if (mHairStyle > 0 && mHairColor < NR_HAIR_COLORS &&
- mHairStyle < NR_HAIR_STYLES)
+ if (mPlayer)
{
- int hf = 5 * mHairColor;
- if (hf >= 0 && hf < (int)hairset[mHairStyle]->size()) {
- dynamic_cast<Graphics*>(graphics)->drawImage(
- hairset[mHairStyle - 1]->get(hf), 35, 7);
- }
+ // Draw character
+ mPlayer->draw(dynamic_cast<Graphics*>(graphics), 40, 42);
}
}
-void PlayerBox::drawBorder(gcn::Graphics *graphics)
+void
+PlayerBox::drawBorder(gcn::Graphics *graphics)
{
int w, h, bs;
bs = getBorderSize();
diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h
index ec04eaf6..6bba1b51 100644
--- a/src/gui/playerbox.h
+++ b/src/gui/playerbox.h
@@ -27,10 +27,10 @@
#include <guichan/widgets/scrollarea.hpp>
class ImageRect;
+class Player;
/**
- * A box showing a player. Draws the various hair styles a player can have
- * currently.
+ * A box showing a player character.
*
* \ingroup GUI
*/
@@ -38,9 +38,10 @@ class PlayerBox : public gcn::ScrollArea
{
public:
/**
- * Constructor.
+ * Constructor. Takes the initial player character that this box should
+ * display, which defaults to <code>NULL</code>.
*/
- PlayerBox(unsigned char sex);
+ PlayerBox(const Player *player = NULL);
/**
* Destructor.
@@ -48,6 +49,14 @@ class PlayerBox : public gcn::ScrollArea
~PlayerBox();
/**
+ * Sets a new player character to be displayed by this box. Setting the
+ * player to <code>NULL</code> causes the box not to draw any
+ * character.
+ */
+ void
+ setPlayer(const Player *player) { mPlayer = player; }
+
+ /**
* Draws the scroll area.
*/
void draw(gcn::Graphics *graphics);
@@ -57,12 +66,9 @@ class PlayerBox : public gcn::ScrollArea
*/
void drawBorder(gcn::Graphics *graphics);
- unsigned char mHairColor; /**< The hair color index */
- unsigned char mHairStyle; /**< The hair style index */
- unsigned char mSex; /**< Sex */
- bool mShowPlayer; /**< Wether to show the player or not */
-
private:
+ const Player *mPlayer; /**< The character used for display */
+
static int instances;
static ImageRect background;
};
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index ab81f7d0..c2959e1d 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -40,7 +40,7 @@
#include "../npc.h"
#include "../resources/iteminfo.h"
-#include "../resources/itemmanager.h"
+#include "../resources/itemdb.h"
extern std::string tradePartnerName;
@@ -106,7 +106,7 @@ void PopupMenu::showPopup(int x, int y, FloorItem *floorItem)
mBrowserBox->clearRows();
// Floor item can be picked up (single option, candidate for removal)
- std::string name = itemDb->getItemInfo(mFloorItem->getItemId()).getName();
+ std::string name = ItemDB::get(mFloorItem->getItemId()).getName();
mBrowserBox->addRow("@@pickup|Pick Up " + name + "@@");
//browserBox->addRow("@@look|Look To@@");
diff --git a/src/gui/register.cpp b/src/gui/register.cpp
index 7cef62a2..70cd6dc4 100644
--- a/src/gui/register.cpp
+++ b/src/gui/register.cpp
@@ -97,6 +97,7 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
add(mCancelButton);
setLocationRelativeTo(getParent());
+ setVisible(true);
mUserField->requestFocus();
mUserField->setCaretPosition(mUserField->getText().length());
}
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index fd63633c..499bbd05 100644
--- a/src/gui/sell.cpp
+++ b/src/gui/sell.cpp
@@ -37,7 +37,7 @@
#include "../npc.h"
#include "../resources/iteminfo.h"
-#include "../resources/itemmanager.h"
+#include "../resources/itemdb.h"
#include "../utils/tostring.h"
@@ -232,6 +232,7 @@ void SellDialog::action(const std::string &eventId, gcn::Widget *widget)
mMaxItems -= mAmountItems;
mShopItems->getShop()->at(selectedItem).quantity = mMaxItems;
+ mPlayerMoney += (mAmountItems * mShopItems->at(selectedItem).price);
mAmountItems = 0;
mSlider->setValue(0);
mSlider->setEnabled(mMaxItems != 0);
@@ -274,7 +275,7 @@ void SellDialog::selectionChanged(const SelectionEvent &event)
if (selectedItem > -1)
{
const ItemInfo &info =
- itemDb->getItemInfo(mShopItems->at(selectedItem).id);
+ ItemDB::get(mShopItems->at(selectedItem).id);
mItemDescLabel->setCaption("Description: " + info.getDescription());
mItemEffectLabel->setCaption("Effect: " + info.getEffect());
diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp
index 39abd5ed..bd17bff7 100644
--- a/src/gui/serverdialog.cpp
+++ b/src/gui/serverdialog.cpp
@@ -174,6 +174,7 @@ ServerDialog::ServerDialog(LoginData *loginData):
add(mCancelButton);
setLocationRelativeTo(getParent());
+ setVisible(true);
if (mServerNameField->getText().empty()) {
mServerNameField->requestFocus();
diff --git a/src/gui/serverdialog.h b/src/gui/serverdialog.h
index 5b265c17..d907f340 100644
--- a/src/gui/serverdialog.h
+++ b/src/gui/serverdialog.h
@@ -132,7 +132,7 @@ class ServerDialog : public Window, public gcn::ActionListener
/**
* Called when receiving actions from the widgets.
*/
- void action(const std::string& eventId, gcn::Widget* widget);
+ void action(const std::string &eventId, gcn::Widget *widget);
private:
gcn::TextField *mServerNameField;
diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp
index d9212728..685d88cf 100644
--- a/src/gui/setup_joystick.cpp
+++ b/src/gui/setup_joystick.cpp
@@ -42,7 +42,7 @@ Setup_Joystick::Setup_Joystick():
mCalibrateLabel->setPosition(10, 25);
mCalibrateButton->setPosition(10, 30 + mCalibrateLabel->getHeight());
- mOriginalJoystickEnabled = (joystick ? joystick->isEnabled() : false);
+ mOriginalJoystickEnabled = (int)config.getValue("joystickEnabled", 0) != 0;
mJoystickEnabled->setMarked(mOriginalJoystickEnabled);
mJoystickEnabled->setEventId("joystickEnabled");
diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp
index 3f30732a..2d33e8a8 100644
--- a/src/gui/shop.cpp
+++ b/src/gui/shop.cpp
@@ -23,7 +23,7 @@
#include "shop.h"
#include "../utils/tostring.h"
-#include "../resources/itemmanager.h"
+#include "../resources/itemdb.h"
ShopItems::~ShopItems()
{
@@ -44,11 +44,11 @@ void ShopItems::addItem(short id, int price)
{
ITEM_SHOP item_shop;
- item_shop.name = itemDb->getItemInfo(id).getName()
+ item_shop.name = ItemDB::get(id).getName()
+ " " + toString(price) + " GP";
item_shop.price = price;
item_shop.id = id;
- item_shop.image = itemDb->getItemInfo(id).getImage();
+ item_shop.image = ItemDB::get(id).getImage();
mItemsShop.push_back(item_shop);
}
diff --git a/src/gui/textfield.h b/src/gui/textfield.h
index 1ed802d7..4748830c 100644
--- a/src/gui/textfield.h
+++ b/src/gui/textfield.h
@@ -28,7 +28,6 @@
class ImageRect;
-
/**
* A text field.
*
diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp
index 2ac56ae5..82262563 100644
--- a/src/gui/trade.cpp
+++ b/src/gui/trade.cpp
@@ -48,7 +48,7 @@ TradeWindow::TradeWindow():
mPartnerInventory(new Inventory())
{
setWindowName("Trade");
- setDefaultSize(115, 197, 322, 150);
+ setDefaultSize(115, 197, 332, 209);
mAddButton = new Button("Add", "add", this);
mOkButton = new Button("Ok", "ok", this);
@@ -95,33 +95,33 @@ TradeWindow::TradeWindow():
add(mMoneyField);
add(mMoneyLabel);
- mMoneyField->setPosition(8 + 60, getHeight() - 20);
+ gcn::Rectangle area = getChildrenArea();
+ int width = area.width;
+ int height = area.height;
+
+ mMoneyField->setPosition(8 + 60, height - 20);
mMoneyField->setWidth(50);
- mMoneyLabel->setPosition(8 + 60 + 50 + 6, getHeight() - 20);
- mMoneyLabel2->setPosition(8, getHeight() - 20);
+ mMoneyLabel->setPosition(8 + 60 + 50 + 6, height - 20);
+ mMoneyLabel2->setPosition(8, height - 20);
- mCancelButton->setPosition(getWidth() - 54, getHeight() - 49);
- mTradeButton->setPosition(mCancelButton->getX() - 41
- , getHeight() - 49);
- mOkButton->setPosition(mTradeButton->getX() - 24,
- getHeight() - 49);
- mAddButton->setPosition(mOkButton->getX() - 31,
- getHeight() - 49);
+ mCancelButton->setPosition(width - 54, height - 49);
+ mTradeButton->setPosition(mCancelButton->getX() - 41, height - 49);
+ mOkButton->setPosition(mTradeButton->getX() - 24, height - 49);
+ mAddButton->setPosition(mOkButton->getX() - 31, height - 49);
- mMyItemContainer->setSize(getWidth() - 24 - 12 - 1,
- (INVENTORY_SIZE * 24) / (getWidth() / 24) - 1);
- mMyScroll->setSize(getWidth() - 16, (getHeight() - 76) / 2);
+ mMyItemContainer->setSize(width - 24 - 12 - 1,
+ (INVENTORY_SIZE * 24) / (width / 24) - 1);
+ mMyScroll->setSize(width - 16, (height - 76) / 2);
- mPartnerItemContainer->setSize(getWidth() - 24 - 12 - 1,
- (INVENTORY_SIZE * 24) / (getWidth() / 24) - 1);
- mPartnerScroll->setSize(getWidth() - 16, (getHeight() - 76) / 2);
+ mPartnerItemContainer->setSize(width - 24 - 12 - 1,
+ (INVENTORY_SIZE * 24) / (width / 24) - 1);
+ mPartnerScroll->setSize(width - 16, (height - 76) / 2);
mItemNameLabel->setPosition(8,
mPartnerScroll->getY() + mPartnerScroll->getHeight() + 4);
mItemDescriptionLabel->setPosition(8,
mItemNameLabel->getY() + mItemNameLabel->getHeight() + 4);
-
}
TradeWindow::~TradeWindow()
diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp
index c29906a1..73343483 100644
--- a/src/gui/updatewindow.cpp
+++ b/src/gui/updatewindow.cpp
@@ -192,7 +192,7 @@ int UpdaterWindow::updateProgress(void *ptr,
if (progress > 1) progress = 1.0f;
uw->setLabel(
- uw->mCurrentFile + " (" + toString((int)progress * 100) + "%)");
+ uw->mCurrentFile + " (" + toString((int) (progress * 100)) + "%)");
uw->setProgress(progress);
if (state != STATE_UPDATE || uw->mDownloadStatus == UPDATE_ERROR)
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
new file mode 100644
index 00000000..d0525a2f
--- /dev/null
+++ b/src/gui/viewport.cpp
@@ -0,0 +1,392 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "viewport.h"
+
+#include <guichan/sdl/sdlinput.hpp>
+
+#include "gui.h"
+#include "popupmenu.h"
+
+#include "../beingmanager.h"
+#include "../configuration.h"
+#include "../flooritemmanager.h"
+#include "../graphics.h"
+#include "../localplayer.h"
+#include "../map.h"
+#include "../npc.h"
+
+#include "../resources/monsterdb.h"
+
+#include "../utils/tostring.h"
+
+Viewport::Viewport():
+ mMap(0),
+ mViewX(0.0f),
+ mViewY(0.0f),
+ mCameraX(0),
+ mCameraY(0),
+ mShowDebugPath(false),
+ mPopupActive(false)
+{
+ setOpaque(false);
+ addMouseListener(this);
+
+ mScrollLaziness = (int) config.getValue("ScrollLaziness", 32);
+ mScrollRadius = (int) config.getValue("ScrollRadius", 32);
+
+ config.addListener("ScrollLaziness", this);
+ config.addListener("ScrollRadius", this);
+
+ mPopupMenu = new PopupMenu();
+}
+
+Viewport::~Viewport()
+{
+ delete mPopupMenu;
+}
+
+void
+Viewport::setMap(Map *map)
+{
+ mMap = map;
+}
+
+void
+Viewport::draw(gcn::Graphics *gcnGraphics)
+{
+ static int lastTick = tick_time;
+
+ if (!mMap || !player_node)
+ return;
+
+ Graphics *graphics = static_cast<Graphics*>(gcnGraphics);
+
+ // Avoid freaking out when tick_time overflows
+ if (tick_time < lastTick)
+ {
+ lastTick = tick_time;
+ }
+
+ // Calculate viewpoint
+ int midTileX = graphics->getWidth() / 2;
+ int midTileY = graphics->getHeight() / 2;
+
+ int player_x = player_node->mX - midTileX + player_node->getXOffset();
+ int player_y = player_node->mY - midTileY + player_node->getYOffset();
+
+ if (mScrollLaziness < 1)
+ mScrollLaziness = 1; // Avoids division by zero
+
+ // Apply lazy scrolling
+ while (lastTick < tick_time)
+ {
+ if (player_x > mViewX + mScrollRadius)
+ {
+ mViewX += (player_x - mViewX - mScrollRadius) / mScrollLaziness;
+ }
+ if (player_x < mViewX - mScrollRadius)
+ {
+ mViewX += (player_x - mViewX + mScrollRadius) / mScrollLaziness;
+ }
+ if (player_y > mViewY + mScrollRadius)
+ {
+ mViewY += (player_y - mViewY - mScrollRadius) / mScrollLaziness;
+ }
+ if (player_y < mViewY - mScrollRadius)
+ {
+ mViewY += (player_y - mViewY + mScrollRadius) / mScrollLaziness;
+ }
+ lastTick++;
+ }
+
+ // Auto center when player is off screen
+ if ( player_x - mViewX > graphics->getWidth() / 2
+ || mViewX - player_x > graphics->getWidth() / 2
+ || mViewY - player_y > graphics->getHeight() / 2
+ || player_y - mViewY > graphics->getHeight() / 2
+ )
+ {
+ mViewX = player_x;
+ mViewY = player_y;
+ };
+
+ if (mMap) {
+ if (mViewX < 0) {
+ mViewX = 0;
+ }
+ if (mViewY < 0) {
+ mViewY = 0;
+ }
+ if (mViewX > mMap->getWidth() * 32 - midTileX) {
+ mViewX = mMap->getWidth() * 32 - midTileX;
+ }
+ if (mViewY > mMap->getHeight() * 32 - midTileY) {
+ mViewY = mMap->getHeight() * 32 - midTileY;
+ }
+ }
+
+ mCameraX = (int) mViewX;
+ mCameraY = (int) mViewY;
+
+ // Draw tiles and sprites
+ if (mMap)
+ {
+ mMap->draw(graphics, mCameraX, mCameraY, 0);
+ mMap->draw(graphics, mCameraX, mCameraY, 1);
+ mMap->draw(graphics, mCameraX, mCameraY, 2);
+ mMap->drawOverlay(graphics, mViewX, mViewY,
+ (int) config.getValue("OverlayDetail", 2));
+ }
+
+ // Find a path from the player to the mouse, and draw it. This is for debug
+ // purposes.
+ if (mShowDebugPath && mMap)
+ {
+ // Get the current mouse position
+ int mouseX, mouseY;
+ SDL_GetMouseState(&mouseX, &mouseY);
+
+ int mouseTileX = (mouseX + mCameraX) / 32;
+ int mouseTileY = (mouseY + mCameraY) / 32;
+
+ Path debugPath = mMap->findPath(
+ player_node->mX / 32, player_node->mY / 32,
+ mouseTileX, mouseTileY);
+
+ graphics->setColor(gcn::Color(255, 0, 0));
+ for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++)
+ {
+ int squareX = i->x * 32 - mCameraX + 12;
+ int squareY = i->y * 32 - mCameraY + 12;
+
+ graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
+ graphics->drawText(
+ toString(mMap->getMetaTile(i->x, i->y)->Gcost),
+ squareX + 4, squareY + 12, gcn::Graphics::CENTER);
+ }
+ }
+
+ // Draw player nickname, speech, and emotion sprite as needed
+ Beings &beings = beingManager->getAll();
+ for (BeingIterator i = beings.begin(); i != beings.end(); i++)
+ {
+ (*i)->drawSpeech(graphics, -mCameraX, -mCameraY);
+ (*i)->drawName(graphics, -mCameraX, -mCameraY);
+ (*i)->drawEmotion(graphics, -mCameraX, -mCameraY);
+ }
+
+ // Draw target marker if needed
+ Being *target;
+ if ((target = player_node->getTarget()))
+ {
+ graphics->setFont(speechFont);
+ graphics->setColor(gcn::Color(255, 32, 32));
+ int dy = (target->getType() == Being::PLAYER) ? 80 : 42;
+
+ std::string mobName = "";
+
+ if (target->mJob >= 1002)
+ {
+ int mobId = target->mJob - 1002;
+ mobName = MonsterDB::get(mobId).getName();
+
+ graphics->drawText(mobName,
+ target->getPixelX() - mCameraX + 15,
+ target->getPixelY() - mCameraY - dy,
+ gcn::Graphics::CENTER);
+ }
+ }
+
+ // Draw contained widgets
+ WindowContainer::draw(gcnGraphics);
+}
+
+void
+Viewport::logic()
+{
+ WindowContainer::logic();
+
+ if (!mMap || !player_node)
+ return;
+
+ int mouseX, mouseY;
+ Uint8 button = SDL_GetMouseState(&mouseX, &mouseY);
+
+ if (mPlayerFollowMouse && button & SDL_BUTTON(1) &&
+ mWalkTime != player_node->mWalkTime)
+ {
+ player_node->setDestination(mouseX + mCameraX,
+ mouseY + mCameraY);
+ mWalkTime = player_node->mWalkTime;
+ }
+}
+
+void
+Viewport::mousePress(int mx, int my, int button)
+{
+ // Check if we are alive and kickin'
+ if (!mMap || !player_node || player_node->mAction == Being::DEAD)
+ return;
+
+ // Check if we are busy
+ if (current_npc)
+ return;
+
+ mPlayerFollowMouse = false;
+
+ int tilex = (mx + mCameraX) / 32;
+ int tiley = (my + mCameraY) / 32;
+
+ // Right click might open a popup
+ if (button == gcn::MouseInput::RIGHT)
+ {
+ Being *being;
+ FloorItem *floorItem;
+
+ if ((being = beingManager->findBeing(tilex, tiley)) &&
+ being->getType() != Being::LOCALPLAYER)
+ {
+ showPopup(mx, my, being);
+ return;
+ }
+ else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley)))
+ {
+ showPopup(mx, my, floorItem);
+ return;
+ }
+ }
+
+ // If a popup is active, just remove it
+ if (mPopupActive)
+ {
+ mPopupMenu->setVisible(false);
+ mPopupActive = false;
+ return;
+ }
+
+ // Left click can cause different actions
+ if (button == gcn::MouseInput::LEFT)
+ {
+ Being *being;
+ FloorItem *item;
+
+ // Interact with some being
+ if ((being = beingManager->findBeing(tilex, tiley)))
+ {
+ switch (being->getType())
+ {
+ case Being::NPC:
+ dynamic_cast<NPC*>(being)->talk();
+ break;
+
+ case Being::MONSTER:
+ case Being::PLAYER:
+ if (being->mAction == Being::DEAD)
+ break;
+
+ player_node->attack(being, true);
+ break;
+
+ default:
+ break;
+ }
+ }
+ // Pick up some item
+ else if ((item = floorItemManager->findByCoordinates(tilex, tiley)))
+ {
+ player_node->pickUp(item);
+ }
+ // Just walk around
+ else if (mMap->getWalk(tilex, tiley))
+ {
+ // XXX XXX XXX REALLY UGLY!
+ Uint8 *keys = SDL_GetKeyState(NULL);
+ if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]))
+ {
+ player_node->setDestination(mx + mCameraX, my + mCameraY);
+ player_node->stopAttack();
+ }
+ mPlayerFollowMouse = true;
+ }
+ }
+
+ if (button == gcn::MouseInput::MIDDLE)
+ {
+ // Find the being nearest to the clicked position
+ Being *target = beingManager->findNearestLivingBeing(
+ tilex, tiley,
+ 20, Being::MONSTER);
+
+ if (target)
+ {
+ player_node->setTarget(target);
+ }
+ }
+}
+
+void
+Viewport::mouseMotion(int mx, int my)
+{
+ if (!mMap || !player_node)
+ return;
+
+ if (mPlayerFollowMouse && mWalkTime == player_node->mWalkTime)
+ {
+ player_node->setDestination(mx + mCameraX, my + mCameraY);
+ }
+}
+
+void
+Viewport::mouseRelease(int mx, int my, int button)
+{
+ mPlayerFollowMouse = false;
+}
+
+void
+Viewport::showPopup(int x, int y, Item *item)
+{
+ mPopupMenu->showPopup(x, y, item);
+ mPopupActive = true;
+}
+
+void
+Viewport::showPopup(int x, int y, FloorItem *floorItem)
+{
+ mPopupMenu->showPopup(x, y, floorItem);
+ mPopupActive = true;
+}
+
+void
+Viewport::showPopup(int x, int y, Being *being)
+{
+ mPopupMenu->showPopup(x, y, being);
+ mPopupActive = true;
+}
+
+void
+Viewport::optionChanged(const std::string &name)
+{
+ mScrollLaziness = (int) config.getValue("ScrollLaziness", 32);
+ mScrollRadius = (int) config.getValue("ScrollRadius", 32);
+}
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
new file mode 100644
index 00000000..df78b1da
--- /dev/null
+++ b/src/gui/viewport.h
@@ -0,0 +1,145 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_VIEWPORT_H_
+#define _TMW_VIEWPORT_H_
+
+#include <guichan/mouselistener.hpp>
+
+#include "windowcontainer.h"
+
+#include "../configlistener.h"
+
+class Map;
+class Being;
+class FloorItem;
+class Item;
+class PopupMenu;
+
+/**
+ * The viewport on the map. Displays the current map and handles mouse input
+ * and the popup menu.
+ *
+ * TODO: This class is planned to be extended to allow floating widgets on top
+ * of it such as NPC messages, which are positioned using map pixel
+ * coordinates.
+ */
+class Viewport : public WindowContainer, public gcn::MouseListener,
+ public ConfigListener
+{
+ public:
+ /**
+ * Constructor.
+ */
+ Viewport();
+
+ /**
+ * Destructor.
+ */
+ ~Viewport();
+
+ /**
+ * Sets the map displayed by the viewport.
+ */
+ void
+ setMap(Map *map);
+
+ /**
+ * Draws the viewport.
+ */
+ void
+ draw(gcn::Graphics *graphics);
+
+ /**
+ * Implements player to keep following mouse.
+ */
+ void
+ logic();
+
+ /**
+ * Toggles whether the path debug graphics are shown
+ */
+ void toggleDebugPath() { mShowDebugPath = !mShowDebugPath; }
+
+ /**
+ * Handles mouse press on map.
+ */
+ void
+ mousePress(int mx, int my, int button);
+
+ /**
+ * Handles mouse move on map
+ */
+ void
+ mouseMotion(int mx, int my);
+
+ /**
+ * Handles mouse button release on map.
+ */
+ void
+ mouseRelease(int mx, int my, int button);
+
+ /**
+ * Shows a popup for an item.
+ * TODO Find some way to get rid of Item here
+ */
+ void showPopup(int x, int y, Item *item);
+
+ /**
+ * A relevant config option changed.
+ */
+ void
+ optionChanged(const std::string &name);
+
+ private:
+ /**
+ * Shows a popup for a floor item.
+ * TODO Find some way to get rid of FloorItem here
+ */
+ void showPopup(int x, int y, FloorItem *floorItem);
+
+ /**
+ * Shows a popup for a being.
+ * TODO Find some way to get rid of Being here
+ */
+ void showPopup(int x, int y, Being *being);
+
+
+ Map *mMap; /**< The current map. */
+
+ int mScrollRadius;
+ int mScrollLaziness;
+ float mViewX; /**< Current viewpoint in pixels. */
+ float mViewY; /**< Current viewpoint in pixels. */
+ int mCameraX;
+ int mCameraY;
+ bool mShowDebugPath; /**< Show a path from player to pointer. */
+
+ bool mPlayerFollowMouse;
+ int mWalkTime;
+
+ PopupMenu *mPopupMenu; /**< Popup menu. */
+ bool mPopupActive;
+};
+
+#endif
diff --git a/src/gui/window.cpp b/src/gui/window.cpp
index 13d42c78..1960d6ca 100644
--- a/src/gui/window.cpp
+++ b/src/gui/window.cpp
@@ -113,6 +113,9 @@ Window::Window(const std::string& caption, bool modal, Window *parent):
{
requestModalFocus();
}
+
+ // Windows are invisible by default
+ setVisible(false);
}
Window::~Window()
diff --git a/src/gui/window.h b/src/gui/window.h
index 51c876e3..158035c0 100644
--- a/src/gui/window.h
+++ b/src/gui/window.h
@@ -36,7 +36,8 @@ class WindowContainer;
/**
- * A window. This window can be dragged around and has a title bar.
+ * A window. This window can be dragged around and has a title bar. Windows are
+ * invisible by default.
*
* \ingroup GUI
*/
diff --git a/src/gui/windowcontainer.h b/src/gui/windowcontainer.h
index b860fa3c..df255f84 100644
--- a/src/gui/windowcontainer.h
+++ b/src/gui/windowcontainer.h
@@ -27,7 +27,8 @@
#include <guichan/widgets/container.hpp>
/**
- * A window container. This container makes draggable windows possible.
+ * A window container. This container adds functionality for more convenient
+ * widget (windows in particular) destruction.
*
* \ingroup GUI
*/
diff --git a/src/item.h b/src/item.h
index 1375886e..47cdb1a9 100644
--- a/src/item.h
+++ b/src/item.h
@@ -24,7 +24,7 @@
#ifndef _ITEM_H_
#define _ITEM_H_
-#include "resources/itemmanager.h"
+#include "resources/itemdb.h"
/**
* Represents one or more instances of a certain item type.
@@ -119,7 +119,7 @@ class Item
* Returns information about this item type.
*/
const ItemInfo&
- getInfo() const { return itemDb->getItemInfo(mId); }
+ getInfo() const { return ItemDB::get(mId); }
protected:
int mId; /**< Item type id. */
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 6898dfb7..c887dd1c 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -30,6 +30,7 @@
#include "item.h"
#include "main.h"
#include "sound.h"
+#include "log.h"
#include "net/gameserver/player.h"
@@ -65,9 +66,19 @@ void LocalPlayer::logic()
void LocalPlayer::nextStep()
{
- if (mPath.empty() && mPickUpTarget) {
- pickUp(mPickUpTarget);
+ if (mPath.empty())
+ {
+ if (mPickUpTarget)
+ {
+ pickUp(mPickUpTarget);
+ }
+
+ if (mWalkingDir)
+ {
+ walk(mWalkingDir);
+ }
}
+
Player::nextStep();
}
@@ -161,10 +172,15 @@ void LocalPlayer::pickUp(FloorItem *item)
void LocalPlayer::walk(unsigned char dir)
{
+ if (mWalkingDir != dir)
+ {
+ mWalkingDir = dir;
+ }
+
if (!mMap || !dir)
return;
- if (mAction == WALK)
+ if (mAction == WALK && !mPath.empty())
{
// Just finish the current action, otherwise we get out of sync
Being::setDestination(mX, mY);
@@ -198,10 +214,8 @@ void LocalPlayer::walk(unsigned char dir)
}
else if (dir)
{
- // Update the player direction to where he wants to walk
- // Warning: Not communicated to the server yet
-
// If the being can't move, just change direction
+ // TODO: Communicate this to the server (waiting on tmwserv)
setDirection(dir);
}
}
@@ -216,10 +230,16 @@ void LocalPlayer::setDestination(Uint16 x, Uint16 y)
x = tx * 32 + fx;
y = ty * 32 + fy;
- Net::GameServer::Player::walk(x, y);
+ // Only send a new message to the server when destination changes
+ if (x != mDestX || y != mDestY)
+ {
+ mDestX = x;
+ mDestY = y;
- mPickUpTarget = NULL;
+ Net::GameServer::Player::walk(x, y);
+ }
+ mPickUpTarget = NULL;
Being::setDestination(x, y);
}
diff --git a/src/localplayer.h b/src/localplayer.h
index dbf2a147..f632b1b9 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -47,6 +47,11 @@ class LocalPlayer : public Player
virtual ~LocalPlayer();
virtual void logic();
+
+ /**
+ * Adds a new step when walking before calling super. Also, when
+ * specified it picks up an item at the end of a path.
+ */
virtual void nextStep();
/**
@@ -151,7 +156,10 @@ class LocalPlayer : public Player
FloorItem *mPickUpTarget;
bool mTrading;
- int mLastAction; /**< Time stamp of the last action, -1 if none */
+ int mLastAction; /**< Time stamp of the last action, -1 if none. */
+ int mWalkingDir; /**< The direction the player is walking in. */
+ int mDestX; /**< X coordinate of destination. */
+ int mDestY; /**< Y coordinate of destination. */
};
extern LocalPlayer *player_node;
diff --git a/src/log.cpp b/src/log.cpp
index 07eb55f7..3a3c91b8 100644
--- a/src/log.cpp
+++ b/src/log.cpp
@@ -21,7 +21,9 @@
#include "log.h"
#ifdef WIN32
-#include <windows.h>
+ #include "utils/wingettimeofday.h"
+#else
+ #include <sys/time.h>
#endif
#ifdef __APPLE__
#include <Carbon/Carbon.h>
@@ -64,7 +66,6 @@ void Logger::log(const char *log_text, ...)
char* buf = new char[1024];
va_list ap;
- time_t t;
// Use a temporary buffer to fill in the variables
va_start(ap, log_text);
@@ -72,19 +73,23 @@ void Logger::log(const char *log_text, ...)
va_end(ap);
// Get the current system time
- time(&t);
+ timeval tv;
+ gettimeofday(&tv, NULL);
// Print the log entry
std::stringstream timeStr;
timeStr << "["
- << ((((t / 60) / 60) % 24 < 10) ? "0" : "")
- << (int)(((t / 60) / 60) % 24)
+ << ((((tv.tv_sec / 60) / 60) % 24 < 10) ? "0" : "")
+ << (int)(((tv.tv_sec / 60) / 60) % 24)
<< ":"
- << (((t / 60) % 60 < 10) ? "0" : "")
- << (int)((t / 60) % 60)
+ << (((tv.tv_sec / 60) % 60 < 10) ? "0" : "")
+ << (int)((tv.tv_sec / 60) % 60)
<< ":"
- << ((t % 60 < 10) ? "0" : "")
- << (int)(t % 60)
+ << ((tv.tv_sec % 60 < 10) ? "0" : "")
+ << (int)(tv.tv_sec % 60)
+ << "."
+ << (((tv.tv_usec / 10000) % 100) < 10 ? "0" : "")
+ << (int)((tv.tv_usec / 10000) % 100)
<< "] ";
mLogFile << timeStr.str() << buf << std::endl;
diff --git a/src/main.cpp b/src/main.cpp
index 59bb1566..90368b7d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -76,7 +76,10 @@
#include "net/gameserver/gameserver.h"
+#include "resources/equipmentdb.h"
#include "resources/image.h"
+#include "resources/itemdb.h"
+#include "resources/monsterdb.h"
#include "resources/resourcemanager.h"
#include "resources/spriteset.h"
@@ -87,8 +90,6 @@
char n_character;
std::string token;
-std::vector<Spriteset *> hairset;
-Spriteset *playerset[2];
Graphics *graphics;
unsigned char state;
@@ -171,6 +172,7 @@ void initHomeDir()
void initConfiguration(const Options &options)
{
// Fill configuration with defaults
+ logger->log("Initializing configuration...");
config.setValue("host", "animesites.de");
config.setValue("port", 9601);
config.setValue("hwaccel", 0);
@@ -219,6 +221,7 @@ void initConfiguration(const Options &options)
void init_engine()
{
// Initialize SDL
+ logger->log("Initializing SDL...");
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
std::cerr << "Could not initialize SDL: " <<
SDL_GetError() << std::endl;
@@ -288,26 +291,6 @@ void init_engine()
// Initialize for drawing
graphics->_beginDraw();
- playerset[0] = resman->getSpriteset(
- "graphics/sprites/player_male_base.png", 64, 64);
- if (!playerset[0]) logger->error("Couldn't load male player spriteset!");
- playerset[1] = resman->getSpriteset(
- "graphics/sprites/player_female_base.png", 64, 64);
- if (!playerset[1]) logger->error("Couldn't load female player spriteset!");
-
-
- for (int i = 0; i < NR_HAIR_STYLES - 1; i++)
- {
- Spriteset *tmp = ResourceManager::getInstance()->getSpriteset(
- "graphics/sprites/hairstyle" + toString(i + 1) + ".png",
- 40, 40);
- if (!tmp) {
- logger->error("Unable to load hairstyle");
- } else {
- hairset.push_back(tmp);
- }
- }
-
gui = new Gui(graphics);
state = STATE_CHOOSE_SERVER; /**< Initial game state */
@@ -316,8 +299,9 @@ void init_engine()
if (config.getValue("sound", 0) == 1) {
sound.init();
}
- sound.setSfxVolume((int)config.getValue("sfxVolume", defaultSfxVolume));
- sound.setMusicVolume((int)config.getValue("musicVolume",
+ sound.setSfxVolume((int) config.getValue("sfxVolume",
+ defaultSfxVolume));
+ sound.setMusicVolume((int) config.getValue("musicVolume",
defaultMusicVolume));
}
catch (const char *err) {
@@ -325,6 +309,11 @@ void init_engine()
errorMessage = err;
logger->log("Warning: %s", err);
}
+
+ // Load XML databases
+ EquipmentDB::load();
+ ItemDB::load();
+ MonsterDB::load();
}
/** Clear the engine */
@@ -334,19 +323,17 @@ void exit_engine()
delete gui;
delete graphics;
- std::for_each(hairset.begin(), hairset.end(),
- std::mem_fun(&Spriteset::decRef));
- hairset.clear();
-
- playerset[0]->decRef();
- playerset[1]->decRef();
-
// Shutdown libxml
xmlCleanupParser();
// Shutdown sound
sound.close();
+ // Unload XML databases
+ EquipmentDB::unload();
+ ItemDB::unload();
+ MonsterDB::unload();
+
ResourceManager::deleteInstance();
}
@@ -599,7 +586,7 @@ int main(int argc, char *argv[])
gui->logic();
Net::flush();
- if (state > STATE_CONNECT_ACCOUNT && state < STATE_GAME)
+ if (state > STATE_CONNECT_ACCOUNT && state < STATE_GAME)
{
if (!accountServerConnection->isConnected())
{
diff --git a/src/map.cpp b/src/map.cpp
index 1cdc1077..1bd8f235 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -282,35 +282,35 @@ Map::setWalk(int x, int y, bool walkable)
bool
Map::getWalk(int x, int y)
{
- // Check for being walkable
- if (tileCollides(x, y)) {
- return false;
- }
+ return !tileCollides(x, y) && !occupied(x, y);
+}
- /*
- // Check for collision with a being
+bool
+Map::occupied(int x, int y)
+{
Beings &beings = beingManager->getAll();
- for (BeingIterator i = beings.begin(); i != beings.end(); i++) {
+ for (BeingIterator i = beings.begin(); i != beings.end(); i++)
+ {
// job 45 is a portal, they don't collide
- if ((*i)->mX / 32 == x && (*i)->mY / 32 == y && (*i)->mJob != 45) {
- return false;
+ if ((*i)->mX / 32 == x && (*i)->mY / 32 == y && (*i)->mJob != 45)
+ {
+ return true;
}
}
- */
- return true;
+ return false;
}
bool
Map::tileCollides(int x, int y)
{
- // You can't walk outside of the map
- if (x < 0 || y < 0 || x >= mWidth || y >= mHeight) {
- return true;
- }
+ return !(contains(x, y) && mMetaTiles[x + y * mWidth].walkable);
+}
- // Check if the tile is walkable
- return !mMetaTiles[x + y * mWidth].walkable;
+bool
+Map::contains(int x, int y)
+{
+ return x >= 0 && y >= 0 && x < mWidth && y < mHeight;
}
void
@@ -355,8 +355,9 @@ Map::findPath(int startX, int startY, int destX, int destY)
// Declare open list, a list with open tiles sorted on F cost
std::priority_queue<Location> openList;
- // Return empty path when destination not walkable
- if (!getWalk(destX, destY)) return path;
+ // Return empty path when destination collides
+ if (tileCollides(destX, destY))
+ return path;
// Reset starting tile's G cost to 0
MetaTile *startTile = getMetaTile(startX, startY);
@@ -395,16 +396,15 @@ Map::findPath(int startX, int startY, int destX, int destY)
// Skip if if we're checking the same tile we're leaving from,
// or if the new location falls outside of the map boundaries
- if ((dx == 0 && dy == 0) ||
- (x < 0 || y < 0 || x >= mWidth || y >= mHeight))
+ if ((dx == 0 && dy == 0) || !contains(x, y))
{
continue;
}
MetaTile *newTile = getMetaTile(x, y);
- // Skip if the tile is on the closed list or is not walkable
- if (newTile->whichList == mOnClosedList || !getWalk(x, y))
+ // Skip if the tile is on the closed list or collides
+ if (newTile->whichList == mOnClosedList || tileCollides(x, y))
{
continue;
}
@@ -441,6 +441,13 @@ Map::findPath(int startX, int startY, int destX, int destY)
++Gcost;
}
+ // It costs extra to walk through a being (needs to be enough
+ // to make it more attractive to walk around).
+ if (occupied(x, y))
+ {
+ Gcost += 30;
+ }
+
// Skip if Gcost becomes too much
// Warning: probably not entirely accurate
if (Gcost > 20 * basicCost)
diff --git a/src/map.h b/src/map.h
index 961326b8..15b9b0dc 100644
--- a/src/map.h
+++ b/src/map.h
@@ -129,7 +129,7 @@ class Map : public Properties
MetaTile *getMetaTile(int x, int y);
/**
- * Set walkability flag for a tile
+ * Set walkability flag for a tile.
*/
void setWalk(int x, int y, bool walkable);
@@ -199,6 +199,16 @@ class Map : public Properties
Tileset*
getTilesetWithGid(int gid);
+ /**
+ * Tells whether a tile is occupied by a being.
+ */
+ bool occupied(int x, int y);
+
+ /**
+ * Tells whether the given coordinates fall within the map boundaries.
+ */
+ bool contains(int x, int y);
+
int mWidth, mHeight;
int mTileWidth, mTileHeight;
MetaTile *mMetaTiles;
diff --git a/src/monster.cpp b/src/monster.cpp
index a4317e5e..f2e4d93d 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -25,6 +25,9 @@
#include "animatedsprite.h"
#include "game.h"
+#include "sound.h"
+
+#include "resources/monsterdb.h"
#include "utils/tostring.h"
@@ -32,7 +35,8 @@
Monster::Monster(Uint16 id, Uint16 job, Map *map):
Being(id, job, map)
{
- mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/monster" + toString(job - 1002) + ".xml", 0);
+ mSprites[BASE_SPRITE] = new AnimatedSprite(
+ "graphics/sprites/" + MonsterDB::get(job - 1002).getSprite());
}
Being::Type
@@ -41,3 +45,36 @@ Monster::getType() const
return MONSTER;
}
+void
+Monster::setAction(Uint8 action)
+{
+ SpriteAction currentAction = ACTION_INVALID;
+
+ switch (action)
+ {
+ case WALK:
+ currentAction = ACTION_WALK;
+ break;
+ case DEAD:
+ currentAction = ACTION_DEAD;
+ sound.playSfx(MonsterDB::get(mJob - 1002).getSound(EVENT_DIE));
+ break;
+ case ATTACK:
+ currentAction = ACTION_ATTACK;
+ sound.playSfx(MonsterDB::get(mJob - 1002).getSound(EVENT_HIT));
+ mSprites[BASE_SPRITE]->reset();
+ break;
+ case STAND:
+ currentAction = ACTION_STAND;
+ break;
+ case HURT:
+ // Not implemented yet
+ break;
+ }
+
+ if (currentAction != ACTION_INVALID)
+ {
+ mSprites[BASE_SPRITE]->play(currentAction);
+ mAction = action;
+ }
+}
diff --git a/src/monster.h b/src/monster.h
index 0314a035..7f129e14 100644
--- a/src/monster.h
+++ b/src/monster.h
@@ -31,6 +31,8 @@ class Monster : public Being
public:
Monster(Uint16 id, Uint16 job, Map *map);
+ virtual void setAction(Uint8 action);
+
virtual Type getType() const;
};
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
index 2d68dd28..6d8ff6c6 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -66,6 +66,7 @@ void BeingHandler::handleMessage(MessageIn &msg)
/*
Uint32 id;
Uint16 job, speed;
+ Uint16 headBottom, headTop, headMid;
Sint16 param1;
Sint8 type;
Being *srcBeing, *dstBeing;
@@ -124,7 +125,8 @@ void BeingHandler::handleMessage(MessageIn &msg)
dstBeing->mJob = job;
dstBeing->setHairStyle(msg.readShort());
dstBeing->setWeapon(msg.readShort());
- dstBeing->setVisibleEquipment(3, msg.readShort()); // head bottom
+ dstBeing->setVisibleEquipment(
+ Being::BOTTOMCLOTHES_SPRITE, msg.readShort());
if (msg.getId() == SMSG_BEING_MOVE)
{
@@ -132,8 +134,9 @@ void BeingHandler::handleMessage(MessageIn &msg)
}
msg.readShort(); // shield
- dstBeing->setVisibleEquipment(4, msg.readShort()); // head top
- dstBeing->setVisibleEquipment(5, msg.readShort()); // head mid
+ dstBeing->setVisibleEquipment(Being::HAIT_SPRITE, msg.readShort());
+ dstBeing->setVisibleEquipment(
+ Being::TOPCLOTHES_SPRITE, msg.readShort());
dstBeing->setHairColor(msg.readShort());
msg.readShort(); // unknown
msg.readShort(); // head dir
@@ -156,7 +159,9 @@ void BeingHandler::handleMessage(MessageIn &msg)
}
else
{
- //msg.readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection);
+ //Uint8 dir;
+ //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir);
+ //dstBeing->setDirection(dir);
}
msg.readByte(); // unknown
@@ -173,19 +178,7 @@ void BeingHandler::handleMessage(MessageIn &msg)
if (msg.readByte() == 1)
{
- // Death
- switch (dstBeing->getType())
- {
- case Being::MONSTER:
- dstBeing->setAction(Being::MONSTER_DEAD);
- dstBeing->mFrame = 0;
- dstBeing->mWalkTime = tick_time;
- break;
-
- default:
- dstBeing->setAction(Being::DEAD);
- break;
- }
+ dstBeing->setAction(Being::DEAD);
}
else
{
@@ -219,15 +212,7 @@ void BeingHandler::handleMessage(MessageIn &msg)
if (srcBeing != NULL &&
srcBeing != player_node)
{
- // buggy
- if (srcBeing->getType() == Being::MONSTER)
- {
- srcBeing->setAction(Being::MONSTER_ATTACK);
- }
- else
- {
- srcBeing->setAction(Being::ATTACK);
- }
+ srcBeing->setAction(Being::ATTACK);
srcBeing->mFrame = 0;
srcBeing->mWalkTime = tick_time;
}
@@ -275,27 +260,35 @@ void BeingHandler::handleMessage(MessageIn &msg)
}
int type = msg.readByte();
+ int id = msg.readByte();
switch (type) {
case 1:
- dstBeing->setHairStyle(msg.readByte());
+ dstBeing->setHairStyle(id);
break;
case 2:
- dstBeing->setWeapon(msg.readByte());
+ dstBeing->setWeapon(id);
+ break;
+ case 3: // Change lower headgear for eAthena, pants for us
+ dstBeing->setVisibleEquipment(
+ Being::BOTTOMCLOTHES_SPRITE,
+ id);
+ break;
+ case 4: // Change upper headgear for eAthena, hat for us
+ dstBeing->setVisibleEquipment(
+ Being::HAT_SPRITE,
+ id);
break;
- case 3:
- case 4:
- case 5:
- // Equip/unequip head 3. Bottom 4. Top 5. Middle
- dstBeing->setVisibleEquipment(type, msg.readByte());
- // First 3 slots of mVisibleEquipments are reserved for
- // later use, probably accessories.
+ case 5: // Change middle headgear for eathena, armor for us
+ dstBeing->setVisibleEquipment(
+ Being::TOPCLOTHES_SPRITE,
+ id);
break;
case 6:
- dstBeing->setHairColor(msg.readByte());
+ dstBeing->setHairColor(id);
break;
default:
- printf("c3: %i\n", msg.readByte()); // unsupported
+ logger->log("c3: %i\n", id); // unsupported
break;
}
}
@@ -331,15 +324,15 @@ void BeingHandler::handleMessage(MessageIn &msg)
dstBeing->setHairStyle(msg.readShort());
dstBeing->setWeaponById(msg.readShort()); // item id 1
msg.readShort(); // item id 2
- dstBeing->setVisibleEquipment(3, msg.readShort()); // head bottom
+ headBottom = msg.readShort();
if (msg.getId() == SMSG_PLAYER_MOVE)
{
msg.readLong(); // server tick
}
- dstBeing->setVisibleEquipment(4, msg.readShort()); // head top
- dstBeing->setVisibleEquipment(5, msg.readShort()); // head mid
+ headTop = msg.readShort();
+ headMid = msg.readShort();
dstBeing->setHairColor(msg.readShort());
msg.readShort(); // unknown
msg.readShort(); // head dir
@@ -348,6 +341,10 @@ void BeingHandler::handleMessage(MessageIn &msg)
msg.readShort(); // manner
msg.readByte(); // karma
dstBeing->setSex(1 - msg.readByte()); // sex
+ dstBeing->setVisibleEquipment(
+ Being::BOTTOMCLOTHES_SPRITE, headBottom);
+ dstBeing->setVisibleEquipment(Being::HAT_SPRITE, headTop);
+ dstBeing->setVisibleEquipment(Being::TOPCLOTHES_SPRITE, headMid);
if (msg.getId() == SMSG_PLAYER_MOVE)
{
@@ -359,7 +356,9 @@ void BeingHandler::handleMessage(MessageIn &msg)
}
else
{
- //msg.readCoordinates(dstBeing->mX, dstBeing->mY, dstBeing->mDirection);
+ //Uint8 dir;
+ //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir);
+ //dstBeing->setDirection(dir);
}
msg.readByte(); // unknown
@@ -386,7 +385,7 @@ void BeingHandler::handleMessage(MessageIn &msg)
case 0x0119:
// Change in players look
- printf("0x0119 %li %i %i %x %i\n", msg.readLong(),
+ logger->log("0x0119 %li %i %i %x %i\n", msg.readLong(),
msg.readShort(), msg.readShort(), msg.readShort(),
msg.readByte());
break;
diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp
index 3f7e8709..f003d77a 100644
--- a/src/net/inventoryhandler.cpp
+++ b/src/net/inventoryhandler.cpp
@@ -92,7 +92,7 @@ void InventoryHandler::handleMessage(MessageIn &msg)
if (msg.readByte()> 0) {
chatWindow->chatLog("Unable to pick up item", BY_SERVER);
} else {
- const ItemInfo &itemInfo = itemDb->getItemInfo(itemId);
+ const ItemInfo &itemInfo = ItemDB::get(itemId);
chatWindow->chatLog("You picked up a " +
itemInfo.getName(), BY_SERVER);
player_node->addInvItem(index, itemId, amount, equipType != 0);
diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp
index 9c89e71f..02204a84 100644
--- a/src/net/npchandler.cpp
+++ b/src/net/npchandler.cpp
@@ -49,20 +49,22 @@ NPCHandler::NPCHandler()
void NPCHandler::handleMessage(MessageIn &msg)
{
+ int id;
+
switch (msg.getId())
{
case SMSG_NPC_CHOICE:
msg.readShort(); // length
- current_npc = dynamic_cast<NPC*>(
- beingManager->findBeing(msg.readLong()));
+ id = msg.readLong();
+ current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
npcListDialog->parseItems(msg.readString(msg.getLength() - 8));
npcListDialog->setVisible(true);
break;
case SMSG_NPC_MESSAGE:
msg.readShort(); // length
- current_npc = dynamic_cast<NPC*>(
- beingManager->findBeing(msg.readLong()));
+ id = msg.readLong();
+ current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
npcTextDialog->addText(msg.readString(msg.getLength() - 8));
npcListDialog->setVisible(false);
npcTextDialog->setVisible(true);
diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp
index 6eb80d59..37291c0a 100644
--- a/src/net/playerhandler.cpp
+++ b/src/net/playerhandler.cpp
@@ -46,7 +46,8 @@ OkDialog *deathNotice = NULL;
namespace {
struct WeightListener : public gcn::ActionListener
{
- void action(const std::string &eventId, gcn::Widget *widget) {
+ void action(const std::string &eventId, gcn::Widget *widget)
+ {
weightNotice = NULL;
}
} weightListener;
@@ -57,8 +58,10 @@ namespace {
*/
// TODO Move somewhere else
namespace {
- struct DeathListener : public gcn::ActionListener {
- void action(const std::string &eventId, gcn::Widget *widget) {
+ struct DeathListener : public gcn::ActionListener
+ {
+ void action(const std::string &eventId, gcn::Widget *widget)
+ {
player_node->revive();
deathNotice = NULL;
}
@@ -114,10 +117,11 @@ void PlayerHandler::handleMessage(MessageIn &msg)
player_node->mMaxWeight / 2)
{
weightNotice = new OkDialog("Message",
- "You are carrying more then half your "
- "weight. You are unable to regain "
- "health.");
- weightNotice->addActionListener(&weightListener);
+ "You are carrying more then half "
+ "your weight. You are unable to "
+ "regain health.");
+ weightNotice->addActionListener(
+ &weightListener);
}
player_node->mTotalWeight = value;
break;
diff --git a/src/net/skillhandler.cpp b/src/net/skillhandler.cpp
index d9bea775..17dea606 100644
--- a/src/net/skillhandler.cpp
+++ b/src/net/skillhandler.cpp
@@ -26,6 +26,8 @@
#include "messagein.h"
#include "protocol.h"
+#include "../log.h"
+
#include "../gui/chat.h"
#include "../gui/skill.h"
@@ -85,7 +87,7 @@ void SkillHandler::handleMessage(MessageIn &msg)
if (action.success != SKILL_FAILED &&
action.bskill == BSKILL_EMOTE)
{
- printf("Action: %d/%d", action.bskill, action.success);
+ logger->log("Action: %d/%d", action.bskill, action.success);
}
chatWindow->chatLog(action);
break;
diff --git a/src/npc.cpp b/src/npc.cpp
index 3bd4371b..3c142889 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -24,6 +24,9 @@
#include "npc.h"
#include "animatedsprite.h"
+#include "graphics.h"
+
+#include "gui/gui.h"
class Spriteset;
extern Spriteset *npcset;
@@ -33,7 +36,8 @@ NPC *current_npc = 0;
NPC::NPC(Uint16 id, Uint16 job, Map *map):
Being(id, job, map)
{
- mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/npc.xml", job-100);
+ mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/npc.xml",
+ job - 100);
}
Being::Type
@@ -43,6 +47,17 @@ NPC::getType() const
}
void
+NPC::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY)
+{
+ int px = mPx + offsetX;
+ int py = mPy + offsetY;
+
+ graphics->setFont(speechFont);
+ graphics->setColor(gcn::Color(200, 200, 255));
+ graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER);
+}
+
+void
NPC::talk()
{
// XXX Convert for new server
diff --git a/src/npc.h b/src/npc.h
index 3b61123b..cf5defbc 100644
--- a/src/npc.h
+++ b/src/npc.h
@@ -26,12 +26,18 @@
#include "being.h"
+class Graphics;
+
class NPC : public Being
{
public:
NPC(Uint16 id, Uint16 job, Map *map);
- virtual Type getType() const;
+ virtual Type
+ getType() const;
+
+ virtual void
+ drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY);
void talk();
void nextDialog();
diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp
index 05bbb6b3..ec6c1ee3 100644
--- a/src/openglgraphics.cpp
+++ b/src/openglgraphics.cpp
@@ -52,6 +52,9 @@ OpenGLGraphics::~OpenGLGraphics()
bool OpenGLGraphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
{
+ logger->log("Setting video mode %dx%d %s",
+ w, h, fs ? "fullscreen" : "windowed");
+
int displayFlags = SDL_ANYFORMAT | SDL_OPENGL;
mFullscreen = fs;
diff --git a/src/player.cpp b/src/player.cpp
index 0acf8262..63ed5455 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -28,6 +28,8 @@
#include "graphics.h"
#include "log.h"
+#include "resources/equipmentdb.h"
+
#include "utils/tostring.h"
#include "gui/gui.h"
@@ -35,9 +37,6 @@
Player::Player(Uint16 id, Uint16 job, Map *map):
Being(id, job, map)
{
- // Load the weapon sprite.
- // When there are more different weapons this should be moved to the
- // setWeapon Method.
setWeapon(0);
}
@@ -70,52 +69,72 @@ Player::setSex(Uint8 sex)
if (sex != mSex)
{
- delete mSprites[BASE_SPRITE];
+ Being::setSex(sex);
+
+ // Reload base sprite
+ AnimatedSprite *newBaseSprite;
if (sex == 0)
{
- mSprites[BASE_SPRITE] = new AnimatedSprite(
- "graphics/sprites/player_male_base.xml", 0);
+ newBaseSprite = new AnimatedSprite(
+ "graphics/sprites/player_male_base.xml");
}
else
{
- mSprites[BASE_SPRITE] = new AnimatedSprite(
- "graphics/sprites/player_female_base.xml", 0);
+ newBaseSprite = new AnimatedSprite(
+ "graphics/sprites/player_female_base.xml");
}
- Being::setSex(sex);
- resetAnimations();
+ delete mSprites[BASE_SPRITE];
+ mSprites[BASE_SPRITE] = newBaseSprite;
+
+ // Reload equipment
+ for (int i = 1; i < VECTOREND_SPRITE; i++)
+ {
+ if (i != HAIR_SPRITE && mEquipmentSpriteIDs.at(i) != 0)
+ {
+ AnimatedSprite *newEqSprite = new AnimatedSprite(
+ "graphics/sprites/" + EquipmentDB::get(
+ mEquipmentSpriteIDs.at(i))->getSprite(sex));
+ delete mSprites[i];
+ mSprites[i] = newEqSprite;
+ }
+ }
}
}
-
void
Player::setWeapon(Uint16 weapon)
{
if (weapon != mWeapon)
{
- delete mSprites[WEAPON_SPRITE];
- mSprites[WEAPON_SPRITE] = NULL;
+ AnimatedSprite *newWeaponSprite = NULL;
switch (weapon)
{
case 0:
- mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-fist.xml", 0);
+ newWeaponSprite =
+ new AnimatedSprite("graphics/sprites/weapon-fist.xml");
break;
case 1:
- mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-dagger.xml", 0);
+ newWeaponSprite =
+ new AnimatedSprite("graphics/sprites/weapon-dagger.xml");
break;
case 2:
- mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-bow.xml", 0);
+ newWeaponSprite =
+ new AnimatedSprite("graphics/sprites/weapon-bow.xml");
break;
case 3:
- mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapon-scythe.xml", 0);
+ newWeaponSprite =
+ new AnimatedSprite("graphics/sprites/weapon-scythe.xml");
break;
}
+
+ delete mSprites[WEAPON_SPRITE];
+ mSprites[WEAPON_SPRITE] = newWeaponSprite;
}
Being::setWeapon(weapon);
}
-
void
Player::setHairColor(Uint16 color)
{
@@ -128,7 +147,6 @@ Player::setHairColor(Uint16 color)
delete mSprites[HAIR_SPRITE];
mSprites[HAIR_SPRITE] = newHairSprite;
- resetAnimations();
setAction(mAction);
}
@@ -148,7 +166,6 @@ Player::setHairStyle(Uint16 style)
delete mSprites[HAIR_SPRITE];
mSprites[HAIR_SPRITE] = newHairSprite;
- resetAnimations();
setAction(mAction);
}
@@ -157,55 +174,35 @@ Player::setHairStyle(Uint16 style)
}
void
-Player::setVisibleEquipment(Uint8 slot, Uint8 id)
+Player::setVisibleEquipment(Uint8 slot, int id)
{
- // Translate eAthena specific slot
- Uint8 position = 0;
- switch (slot) {
- case 3:
- position = BOTTOMCLOTHES_SPRITE;
- break;
- case 4:
- position = HAT_SPRITE;
- break;
- case 5:
- position = TOPCLOTHES_SPRITE;
- break;
- }
-
// id = 0 means unequip
if (id == 0)
{
- delete mSprites[position];
- mSprites[position] = NULL;
+ delete mSprites[slot];
+ mSprites[slot] = NULL;
}
else
{
- char stringId[4];
- sprintf(stringId, "%03i", id);
+ AnimatedSprite *equipmentSprite;
+
+ if (mSex == 0)
+ {
+ equipmentSprite = new AnimatedSprite(
+ "graphics/sprites/" + EquipmentDB::get(id)->getSprite(0));
+ }
+ else {
+ equipmentSprite = new AnimatedSprite(
+ "graphics/sprites/" + EquipmentDB::get(id)->getSprite(1));
+ }
- AnimatedSprite *equipmentSprite = new AnimatedSprite(
- "graphics/sprites/item" + toString(stringId) + ".xml", 0);
equipmentSprite->setDirection(getSpriteDirection());
- delete mSprites[position];
- mSprites[position] = equipmentSprite;
- resetAnimations();
+ delete mSprites[slot];
+ mSprites[slot] = equipmentSprite;
setAction(mAction);
}
Being::setVisibleEquipment(slot, id);
}
-
-void
-Player::resetAnimations()
-{
- for (int i = 0; i < VECTOREND_SPRITE; i++)
- {
- if (mSprites[i] != NULL)
- {
- mSprites[i]->reset();
- }
- }
-}
diff --git a/src/player.h b/src/player.h
index 3c061be6..b062a55f 100644
--- a/src/player.h
+++ b/src/player.h
@@ -26,12 +26,14 @@
#include "being.h"
-#include <string>
-
class Graphics;
class Map;
-class AnimatedSprite;
+/**
+ * A player being. Players have their name drawn beneath them. This class also
+ * implements player-specific loading of base sprite, hair sprite and equipment
+ * sprites.
+ */
class Player : public Being
{
public:
@@ -56,18 +58,10 @@ class Player : public Being
setHairStyle(Uint16 style);
virtual void
- setVisibleEquipment(Uint8 slot, Uint8 id);
+ setVisibleEquipment(Uint8 slot, int id);
virtual void
setWeapon(Uint16 weapon);
-
- private:
- /**
- * Resets all animations associated with this player. This is used to
- * synchronize the animations after a new one has been added.
- */
- void
- resetAnimations();
};
#endif
diff --git a/src/resources/equipmentdb.cpp b/src/resources/equipmentdb.cpp
new file mode 100644
index 00000000..78ae3b6a
--- /dev/null
+++ b/src/resources/equipmentdb.cpp
@@ -0,0 +1,158 @@
+/*
+ * The Mana World
+ * Copyright 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id:
+ */
+
+#include "equipmentdb.h"
+
+#include "resourcemanager.h"
+
+#include "../log.h"
+
+#include "../utils/dtor.h"
+#include "../utils/xml.h"
+
+namespace
+{
+ EquipmentDB::EquipmentInfos mEquipmentInfos;
+ EquipmentInfo mUnknown;
+ bool mLoaded = false;
+}
+
+void
+EquipmentDB::load()
+{
+ logger->log("Initializing equipment database...");
+ mUnknown.setSprite("error.xml", 0);
+ mUnknown.setSprite("error.xml", 1);
+
+ ResourceManager *resman = ResourceManager::getInstance();
+ int size;
+ char *data = (char*)resman->loadFile("equipment.xml", size);
+
+ if (!data)
+ {
+ logger->error("Equipment Database: Could not find equipment.xml!");
+ }
+
+ xmlDocPtr doc = xmlParseMemory(data, size);
+ free(data);
+
+ if (!doc)
+ {
+ logger->error("Equipment Database: Error while parsing equipment database (equipment.xml)!");
+ }
+
+ xmlNodePtr rootNode = xmlDocGetRootElement(doc);
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "equipments"))
+ {
+ logger->error("Equipment Database: equipment.xml is not a valid database file!");
+ }
+
+ //iterate <equipment>s
+ for ( xmlNodePtr equipmentNode = rootNode->xmlChildrenNode;
+ equipmentNode != NULL;
+ equipmentNode = equipmentNode->next)
+ {
+
+ if (!xmlStrEqual(equipmentNode->name, BAD_CAST "equipment"))
+ {
+ continue;
+ }
+
+ EquipmentInfo *currentInfo = new EquipmentInfo();
+
+ currentInfo->setSlot (XML::getProperty(equipmentNode, "slot", 0));
+
+ //iterate <sprite>s
+ for ( xmlNodePtr spriteNode = equipmentNode->xmlChildrenNode;
+ spriteNode != NULL;
+ spriteNode = spriteNode->next)
+ {
+ if (!xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
+ {
+ continue;
+ }
+
+ std::string gender = XML::getProperty(spriteNode, "gender", "unisex");
+ std::string filename = (const char*) spriteNode->xmlChildrenNode->content;
+
+ if (gender == "male" || gender == "unisex")
+ {
+ currentInfo->setSprite(filename, 0);
+ }
+
+ if (gender == "female" || gender == "unisex")
+ {
+ currentInfo->setSprite(filename, 1);
+ }
+ }
+
+ setEquipment( XML::getProperty(equipmentNode, "id", 0),
+ currentInfo);
+ }
+
+ mLoaded = true;
+}
+
+void
+EquipmentDB::unload()
+{
+ // kill EquipmentInfos
+ for_each ( mEquipmentInfos.begin(), mEquipmentInfos.end(),
+ make_dtor(mEquipmentInfos));
+ mEquipmentInfos.clear();
+
+ mLoaded = false;
+}
+
+EquipmentInfo*
+EquipmentDB::get(int id)
+{
+ if (!mLoaded) {
+ logger->error("Error: Equipment database used before initialization!");
+ }
+
+ EquipmentInfoIterator i = mEquipmentInfos.find(id);
+
+ if (i == mEquipmentInfos.end() )
+ {
+ logger->log("EquipmentDB: Error, unknown equipment ID# %d", id);
+ return &mUnknown;
+ }
+ else
+ {
+ return i->second;
+ }
+}
+
+void
+EquipmentDB::setEquipment(int id, EquipmentInfo* equipmentInfo)
+{
+ if (mEquipmentInfos.find(id) != mEquipmentInfos.end()) {
+ logger->log("Warning: Equipment Piece with ID %d defined multiple times",
+ id);
+ delete equipmentInfo;
+ }
+ else {
+ mEquipmentInfos[id] = equipmentInfo;
+ };
+}
diff --git a/src/resources/equipmentdb.h b/src/resources/equipmentdb.h
new file mode 100644
index 00000000..b8618f5f
--- /dev/null
+++ b/src/resources/equipmentdb.h
@@ -0,0 +1,52 @@
+/*
+ * The Mana World
+ * Copyright 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id:
+ */
+
+#ifndef _TMW_EQUIPMENT_DB_H
+#define _TMW_EQUIPMENT_DB_H
+
+#include <map>
+
+#include "equipmentinfo.h"
+
+namespace EquipmentDB
+{
+ /**
+ * Loads the equipment info from Items.xml
+ */
+ void load();
+
+ /**
+ * Frees equipment data
+ */
+ void unload();
+
+ void setEquipment(int id, EquipmentInfo* equipmentInfo);
+
+ EquipmentInfo* get(int id);
+
+ // Equipment database types
+ typedef std::map<int, EquipmentInfo*> EquipmentInfos;
+ typedef EquipmentInfos::iterator EquipmentInfoIterator;
+}
+
+#endif
diff --git a/src/resources/equipmentinfo.h b/src/resources/equipmentinfo.h
new file mode 100644
index 00000000..93a1cb42
--- /dev/null
+++ b/src/resources/equipmentinfo.h
@@ -0,0 +1,52 @@
+/*
+ * The Mana World
+ * Copyright 2006 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id:
+ */
+
+#ifndef _TMW_EQUIPMENTINFO_H_
+#define _TMW_EQUIPMENTINFO_H_
+
+#include <string>
+#include <map>
+
+class EquipmentInfo
+{
+ public:
+ EquipmentInfo():
+ mSlot (0)
+ {
+ };
+
+ void
+ setSlot (int slot) { mSlot = slot; };
+
+ const std::string&
+ getSprite(int gender) {return animationFiles[gender]; };
+
+ void
+ setSprite(std::string animationFile, int gender) {animationFiles[gender] = animationFile; };
+
+ private:
+ int mSlot; //not used at the moment but maybe useful on our own server
+ std::map<int, std::string> animationFiles;
+};
+
+#endif
diff --git a/src/resources/image.cpp b/src/resources/image.cpp
index eb3a2409..48818f6f 100644
--- a/src/resources/image.cpp
+++ b/src/resources/image.cpp
@@ -68,9 +68,17 @@ Image* Image::load(void *buffer, unsigned int bufferSize,
{
// Load the raw file data from the buffer in an RWops structure
SDL_RWops *rw = SDL_RWFromMem(buffer, bufferSize);
+ SDL_Surface *tmpImage;
// Use SDL_Image to load the raw image data and have it free the data
- SDL_Surface *tmpImage = IMG_Load_RW(rw, 1);
+ if (!idPath.compare(idPath.length() - 4, 4, ".tga"))
+ {
+ tmpImage = IMG_LoadTyped_RW(rw, 1, const_cast<char*>("TGA"));
+ }
+ else
+ {
+ tmpImage = IMG_Load_RW(rw, 1);
+ }
if (tmpImage == NULL) {
logger->log("Error, image load failed: %s", IMG_GetError());
diff --git a/src/resources/itemmanager.cpp b/src/resources/itemdb.cpp
index 7d0b13f2..b91e34cc 100644
--- a/src/resources/itemmanager.cpp
+++ b/src/resources/itemdb.cpp
@@ -1,173 +1,170 @@
-/*
- * The Mana World
- * Copyright 2004 The Mana World Development Team
- *
- * This file is part of The Mana World.
- *
- * The Mana World 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 World 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 World; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * $Id$
- */
-
-#include "itemmanager.h"
-
-#include <libxml/tree.h>
-
-#include "iteminfo.h"
-#include "resourcemanager.h"
-
-#include "../log.h"
-
-#include "../utils/dtor.h"
-
-#define READ_PROP(node, prop, name, target, cast) \
- prop = xmlGetProp(node, BAD_CAST name); \
- if (prop) { \
- target = cast((const char*)prop); \
- xmlFree(prop); \
- }
-
-ItemManager::ItemManager()
-{
- mUnknown.setName("Unknown item");
-
- ResourceManager *resman = ResourceManager::getInstance();
- int size;
- char *data = (char*)resman->loadFile("items.xml", size);
-
- if (!data) {
- logger->error("Item Manager: Could not find items.xml!");
- }
-
- xmlDocPtr doc = xmlParseMemory(data, size);
- free(data);
-
- if (!doc)
- {
- logger->error("Item Manager: Error while parsing item database (items.xml)!");
- }
-
- xmlNodePtr node = xmlDocGetRootElement(doc);
- if (!node || !xmlStrEqual(node->name, BAD_CAST "items"))
- {
- logger->error("Item Manager: items.xml is not a valid database file!");
- }
-
- for (node = node->xmlChildrenNode; node != NULL; node = node->next)
- {
- int id = 0, art = 0, type = 0, weight = 0, slot = 0;
- std::string name = "", description = "", effect = "", image = "";
-
- if (!xmlStrEqual(node->name, BAD_CAST "item")) {
- continue;
- }
-
- xmlChar *prop = NULL;
- READ_PROP(node, prop, "id", id, atoi);
- READ_PROP(node, prop, "image", image, );
- READ_PROP(node, prop, "art", art, atoi);
- READ_PROP(node, prop, "name", name, );
- READ_PROP(node, prop, "description", description, );
- READ_PROP(node, prop, "effect", effect, );
- READ_PROP(node, prop, "type", type, atoi);
- READ_PROP(node, prop, "weight", weight, atoi);
- READ_PROP(node, prop, "slot", slot, atoi);
-
-
- if (id && name != "")
- {
- ItemInfo *itemInfo = new ItemInfo();
- itemInfo->setImage(image);
- itemInfo->setArt(art);
- itemInfo->setName(name);
- itemInfo->setDescription(description);
- itemInfo->setEffect(effect);
- itemInfo->setType(type);
- itemInfo->setWeight(weight);
- itemInfo->setSlot(slot);
- mItemInfos[id] = itemInfo;
- }
-
-
- if (id == 0)
- {
- logger->log("Item Manager: An item has no ID in items.xml!");
- }
- if (name == "")
- {
- logger->log("Item Manager: An item has no name in items.xml!");
- }
-
- if (image == "")
- {
- logger->log("Item Manager: Missing image parameter for item: %i. %s",
- id, name.c_str());
- }
- /*if (art == 0)
- {
- logger->log("Item Manager: Missing art parameter for item: %i. %s",
- id, name.c_str());
- }*/
- if (description == "")
- {
- logger->log("Item Manager: Missing description parameter for item: %i. %s",
- id, name.c_str());
- }
- if (effect == "")
- {
- logger->log("Item Manager: Missing effect parameter for item: %i. %s",
- id, name.c_str());
- }
- /*if (type == 0)
- {
- logger->log("Item Manager: Missing type parameter for item: %i. %s",
- id, name.c_str());
- }*/
- if (weight == 0)
- {
- logger->log("Item Manager: Missing weight parameter for item: %i. %s",
- id, name.c_str());
- }
- if (slot == 0)
- {
- logger->log("Item Manager: Missing slot parameter for item: %i. %s",
- id, name.c_str());
- }
-
- /*logger->log("Item: %i %i %i %s %s %i %i %i", id,
- getImage(id), getArt(id), getName(id).c_str(),
- getDescription(id).c_str(), getType(id), getWeight(id),
- getSlot(id));*/
- }
-
- xmlFreeDoc(doc);
-}
-
-ItemManager::~ItemManager()
-{
- for (ItemInfoIterator i = mItemInfos.begin(); i != mItemInfos.end(); i++)
- {
- delete i->second;
- }
- mItemInfos.clear();
-}
-
-const ItemInfo&
-ItemManager::getItemInfo(int id)
-{
- ItemInfoIterator i = mItemInfos.find(id);
-
- return (i != mItemInfos.end()) ? *(i->second) : mUnknown;
-}
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id:
+ */
+
+#include "itemdb.h"
+
+#include <libxml/tree.h>
+
+#include "iteminfo.h"
+#include "resourcemanager.h"
+
+#include "../log.h"
+
+#include "../utils/dtor.h"
+#include "../utils/xml.h"
+
+namespace
+{
+ ItemDB::ItemInfos mItemInfos;
+ ItemInfo mUnknown;
+}
+
+
+void ItemDB::load()
+{
+ logger->log("Initializing item database...");
+ mUnknown.setName("Unknown item");
+
+ ResourceManager *resman = ResourceManager::getInstance();
+ int size;
+ char *data = (char*)resman->loadFile("items.xml", size);
+
+ if (!data) {
+ logger->error("ItemDB: Could not find items.xml!");
+ }
+
+ xmlDocPtr doc = xmlParseMemory(data, size);
+ free(data);
+
+ if (!doc)
+ {
+ logger->error("ItemDB: Error while parsing item database (items.xml)!");
+ }
+
+ xmlNodePtr node = xmlDocGetRootElement(doc);
+ if (!node || !xmlStrEqual(node->name, BAD_CAST "items"))
+ {
+ logger->error("ItemDB: items.xml is not a valid database file!");
+ }
+
+ for (node = node->xmlChildrenNode; node != NULL; node = node->next)
+ {
+ if (!xmlStrEqual(node->name, BAD_CAST "item")) {
+ continue;
+ }
+
+ int id = XML::getProperty(node, "id", 0);
+ int art = XML::getProperty(node, "art", 0);
+ int type = XML::getProperty(node, "type", 0);
+ int weight = XML::getProperty(node, "weight", 0);
+ int slot = XML::getProperty(node, "slot", 0);
+
+ std::string name = XML::getProperty(node, "name", "");
+ std::string image = XML::getProperty(node, "image", "");
+ std::string description = XML::getProperty(node, "description", "");
+ std::string effect = XML::getProperty(node, "effect", "");
+
+ if (id && name != "")
+ {
+ ItemInfo *itemInfo = new ItemInfo();
+ itemInfo->setImage(image);
+ itemInfo->setArt(art);
+ itemInfo->setName(name);
+ itemInfo->setDescription(description);
+ itemInfo->setEffect(effect);
+ itemInfo->setType(type);
+ itemInfo->setWeight(weight);
+ itemInfo->setSlot(slot);
+ mItemInfos[id] = itemInfo;
+ }
+
+
+ if (id == 0)
+ {
+ logger->log("ItemDB: An item has no ID in items.xml!");
+ }
+ if (name == "")
+ {
+ logger->log("ItemDB: Missing name for item %d!", id);
+ }
+
+ if (image == "")
+ {
+ logger->log("ItemDB: Missing image parameter for item: %i. %s",
+ id, name.c_str());
+ }
+ /*
+ if (art == 0)
+ {
+ logger->log("Item Manager: Missing art parameter for item: %i. %s",
+ id, name.c_str());
+ }
+ if (description == "")
+ {
+ logger->log("ItemDB: Missing description parameter for item: %i. %s",
+ id, name.c_str());
+ }
+ if (effect == "")
+ {
+ logger->log("ItemDB: Missing effect parameter for item: %i. %s",
+ id, name.c_str());
+ }
+ if (type == 0)
+ {
+ logger->log("Item Manager: Missing type parameter for item: %i. %s",
+ id, name.c_str());
+ }
+ */
+ if (weight == 0)
+ {
+ logger->log("Item Manager: Missing weight parameter for item: %i. %s",
+ id, name.c_str());
+ }
+ /*
+ if (slot == 0)
+ {
+ logger->log("Item Manager: Missing slot parameter for item: %i. %s",
+ id, name.c_str());
+ }
+ */
+ }
+
+ xmlFreeDoc(doc);
+}
+
+void ItemDB::unload()
+{
+ for (ItemInfoIterator i = mItemInfos.begin(); i != mItemInfos.end(); i++)
+ {
+ delete i->second;
+ }
+ mItemInfos.clear();
+}
+
+const ItemInfo&
+ItemDB::get(int id)
+{
+ ItemInfoIterator i = mItemInfos.find(id);
+
+ return (i != mItemInfos.end()) ? *(i->second) : mUnknown;
+}
diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h
new file mode 100644
index 00000000..5922984a
--- /dev/null
+++ b/src/resources/itemdb.h
@@ -0,0 +1,53 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: itemdb.h 2650 2006-09-03 15:00:47Z b_lindeijer $
+ */
+
+#ifndef _TMW_ITEM_MANAGER_H
+#define _TMW_ITEM_MANAGER_H
+
+#include "iteminfo.h"
+
+#include <map>
+
+/**
+ * The namespace that holds the item information
+ */
+namespace ItemDB
+{
+ /**
+ * Loads the item data from Items.xml
+ */
+ void load();
+
+ /**
+ * Frees item data
+ */
+ void unload();
+
+ const ItemInfo& get(int id);
+
+ // Items database
+ typedef std::map<int, ItemInfo*> ItemInfos;
+ typedef ItemInfos::iterator ItemInfoIterator;
+}
+
+#endif
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index 9a04bb2e..e4f851bb 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -33,8 +33,6 @@ class Image;
*/
class ItemInfo
{
- friend class ItemManager;
-
public:
/**
* Constructor.
@@ -49,6 +47,11 @@ class ItemInfo
{
}
+ /**
+ * Destructor.
+ */
+ ~ItemInfo();
+
void
setArt(short art) { mArt = art; }
@@ -101,11 +104,6 @@ class ItemInfo
getSlot() const { return mSlot; }
protected:
- /**
- * Destructor.
- */
- ~ItemInfo();
-
std::string mImageName;
/* TODO (BL): I do not think the item info should keep a reference to
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp
index 2aea3dc5..09a6eb74 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -36,6 +36,7 @@
#include "../tileset.h"
#include "../utils/tostring.h"
+#include "../utils/xml.h"
const unsigned int DEFAULT_TILE_WIDTH = 32;
const unsigned int DEFAULT_TILE_HEIGHT = 32;
@@ -205,10 +206,10 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
prop = xmlGetProp(node, BAD_CAST "version");
xmlFree(prop);
- int w = getProperty(node, "width", 0);
- int h = getProperty(node, "height", 0);
- int tilew = getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
- int tileh = getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
+ int w = XML::getProperty(node, "width", 0);
+ int h = XML::getProperty(node, "height", 0);
+ int tilew = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
+ int tileh = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
int layerNr = 0;
Map *map = new Map(w, h, tilew, tileh);
@@ -308,7 +309,7 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
int binLen;
unsigned char *binData =
- php_base64_decode(charData, strlen((char*)charData), &binLen);
+ php3_base64_decode(charData, strlen((char*)charData), &binLen);
delete[] charData;
@@ -354,7 +355,7 @@ MapReader::readLayer(xmlNodePtr node, Map *map, int layer)
if (!xmlStrEqual(n2->name, BAD_CAST "tile"))
continue;
- int gid = getProperty(n2, "gid", -1);
+ int gid = XML::getProperty(n2, "gid", -1);
map->setTileWithGid(x, y, layer, gid);
x++;
@@ -387,9 +388,9 @@ MapReader::readTileset(xmlNodePtr node,
return NULL;
}
- int firstGid = getProperty(node, "firstgid", 0);
- int tw = getProperty(node, "tilewidth", map->getTileWidth());
- int th = getProperty(node, "tileheight", map->getTileHeight());
+ int firstGid = XML::getProperty(node, "firstgid", 0);
+ int tw = XML::getProperty(node, "tilewidth", map->getTileWidth());
+ int th = XML::getProperty(node, "tileheight", map->getTileHeight());
for (node = node->xmlChildrenNode; node; node = node->next) {
if (!xmlStrEqual(node->name, BAD_CAST "image"))
@@ -422,16 +423,3 @@ MapReader::readTileset(xmlNodePtr node,
return NULL;
}
-
-int
-MapReader::getProperty(xmlNodePtr node, const char* name, int def)
-{
- int &ret = def;
-
- xmlChar *prop = xmlGetProp(node, BAD_CAST name);
- if (prop) {
- ret = atoi((char*)prop);
- xmlFree(prop);
- }
- return ret;
-}
diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp
new file mode 100644
index 00000000..fb03f6c1
--- /dev/null
+++ b/src/resources/monsterdb.cpp
@@ -0,0 +1,151 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id:
+ */
+
+#include "monsterdb.h"
+
+#include "resourcemanager.h"
+
+#include "../log.h"
+
+#include "../utils/dtor.h"
+#include "../utils/xml.h"
+
+namespace
+{
+ MonsterDB::MonsterInfos mMonsterInfos;
+ MonsterInfo mUnknown;
+}
+
+void
+MonsterDB::load()
+{
+ mUnknown.setSprite("error.xml");
+ mUnknown.setName("unnamed");
+
+ logger->log("Initializing monster database...");
+
+ ResourceManager *resman = ResourceManager::getInstance();
+ int size;
+ char *data = (char*)resman->loadFile("monsters.xml", size);
+
+ if (!data)
+ {
+ logger->error("Monster Database: Could not find monsters.xml!");
+ }
+
+ xmlDocPtr doc = xmlParseMemory(data, size);
+ free(data);
+
+ if (!doc)
+ {
+ logger->error("Monster Database: Error while parsing monster database (monsters.xml)!");
+ }
+
+ xmlNodePtr rootNode = xmlDocGetRootElement(doc);
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "monsters"))
+ {
+ logger->error("Monster Database: monster.xml is not a valid database file!");
+ }
+
+ //iterate <monster>s
+ for ( xmlNodePtr monsterNode = rootNode->xmlChildrenNode;
+ monsterNode != NULL;
+ monsterNode = monsterNode->next)
+ {
+
+ if (!xmlStrEqual(monsterNode->name, BAD_CAST "monster"))
+ {
+ continue;
+ }
+
+ MonsterInfo *currentInfo = new MonsterInfo();
+
+ currentInfo->setName (XML::getProperty(monsterNode, "name", "unnamed"));
+
+ //iterate <sprite>s and <sound>s
+ for ( xmlNodePtr spriteNode = monsterNode->xmlChildrenNode;
+ spriteNode != NULL;
+ spriteNode = spriteNode->next)
+ {
+ if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
+ {
+ currentInfo->setSprite((const char*) spriteNode->xmlChildrenNode->content);
+ }
+
+ if (xmlStrEqual(spriteNode->name, BAD_CAST "sound"))
+ {
+ std::string event = XML::getProperty(spriteNode, "event", "");
+ const char *filename;
+ filename = (const char*) spriteNode->xmlChildrenNode->content;
+
+ if (event == "hit")
+ {
+ currentInfo->addSound(EVENT_HIT, filename);
+ }
+ else if (event == "miss")
+ {
+ currentInfo->addSound(EVENT_MISS, filename);
+ }
+ else if (event == "hurt")
+ {
+ currentInfo->addSound(EVENT_HURT, filename);
+ }
+ else if (event == "die")
+ {
+ currentInfo->addSound(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());
+ }
+ }
+ }
+ mMonsterInfos[XML::getProperty(monsterNode, "id", 0)] = currentInfo;
+ }
+}
+
+void
+MonsterDB::unload()
+{
+ for_each ( mMonsterInfos.begin(), mMonsterInfos.end(),
+ make_dtor(mMonsterInfos));
+ mMonsterInfos.clear();
+}
+
+
+const MonsterInfo&
+MonsterDB::get (int id)
+{
+ MonsterInfoIterator i = mMonsterInfos.find(id);
+
+ if (i == mMonsterInfos.end())
+ {
+ logger->log("MonsterDB: Warning, unknown monster ID %d requested", id);
+ return mUnknown;
+ }
+ else
+ {
+ return *(i->second);
+ }
+}
diff --git a/src/resources/monsterdb.h b/src/resources/monsterdb.h
new file mode 100644
index 00000000..b105665a
--- /dev/null
+++ b/src/resources/monsterdb.h
@@ -0,0 +1,45 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id:
+ */
+
+#ifndef _TMW_MONSTER_DB_H
+#define _TMW_MONSTER_DB_H
+
+#include <map>
+
+#include "monsterinfo.h"
+
+namespace MonsterDB
+{
+ void
+ load();
+
+ void
+ unload();
+
+ const MonsterInfo& get (int id);
+
+ typedef std::map<int, MonsterInfo*> MonsterInfos;
+ typedef MonsterInfos::iterator MonsterInfoIterator;
+}
+
+#endif
diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp
new file mode 100644
index 00000000..43aac32a
--- /dev/null
+++ b/src/resources/monsterinfo.cpp
@@ -0,0 +1,70 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: monsterinfo.cpp 2650 2006-09-03 15:00:47Z b_lindeijer $
+ */
+
+#include "monsterinfo.h"
+
+#include "../utils/dtor.h"
+
+MonsterInfo::MonsterInfo():
+ mSprite("error.xml")
+{
+
+}
+
+MonsterInfo::~MonsterInfo()
+{
+ //kill vectors in mSoundEffects
+ for_each ( mSounds.begin(), mSounds.end(),
+ make_dtor(mSounds));
+ mSounds.clear();
+}
+
+
+void
+MonsterInfo::addSound (SoundEvent event, std::string filename)
+{
+ if (mSounds.find(event) == mSounds.end())
+ {
+ mSounds[event] = new std::vector<std::string>;
+ }
+
+ mSounds[event]->push_back("sfx/" + filename);
+}
+
+
+std::string
+MonsterInfo::getSound (SoundEvent event) const
+{
+ std::map<SoundEvent, std::vector<std::string>* >::const_iterator i;
+
+ i = mSounds.find(event);
+
+ if (i == mSounds.end())
+ {
+ return "";
+ }
+ else
+ {
+ return i->second->at(rand()%i->second->size());
+ }
+}
diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h
new file mode 100644
index 00000000..413dafa0
--- /dev/null
+++ b/src/resources/monsterinfo.h
@@ -0,0 +1,74 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: monsterinfo.h 2650 2006-09-03 15:00:47Z b_lindeijer $
+ */
+
+#ifndef _TMW_MONSTERINFO_H_
+#define _TMW_MONSTERINFO_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+
+enum SoundEvent
+{
+ EVENT_HIT,
+ EVENT_MISS,
+ EVENT_HURT,
+ EVENT_DIE
+};
+
+
+class MonsterInfo
+{
+ public:
+ MonsterInfo();
+
+ ~MonsterInfo();
+
+ void
+ setName(std::string name) { mName = name; } ;
+
+ void
+ setSprite(std::string filename) { mSprite = filename; }
+
+ void
+ addSound (SoundEvent event, std::string filename);
+
+ const std::string&
+ getName () const { return mName; };
+
+ const std::string&
+ getSprite () const { return mSprite; };
+
+ std::string
+ getSound (SoundEvent event) const;
+
+ private:
+
+ std::string mName;
+ std::string mSprite;
+
+ std::map<SoundEvent, std::vector<std::string>* > mSounds;
+};
+
+#endif
diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index bb51d023..45067302 100644
--- a/src/resources/resourcemanager.cpp
+++ b/src/resources/resourcemanager.cpp
@@ -32,6 +32,7 @@
#include "music.h"
#include "soundeffect.h"
#include "spriteset.h"
+#include "spritedef.h"
#include "../log.h"
@@ -40,15 +41,33 @@ ResourceManager *ResourceManager::instance = NULL;
ResourceManager::ResourceManager()
{
+ logger->log("Initializing resource manager...");
}
ResourceManager::~ResourceManager()
{
- // Release any remaining spritesets first because they depend on images
+ // Release any remaining spritedefs first because they depend on spritesets
ResourceIterator iter = mResources.begin();
while (iter != mResources.end())
{
- if (dynamic_cast<Spriteset*>(iter->second) != NULL)
+ if (dynamic_cast<SpriteDef*>(iter->second) != 0)
+ {
+ cleanUp(iter->second);
+ ResourceIterator toErase = iter;
+ ++iter;
+ mResources.erase(toErase);
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+
+ // Release any remaining spritesets first because they depend on images
+ iter = mResources.begin();
+ while (iter != mResources.end())
+ {
+ if (dynamic_cast<Spriteset*>(iter->second) != 0)
{
cleanUp(iter->second);
ResourceIterator toErase = iter;
@@ -83,7 +102,7 @@ ResourceManager::cleanUp(Resource *res)
bool
ResourceManager::setWriteDir(const std::string &path)
{
- return (bool)PHYSFS_setWriteDir(path.c_str());
+ return (bool) PHYSFS_setWriteDir(path.c_str());
}
void
@@ -96,7 +115,7 @@ ResourceManager::addToSearchPath(const std::string &path, bool append)
bool
ResourceManager::mkdir(const std::string &path)
{
- return (bool)PHYSFS_mkdir(path.c_str());
+ return (bool) PHYSFS_mkdir(path.c_str());
}
bool
@@ -158,9 +177,9 @@ ResourceManager::get(const E_RESOURCE_TYPE &type, const std::string &idPath)
free(buffer);
- if (resource) {
+ if (resource)
+ {
resource->incRef();
-
mResources[idPath] = resource;
}
@@ -215,6 +234,27 @@ ResourceManager::getSpriteset(const std::string &imagePath, int w, int h)
return spriteset;
}
+SpriteDef*
+ResourceManager::getSprite(const std::string &path, int variant)
+{
+ std::stringstream ss;
+ ss << path << "[" << variant << "]";
+ const std::string idPath = ss.str();
+
+ ResourceIterator resIter = mResources.find(idPath);
+
+ if (resIter != mResources.end()) {
+ resIter->second->incRef();
+ return dynamic_cast<SpriteDef*>(resIter->second);
+ }
+
+ SpriteDef *sprite = new SpriteDef(idPath, path, variant);
+ sprite->incRef();
+ mResources[idPath] = sprite;
+
+ return sprite;
+}
+
void
ResourceManager::release(const std::string &idPath)
{
@@ -246,18 +286,13 @@ ResourceManager::deleteInstance()
void*
ResourceManager::loadFile(const std::string &fileName, int &fileSize)
{
- // If the file doesn't exist indicate failure
- if (!PHYSFS_exists(fileName.c_str())) {
- logger->log("Warning: %s not found!", fileName.c_str());
- return NULL;
- }
-
// Attempt to open the specified file using PhysicsFS
PHYSFS_file *file = PHYSFS_openRead(fileName.c_str());
// If the handler is an invalid pointer indicate failure
if (file == NULL) {
- logger->log("Warning: %s failed to load!", fileName.c_str());
+ logger->log("Warning: Failed to load %s: %s",
+ fileName.c_str(), PHYSFS_getLastError());
return NULL;
}
diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h
index 0086b167..d458f96e 100644
--- a/src/resources/resourcemanager.h
+++ b/src/resources/resourcemanager.h
@@ -34,6 +34,7 @@ class Image;
class Music;
class SoundEffect;
class Spriteset;
+class SpriteDef;
/**
* A class for loading and managing resources.
@@ -113,21 +114,21 @@ class ResourceManager
get(const E_RESOURCE_TYPE &type, const std::string &idPath);
/**
- * Convenience wrapper around ResourceManager::create for loading
+ * Convenience wrapper around ResourceManager::get for loading
* images.
*/
Image*
getImage(const std::string &idPath);
/**
- * Convenience wrapper around ResourceManager::create for loading
+ * Convenience wrapper around ResourceManager::get for loading
* songs.
*/
Music*
getMusic(const std::string &idPath);
/**
- * Convenience wrapper around ResourceManager::create for loading
+ * Convenience wrapper around ResourceManager::get for loading
* samples.
*/
SoundEffect*
@@ -137,7 +138,15 @@ class ResourceManager
* Creates a spriteset based on the image referenced by the given
* path and the supplied sprite sizes
*/
- Spriteset* getSpriteset(const std::string &imagePath, int w, int h);
+ Spriteset*
+ getSpriteset(const std::string &imagePath, int w, int h);
+
+ /**
+ * Creates a sprite definition based on a given path and the supplied
+ * variant.
+ */
+ SpriteDef*
+ getSprite(const std::string &path, int variant = 0);
/**
* Releases a resource, removing it from the set of loaded resources.
diff --git a/src/resources/soundeffect.cpp b/src/resources/soundeffect.cpp
index 3340e5ea..bb35218e 100644
--- a/src/resources/soundeffect.cpp
+++ b/src/resources/soundeffect.cpp
@@ -23,6 +23,8 @@
#include "soundeffect.h"
+#include "../log.h"
+
SoundEffect::SoundEffect(const std::string &idPath, Mix_Chunk *soundEffect):
Resource(idPath),
mChunk(soundEffect)
@@ -41,13 +43,18 @@ SoundEffect::load(void *buffer, unsigned int bufferSize,
// Load the raw file data from the buffer in an RWops structure
SDL_RWops *rw = SDL_RWFromMem(buffer, bufferSize);
- // Use Mix_LoadWAV_RW to load the raw music data
- Mix_Chunk *tmpSoundEffect = Mix_LoadWAV_RW(rw, 0);
-
- // Now free the SDL_RWops data
- SDL_FreeRW(rw);
+ // Load the music data and free the RWops structure
+ Mix_Chunk *tmpSoundEffect = Mix_LoadWAV_RW(rw, 1);
- return new SoundEffect(idPath, tmpSoundEffect);
+ if (tmpSoundEffect)
+ {
+ return new SoundEffect(idPath, tmpSoundEffect);
+ }
+ else
+ {
+ logger->log("Error while loading sound effect (%s)", idPath.c_str());
+ return NULL;
+ }
}
bool
diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp
new file mode 100644
index 00000000..bd273b3b
--- /dev/null
+++ b/src/resources/spritedef.cpp
@@ -0,0 +1,381 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "spritedef.h"
+
+#include "../animation.h"
+#include "../action.h"
+#include "../graphics.h"
+#include "../log.h"
+
+#include "resourcemanager.h"
+#include "spriteset.h"
+#include "image.h"
+
+#include "../utils/xml.h"
+
+SpriteDef::SpriteDef(const std::string &idPath,
+ const std::string &file, int variant):
+ Resource(idPath),
+ mAction(NULL),
+ mDirection(DIRECTION_DOWN),
+ mLastTime(0)
+{
+ load(file, variant);
+}
+
+Action*
+SpriteDef::getAction(SpriteAction action) const
+{
+ Actions::const_iterator i = mActions.find(action);
+
+ if (i == mActions.end())
+ {
+ logger->log("Warning: no action \"%u\" defined!", action);
+ return NULL;
+ }
+
+ return i->second;
+}
+
+void
+SpriteDef::load(const std::string &animationFile, int variant)
+{
+ int size;
+ ResourceManager *resman = ResourceManager::getInstance();
+ char *data = (char*) resman->loadFile(animationFile.c_str(), size);
+
+ if (!data) {
+ logger->error("Animation: Could not find " + animationFile + "!");
+ }
+
+ xmlDocPtr doc = xmlParseMemory(data, size);
+ free(data);
+
+ if (!doc) {
+ logger->error(
+ "Animation: Error while parsing animation definition file!");
+ }
+
+ xmlNodePtr node = xmlDocGetRootElement(doc);
+ if (!node || !xmlStrEqual(node->name, BAD_CAST "sprite")) {
+ logger->error(
+ "Animation: this is not a valid animation definition file!");
+ }
+
+ // Get the variant
+ int variant_num = XML::getProperty(node, "variants", 0);
+ int variant_offset = 0;
+
+ if (variant_num > 0 && variant < variant_num)
+ {
+ variant_offset = variant * XML::getProperty(node, "variant_offset", 0);
+ }
+
+ for (node = node->xmlChildrenNode; node != NULL; node = node->next)
+ {
+ if (xmlStrEqual(node->name, BAD_CAST "imageset"))
+ {
+ loadImageSet(node);
+ }
+ else if (xmlStrEqual(node->name, BAD_CAST "action"))
+ {
+ loadAction(node, variant_offset);
+ }
+ else if (xmlStrEqual(node->name, BAD_CAST "include"))
+ {
+ includeSprite(node);
+ }
+ }
+
+ xmlFreeDoc(doc);
+
+ // Complete missing actions
+ substituteAction(ACTION_STAND, ACTION_DEFAULT);
+ substituteAction(ACTION_WALK, ACTION_STAND);
+ substituteAction(ACTION_WALK, ACTION_RUN);
+ substituteAction(ACTION_ATTACK, ACTION_STAND);
+ substituteAction(ACTION_ATTACK_SWING, ACTION_ATTACK);
+ substituteAction(ACTION_ATTACK_STAB, ACTION_ATTACK_SWING);
+ substituteAction(ACTION_ATTACK_BOW, ACTION_ATTACK_STAB);
+ substituteAction(ACTION_ATTACK_THROW, ACTION_ATTACK_SWING);
+ substituteAction(ACTION_CAST_MAGIC, ACTION_ATTACK_SWING);
+ substituteAction(ACTION_USE_ITEM, ACTION_CAST_MAGIC);
+ substituteAction(ACTION_SIT, ACTION_STAND);
+ substituteAction(ACTION_SLEEP, ACTION_SIT);
+ substituteAction(ACTION_HURT, ACTION_STAND);
+ substituteAction(ACTION_DEAD, ACTION_HURT);
+}
+
+void
+SpriteDef::loadImageSet(xmlNodePtr node)
+{
+ int width = XML::getProperty(node, "width", 0);
+ int height = XML::getProperty(node, "height", 0);
+ std::string name = XML::getProperty(node, "name", "");
+ std::string imageSrc = XML::getProperty(node, "src", "");
+
+ ResourceManager *resman = ResourceManager::getInstance();
+ Spriteset *spriteset = resman->getSpriteset(imageSrc, width, height);
+
+ if (!spriteset)
+ {
+ logger->error("Couldn't load imageset!");
+ }
+
+ mSpritesets[name] = spriteset;
+}
+
+void
+SpriteDef::loadAction(xmlNodePtr node, int variant_offset)
+{
+ const std::string actionName = XML::getProperty(node, "name", "");
+ const std::string imagesetName = XML::getProperty(node, "imageset", "");
+
+ SpritesetIterator si = mSpritesets.find(imagesetName);
+ if (si == mSpritesets.end())
+ {
+ logger->log("Warning: imageset \"%s\" not defined in %s",
+ imagesetName.c_str(), getIdPath().c_str());
+ return;
+ }
+ Spriteset *imageset = si->second;
+
+ SpriteAction actionType = makeSpriteAction(actionName);
+ if (actionType == ACTION_INVALID)
+ {
+ logger->log("Warning: Unknown action \"%s\" defined in %s",
+ actionName.c_str(), getIdPath().c_str());
+ return;
+ }
+ Action *action = new Action();
+ mActions[actionType] = action;
+
+ // When first action set it as default direction
+ if (mActions.empty())
+ {
+ mActions[ACTION_DEFAULT] = action;
+ }
+
+ // Load animations
+ for (xmlNodePtr animationNode = node->xmlChildrenNode;
+ animationNode != NULL;
+ animationNode = animationNode->next)
+ {
+ if (xmlStrEqual(animationNode->name, BAD_CAST "animation"))
+ {
+ loadAnimation(animationNode, action, imageset, variant_offset);
+ }
+ }
+}
+
+void
+SpriteDef::loadAnimation(xmlNodePtr animationNode,
+ Action *action, Spriteset *imageset,
+ int variant_offset)
+{
+ std::string directionName =
+ XML::getProperty(animationNode, "direction", "");
+ SpriteDirection directionType = makeSpriteDirection(directionName);
+
+ if (directionType == DIRECTION_INVALID)
+ {
+ logger->log("Warning: Unknown direction \"%s\" used in %s",
+ directionName.c_str(), getIdPath().c_str());
+ return;
+ }
+
+ Animation *animation = new Animation();
+ action->setAnimation(directionType, animation);
+
+ // Get animation phases
+ for (xmlNodePtr phaseNode = animationNode->xmlChildrenNode;
+ phaseNode != NULL;
+ phaseNode = phaseNode->next)
+ {
+ int delay = XML::getProperty(phaseNode, "delay", 0);
+ int offsetX = XML::getProperty(phaseNode, "offsetX", 0);
+ int offsetY = XML::getProperty(phaseNode, "offsetY", 0);
+ offsetY -= imageset->getHeight() - 32;
+ offsetX -= imageset->getWidth() / 2 - 16;
+
+ if (xmlStrEqual(phaseNode->name, BAD_CAST "frame"))
+ {
+ int index = XML::getProperty(phaseNode, "index", -1);
+
+ if (index < 0)
+ {
+ logger->log("No valid value for 'index'");
+ continue;
+ }
+
+ Image *img = imageset->get(index + variant_offset);
+
+ if (!img)
+ {
+ logger->log("No image at index " + (index + variant_offset));
+ continue;
+ }
+
+ animation->addPhase(img, delay, offsetX, offsetY);
+ }
+ else if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence"))
+ {
+ int start = XML::getProperty(phaseNode, "start", -1);
+ int end = XML::getProperty(phaseNode, "end", -1);
+
+ if (start < 0 || end < 0)
+ {
+ logger->log("No valid value for 'start' or 'end'");
+ continue;
+ }
+
+ while (end >= start)
+ {
+ Image *img = imageset->get(start + variant_offset);
+
+ if (!img)
+ {
+ logger->log("No image at index " +
+ (start + variant_offset));
+ continue;
+ }
+
+ animation->addPhase(img, delay, offsetX, offsetY);
+ start++;
+ }
+ }
+ else if (xmlStrEqual(phaseNode->name, BAD_CAST "end"))
+ {
+ animation->addTerminator();
+ }
+ } // for phaseNode
+}
+
+void
+SpriteDef::includeSprite(xmlNodePtr includeNode)
+{
+ std::string filename = XML::getProperty(includeNode, "file", "");
+ ResourceManager *resman = ResourceManager::getInstance();
+ SpriteDef *sprite = resman->getSprite("graphics/sprites/" + filename);
+
+ // TODO: Somehow implement actually including it
+ sprite->decRef();
+}
+
+void
+SpriteDef::substituteAction(SpriteAction complete, SpriteAction with)
+{
+ if (mActions.find(complete) == mActions.end())
+ {
+ Actions::iterator i = mActions.find(with);
+ if (i != mActions.end()) {
+ mActions[complete] = i->second;
+ }
+ }
+}
+
+SpriteDef::~SpriteDef()
+{
+ for (SpritesetIterator i = mSpritesets.begin();
+ i != mSpritesets.end(); ++i)
+ {
+ i->second->decRef();
+ }
+}
+
+SpriteAction
+SpriteDef::makeSpriteAction(const std::string& action)
+{
+ if (action == "" || action == "default") {
+ return ACTION_DEFAULT;
+ }
+ if (action == "stand") {
+ return ACTION_STAND;
+ }
+ else if (action == "walk") {
+ return ACTION_WALK;
+ }
+ else if (action == "run") {
+ return ACTION_RUN;
+ }
+ else if (action == "attack") {
+ return ACTION_ATTACK;
+ }
+ else if (action == "attack_swing") {
+ return ACTION_ATTACK_SWING;
+ }
+ else if (action == "attack_stab") {
+ return ACTION_ATTACK_STAB;
+ }
+ else if (action == "attack_bow") {
+ return ACTION_ATTACK_BOW;
+ }
+ else if (action == "attack_throw") {
+ return ACTION_ATTACK_THROW;
+ }
+ else if (action == "cast_magic") {
+ return ACTION_CAST_MAGIC;
+ }
+ else if (action == "use_item") {
+ return ACTION_USE_ITEM;
+ }
+ else if (action == "sit") {
+ return ACTION_SIT;
+ }
+ else if (action == "sleep") {
+ return ACTION_SLEEP;
+ }
+ else if (action == "hurt") {
+ return ACTION_HURT;
+ }
+ else if (action == "dead") {
+ return ACTION_DEAD;
+ }
+ else {
+ return ACTION_INVALID;
+ }
+}
+
+SpriteDirection
+SpriteDef::makeSpriteDirection(const std::string& direction)
+{
+ if (direction == "" || direction == "default") {
+ return DIRECTION_DEFAULT;
+ }
+ else if (direction == "up") {
+ return DIRECTION_UP;
+ }
+ else if (direction == "left") {
+ return DIRECTION_LEFT;
+ }
+ else if (direction == "right") {
+ return DIRECTION_RIGHT;
+ }
+ else if (direction == "down") {
+ return DIRECTION_DOWN;
+ }
+ else {
+ return DIRECTION_INVALID;
+ };
+}
diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h
new file mode 100644
index 00000000..64414259
--- /dev/null
+++ b/src/resources/spritedef.h
@@ -0,0 +1,158 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_SPRITEDEF_H
+#define _TMW_SPRITEDEF_H
+
+#include "resource.h"
+
+#include <map>
+#include <string>
+
+#include <libxml/tree.h>
+
+class Action;
+class Graphics;
+class Spriteset;
+struct AnimationPhase;
+class Animation;
+
+enum SpriteAction
+{
+ ACTION_DEFAULT = 0,
+ ACTION_STAND,
+ ACTION_WALK,
+ ACTION_RUN,
+ ACTION_ATTACK,
+ ACTION_ATTACK_SWING,
+ ACTION_ATTACK_STAB,
+ ACTION_ATTACK_BOW,
+ ACTION_ATTACK_THROW,
+ ACTION_CAST_MAGIC,
+ ACTION_USE_ITEM,
+ ACTION_SIT,
+ ACTION_SLEEP,
+ ACTION_HURT,
+ ACTION_DEAD,
+ ACTION_INVALID
+};
+
+enum SpriteDirection
+{
+ DIRECTION_DEFAULT = 0,
+ DIRECTION_DOWN,
+ DIRECTION_UP,
+ DIRECTION_LEFT,
+ DIRECTION_RIGHT,
+ DIRECTION_INVALID
+};
+
+/**
+ * Defines a class to load an animation.
+ */
+class SpriteDef : public Resource
+{
+ public:
+ /**
+ * Constructor.
+ */
+ SpriteDef(const std::string &idPath,
+ const std::string &file, int variant);
+
+ /**
+ * Destructor.
+ */
+ ~SpriteDef();
+
+ /**
+ * Returns the specified action.
+ */
+ Action*
+ getAction(SpriteAction action) const;
+
+ private:
+ /**
+ * Loads a sprite definition file.
+ */
+ void
+ load(const std::string &file, int variant);
+
+ /**
+ * Loads an imageset element.
+ */
+ void
+ loadImageSet(xmlNodePtr node);
+
+ /**
+ * Loads an action element.
+ */
+ void
+ loadAction(xmlNodePtr node, int variant_offset);
+
+ /**
+ * Loads an animation element.
+ */
+ void
+ loadAnimation(xmlNodePtr animationNode,
+ Action *action, Spriteset *imageset,
+ int variant_offset);
+
+ /**
+ * Include another sprite into this one.
+ */
+ void
+ includeSprite(xmlNodePtr includeNode);
+
+ /**
+ * When there are no animations defined for the action "complete", its
+ * animations become a copy of those of the action "with".
+ */
+ void
+ substituteAction(SpriteAction complete, SpriteAction with);
+
+ /**
+ * Converts a string into a SpriteAction enum.
+ */
+ static SpriteAction
+ makeSpriteAction(const std::string &action);
+
+ /**
+ * Converts a string into a SpriteDirection enum.
+ */
+ static SpriteDirection
+ makeSpriteDirection(const std::string &direction);
+
+
+ typedef std::map<std::string, Spriteset*> Spritesets;
+ typedef Spritesets::iterator SpritesetIterator;
+
+ typedef std::map<SpriteAction, Action*> Actions;
+
+ Spritesets mSpritesets;
+ Actions mActions;
+ Action *mAction;
+ SpriteDirection mDirection;
+ int mLastTime;
+};
+
+#endif
diff --git a/src/resources/spriteset.h b/src/resources/spriteset.h
index c51e6a75..7f6b42df 100644
--- a/src/resources/spriteset.h
+++ b/src/resources/spriteset.h
@@ -32,7 +32,9 @@ class Image;
/**
- * Stores a complete set of sprites.
+ * Stores a set of subimages originating from a single image.
+ *
+ * TODO: Should probably be renamed to ImageSet or TileSet.
*/
class Spriteset : public Resource
{
@@ -40,7 +42,7 @@ class Spriteset : public Resource
/*
* Cuts the passed image in a grid of sub images.
*/
- Spriteset(const std::string& idPath, Image *img, int w, int h);
+ Spriteset(const std::string &idPath, Image *img, int w, int h);
/**
* Destructor.
diff --git a/src/sound.cpp b/src/sound.cpp
index 182be3d6..8ba8fe99 100644
--- a/src/sound.cpp
+++ b/src/sound.cpp
@@ -191,15 +191,15 @@ void Sound::fadeOutMusic(int ms)
}
}
-void Sound::playSfx(const char *path)
+void Sound::playSfx(const std::string &path)
{
- if (!mInstalled) return;
+ if (!mInstalled || path.length() == 0) return;
ResourceManager *resman = ResourceManager::getInstance();
SoundEffect *sample = resman->getSoundEffect(path);
if (sample) {
+ logger->log("Sound::playSfx() Playing: %s", path.c_str());
sample->play(0, 120);
- logger->log("Sound::playSfx() Playing: %s", path);
}
}
diff --git a/src/sound.h b/src/sound.h
index 39901121..07db0587 100644
--- a/src/sound.h
+++ b/src/sound.h
@@ -26,6 +26,8 @@
#include <SDL_mixer.h>
+#include <string>
+
/** Sound engine
*
* \ingroup CORE
@@ -105,7 +107,7 @@ class Sound {
*
* \param path Full path to file
*/
- void playSfx(const char *path);
+ void playSfx(const std::string &path);
private:
bool mInstalled;
diff --git a/src/sprite.h b/src/sprite.h
index 282091cc..51811149 100644
--- a/src/sprite.h
+++ b/src/sprite.h
@@ -47,7 +47,7 @@ class Sprite
* partly with the clipping rectangle support.
*/
virtual void
- draw(Graphics *graphics, int offsetX, int offsetY) = 0;
+ draw(Graphics *graphics, int offsetX, int offsetY) const = 0;
/**
* Returns the pixel Y coordinate of the sprite.
diff --git a/src/utils/wingettimeofday.h b/src/utils/wingettimeofday.h
new file mode 100644
index 00000000..0f8b767a
--- /dev/null
+++ b/src/utils/wingettimeofday.h
@@ -0,0 +1,111 @@
+/*
+ * The Mana World Server
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMWSERV_WINGETTIMEOFDAY_H_
+#define _TMWSERV_WINGETTIMEOFDAY_H_
+
+#ifdef WIN32
+
+#include <windows.h>
+
+/*
+ * the function gettimeofday() is available on UNIX but not on windows.
+ * this header defines a windows implementation as a
+ * GetSystemTimeAsFileTime() wrapper.
+ */
+
+int gettimeofday(struct timeval* tv, void *tz)
+/*---------------------------------------------------------------
+ * Copyright (c) 1999,2000,2001,2002,2003
+ * The Board of Trustees of the University of Illinois
+ * All Rights Reserved.
+ *---------------------------------------------------------------
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software (Iperf) and associated
+ * documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ *
+ * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and
+ * the following disclaimers.
+ *
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimers in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ *
+ * Neither the names of the University of Illinois, NCSA,
+ * nor the names of its contributors may be used to endorse
+ * or promote products derived from this Software without
+ * specific prior written permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * ________________________________________________________________
+ * National Laboratory for Applied Network Research
+ * National Center for Supercomputing Applications
+ * University of Illinois at Urbana-Champaign
+ * http://www.ncsa.uiuc.edu
+ * ________________________________________________________________
+ *
+ * gettimeofday.c
+ * by Mark Gates <mgates@nlanr.net>
+ * -------------------------------------------------------------------
+ * A (hack) implementation of gettimeofday for Windows.
+ * Since I send sec/usec in UDP packets, this made the most sense.
+ * ------------------------------------------------------------------- */
+{
+ FILETIME time;
+ double timed;
+
+ GetSystemTimeAsFileTime( &time );
+
+ // Apparently Win32 has units of 1e-7 sec (tenths of microsecs)
+ // 4294967296 is 2^32, to shift high word over
+ // 11644473600 is the number of seconds between
+ // the Win32 epoch 1601-Jan-01 and the Unix epoch 1970-Jan-01
+ // Tests found floating point to be 10x faster than 64bit int math.
+
+ timed = ((time.dwHighDateTime * 4294967296e-7) - 11644473600.0) +
+ (time.dwLowDateTime * 1e-7);
+
+ tv->tv_sec = (long) timed;
+ tv->tv_usec = (long) ((timed - tv->tv_sec) * 1e6);
+
+ return 0;
+}
+
+
+#endif // WIN32
+#endif
diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp
new file mode 100644
index 00000000..7c917dc0
--- /dev/null
+++ b/src/utils/xml.cpp
@@ -0,0 +1,54 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "xml.h"
+
+namespace XML
+{
+ int
+ getProperty(xmlNodePtr node, const char* name, int def)
+ {
+ int &ret = def;
+
+ xmlChar *prop = xmlGetProp(node, BAD_CAST name);
+ if (prop) {
+ ret = atoi((char*)prop);
+ xmlFree(prop);
+ }
+
+ return ret;
+ }
+
+ std::string
+ getProperty(xmlNodePtr node, const char *name, const std::string &def)
+ {
+ xmlChar *prop = xmlGetProp(node, BAD_CAST name);
+ if (prop) {
+ std::string val = (char*)prop;
+ xmlFree(prop);
+ return val;
+ }
+
+ return def;
+ }
+}
diff --git a/src/utils/xml.h b/src/utils/xml.h
new file mode 100644
index 00000000..54ed9951
--- /dev/null
+++ b/src/utils/xml.h
@@ -0,0 +1,46 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 World 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 World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_XML_H
+#define _TMW_XML_H
+
+#include <libxml/tree.h>
+
+#include <string>
+
+namespace XML
+{
+ /**
+ * Gets an integer property from an xmlNodePtr.
+ */
+ int
+ getProperty(xmlNodePtr node, const char *name, int def);
+
+ /**
+ * Gets a string property from an xmlNodePtr.
+ */
+ std::string
+ getProperty(xmlNodePtr node, const char *name, const std::string &def);
+}
+
+#endif