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 "game.h"
24
#include "localplayer.h"
25
#include "monster.h"
26
#include "particle.h"
27
#include "sound.h"
28
#include "text.h"
29
30
#include "gui/palette.h"
31
32
#include "resources/monsterdb.h"
33
#include "resources/monsterinfo.h"
34
35
Monster::Monster(int id, int job, Map *map):
36
    Being(id, job, map)
37
{
38
    const MonsterInfo& info = getInfo();
39
40
    // Setup Monster sprites
41
    const std::list<std::string> &sprites = info.getSprites();
42
43
    for (std::list<std::string>::const_iterator i = sprites.begin();
44
         i != sprites.end(); i++)
45
    {
46
        std::string file = "graphics/sprites/" + *i;
47
        mSprites.push_back(AnimatedSprite::load(file));
48
    }
49
50
    // Ensure that something is shown
51
    if (mSprites.size() == 0)
52
    {
53
        mSprites.push_back(AnimatedSprite::load("graphics/sprites/error.xml"));
54
    }
55
56
    if (mParticleEffects)
57
    {
58
        const std::list<std::string> &particleEffects = info.getParticleEffects();
59
        for (std::list<std::string>::const_iterator i = particleEffects.begin();
60
             i != particleEffects.end(); i++)
61
        {
62
            controlParticle(particleEngine->addEffect((*i), 0, 0));
63
        }
64
    }
65
66
    mNameColor = &guiPalette->getColor(Palette::MONSTER);
67
    mTextColor = &guiPalette->getColor(Palette::MONSTER);
68
69
    Being::setName(getInfo().getName());
70
}
71
72
#ifdef EATHENA_SUPPORT
73
void Monster::logic()
74
{
75
    if (mAction != STAND)
76
    {
77
        mFrame = (get_elapsed_time(mWalkTime) * 4) / getWalkSpeed();
78
79
        if (mFrame >= 4 && mAction != DEAD)
80
            nextStep();
81
    }
82
83
    Being::logic();
84
}
85
#endif
86
87
void Monster::setAction(Action action, int attackType)
88
{
89
    SpriteAction currentAction = ACTION_INVALID;
90
    int rotation = 0;
91
    std::string particleEffect;
92
93
    switch (action)
94
    {
95
        case WALK:
96
            currentAction = ACTION_WALK;
97
            break;
98
        case DEAD:
99
            currentAction = ACTION_DEAD;
100
            sound.playSfx(getInfo().getSound(MONSTER_EVENT_DIE));
101
            break;
102
        case ATTACK:
103
            currentAction = getInfo().getAttackAction(attackType);
104
            for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
105
                (*it)->reset();
106
107
            //attack particle effect
108
            particleEffect = getInfo().getAttackParticleEffect(attackType);
109
            if (!particleEffect.empty() && mParticleEffects)
110
            {
111
                switch (mSpriteDirection)
112
                {
113
                    case DIRECTION_DOWN: rotation = 0; break;
114
                    case DIRECTION_LEFT: rotation = 90; break;
115
                    case DIRECTION_UP: rotation = 180; break;
116
                    case DIRECTION_RIGHT: rotation = 270; break;
117
                    default: break;
118
                }
119
                Particle *p;
120
                p = particleEngine->addEffect(particleEffect, 0, 0, rotation);
121
                controlParticle(p);
122
            }
123
            break;
124
        case STAND:
125
           currentAction = ACTION_STAND;
126
           break;
127
        case HURT:
128
           // Not implemented yet
129
           break;
130
        case SIT:
131
           // Also not implemented yet
132
           break;
133
    }
134
135
    if (currentAction != ACTION_INVALID)
136
    {
137
        for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
138
            if (*it)
139
                (*it)->play(currentAction);
140
        mAction = action;
141
    }
142
}
143
144
void Monster::handleAttack(Being *victim, int damage, AttackType type)
145
{
146
    Being::handleAttack(victim, damage, type);
147
148
    const MonsterInfo &mi = getInfo();
149
    sound.playSfx(mi.getSound((damage > 0) ?
150
                MONSTER_EVENT_HIT : MONSTER_EVENT_MISS));
151
}
152
153
void Monster::takeDamage(Being *attacker, int amount, AttackType type)
154
{
155
    if (amount > 0)
156
        sound.playSfx(getInfo().getSound(MONSTER_EVENT_HURT));
157
158
    Being::takeDamage(attacker, amount, type);
159
}
160
161
Being::TargetCursorSize Monster::getTargetCursorSize() const
162
{
163
    return getInfo().getTargetCursorSize();
164
}
165
166
const MonsterInfo &Monster::getInfo() const
167
{
168
    return MonsterDB::get(mJob);
169
}
170
171
void Monster::updateCoords()
172
{
173
    if (mDispName)
174
    {
175
        mDispName->adviseXY(getPixelX(),
176
                        getPixelY() - getHeight() - mDispName->getHeight());
177
    }
178
}
179
180
void Monster::showName()
181
{
182
    Being::showName();
183
184
    updateCoords();
185
}