3
* Copyright (C) 2010 The Mana Developers
4
* Copyright (C) 2011-2013 The ManaPlus Developers
6
* This file is part of The ManaPlus Client.
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
#include "actorsprite.h"
24
#include "actorspritelistener.h"
26
#include "configuration.h"
27
#include "effectmanager.h"
28
#include "imagesprite.h"
29
#include "localplayer.h"
30
#include "simpleanimation.h"
31
#include "soundmanager.h"
32
#include "statuseffect.h"
34
#include "gui/theme.h"
38
#include "resources/imageset.h"
39
#include "resources/resourcemanager.h"
41
#include "utils/checkutils.h"
45
AnimatedSprite *ActorSprite::targetCursor[2][NUM_TC];
46
bool ActorSprite::loaded = false;
48
ActorSprite::ActorSprite(const int id) :
52
mStunParticleEffects(),
53
mStatusParticleEffects(&mStunParticleEffects, false),
54
mChildParticleEffects(&mStatusParticleEffects, false),
57
mUsedTargetCursor(nullptr),
58
mActorSpriteListeners(),
61
mMustResetParticles(false)
65
ActorSprite::~ActorSprite()
69
mUsedTargetCursor = nullptr;
71
if (player_node && player_node->getTarget() == this)
72
player_node->setTarget(nullptr);
74
// Notify listeners of the destruction.
75
FOR_EACH (ActorSpriteListenerIterator, iter, mActorSpriteListeners)
77
if (reportFalse(*iter))
78
(*iter)->actorSpriteDestroyed(*this);
82
bool ActorSprite::draw(Graphics *const graphics,
83
const int offsetX, const int offsetY) const
85
FUNC_BLOCK("ActorSprite::draw", 1)
86
const int px = getPixelX() + offsetX - 16;
87
// Temporary fix to the Y offset.
88
#ifdef MANASERV_SUPPORT
89
const int py = getPixelY() + offsetY -
90
((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : 32);
92
const int py = getPixelY() + offsetY - 32;
95
if (mUsedTargetCursor)
97
mUsedTargetCursor->update(tick_time * MILLISECONDS_IN_A_TICK);
98
mUsedTargetCursor->draw(graphics,
99
px + getTargetOffsetX() - mCursorPaddingX,
100
py + getTargetOffsetY() - mCursorPaddingY);
103
return drawSpriteAt(graphics, px, py);
106
bool ActorSprite::drawSpriteAt(Graphics *const graphics,
107
const int x, const int y) const
109
return CompoundSprite::draw(graphics, x, y);
112
void ActorSprite::logic()
114
BLOCK_START("ActorSprite::logic")
115
// Update sprite animations
116
update(tick_time * MILLISECONDS_IN_A_TICK);
118
// Restart status/particle effects, if needed
119
if (mMustResetParticles)
121
mMustResetParticles = false;
122
FOR_EACH (std::set<int>::const_iterator, it, mStatusEffects)
124
const StatusEffect *const effect
125
= StatusEffect::getStatusEffect(*it, true);
126
if (effect && effect->particleEffectIsPersistent())
127
updateStatusEffect(*it, true);
131
// Update particle effects
132
mChildParticleEffects.moveTo(mPos.x, mPos.y);
133
BLOCK_END("ActorSprite::logic")
136
void ActorSprite::actorLogic()
140
void ActorSprite::setMap(Map *const map)
144
// Clear particle effect list because child particles became invalid
145
mChildParticleEffects.clear();
146
mMustResetParticles = true; // Reset status particles on next redraw
149
void ActorSprite::controlParticle(Particle *const particle)
151
mChildParticleEffects.addLocally(particle);
154
void ActorSprite::setTargetType(const TargetCursorType type)
156
static const int targetWidths[ActorSprite::NUM_TC] = {0, 0, 0};
157
static const int targetHeights[ActorSprite::NUM_TC] = {-16, -16, -32};
159
if (type == TCT_NONE)
165
const TargetCursorSize sz = getTargetCursorSize();
166
mUsedTargetCursor = targetCursor[type][sz];
167
if (mUsedTargetCursor)
169
mCursorPaddingX = targetWidths[sz];
170
mCursorPaddingY = targetHeights[sz];
175
struct EffectDescription final
177
std::string mGFXEffect;
178
std::string mSFXEffect;
181
void ActorSprite::setStatusEffect(const int index, const bool active)
183
const bool wasActive = mStatusEffects.find(index) != mStatusEffects.end();
185
if (active != wasActive)
187
updateStatusEffect(index, active);
189
mStatusEffects.insert(index);
191
mStatusEffects.erase(index);
195
void ActorSprite::setStatusEffectBlock(const int offset,
196
const uint16_t newEffects)
198
for (unsigned i = 0; i < STATUS_EFFECTS; i++)
200
const int index = StatusEffect::blockEffectIndexToEffectIndex(
204
setStatusEffect(index, (newEffects & (1 << i)) > 0);
208
void ActorSprite::updateStunMode(const int oldMode, const int newMode)
210
handleStatusEffect(StatusEffect::getStatusEffect(oldMode, false), -1);
211
handleStatusEffect(StatusEffect::getStatusEffect(newMode, true), -1);
214
void ActorSprite::updateStatusEffect(const int index, const bool newStatus)
216
handleStatusEffect(StatusEffect::getStatusEffect(index, newStatus), index);
219
void ActorSprite::handleStatusEffect(StatusEffect *const effect,
225
Particle *const particle = effect->getParticle();
229
mStatusParticleEffects.setLocally(effectId, particle);
233
mStunParticleEffects.clearLocally();
235
mStunParticleEffects.addLocally(particle);
239
void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
240
const bool forceDisplay,
242
const std::string &color)
246
FOR_EACH (SpriteRefs, it, display.sprites)
250
const std::string file = paths.getStringValue("sprites").append(
251
combineDye3((*it)->sprite, color));
253
const int variant = (*it)->variant;
254
addSprite(AnimatedSprite::delayedLoad(file, variant));
257
// Ensure that something is shown, if desired
258
if (empty() && forceDisplay)
260
if (display.image.empty())
262
addSprite(AnimatedSprite::delayedLoad(
263
paths.getStringValue("sprites").append(
264
paths.getStringValue("spriteErrorFile"))));
268
ResourceManager *const resman = ResourceManager::getInstance();
269
std::string imagePath;
274
imagePath = paths.getStringValue("itemIcons").append(
278
imagePath = paths.getStringValue("itemIcons").append(
282
imagePath = combineDye2(imagePath, color);
284
Image *img = resman->getImage(imagePath);
287
img = Theme::getImageFromTheme("unknown-item.png");
289
addSprite(new ImageSprite(img));
295
mChildParticleEffects.clear();
297
// setup particle effects
298
if (Particle::enabled && particleEngine)
300
FOR_EACH (StringVectCIter, itr, display.particles)
302
Particle *const p = particleEngine->addEffect(*itr, 0, 0);
307
mMustResetParticles = true;
310
void ActorSprite::load()
320
void ActorSprite::unload()
322
if (reportTrue(!loaded))
325
cleanupTargetCursors();
329
void ActorSprite::addActorSpriteListener(ActorSpriteListener *const listener)
331
mActorSpriteListeners.push_front(listener);
334
void ActorSprite::removeActorSpriteListener(ActorSpriteListener *const
337
mActorSpriteListeners.remove(listener);
340
static const char *cursorType(const int type)
344
case ActorSprite::TCT_IN_RANGE:
347
case ActorSprite::TCT_NORMAL:
352
static const char *cursorSize(const int size)
356
case ActorSprite::TC_LARGE:
358
case ActorSprite::TC_MEDIUM:
361
case ActorSprite::TC_SMALL:
366
void ActorSprite::initTargetCursor()
368
static const std::string targetCursorFile = "%s/target-cursor-%s-%s.xml";
370
const std::string path = branding.getStringValue("guiPath");
372
// Load target cursors
373
for (int size = TC_SMALL; size < NUM_TC; size++)
375
for (int type = TCT_NORMAL; type < NUM_TCT; type++)
377
targetCursor[type][size] = AnimatedSprite::load(strprintf(
378
targetCursorFile.c_str(), path.c_str(), cursorType(type),
384
void ActorSprite::cleanupTargetCursors()
386
for (int size = TC_SMALL; size < NUM_TC; size++)
388
for (int type = TCT_NORMAL; type < NUM_TCT; type++)
390
if (targetCursor[type][size])
392
delete targetCursor[type][size];
393
targetCursor[type][size] = nullptr;