1
/*
2
 *  The Mana World
3
 *  Copyright (C) 2004  The Mana World Development Team
4
 *
5
 *  This file is part of The Mana World.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
22
#include "animatedsprite.h"
23
#include "graphics.h"
24
#include "log.h"
25
26
#include "resources/action.h"
27
#include "resources/animation.h"
28
#include "resources/image.h"
29
#include "resources/resourcemanager.h"
30
31
#include "utils/xml.h"
32
33
#include <cassert>
34
35
AnimatedSprite::AnimatedSprite(SpriteDef *sprite):
36
    mDirection(DIRECTION_DOWN),
37
    mLastTime(0),
38
    mFrameIndex(0),
39
    mFrameTime(0),
40
    mSprite(sprite),
41
    mAction(0),
42
    mAnimation(0),
43
    mFrame(0),
44
    mAlpha(1.0f)
45
{
46
    assert(mSprite);
47
48
    // Take possession of the sprite
49
    mSprite->incRef();
50
51
    // Play the stand animation by default
52
    play(ACTION_STAND);
53
}
54
55
AnimatedSprite *AnimatedSprite::load(const std::string &filename, int variant)
56
{
57
    ResourceManager *resman = ResourceManager::getInstance();
58
    SpriteDef *s = resman->getSprite(filename, variant);
59
    if (!s)
60
        return NULL;
61
    AnimatedSprite *as = new AnimatedSprite(s);
62
    s->decRef();
63
    return as;
64
}
65
66
AnimatedSprite::~AnimatedSprite()
67
{
68
    mSprite->decRef();
69
}
70
71
void AnimatedSprite::reset()
72
{
73
    mFrameIndex = 0;
74
    mFrameTime = 0;
75
    mLastTime = 0;
76
}
77
78
void AnimatedSprite::play(SpriteAction spriteAction)
79
{
80
    Action *action = mSprite->getAction(spriteAction);
81
    if (!action)
82
        return;
83
84
    mAction = action;
85
    Animation *animation = mAction->getAnimation(mDirection);
86
87
    if (animation && animation != mAnimation && animation->getLength() > 0)
88
    {
89
        mAnimation = animation;
90
        mFrame = mAnimation->getFrame(0);
91
92
        reset();
93
    }
94
}
95
96
void AnimatedSprite::update(int time)
97
{
98
    // Avoid freaking out at first frame or when tick_time overflows
99
    if (time < mLastTime || mLastTime == 0)
100
        mLastTime = time;
101
102
    // If not enough time has passed yet, do nothing
103
    if (time <= mLastTime || !mAnimation)
104
        return;
105
106
    unsigned int dt = time - mLastTime;
107
    mLastTime = time;
108
109
    if (!updateCurrentAnimation(dt))
110
    {
111
        // Animation finished, reset to default
112
        play(ACTION_STAND);
113
    }
114
}
115
116
bool AnimatedSprite::updateCurrentAnimation(unsigned int time)
117
{
118
    if (!mFrame || Animation::isTerminator(*mFrame))
119
        return false;
120
121
    mFrameTime += time;
122
123
    while (mFrameTime > mFrame->delay && mFrame->delay > 0)
124
    {
125
        mFrameTime -= mFrame->delay;
126
        mFrameIndex++;
127
128
        if (mFrameIndex == mAnimation->getLength())
129
            mFrameIndex = 0;
130
131
        mFrame = mAnimation->getFrame(mFrameIndex);
132
133
        if (Animation::isTerminator(*mFrame))
134
        {
135
            mAnimation = 0;
136
            mFrame = 0;
137
            return false;
138
        }
139
    }
140
141
    return true;
142
}
143
144
bool AnimatedSprite::draw(Graphics *graphics, int posX, int posY) const
145
{
146
    if (!mFrame)
147
        return false;
148
149
    if (!mFrame->image)
150
      return false;
151
152
    if (mFrame->image->getAlpha() != mAlpha)
153
        mFrame->image->setAlpha(mAlpha);
154
155
    return graphics->drawImage(mFrame->image,
156
                               posX + mFrame->offsetX,
157
                               posY + mFrame->offsetY);
158
}
159
160
void AnimatedSprite::setDirection(SpriteDirection direction)
161
{
162
    if (mDirection != direction)
163
    {
164
        mDirection = direction;
165
166
        if (!mAction)
167
            return;
168
169
        Animation *animation = mAction->getAnimation(mDirection);
170
171
        if (animation && animation != mAnimation && animation->getLength() > 0)
172
        {
173
            mAnimation = animation;
174
            mFrame = mAnimation->getFrame(0);
175
            reset();
176
        }
177
    }
178
}
179
180
int AnimatedSprite::getWidth() const
181
{
182
    if (mFrame)
183
        return mFrame->image ? mFrame->image->getWidth() : 0;
184
    else
185
        return 0;
186
}
187
188
int AnimatedSprite::getHeight() const
189
{
190
    if (mFrame)
191
        return mFrame->image ? mFrame->image->getHeight() : 0;
192
    else
193
        return 0;
194
}