summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Lindeijer <bjorn@lindeijer.nl>2006-11-19 21:24:36 +0000
committerBjørn Lindeijer <bjorn@lindeijer.nl>2006-11-19 21:24:36 +0000
commit7ac7d0e030464f744546b4e6183a7242f640d5d3 (patch)
treef19831b29511d46e8aba45ace6017c8e6afe815b
parentb7cfcffd7a156e19dfa9882d67426f4fa6edef57 (diff)
downloadmana-7ac7d0e030464f744546b4e6183a7242f640d5d3.tar.gz
mana-7ac7d0e030464f744546b4e6183a7242f640d5d3.tar.bz2
mana-7ac7d0e030464f744546b4e6183a7242f640d5d3.tar.xz
mana-7ac7d0e030464f744546b4e6183a7242f640d5d3.zip
Separated sprite definition from playback.
-rw-r--r--ChangeLog8
-rw-r--r--NEWS3
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Makefile.am2
-rw-r--r--src/action.cpp10
-rw-r--r--src/action.h9
-rw-r--r--src/animatedsprite.cpp408
-rw-r--r--src/animatedsprite.h115
-rw-r--r--src/animation.cpp56
-rw-r--r--src/animation.h47
-rw-r--r--src/being.cpp14
-rw-r--r--src/being.h2
-rw-r--r--src/game.cpp14
-rw-r--r--src/localplayer.cpp39
-rw-r--r--src/localplayer.h10
-rw-r--r--src/monster.cpp3
-rw-r--r--src/player.cpp16
-rw-r--r--src/player.h8
-rw-r--r--src/resources/resourcemanager.cpp47
-rw-r--r--src/resources/resourcemanager.h17
-rw-r--r--src/resources/spritedef.cpp329
-rw-r--r--src/resources/spritedef.h130
-rw-r--r--src/resources/spriteset.h6
23 files changed, 729 insertions, 566 deletions
diff --git a/ChangeLog b/ChangeLog
index 7ef70afd..9c8e2b08 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,14 @@
* src/gui/setup_joystick.cpp: Fixed joystick option to show enabled
when the joystick is enabled.
+ * src/localplayer.cpp, src/game.cpp, src/action.h, src/action.cpp,
+ src/player.cpp, src/animatedsprite.h, src/being.cpp, src/animation.h,
+ src/monster.cpp, src/CMakeLists.txt, src/player.h,
+ src/animatedsprite.cpp, src/localplayer.h, src/animation.cpp,
+ src/Makefile.am, src/being.h, src/resources/resourcemanager.cpp,
+ src/resources/spritedef.cpp, src/resources/resourcemanager.h,
+ src/resources/spriteset.h, src/resources/spritedef.cpp: Separated
+ sprite definition from playback.
2006-11-17 Björn Steinbrink <B.Steinbrink@gmx.de>
diff --git a/NEWS b/NEWS
index 8d11079e..0135b579 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
0.0.21.2 (...)
- Changed to new update host (http://updates.themanaworld.org)
- Worked around a Guichan exception thrown for mice with many buttons
+- Changed mouse walk to keep following mouse while button is held down
+- Extended font support for å and Å.
+- Fixed joystick setting not to show disabled when it's actually enabled
- Fixed money field to no longer hide below the bottom of the window
- Fixed pathfinding to allow walking through beings when they block your path
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3981ee58..51b68935 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -221,6 +221,8 @@ SET(SRCS
resources/sdlimageloader.cpp
resources/soundeffect.h
resources/soundeffect.cpp
+ resources/spritedef.h
+ resources/spritedef.cpp
resources/spriteset.h
resources/spriteset.cpp
resources/buddylist.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 5f29bebc..8715bac6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -183,6 +183,8 @@ tmw_SOURCES = graphic/imagerect.h \
resources/sdlimageloader.cpp \
resources/soundeffect.h \
resources/soundeffect.cpp \
+ resources/spritedef.h \
+ resources/spritedef.cpp \
resources/spriteset.h \
resources/spriteset.cpp \
resources/buddylist.h \
diff --git a/src/action.cpp b/src/action.cpp
index 0a382af3..148ea105 100644
--- a/src/action.cpp
+++ b/src/action.cpp
@@ -64,13 +64,3 @@ Action::setAnimation(int direction, Animation *animation)
mAnimations[direction] = animation;
}
-
-void
-Action::reset()
-{
- for (AnimationIterator i = mAnimations.begin();
- i != mAnimations.end(); ++i)
- {
- i->second->reset();
- }
-}
diff --git a/src/action.h b/src/action.h
index 3dcc02f7..8d5e8d11 100644
--- a/src/action.h
+++ b/src/action.h
@@ -28,9 +28,6 @@
#include <libxml/tree.h>
-class Image;
-
-struct AnimationPhase;
class Animation;
/**
@@ -52,12 +49,6 @@ class Action
void
setAnimation(int direction, Animation *animation);
- /**
- * Resets all animations associated with this action.
- */
- void
- reset();
-
Animation*
getAnimation(int direction) const;
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp
index c2f7f133..46369c80 100644
--- a/src/animatedsprite.cpp
+++ b/src/animatedsprite.cpp
@@ -34,381 +34,167 @@
#include "utils/xml.h"
-AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant):
- mAction(NULL),
+#include <cassert>
+
+AnimatedSprite::AnimatedSprite(SpriteDef *sprite):
mDirection(DIRECTION_DOWN),
- mLastTime(0)
+ mLastTime(0),
+ 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 = XML::getProperty(node, "variants", 0);
- int variant_offset = XML::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 = 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", "");
-
- 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 = XML::getProperty(node, "name", "");
- 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(),
- animationFile.c_str());
-
- // skip loading animations
- continue;
- }
- Spriteset *imageset = si->second;
-
- 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();
- 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 =
- XML::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 = XML::getProperty(phaseNode, "delay", 0);
-
- if (xmlStrEqual(phaseNode->name, BAD_CAST "frame"))
- {
- int index = XML::getProperty(phaseNode, "index", -1);
- int offsetX = XML::getProperty(phaseNode, "offsetX", 0);
- int offsetY = XML::getProperty(phaseNode, "offsetY", 0);
-
- offsetY -= imageset->getHeight() - 32;
- offsetX -= imageset->getWidth() / 2 - 16;
- Image *img = imageset->get(index + variant_offset);
- animation->addPhase(img, delay, offsetX, offsetY);
- }
- else if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence"))
- {
- int start = XML::getProperty(phaseNode, "start", 0);
- int end = XML::getProperty(phaseNode, "end", 0);
- int offsetY = -imageset->getHeight() + 32;
- int offsetX = -imageset->getWidth() / 2 + 16;
- while (end >= start)
- {
- Image *img = imageset->get(start + variant_offset);
- animation->addPhase(img, 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);
}
-void
-AnimatedSprite::substituteAction(SpriteAction complete,
- SpriteAction with)
+AnimatedSprite::AnimatedSprite(const std::string& filename, int variant):
+ mDirection(DIRECTION_DOWN),
+ mLastTime(0),
+ mFrameIndex(0),
+ mFrameTime(0),
+ mAnimation(0),
+ mFrame(0)
{
- if (mActions.find(complete) == mActions.end())
- {
- ActionIterator i = mActions.find(with);
- if (i != mActions.end()) {
- mActions[complete] = i->second;
- }
- }
+ ResourceManager *resman = ResourceManager::getInstance();
+ mSprite = resman->getSprite(filename, variant);
+ assert(mSprite);
+
+ // 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!", action);
- 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 finished = false;
// 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) {
- finished = !animation->update((unsigned int)(time - mLastTime));
- }
- mLastTime = time;
+ return;
}
- if (finished)
+ 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)
{
- const AnimationPhase *phase = getCurrentPhase();
- if (!phase || !phase->image)
+ if (!mFrame || Animation::isTerminator(*mFrame))
{
return false;
}
- Sint32 offsetX = phase->offsetX;
- Sint32 offsetY = phase->offsetY;
- return graphics->drawImage(phase->image, posX + offsetX, posY + offsetY);
-}
+ mFrameTime += time;
-int
-AnimatedSprite::getWidth() const
-{
- const AnimationPhase *phase = getCurrentPhase();
- return (phase && phase->image) ? phase->image->getWidth() : 0;
-}
+ while (mFrameTime > mFrame->delay && mFrame->delay > 0)
+ {
+ mFrameTime -= mFrame->delay;
+ mFrameIndex++;
-int
-AnimatedSprite::getHeight() const
-{
- const AnimationPhase *phase = getCurrentPhase();
- return (phase && phase->image) ? phase->image->getHeight() : 0;
-}
+ if (mFrameIndex == mAnimation->getLength())
+ {
+ mFrameIndex = 0;
+ }
-const AnimationPhase*
-AnimatedSprite::getCurrentPhase() const
-{
- if (!mAction)
- {
- return NULL;
- }
+ mFrame = mAnimation->getFrame(mFrameIndex);
- Animation *animation = mAction->getAnimation(mDirection);
- if (animation == NULL)
- {
- return NULL;
+ if (Animation::isTerminator(*mFrame))
+ {
+ mAnimation = 0;
+ mFrame = 0;
+ return false;
+ }
}
- return animation->getCurrentPhase();
+ 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 721a2824..e5a435f9 100644
--- a/src/animatedsprite.h
+++ b/src/animatedsprite.h
@@ -24,55 +24,34 @@
#ifndef _TMW_ANIMATEDSPRITE_H
#define _TMW_ANIMATEDSPRITE_H
+#include "resources/spritedef.h"
+
#include <map>
#include <string>
-#include <SDL_types.h>
-class Action;
class Graphics;
-class Spriteset;
struct AnimationPhase;
-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.
+ * 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);
/**
* Destructor.
@@ -80,8 +59,7 @@ class AnimatedSprite
~AnimatedSprite();
/**
- * Resets the animated sprite. This is used to synchronize several
- * animated sprites.
+ * Resets the animated sprite.
*/
void
reset();
@@ -104,67 +82,28 @@ class AnimatedSprite
* pixels.
*/
bool
- draw(Graphics* graphics, Sint32 posX, Sint32 posY) const;
-
- /**
- * Returns the width in pixels of the current animation phase.
- */
- int
- getWidth() const;
-
- /**
- * Returns 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);
-
- /**
- * Returns the current animation frame.
- */
- const AnimationPhase*
- getCurrentPhase() const;
-
- /**
- * 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;
+ SpriteDef *mSprite; /**< The sprite definition. */
+ Action *mAction; /**< The currently active action. */
+ Animation *mAnimation; /**< The currently active animation. */
+ AnimationPhase *mFrame; /**< The currently active frame. */
};
#endif
diff --git a/src/animation.cpp b/src/animation.cpp
index a91bdf8d..67fdae11 100644
--- a/src/animation.cpp
+++ b/src/animation.cpp
@@ -28,74 +28,28 @@
#include "utils/dtor.h"
Animation::Animation():
- mLength(0)
+ mDuration(0)
{
- reset();
-}
-
-void
-Animation::reset()
-{
- 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;
-}
-
-const AnimationPhase*
-Animation::getCurrentPhase() const
-{
- return mAnimationPhases.empty() ? NULL : &(*iCurrentPhase);
}
void
Animation::addPhase(Image *image, unsigned int delay, int offsetX, int offsetY)
{
// Add new phase to animation list
- AnimationPhase newPhase = { image, delay, offsetX, offsetY};
+ AnimationPhase newPhase = { image, delay, offsetX, offsetY };
mAnimationPhases.push_back(newPhase);
- mLength += delay;
- // Reset animation circle
- iCurrentPhase = mAnimationPhases.begin();
+ mDuration += delay;
}
void
Animation::addTerminator()
{
- AnimationPhase terminator = { NULL, 0, 0, 0};
- mAnimationPhases.push_back(terminator);
- iCurrentPhase = mAnimationPhases.begin();
+ addPhase(NULL, 0, 0, 0);
}
bool
-Animation::isTerminator(AnimationPhase candidate)
+Animation::isTerminator(const AnimationPhase candidate)
{
return (candidate.image == NULL);
}
diff --git a/src/animation.h b/src/animation.h
index 0230e820..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,6 +33,8 @@ class Spriteset;
/**
* A single frame in an animation, with a delay and an offset.
+ *
+ * TODO: Rename this struct to Frame
*/
struct AnimationPhase
{
@@ -56,12 +57,6 @@ class Animation
Animation();
/**
- * Restarts the animation from the first frame.
- */
- void
- reset();
-
- /**
* Appends a new animation at the end of the sequence
*/
void
@@ -69,46 +64,38 @@ class Animation
/**
* 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);
-
- const AnimationPhase*
- 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() const { return mLength; }
+ static bool
+ isTerminator(const AnimationPhase phase);
protected:
- static bool isTerminator(AnimationPhase phase);
- std::list<AnimationPhase> mAnimationPhases;
- std::list<AnimationPhase>::iterator iCurrentPhase;
- unsigned int mTime;
- int mLength;
+ std::vector<AnimationPhase> mAnimationPhases;
+ int mDuration;
};
#endif
diff --git a/src/being.cpp b/src/being.cpp
index 47f9965c..14d2df00 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -193,24 +193,10 @@ Being::setAction(Uint8 action)
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])
- {
- mSprites[i]->reset();
- }
- }
break;
case DEAD:
currentAction = ACTION_DEAD;
diff --git a/src/being.h b/src/being.h
index 42f37058..362fa393 100644
--- a/src/being.h
+++ b/src/being.h
@@ -206,7 +206,7 @@ class Being : public Sprite
/**
* Makes this being take the next step of his path.
*/
- void
+ virtual void
nextStep();
/**
diff --git a/src/game.cpp b/src/game.cpp
index ba65298f..7da80069 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -86,7 +86,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;
@@ -650,35 +650,35 @@ void Game::handleInput()
{
Uint16 x = player_node->mX;
Uint16 y = player_node->mY;
- 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] ||
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 802da92f..46348efc 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -82,9 +82,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();
}
@@ -171,10 +181,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);
@@ -218,14 +233,20 @@ void LocalPlayer::walk(unsigned char dir)
void LocalPlayer::setDestination(Uint16 x, Uint16 y)
{
- char temp[3];
- MessageOut outMsg(mNetwork);
- set_coordinates(temp, x, y, mDirection);
- outMsg.writeInt16(0x0085);
- outMsg.writeString(temp, 3);
+ // Only send a new message to the server when destination changes
+ if (x != destX || y != destY)
+ {
+ destX = x;
+ destY = y;
- mPickUpTarget = NULL;
+ char temp[3];
+ MessageOut outMsg(mNetwork);
+ set_coordinates(temp, x, y, mDirection);
+ outMsg.writeInt16(0x0085);
+ outMsg.writeString(temp, 3);
+ }
+ mPickUpTarget = NULL;
Being::setDestination(x, y);
}
diff --git a/src/localplayer.h b/src/localplayer.h
index a3fe91f7..04477af2 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -50,6 +50,11 @@ class LocalPlayer : public Player
void setNetwork(Network *network) { mNetwork = network; }
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();
/**
@@ -155,7 +160,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 destX; /**< X coordinate of destination. */
+ int destY; /**< Y coordinate of destination. */
};
extern LocalPlayer *player_node;
diff --git a/src/monster.cpp b/src/monster.cpp
index 8a7e2f32..ce073a04 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -32,7 +32,8 @@
Monster::Monster(Uint32 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/monster" + toString(job - 1002) + ".xml", 0);
}
void
diff --git a/src/player.cpp b/src/player.cpp
index 3f0ebfc4..df9b74f6 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -98,7 +98,6 @@ Player::setSex(Uint8 sex)
mSprites[BASE_SPRITE] = new AnimatedSprite(
"graphics/sprites/player_female_base.xml", 0);
}
- resetAnimations();
}
Being::setSex(sex);
}
@@ -144,7 +143,6 @@ Player::setHairColor(Uint16 color)
delete mSprites[HAIR_SPRITE];
mSprites[HAIR_SPRITE] = newHairSprite;
- resetAnimations();
setAction(mAction);
}
@@ -164,7 +162,6 @@ Player::setHairStyle(Uint16 style)
delete mSprites[HAIR_SPRITE];
mSprites[HAIR_SPRITE] = newHairSprite;
- resetAnimations();
setAction(mAction);
}
@@ -206,22 +203,9 @@ Player::setVisibleEquipment(Uint8 slot, Uint8 id)
delete mSprites[position];
mSprites[position] = equipmentSprite;
- resetAnimations();
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 e23110be..dab081f8 100644
--- a/src/player.h
+++ b/src/player.h
@@ -60,14 +60,6 @@ class Player : public Being
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/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index e729ecfc..f9a57e87 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"
@@ -44,11 +45,28 @@ ResourceManager::ResourceManager()
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;
@@ -80,7 +98,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
@@ -93,7 +111,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
@@ -212,6 +230,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)
{
diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h
index 0086b167..4367cd5e 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);
/**
* Releases a resource, removing it from the set of loaded resources.
diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp
new file mode 100644
index 00000000..21eae6e0
--- /dev/null
+++ b/src/resources/spritedef.cpp
@@ -0,0 +1,329 @@
+/*
+ * 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 = XML::getProperty(node, "variant_offset", 0);
+
+ if (variant_num > 0 && variant < variant_num ) {
+ variant_offset *= variant;
+ } else {
+ variant_offset = 0;
+ }
+
+ for (node = node->xmlChildrenNode; node != NULL; node = node->next)
+ {
+ if (xmlStrEqual(node->name, BAD_CAST "imageset"))
+ {
+ 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", "");
+
+ 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 = XML::getProperty(node, "name", "");
+ 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(),
+ animationFile.c_str());
+
+ // skip loading animations
+ continue;
+ }
+ Spriteset *imageset = si->second;
+
+ 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();
+ 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 =
+ XML::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 = XML::getProperty(phaseNode, "delay", 0);
+
+ if (xmlStrEqual(phaseNode->name, BAD_CAST "frame"))
+ {
+ int index = XML::getProperty(phaseNode, "index", -1);
+ int offsetX = XML::getProperty(phaseNode, "offsetX", 0);
+ int offsetY = XML::getProperty(phaseNode, "offsetY", 0);
+
+ offsetY -= imageset->getHeight() - 32;
+ offsetX -= imageset->getWidth() / 2 - 16;
+ Image *img = imageset->get(index + variant_offset);
+ animation->addPhase(img, delay, offsetX, offsetY);
+ }
+ else if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence"))
+ {
+ int start = XML::getProperty(phaseNode, "start", 0);
+ int end = XML::getProperty(phaseNode, "end", 0);
+ int offsetY = -imageset->getHeight() + 32;
+ int offsetX = -imageset->getWidth() / 2 + 16;
+ while (end >= start)
+ {
+ Image *img = imageset->get(start + variant_offset);
+ animation->addPhase(img, 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);
+
+ xmlFreeDoc(doc);
+}
+
+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..51c47a24
--- /dev/null
+++ b/src/resources/spritedef.h
@@ -0,0 +1,130 @@
+/*
+ * 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>
+
+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);
+
+ /**
+ * 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.