ManaPlus
actorsprite.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2010 The Mana Developers
4  * Copyright (C) 2011-2018 The ManaPlus Developers
5  *
6  * This file is part of The ManaPlus Client.
7  *
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
11  * any later version.
12  *
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.
17  *
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/>.
20  */
21 
22 #include "being/actorsprite.h"
23 
24 #include "configuration.h"
25 #include "statuseffect.h"
26 
27 #include "being/localplayer.h"
28 
29 #include "const/utils/timer.h"
30 
31 #include "gui/theme.h"
32 
34 
35 #include "particle/particle.h"
36 
38 
40 
44 
45 #include "utils/checkutils.h"
46 #include "utils/delete2.h"
47 #include "utils/foreach.h"
48 #include "utils/timer.h"
49 
50 #include "debug.h"
51 
52 #define for_each_cursors() \
53  for (int size = CAST_S32(TargetCursorSize::SMALL); \
54  size < CAST_S32(TargetCursorSize::NUM_TC); \
55  size ++) \
56  { \
57  for (int type = CAST_S32(TargetCursorType::NORMAL); \
58  type < CAST_S32(TargetCursorType::NUM_TCT); \
59  type ++) \
60 
61 #define end_foreach }
62 
66 bool ActorSprite::loaded = false;
67 
70  Actor(),
71  mStatusEffects(),
72  mStatusParticleEffects(nullptr, true),
73  mChildParticleEffects(&mStatusParticleEffects, false),
74  mHorseId(0),
75  mId(id),
76  mUsedTargetCursor(nullptr),
77  mActorSpriteListeners(),
78  mCursorPaddingX(0),
79  mCursorPaddingY(0),
80  mMustResetParticles(false),
81  mPoison(false),
82  mHaveCart(false),
83  mTrickDead(false)
84 {
85 }
86 
88 {
90  mMustResetParticles = true;
91 
92  mUsedTargetCursor = nullptr;
93 
94  if (localPlayer != nullptr &&
95  localPlayer != this &&
96  localPlayer->getTarget() == this)
97  {
98  localPlayer->setTarget(nullptr);
99  }
100 
101  // Notify listeners of the destruction.
103  {
104  if (reportFalse(*iter))
105  (*iter)->actorSpriteDestroyed(*this);
106  }
107 }
108 
110 {
111  BLOCK_START("ActorSprite::logic")
112  // Update sprite animations
114 
115  // Restart status/particle effects, if needed
117  {
118  mMustResetParticles = false;
119  FOR_EACH (std::set<int32_t>::const_iterator, it, mStatusEffects)
120  {
121  const StatusEffect *const effect
123  if (effect != nullptr &&
124  effect->mIsPersistent)
125  {
126  updateStatusEffect(*it,
127  Enable_true,
128  IsStart_false);
129  }
130  }
131  }
132 
133  // Update particle effects
135  BLOCK_END("ActorSprite::logic")
136 }
137 
138 void ActorSprite::setMap(Map *const map)
139 {
140  Actor::setMap(map);
141 
142  // Clear particle effect list because child particles became invalid
144  mMustResetParticles = true; // Reset status particles on next redraw
145 }
146 
148 {
149  if (particle != nullptr)
150  {
151  particle->setActor(mId);
153  }
154 }
155 
157 {
158  if (particle != nullptr)
159  {
160  // The effect may not die without the beings permission or we segfault
161  particle->disableAutoDelete();
163  }
164 }
165 
167 {
168  if (particle != nullptr)
170 }
171 
173 {
174  if (type == TargetCursorType::NONE)
175  {
176  untarget();
177  }
178  else
179  {
180  const size_t sz = CAST_SIZE(getTargetCursorSize());
182  if (mUsedTargetCursor != nullptr)
183  {
184  static const int targetWidths[CAST_SIZE(
186  = {0, 0, 0};
187  static const int targetHeights[CAST_SIZE(
189  = {-mapTileSize / 2, -mapTileSize / 2, -mapTileSize};
190 
191  mCursorPaddingX = CAST_S32(targetWidths[sz]);
192  mCursorPaddingY = CAST_S32(targetHeights[sz]);
193  }
194  }
195 }
196 
197 void ActorSprite::setStatusEffect(const int32_t index,
198  const Enable active,
199  const IsStart start)
200 {
201  const Enable wasActive = fromBool(
202  mStatusEffects.find(index) != mStatusEffects.end(), Enable);
203 
204  if (active != wasActive)
205  {
206  updateStatusEffect(index, active, start);
207  if (active == Enable_true)
208  {
209  mStatusEffects.insert(index);
210  }
211  else
212  {
213  mStatusEffects.erase(index);
214  }
215  }
216 }
217 
218 static void applyEffectByOption(ActorSprite *const actor,
219  uint32_t option,
220  const char *const name,
221  const OptionsMap& options)
222 {
223  FOR_EACH (OptionsMapCIter, it, options)
224  {
225  const uint32_t opt = (*it).first;
226  const int32_t id = (*it).second;
227  const Enable enable = (opt & option) != 0 ? Enable_true : Enable_false;
228  option |= opt;
229  option ^= opt;
230  actor->setStatusEffect(id,
231  enable,
232  IsStart_false);
233  }
234  if (option != 0U &&
235  config.getBoolValue("unimplimentedLog"))
236  {
237  const std::string str = strprintf(
238  "Error: unknown effect by %s. "
239  "Left value: %u",
240  name,
241  option);
242  logger->log(str);
244  }
245 }
246 
247 static void applyEffectByOption1(ActorSprite *const actor,
248  uint32_t option,
249  const char *const name,
250  const OptionsMap& options)
251 {
252  FOR_EACH (OptionsMapCIter, it, options)
253  {
254  const uint32_t opt = (*it).first;
255  const int32_t id = (*it).second;
256  if (opt == option)
257  {
258  actor->setStatusEffect(id,
259  Enable_true,
260  IsStart_false);
261  option = 0U;
262  }
263  else
264  {
265  actor->setStatusEffect(id,
266  Enable_false,
267  IsStart_false);
268  }
269  }
270  if (option != 0 &&
271  config.getBoolValue("unimplimentedLog"))
272  {
273  const std::string str = strprintf(
274  "Error: unknown effect by %s. "
275  "Left value: %u",
276  name,
277  option);
278  logger->log(str);
280  }
281 }
282 
284  const uint32_t opt1,
285  const uint32_t opt2,
286  const uint32_t opt3)
287 {
288  applyEffectByOption(this, option, "option",
290  applyEffectByOption1(this, opt1, "opt1",
292  applyEffectByOption(this, opt2, "opt2",
294  applyEffectByOption(this, opt3, "opt3",
296 }
297 
299  const uint32_t opt1,
300  const uint32_t opt2)
301 {
302  applyEffectByOption(this, option, "option",
304  applyEffectByOption1(this, opt1, "opt1",
306  applyEffectByOption(this, opt2, "opt2",
308 }
309 
311 {
312  applyEffectByOption(this, option, "option",
314 }
315 
316 void ActorSprite::updateStatusEffect(const int32_t index,
317  const Enable newStatus,
318  const IsStart start)
319 {
321  index, newStatus);
322  if (effect == nullptr)
323  return;
324  if (effect->mIsPoison && getType() == ActorType::Player)
325  setPoison(newStatus == Enable_true);
326  else if (effect->mIsCart && localPlayer == this)
327  setHaveCart(newStatus == Enable_true);
328  else if (effect->mIsRiding)
329  setRiding(newStatus == Enable_true);
330  else if (effect->mIsTrickDead)
331  setTrickDead(newStatus == Enable_true);
332  else if (effect->mIsPostDelay)
333  stopCast(newStatus == Enable_true);
334  handleStatusEffect(effect, index, newStatus, start);
335 }
336 
338  const int32_t effectId,
339  const Enable newStatus,
340  const IsStart start)
341 {
342  if (effect == nullptr)
343  return;
344 
345  if (newStatus == Enable_true)
346  {
347  if (effectId >= 0)
348  {
349  Particle *particle = nullptr;
350  if (start == IsStart_true)
351  particle = effect->getStartParticle();
352  if (particle == nullptr)
353  particle = effect->getParticle();
354  if (particle != nullptr)
355  mStatusParticleEffects.setLocally(effectId, particle);
356  }
357  }
358  else
359  {
361  }
362 }
363 
365  const ForceDisplay forceDisplay,
366  const DisplayTypeT displayType,
367  const std::string &color)
368 {
369  clear();
370 
371  FOR_EACH (SpriteRefs, it, display.sprites)
372  {
373  if (*it == nullptr)
374  continue;
375  const std::string file = pathJoin(paths.getStringValue("sprites"),
376  combineDye3((*it)->sprite, color));
377 
378  const int variant = (*it)->variant;
379  addSprite(AnimatedSprite::delayedLoad(file, variant));
380  }
381 
382  // Ensure that something is shown, if desired
383  if (mSprites.empty() && forceDisplay == ForceDisplay_true)
384  {
385  if (display.image.empty())
386  {
388  paths.getStringValue("sprites"),
389  paths.getStringValue("spriteErrorFile")),
390  0));
391  }
392  else
393  {
394  std::string imagePath;
395  switch (displayType)
396  {
397  case DisplayType::Item:
398  default:
399  imagePath = pathJoin(paths.getStringValue("itemIcons"),
400  display.image);
401  break;
402  case DisplayType::Floor:
403  imagePath = pathJoin(paths.getStringValue("itemIcons"),
404  display.floor);
405  break;
406  }
407  imagePath = combineDye2(imagePath, color);
408  Image *img = Loader::getImage(imagePath);
409 
410  if (img == nullptr)
411  img = Theme::getImageFromTheme("unknown-item.png");
412 
413  addSprite(new ImageSprite(img));
414  if (img != nullptr)
415  img->decRef();
416  }
417  }
418 
420 
421  // setup particle effects
422  if (ParticleEngine::enabled && (particleEngine != nullptr))
423  {
424  FOR_EACH (StringVectCIter, itr, display.particles)
425  {
426  Particle *const p = particleEngine->addEffect(*itr, 0, 0, 0);
428  }
429  }
430 
431  mMustResetParticles = true;
432 }
433 
435 {
436  if (loaded)
437  unload();
438 
440 
441  loaded = true;
442 }
443 
445 {
446  if (reportTrue(!loaded))
447  return;
448 
450  loaded = false;
451 }
452 
454 {
455  mActorSpriteListeners.push_front(listener);
456 }
457 
459  listener)
460 {
461  mActorSpriteListeners.remove(listener);
462 }
463 
464 static const char *cursorType(const TargetCursorTypeT type)
465 {
466  switch (type)
467  {
469  return "in-range";
470  default:
474  return "normal";
475  }
476 }
477 
478 static const char *cursorSize(const TargetCursorSizeT size)
479 {
480  switch (size)
481  {
483  return "l";
485  return "m";
486  default:
489  return "s";
490  }
491 }
492 
494 {
495  static const std::string targetCursorFile("target-cursor-%s-%s.xml");
496 
497  // Load target cursors
499  {
502  targetCursorFile.c_str(),
503  cursorType(static_cast<TargetCursorTypeT>(type)),
504  cursorSize(static_cast<TargetCursorSizeT>(size)))),
505  0);
506  }
508 }
509 
511 {
513  {
514  delete2(targetCursor[type][size])
515  }
517 }
518 
520 {
521  std::string effectsStr;
522  if (!mStatusEffects.empty())
523  {
524  FOR_EACH (std::set<int32_t>::const_iterator, it, mStatusEffects)
525  {
526  const StatusEffect *const effect =
528  *it,
529  Enable_true);
530  if (effect == nullptr)
531  continue;
532  if (!effectsStr.empty())
533  effectsStr.append(", ");
534  effectsStr.append(effect->mName);
535  }
536  }
537  return effectsStr;
538 }
void addLocally(Particle *const particle)
#define FOR_EACH(type, iter, array)
Definition: foreach.h:24
const OptionsMap & getOpt2Map()
ParticleVector mStatusParticleEffects
Definition: actorsprite.h:243
static bool enabled
std::string getStringValue(const std::string &key) const
void controlParticleDeleted(const Particle *const particle)
static bool loaded
Definition: actorsprite.h:238
void addActorSpriteListener(ActorSpriteListener *const listener)
void setupSpriteDisplay(const SpriteDisplay &display, const ForceDisplay forceDisplay, const DisplayTypeT displayType, const std::string &color)
bool update(const int time)
std::vector< SpriteReference * > sprites
Definition: spritedisplay.h:46
StringVect::const_iterator StringVectCIter
Definition: stringvector.h:30
volatile int tick_time
Definition: timer.cpp:52
Particle * addEffect(const std::string &particleEffectFile, const int pixelX, const int pixelY, const int rotation)
ParticleList mChildParticleEffects
Definition: actorsprite.h:244
const OptionsMap & getOpt1Map()
static AnimatedSprite * targetCursor[static_cast< size_t >(TargetCursorType::NUM_TCT)][static_cast< size_t >(TargetCursorSize::NUM_TC)]
Definition: actorsprite.h:236
std::string combineDye3(std::string file, const std::string &dye)
std::set< int32_t > mStatusEffects
Definition: actorsprite.h:241
void removeActorSpriteListener(ActorSpriteListener *const listener)
TargetCursorType ::T TargetCursorTypeT
std::string pathJoin(std::string str1, const std::string &str2)
ActorSpriteListeners::iterator ActorSpriteListenerIterator
Definition: actorsprite.h:252
void addSprite(Sprite *const sprite)
ActorSprite(const BeingId id)
Definition: actorsprite.cpp:68
#define BLOCK_START(name)
Definition: perfomance.h:78
std::string getStatusEffectsString() const
int mCursorPaddingX
Definition: actorsprite.h:255
Vector mPos
Definition: actor.h:139
ParticleEngine * particleEngine
Configuration config
int BeingId
Definition: beingid.h:29
virtual void updateStatusEffect(const int32_t index, const Enable newStatus, const IsStart start)
const OptionsMap & getOptionMap()
static const char * cursorSize(const TargetCursorSizeT size)
#define reportFalse(val)
Definition: checkutils.h:250
#define BLOCK_END(name)
Definition: perfomance.h:79
void controlAutoParticle(Particle *const particle)
#define delete2(var)
Definition: delete2.h:24
static AnimatedSprite * load(const std::string &filename, const int variant)
std::string mName
Definition: statuseffect.h:82
#define end_foreach
Definition: actorsprite.cpp:61
const bool Enable_true
Definition: enable.h:29
virtual TargetCursorSizeT getTargetCursorSize() const
Definition: actorsprite.h:98
void setLocally(const int index, Particle *const particle)
bool mMustResetParticles
Definition: actorsprite.h:259
const bool ForceDisplay_true
Definition: forcedisplay.h:29
Logger * logger
Definition: logger.cpp:88
DisplayType ::T DisplayTypeT
Definition: displaytype.h:31
void controlCustomParticle(Particle *const particle)
virtual void setTrickDead(const bool b)
Definition: actorsprite.h:180
bool getBoolValue(const std::string &key) const
#define CAST_S32
Definition: cast.h:29
virtual void stopCast(const bool b)
Definition: actorsprite.h:191
OptionsMap::const_iterator OptionsMapCIter
std::string strprintf(const char *const format,...)
Definition: stringutils.cpp:99
void setStatusEffectOpiton0(const uint32_t option)
Image * getImage(const std::string &idPath)
Definition: imageloader.cpp:85
static AnimatedSprite * delayedLoad(const std::string &filename, const int variant)
#define fromBool(val, name)
Definition: booldefines.h:48
const bool IsStart_true
Definition: isstart.h:29
StringVect particles
Definition: spritedisplay.h:47
static const char * cursorType(const TargetCursorTypeT type)
AnimatedSprite * mUsedTargetCursor
Definition: actorsprite.h:249
void setTargetType(const TargetCursorTypeT type)
LocalPlayer * localPlayer
static Image * getImageFromTheme(const std::string &path)
Definition: theme.cpp:654
std::vector< Sprite * > mSprites
#define for_each_cursors()
Definition: actorsprite.cpp:52
#define nullptr
Definition: localconsts.h:44
static void load()
static const int MILLISECONDS_IN_A_TICK
Definition: timer.h:29
virtual void setMap(Map *const map)
Definition: actor.cpp:47
bool Enable
Definition: enable.h:29
void setHaveCart(const bool b)
Definition: actorsprite.h:171
void setPoison(const bool b)
Definition: actorsprite.h:165
static void applyEffectByOption1(ActorSprite *const actor, uint32_t option, const char *const name, const OptionsMap &options)
const bool IsStart_false
Definition: isstart.h:29
int mCursorPaddingY
Definition: actorsprite.h:256
bool mIsPersistent
Definition: statuseffect.h:83
Definition: map.h:71
std::string floor
Definition: spritedisplay.h:45
const bool Enable_false
Definition: enable.h:29
bool mIsTrickDead
Definition: statuseffect.h:87
virtual void setRiding(const bool b)
Definition: actorsprite.h:177
float x
Definition: vector.h:208
virtual void logic()
Configuration paths
void setActor(const BeingId actor)
Definition: particle.h:243
ActorSpriteListeners mActorSpriteListeners
Definition: actorsprite.h:253
bool mIsPostDelay
Definition: statuseffect.h:88
const OptionsMap & getOpt3Map()
static void cleanupTargetCursors()
void moveTo(const float x, const float y)
static void applyEffectByOption(ActorSprite *const actor, uint32_t option, const char *const name, const OptionsMap &options)
void setStatusEffectOpitons(const uint32_t option, const uint32_t opt1, const uint32_t opt2, const uint32_t opt3)
void setTarget(Being *const target)
float y
Definition: vector.h:208
Definition: actor.h:40
Definition: image.h:61
StatusEffect * getStatusEffect(const int index, const Enable enabling)
static const int mapTileSize
Definition: map.h:26
#define reportTrue(val)
Definition: checkutils.h:251
std::string combineDye2(std::string file, const std::string &dye)
#define CAST_SIZE
Definition: cast.h:33
static void distributeEvent(const std::string &msg)
void setMap(Map *const map)
void log(const char *const log_text,...)
Definition: logger.cpp:264
void removeLocally(const Particle *const particle)
void untarget()
Definition: actorsprite.h:115
void setStatusEffect(const int32_t index, const Enable active, const IsStart start)
Particle * getParticle() const
void disableAutoDelete()
Definition: particle.h:226
void decRef()
Definition: image.cpp:522
BeingId mId
Definition: actorsprite.h:246
static std::string resolveThemePath(const std::string &path)
Definition: theme.cpp:626
TargetCursorSize ::T TargetCursorSizeT
static void unload()
std::map< uint32_t, uint32_t > OptionsMap
static void initTargetCursor()
virtual void handleStatusEffect(const StatusEffect *const effect, const int32_t effectId, const Enable newStatus, const IsStart start)
std::string image
Definition: spritedisplay.h:44
Being * getTarget() const
virtual ActorTypeT getType() const
Definition: actorsprite.h:72
std::vector< SpriteReference * >::const_iterator SpriteRefs
Particle * getStartParticle() const
void delLocally(const int index)