ManaPlus
effectmanager.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2008 Fate <[email protected]>
4  * Copyright (C) 2008 Chuck Miller <[email protected]>
5  * Copyright (C) 2011-2019 The ManaPlus Developers
6  * Copyright (C) 2019-2021 Andrei Karas
7  *
8  * This file is part of The ManaPlus Client.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "effectmanager.h"
25 
26 #include "configuration.h"
27 #include "soundmanager.h"
28 
29 #include "being/being.h"
30 
31 #include "utils/checkutils.h"
32 
33 #include "particle/particle.h"
34 
35 #include "resources/beingcommon.h"
36 
37 #include "debug.h"
38 
40 
42  mEffects(),
43  mTimers()
44 {
45  logger->log1("Effects are now loading");
47  loadXmlFile(paths.getStringValue("effectsPatchFile"), SkipError_true);
48  loadXmlDir("effectsPatchDir", loadXmlFile)
49 }
50 
51 void EffectManager::loadXmlFile(const std::string &fileName,
52  const SkipError skipError)
53 {
54  XML::Document doc(fileName, UseVirtFs_true, skipError);
55  XmlNodeConstPtrConst root = doc.rootNode();
56 
57  if ((root == nullptr) ||
58  !xmlNameEqual(root, "being-effects"))
59  {
60  logger->log("Error loading being effects file: " + fileName);
61  return;
62  }
63 
64  for_each_xml_child_node(node, root)
65  {
66  if (xmlNameEqual(node, "include"))
67  {
68  const std::string name = XML::getProperty(node, "name", "");
69  if (!name.empty())
70  loadXmlFile(name, skipError);
71  continue;
72  }
73  else if (xmlNameEqual(node, "effect"))
74  {
75  mEffects.push_back(EffectDescription(
76  XML::getProperty(node, "id", -1),
77  XML::getProperty(node, "particle", ""),
78  XML::getProperty(node, "audio", ""),
79  XML::getProperty(node, "sprite", "")));
80  }
81  }
82 }
83 
85 {
86 }
87 
89  Being *const being,
90  const SpriteDirection::Type &direction)
91 {
92  int rotation;
93  switch (direction)
94  {
100  default:
101  rotation = 0;
102  break;
104  rotation = 90;
105  break;
106  case SpriteDirection::UP:
109  rotation = 180;
110  break;
112  rotation = 270;
113  break;
114  }
115 
116  return trigger(id, being, rotation);
117 }
118 
119 bool EffectManager::trigger(const int id,
120  Being *const being,
121  const int rotation)
122 {
123  if ((being == nullptr) || (particleEngine == nullptr) || id == -1)
124  return false;
125 
126  BLOCK_START("EffectManager::trigger")
127  bool rValue = false;
128  FOR_EACH (STD_VECTOR<EffectDescription>::const_iterator, i, mEffects)
129  {
130  const EffectDescription &effect = *i;
131  if (effect.id == id)
132  {
133  rValue = true;
134  if (!effect.gfx.empty())
135  {
136  Particle *const selfFX = particleEngine->addEffect(
137  effect.gfx, 0, 0, rotation);
138  being->controlAutoParticle(selfFX);
139  }
140  if (!effect.sfx.empty())
141  soundManager.playSfx(effect.sfx, 0, 0);
142  if (!effect.sprite.empty())
143  being->addEffect(effect.sprite);
144  return rValue;
145  }
146  }
147  reportAlways("Missing effect %d", id)
148  BLOCK_END("EffectManager::trigger")
149  return rValue;
150 }
151 
153  Being *const being,
154  const int rotation)
155 {
156  if ((being == nullptr) || (particleEngine == nullptr) || id == -1)
157  return nullptr;
158 
159  Particle *rValue = nullptr;
160  FOR_EACH (STD_VECTOR<EffectDescription>::const_iterator, i, mEffects)
161  {
162  const EffectDescription &effect = *i;
163  if (effect.id == id)
164  {
165  if (!effect.gfx.empty())
166  {
167  rValue = particleEngine->addEffect(
168  effect.gfx, 0, 0, rotation);
169  being->controlCustomParticle(rValue);
170  }
171  if (!effect.sfx.empty())
172  soundManager.playSfx(effect.sfx, 0, 0);
173  if (!effect.sprite.empty())
174  being->addEffect(effect.sprite);
175  return rValue;
176  }
177  }
178  reportAlways("Missing effect %d", id)
179  return rValue;
180 }
181 
182 bool EffectManager::trigger(const int id,
183  const int x, const int y,
184  const time_t endTime,
185  const int rotation)
186 {
187  if ((particleEngine == nullptr) || id == -1)
188  return false;
189 
190  bool rValue = false;
191  FOR_EACH (STD_VECTOR<EffectDescription>::const_iterator, i, mEffects)
192  {
193  const EffectDescription &effect = *i;
194  if (effect.id == id)
195  {
196  rValue = true;
197  if (!effect.gfx.empty())
198  {
199  Particle *const particle = particleEngine->addEffect(
200  effect.gfx,
201  x, y,
202  rotation);
203  if (particle != nullptr)
204  mTimers.push_back(ParticleTimer(particle, endTime));
205  }
206  if (!effect.sfx.empty())
207  soundManager.playSfx(effect.sfx, 0, 0);
208  return rValue;
209  }
210  }
211  reportAlways("Missing effect %d", id)
212  return rValue;
213 }
214 
216  Being *const being,
217  const int defaultEffectId)
218 {
219  if (effectId == -1)
220  effectId = defaultEffectId;
221  if (effectId == -1)
222  return;
223  trigger(effectId, being, 0);
224 }
225 
227  const int x,
228  const int y,
229  const time_t endTime,
230  const int defaultEffectId)
231 {
232  if (effectId == -1)
233  effectId = defaultEffectId;
234  if (effectId == -1)
235  return;
236  trigger(effectId, x, y, endTime, 0);
237 }
238 
240 {
241  const time_t time = cur_time;
242  bool found(true);
243  while (found)
244  {
245  found = false;
246  FOR_EACH (std::list<ParticleTimer>::iterator, it, mTimers)
247  {
248  const ParticleTimer &timer = *it;
249  if (timer.endTime < time)
250  {
251  found = true;
252  Particle *const particle = timer.particle;
253  if (particle != nullptr)
254  particle->kill();
255  mTimers.erase(it);
256  break;
257  }
258  }
259  }
260 }
261 
263 {
264  FOR_EACH (std::list<ParticleTimer>::iterator, it, mTimers)
265  {
266  Particle *const particle = (*it).particle;
267  if (particle != nullptr)
268  particle->kill();
269  }
270  mTimers.clear();
271 }
volatile time_t cur_time
Definition: timer.cpp:58
#define loadXmlDir(name, function)
Definition: beingcommon.h:39
#define reportAlways(...)
Definition: checkutils.h:253
void controlCustomParticle(Particle *const particle)
void controlAutoParticle(Particle *const particle)
Definition: being.h:96
void addEffect(const std::string &name)
Definition: being.cpp:4959
std::string getStringValue(const std::string &key) const
Particle * triggerReturn(const int id, Being *const being, const int rotation)
std::list< ParticleTimer > mTimers
Definition: effectmanager.h:97
void loadXmlFile(const std::string &fileName, const SkipError skipError)
bool triggerDirection(const int id, Being *const being, const SpriteDirection::Type &direction)
bool trigger(const int id, Being *const being, const int rotation)
void triggerDefault(int effectId, Being *const being, const int defaultEffectId)
std::vector< EffectDescription > mEffects
Definition: effectmanager.h:96
void log(const char *const log_text,...)
Definition: logger.cpp:269
void log1(const char *const log_text)
Definition: logger.cpp:238
Particle * addEffect(const std::string &particleEffectFile, const int pixelX, const int pixelY, const int rotation)
void kill()
Definition: particle.h:220
void playSfx(const std::string &path, const int x, const int y) const
xmlNodePtr rootNode()
Definition: libxml.cpp:169
Configuration paths
EffectManager * effectManager
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define for_each_xml_child_node(var, parent)
Definition: libxml.h:161
Logger * logger
Definition: logger.cpp:89
int getProperty(const xmlNodePtr node, const char *const name, int def)
Definition: libxml.cpp:174
ParticleEngine * particleEngine
#define BLOCK_END(name)
Definition: perfomance.h:80
#define BLOCK_START(name)
Definition: perfomance.h:79
const bool SkipError_false
Definition: skiperror.h:30
const bool SkipError_true
Definition: skiperror.h:30
bool SkipError
Definition: skiperror.h:30
SoundManager soundManager
Particle *const particle
Definition: particletimer.h:40
const time_t endTime
Definition: particletimer.h:41
std::string fileName
Definition: testmain.cpp:39
const bool UseVirtFs_true
Definition: usevirtfs.h:30