summaryrefslogtreecommitdiff
path: root/src/animatedsprite.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/animatedsprite.cpp')
-rw-r--r--src/animatedsprite.cpp430
1 files changed, 103 insertions, 327 deletions
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;
- };
}