ManaPlus
spellmanager.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2009 The Mana World Development Team
4  * Copyright (C) 2011-2019 The ManaPlus Developers
5  * Copyright (C) 2009-2021 Andrei Karas
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "spellmanager.h"
24 
25 #include "configuration.h"
26 #include "textcommand.h"
27 
28 #include "being/localplayer.h"
29 #ifdef TMWA_SUPPORT
30 #include "being/playerinfo.h"
31 #endif // TMWA_SUPPORT
32 
33 #include "const/spells.h"
34 
35 #include "gui/windows/chatwindow.h"
36 
37 #include "net/playerhandler.h"
38 
40 
41 #include "utils/dtor.h"
42 #include "utils/foreach.h"
43 
44 #include <sstream>
45 
46 #include "debug.h"
47 
49 
51  mSpells(),
52  mSpellsVector()
53 {
54  load();
55 }
56 
58 {
60  mSpells.clear();
61  mSpellsVector.clear();
62 }
63 
64 TextCommand* SpellManager::getSpell(const int spellId) const
65 {
66  if (spellId < 0 || CAST_SIZE(spellId) >= mSpells.size())
67  return nullptr;
68 
69  const std::map<unsigned int, TextCommand*>::const_iterator
70  it = mSpells.find(spellId);
71 
72  return it != mSpells.end() ? (*it).second : nullptr;
73 }
74 
75 const TextCommand* SpellManager::getSpellByItem(const int itemId) const
76 {
77  return getSpell(itemId - SPELL_MIN_ID);
78 }
79 
81 {
83 
84  CommandsMap &commands = CommandsDB::getAll();
85  FOR_EACH (CommandsMapIter, it, commands)
86  addSpell((*it).second);
87 
88  for (unsigned f = 0; f < SPELL_SHORTCUT_ITEMS * SPELL_SHORTCUT_TABS; f++)
89  {
90  const std::map<unsigned int, TextCommand*>::const_iterator
91  it = mSpells.find(f);
92  if (it == mSpells.end())
93  addSpell(new TextCommand(f));
94  }
96 }
97 
99 {
100  if (spell == nullptr)
101  return false;
102 
103  const int id = spell->getId();
104  if (id < 0 || id >= CAST_S32(SPELL_SHORTCUT_ITEMS
106  {
107  delete spell;
108  return false;
109  }
110  const std::map<unsigned int, TextCommand*>::const_iterator
111  i = mSpells.find(spell->getId());
112  if (i == mSpells.end())
113  {
114  mSpells[spell->getId()] = spell;
115  mSpellsVector.push_back(spell);
116  return true;
117  }
118  return false;
119 }
120 
121 const STD_VECTOR<TextCommand*> &SpellManager::getAll() const
122 {
123  return mSpellsVector;
124 }
125 
126 void SpellManager::useItem(const int itemId) const
127 {
128  invoke(itemId - SPELL_MIN_ID);
129 }
130 
131 void SpellManager::invoke(const int spellId) const
132 {
133  if (localPlayer == nullptr)
134  return;
135 
136  const TextCommand *const spell = getSpell(spellId);
137  if (spell == nullptr)
138  return;
139 
140  if ((playerHandler == nullptr) || spell->getCommand().empty())
141  return;
142 
143 #ifdef TMWA_SUPPORT
144  if (spell->getCommandType() == TextCommandType::Text ||
147  >= CAST_S32(spell->getBaseLvl()) &&
149  spell->getSchool())) >= CAST_S32(spell->getSchoolLvl())
151  >= CAST_S32(spell->getMana()))
152  )
153 #endif // TMWA_SUPPORT
154  {
155  const Being *const target = localPlayer->getTarget();
156  if (spell->getTargetType() == CommandTarget::NoTarget)
157  {
158  invokeSpell(spell);
159  }
160 #ifdef TMWA_SUPPORT
161  if ((target != nullptr &&
162  (target->getType() != ActorType::Monster ||
163  spell->getCommandType() == TextCommandType::Text)) &&
166 #else // TMWA_SUPPORT
167 
168  if (target != nullptr &&
171 #endif // TMWA_SUPPORT
172  {
173  invokeSpell(spell, target);
174  }
175  else if (spell->getTargetType() == CommandTarget::AllowTarget)
176  {
177  invokeSpell(spell);
178  }
179  }
180 }
181 
182 void SpellManager::invokeSpell(const TextCommand *const spell)
183 {
184  if ((chatWindow == nullptr) || (spell == nullptr))
185  return;
186  chatWindow->localChatInput(parseCommand(spell->getCommand(), nullptr));
187 }
188 
189 void SpellManager::invokeSpell(const TextCommand *const spell,
190  const Being *const target)
191 {
192  if (chatWindow == nullptr ||
193  spell == nullptr ||
194  target == nullptr)
195  {
196  return;
197  }
198  chatWindow->localChatInput(parseCommand(spell->getCommand(), target));
199 }
200 
201 void SpellManager::invokeCommand(const std::string &command,
202  const Being *const target)
203 {
204  if (chatWindow == nullptr)
205  return;
206  chatWindow->localChatInput(parseCommand(command, target));
207 }
208 
209 std::string SpellManager::parseCommand(std::string command,
210  const Being *const target)
211 {
212  if (localPlayer == nullptr)
213  return command;
214 
215  std::string name;
216  std::string id;
217  std::string name2;
218 
219  if (target != nullptr)
220  {
221  name = target->getName();
222  name2 = name;
223  id = toString(toInt(target->getId(), int));
224  }
225  else
226  {
227  name2 = localPlayer->getName();
228  }
229 
230  bool found = false;
231 
232  size_t idx = command.find("<TARGET>");
233  if (idx != std::string::npos)
234  {
235  found = true;
236  command = replaceAll(command, "<TARGET>", name);
237  }
238  idx = command.find("<TARGETID>");
239  if (idx != std::string::npos)
240  {
241  found = true;
242  command = replaceAll(command, "<TARGETID>", id);
243  }
244  idx = command.find("<TARGETORSELF>");
245  if (idx != std::string::npos)
246  {
247  found = true;
248  command = replaceAll(command, "<TARGETORSELF>", name2);
249  }
250 
251  if (!found && !name.empty())
252  command.append(" ").append(name);
253 
254  return command;
255 }
256 
258 {
259  return new TextCommand(CAST_U32(mSpellsVector.size()));
260 }
261 
263 {
264  const Configuration *cfg = &serverConfig;
265 
267  mSpells.clear();
268  mSpellsVector.clear();
269 
270  if (cfg->getValue("commandShortcutFlags0", "").empty())
271  {
272  fillSpells();
273  save();
274  return;
275  }
276 
277  for (unsigned i = 0; i < SPELL_SHORTCUT_ITEMS * SPELL_SHORTCUT_TABS; i++)
278  {
279  unsigned int targetType;
280  unsigned int basicLvl;
281  unsigned int school;
282  unsigned int schoolLvl;
283  unsigned int mana;
284  unsigned int commandType;
285 
286  std::string flags =
287  cfg->getValue("commandShortcutFlags" + toString(i), "");
288  std::stringstream ss(flags);
289  ss >> commandType;
290  ss >> targetType;
291  ss >> basicLvl;
292  ss >> school;
293  ss >> schoolLvl;
294  ss >> mana;
295 
296  std::string cmd = cfg->getValue("commandShortcutCmd"
297  + toString(i), "");
298  std::string comment = cfg->getValue("commandShortcutComment"
299  + toString(i), "");
300  std::string symbol = cfg->getValue("commandShortcutSymbol"
301  + toString(i), "");
302  std::string icon = cfg->getValue("commandShortcutIcon"
303  + toString(i), "");
304 
305 #ifdef TMWA_SUPPORT
306  if (static_cast<TextCommandTypeT>(commandType) ==
308  {
309  addSpell(new TextCommand(i, symbol, cmd, comment,
310  static_cast<CommandTargetT>(targetType), icon, basicLvl,
311  static_cast<MagicSchoolT>(school), schoolLvl, mana));
312  }
313  else
314 #endif // TMWA_SUPPORT
315  {
316  addSpell(new TextCommand(i, symbol, cmd, comment,
317  static_cast<CommandTargetT>(targetType), icon));
318  }
319  }
320 }
321 
322 #define setOrDel(str, method) \
323  const std::string var##method = spell->method(); \
324  if (!var##method.empty()) \
325  serverConfig.setValue((str) + toString(i), var##method); \
326  else \
327  serverConfig.deleteKey((str) + toString(i))
328 
329 void SpellManager::save() const
330 {
331  for (unsigned i = 0; i < SPELL_SHORTCUT_ITEMS * SPELL_SHORTCUT_TABS; i++)
332  {
333  const TextCommand *const spell = mSpellsVector[i];
334  if (spell != nullptr)
335  {
336  setOrDel("commandShortcutCmd", getCommand);
337  setOrDel("commandShortcutComment", getComment);
338  setOrDel("commandShortcutSymbol", getSymbol);
339  setOrDel("commandShortcutIcon", getIcon);
340  if (!spell->getCommand().empty() &&
341  !spell->getSymbol().empty())
342  {
343 #ifdef TMWA_SUPPORT
344  serverConfig.setValue("commandShortcutFlags" + toString(i),
345  strprintf("%u %u %u %u %u %u",
346  CAST_U32(spell->getCommandType()),
347  CAST_U32(spell->getTargetType()),
348  spell->getBaseLvl(),
349  CAST_U32(spell->getSchool()),
350  spell->getSchoolLvl(),
351  CAST_U32(spell->getMana())));
352 #else // TMWA_SUPPORT
353 
354  serverConfig.setValue("commandShortcutFlags" + toString(i),
355  strprintf("%u %u %u %u %u %u", 1U,
356  CAST_U32(spell->getTargetType()),
357  0U,
358  0U,
359  0U,
360  0U));
361 #endif // TMWA_SUPPORT
362  }
363  else
364  {
365  serverConfig.deleteKey("commandShortcutFlags" + toString(i));
366  }
367  }
368  }
369 }
370 
371 #undef setOrDel
372 
373 std::string SpellManager::autoComplete(const std::string &partName) const
374 {
375  STD_VECTOR<TextCommand*>::const_iterator i = mSpellsVector.begin();
376  const STD_VECTOR<TextCommand*>::const_iterator
377  i_end = mSpellsVector.end();
378  std::string newName;
379  const TextCommand *newCommand = nullptr;
380 
381  while (i != i_end)
382  {
383  const TextCommand *const cmd = *i;
384  const std::string line = cmd->getCommand();
385 
386  if (!line.empty())
387  {
388  const size_t pos = line.find(partName, 0);
389  if (pos == 0)
390  {
391  if (!newName.empty())
392  {
393  newName = findSameSubstring(line, newName);
394  newCommand = nullptr;
395  }
396  else
397  {
398  newName = line;
399  newCommand = cmd;
400  }
401  }
402  }
403  ++i;
404  }
405  if (!newName.empty() &&
406  (newCommand != nullptr) &&
407  newCommand->getTargetType() == CommandTarget::NeedTarget)
408  {
409  return newName.append(" ");
410  }
411  return newName;
412 }
413 
414 void SpellManager::swap(const int id1, const int id2)
415 {
416  TextCommand *const spell1 = mSpells[id1];
417  TextCommand *const spell2 = mSpells[id2];
418  if ((spell1 == nullptr) || (spell2 == nullptr))
419  return;
420 
421  // swap in map
422  mSpells[id1] = spell2;
423  mSpells[id2] = spell1;
424 
425  // swap id
426  const int tmp = spell1->getId();
427  spell1->setId(spell2->getId());
428  spell2->setId(tmp);
429 
430  // swap in vector
431  const size_t sz = SPELL_SHORTCUT_ITEMS * SPELL_SHORTCUT_TABS;
432  for (size_t f = 0; f < sz; f++)
433  {
434  const TextCommand *const spellA = mSpellsVector[f];
435  if (spellA == spell1)
436  {
437  for (size_t d = 0; d < sz; d++)
438  {
439  const TextCommand *const spellB = mSpellsVector[d];
440  if (spellB == spell2)
441  {
442  mSpellsVector[f] = spell2;
443  mSpellsVector[d] = spell1;
444  return;
445  }
446  }
447  }
448  }
449 }
#define CAST_S32
Definition: cast.h:30
#define CAST_U32
Definition: cast.h:31
#define CAST_SIZE
Definition: cast.h:34
ChatWindow * chatWindow
Definition: chatwindow.cpp:94
BeingId getId() const
Definition: actorsprite.h:64
Definition: being.h:96
const std::string & getName() const
Definition: being.h:232
ActorTypeT getType() const
Definition: being.h:116
void localChatInput(const std::string &msg) const
Definition: chatwindow.cpp:691
std::string getValue(const std::string &key, const std::string &deflt) const
void deleteKey(const std::string &key)
void setValue(const std::string &key, const std::string &value)
Being * getTarget() const
virtual bool canUseMagic() const =0
std::vector< TextCommand * > mSpellsVector
Definition: spellmanager.h:85
const std::vector< TextCommand * > & getAll() const A_CONST
TextCommand * createNewSpell() const
static void invokeCommand(const std::string &command, const Being *const target)
const TextCommand * getSpellByItem(const int itemId) const
std::map< unsigned int, TextCommand * > mSpells
Definition: spellmanager.h:84
void swap(const int id1, const int id2)
static void invokeSpell(const TextCommand *const spell, const Being *const target)
bool addSpell(TextCommand *const spell)
void fillSpells()
void invoke(const int spellId) const
std::string autoComplete(const std::string &partName) const
TextCommand * getSpell(const int spellId) const
static std::string parseCommand(std::string command, const Being *const target)
void save() const
void useItem(const int itemId) const
unsigned getBaseLvl() const
Definition: textcommand.h:110
unsigned int getMana() const
Definition: textcommand.h:104
std::string getCommand() const
Definition: textcommand.h:85
int getId() const
Definition: textcommand.h:94
unsigned getSchoolLvl() const
Definition: textcommand.h:113
void setId(const int id)
Definition: textcommand.h:144
MagicSchoolT getSchool() const
Definition: textcommand.h:107
std::string getSymbol() const
Definition: textcommand.h:91
TextCommandTypeT getCommandType() const
Definition: textcommand.h:128
CommandTargetT getTargetType() const
Definition: textcommand.h:97
CommandsMap::iterator CommandsMapIter
Definition: commandsdb.h:37
std::map< int, TextCommand * > CommandsMap
Definition: commandsdb.h:34
CommandTarget ::T CommandTargetT
Definition: commandtarget.h:33
Configuration serverConfig
void delete_all(Container &c)
Definition: dtor.h:56
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define toInt(val, name)
Definition: intdefines.h:47
LocalPlayer * localPlayer
MagicSchool ::T MagicSchoolT
Definition: magicschool.h:38
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
void unload()
Definition: commandsdb.cpp:153
CommandsMap & getAll()
Definition: commandsdb.cpp:160
void load()
Definition: commandsdb.cpp:40
const std::string & getIcon(const int id)
Definition: languagedb.cpp:111
int32_t getAttribute(const AttributesT id)
Definition: playerinfo.cpp:102
int getSkillLevel(const int id)
Definition: playerinfo.cpp:120
Net::PlayerHandler * playerHandler
Definition: net.cpp:96
SpellManager * spellManager
#define setOrDel(str, method)
const unsigned int SPELL_SHORTCUT_ITEMS
Definition: spells.h:28
const int SPELL_MIN_ID
Definition: spells.h:27
const unsigned int SPELL_SHORTCUT_TABS
Definition: spells.h:29
std::string & replaceAll(std::string &context, const std::string &from, const std::string &to)
std::string strprintf(const char *const format,...)
const std::string findSameSubstring(const std::string &str1, const std::string &str2)
TextCommandType ::T TextCommandTypeT