spells.h

main 458 lines · 10.7 KB Raw
Alex Alex Commit Server upload 18/10/2026 23:38
1/**
2 * The Forgotten Server - a free and open-source MMORPG server emulator
3 * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifndef FS_SPELLS_H_D78A7CCB7080406E8CAA6B1D31D3DA71
21#define FS_SPELLS_H_D78A7CCB7080406E8CAA6B1D31D3DA71
22
23#include "luascript.h"
24#include "player.h"
25#include "actions.h"
26#include "talkaction.h"
27#include "baseevents.h"
28
29class InstantSpell;
30class RuneSpell;
31class Spell;
32
33using VocSpellMap = std::map<uint16_t, bool>;
34using InstantSpell_ptr = std::unique_ptr<InstantSpell>;
35using RuneSpell_ptr = std::unique_ptr<RuneSpell>;
36
37class Spells final : public BaseEvents
38{
39 public:
40 Spells();
41 ~Spells();
42
43 // non-copyable
44 Spells(const Spells&) = delete;
45 Spells& operator=(const Spells&) = delete;
46
47 Spell* getSpellByName(const std::string& name);
48 RuneSpell* getRuneSpell(uint32_t id);
49 RuneSpell* getRuneSpellByName(const std::string& name);
50
51 InstantSpell* getInstantSpell(const std::string& words);
52 InstantSpell* getInstantSpellByName(const std::string& name);
53
54 InstantSpell* getInstantSpellById(uint32_t spellId);
55
56 TalkActionResult_t playerSaySpell(Player* player, std::string& words);
57
58 static Position getCasterPosition(Creature* creature, Direction dir);
59 std::string getScriptBaseName() const override;
60
61 const std::map<std::string, InstantSpell>& getInstantSpells() const {
62 return instants;
63 };
64
65 void clearMaps(bool fromLua);
66 void clear(bool fromLua) override final;
67 bool registerInstantLuaEvent(InstantSpell* event);
68 bool registerRuneLuaEvent(RuneSpell* event);
69
70 private:
71 LuaScriptInterface& getScriptInterface() override;
72 Event_ptr getEvent(const std::string& nodeName) override;
73 bool registerEvent(Event_ptr event, const pugi::xml_node& node) override;
74
75 std::map<uint16_t, RuneSpell> runes;
76 std::map<std::string, InstantSpell> instants;
77
78 friend class CombatSpell;
79 LuaScriptInterface scriptInterface { "Spell Interface" };
80};
81
82using RuneSpellFunction = std::function<bool(const RuneSpell* spell, Player* player, const Position& posTo)>;
83
84class BaseSpell
85{
86 public:
87 constexpr BaseSpell() = default;
88 virtual ~BaseSpell() = default;
89
90 virtual bool castSpell(Creature* creature) = 0;
91 virtual bool castSpell(Creature* creature, Creature* target) = 0;
92};
93
94class CombatSpell final : public Event, public BaseSpell
95{
96 public:
97 CombatSpell(Combat* combat, bool needTarget, bool needDirection);
98 ~CombatSpell();
99
100 // non-copyable
101 CombatSpell(const CombatSpell&) = delete;
102 CombatSpell& operator=(const CombatSpell&) = delete;
103
104 bool castSpell(Creature* creature) override;
105 bool castSpell(Creature* creature, Creature* target) override;
106 bool configureEvent(const pugi::xml_node&) override {
107 return true;
108 }
109
110 //scripting
111 bool executeCastSpell(Creature* creature, const LuaVariant& var);
112
113 bool loadScriptCombat();
114 Combat* getCombat() {
115 return combat;
116 }
117
118 private:
119 std::string getScriptEventName() const override {
120 return "onCastSpell";
121 }
122
123 Combat* combat;
124
125 bool needDirection;
126 bool needTarget;
127};
128
129class Spell : public BaseSpell
130{
131 public:
132 Spell() = default;
133
134 bool configureSpell(const pugi::xml_node& node);
135 const std::string& getName() const {
136 return name;
137 }
138 void setName(std::string n) {
139 name = n;
140 }
141 uint8_t getId() const {
142 return spellId;
143 }
144 void setId(uint8_t id) {
145 spellId = id;
146 }
147
148 void postCastSpell(Player* player, bool finishedCast = true, bool payCost = true) const;
149 static void postCastSpell(Player* player, uint32_t manaCost, uint32_t soulCost);
150
151 uint32_t getManaCost(const Player* player) const;
152 uint32_t getSoulCost() const {
153 return soul;
154 }
155 void setSoulCost(uint32_t s) {
156 soul = s;
157 }
158 uint32_t getLevel() const {
159 return level;
160 }
161 void setLevel(uint32_t lvl) {
162 level = lvl;
163 }
164 uint32_t getMagicLevel() const {
165 return magLevel;
166 }
167 void setMagicLevel(uint32_t lvl) {
168 magLevel = lvl;
169 }
170 uint32_t getMana() const {
171 return mana;
172 }
173 void setMana(uint32_t m) {
174 mana = m;
175 }
176 uint32_t getManaPercent() const {
177 return manaPercent;
178 }
179 void setManaPercent(uint32_t m) {
180 manaPercent = m;
181 }
182 bool isPremium() const {
183 return premium;
184 }
185 void setPremium(bool p) {
186 premium = p;
187 }
188 bool isEnabled() const {
189 return enabled;
190 }
191 void setEnabled(bool e) {
192 enabled = e;
193 }
194
195 virtual bool isInstant() const = 0;
196 bool isLearnable() const {
197 return learnable;
198 }
199 void setLearnable(bool l) {
200 learnable = l;
201 }
202
203 const VocSpellMap& getVocMap() const {
204 return vocSpellMap;
205 }
206 void addVocMap(uint16_t n, bool b) {
207 vocSpellMap[n] = b;
208 }
209
210 const SpellGroup_t getGroup() const {
211 return group;
212 }
213 void setGroup(SpellGroup_t g) {
214 group = g;
215 }
216 const SpellGroup_t getSecondaryGroup() const {
217 return secondaryGroup;
218 }
219 void setSecondaryGroup(SpellGroup_t g) {
220 secondaryGroup = g;
221 }
222
223 uint32_t getCooldown() const {
224 return cooldown;
225 }
226 void setCooldown(uint32_t cd) {
227 cooldown = cd;
228 }
229 uint32_t getSecondaryCooldown() const {
230 return secondaryGroupCooldown;
231 }
232 void setSecondaryCooldown(uint32_t cd) {
233 secondaryGroupCooldown = cd;
234 }
235 uint32_t getGroupCooldown() const {
236 return groupCooldown;
237 }
238 void setGroupCooldown(uint32_t cd) {
239 groupCooldown = cd;
240 }
241
242 int32_t getRange() const {
243 return range;
244 }
245 void setRange(int32_t r) {
246 range = r;
247 }
248
249 bool getNeedTarget() const {
250 return needTarget;
251 }
252 void setNeedTarget(bool n) {
253 needTarget = n;
254 }
255 bool getNeedWeapon() const {
256 return needWeapon;
257 }
258 void setNeedWeapon(bool n) {
259 needWeapon = n;
260 }
261 bool getNeedLearn() const {
262 return learnable;
263 }
264 void setNeedLearn(bool n) {
265 learnable = n;
266 }
267 bool getSelfTarget() const {
268 return selfTarget;
269 }
270 void setSelfTarget(bool s) {
271 selfTarget = s;
272 }
273 bool getBlockingSolid() const {
274 return blockingSolid;
275 }
276 void setBlockingSolid(bool b) {
277 blockingSolid = b;
278 }
279 bool getBlockingCreature() const {
280 return blockingCreature;
281 }
282 void setBlockingCreature(bool b) {
283 blockingCreature = b;
284 }
285 bool getAggressive() const {
286 return aggressive;
287 }
288 void setAggressive(bool a) {
289 aggressive = a;
290 }
291 bool getPzLock() const {
292 return pzLock;
293 }
294 void setPzLock(bool pzLock) {
295 this->pzLock = pzLock;
296 }
297
298 SpellType_t spellType = SPELL_UNDEFINED;
299
300 protected:
301 bool playerSpellCheck(Player* player) const;
302 bool playerInstantSpellCheck(Player* player, const Position& toPos);
303 bool playerRuneSpellCheck(Player* player, const Position& toPos);
304
305 VocSpellMap vocSpellMap;
306
307 SpellGroup_t group = SPELLGROUP_NONE;
308 SpellGroup_t secondaryGroup = SPELLGROUP_NONE;
309
310 uint32_t cooldown = 1000;
311 uint32_t groupCooldown = 1000;
312 uint32_t secondaryGroupCooldown = 0;
313 uint32_t level = 0;
314 uint32_t magLevel = 0;
315 int32_t range = -1;
316
317 uint8_t spellId = 0;
318
319 bool selfTarget = false;
320 bool needTarget = false;
321
322 private:
323
324 uint32_t mana = 0;
325 uint32_t manaPercent = 0;
326 uint32_t soul = 0;
327
328 bool needWeapon = false;
329 bool blockingSolid = false;
330 bool blockingCreature = false;
331 bool aggressive = true;
332 bool pzLock = false;
333 bool learnable = false;
334 bool enabled = true;
335 bool premium = false;
336
337
338 private:
339 std::string name;
340};
341
342class InstantSpell final : public TalkAction, public Spell
343{
344 public:
345 explicit InstantSpell(LuaScriptInterface* interface) : TalkAction(interface) {}
346
347 bool configureEvent(const pugi::xml_node& node) override;
348
349 virtual bool playerCastInstant(Player* player, std::string& param);
350
351 bool castSpell(Creature* creature) override;
352 bool castSpell(Creature* creature, Creature* target) override;
353
354 //scripting
355 bool executeCastSpell(Creature* creature, const LuaVariant& var);
356
357 bool isInstant() const override {
358 return true;
359 }
360 bool getHasParam() const {
361 return hasParam;
362 }
363 void setHasParam(bool p) {
364 hasParam = p;
365 }
366 bool getHasPlayerNameParam() const {
367 return hasPlayerNameParam;
368 }
369 void setHasPlayerNameParam(bool p) {
370 hasPlayerNameParam = p;
371 }
372 bool getNeedDirection() const {
373 return needDirection;
374 }
375 void setNeedDirection(bool n) {
376 needDirection = n;
377 }
378 bool getNeedCasterTargetOrDirection() const {
379 return casterTargetOrDirection;
380 }
381 void setNeedCasterTargetOrDirection(bool d) {
382 casterTargetOrDirection = d;
383 }
384 bool getBlockWalls() const {
385 return checkLineOfSight;
386 }
387 void setBlockWalls(bool w) {
388 checkLineOfSight = w;
389 }
390 bool canCast(const Player* player) const;
391 bool canThrowSpell(const Creature* creature, const Creature* target) const;
392
393 private:
394 std::string getScriptEventName() const override;
395
396 bool internalCastSpell(Creature* creature, const LuaVariant& var);
397
398 bool needDirection = false;
399 bool hasParam = false;
400 bool hasPlayerNameParam = false;
401 bool checkLineOfSight = true;
402 bool casterTargetOrDirection = false;
403};
404
405class RuneSpell final : public Action, public Spell
406{
407 public:
408 explicit RuneSpell(LuaScriptInterface* interface) : Action(interface) {}
409
410 bool configureEvent(const pugi::xml_node& node) override;
411
412 ReturnValue canExecuteAction(const Player* player, const Position& toPos) override;
413 bool hasOwnErrorHandler() override {
414 return true;
415 }
416 Thing* getTarget(Player*, Creature* targetCreature, const Position&, uint8_t) const override {
417 return targetCreature;
418 }
419
420 bool executeUse(Player* player, Item* item, const Position& fromPosition, Thing* target, const Position& toPosition, bool isHotkey) override;
421
422 bool castSpell(Creature* creature) override;
423 bool castSpell(Creature* creature, Creature* target) override;
424
425 //scripting
426 bool executeCastSpell(Creature* creature, const LuaVariant& var, bool isHotkey);
427
428 bool isInstant() const override {
429 return false;
430 }
431 uint16_t getRuneItemId() const {
432 return runeId;
433 }
434 void setRuneItemId(uint16_t i) {
435 runeId = i;
436 }
437 uint32_t getCharges() const {
438 return charges;
439 }
440 void setCharges(uint32_t c) {
441 if (c > 0) {
442 hasCharges = true;
443 }
444 charges = c;
445 }
446
447 private:
448 std::string getScriptEventName() const override;
449
450 bool internalCastSpell(Creature* creature, const LuaVariant& var, bool isHotkey);
451
452 uint16_t runeId = 0;
453 uint32_t charges = 0;
454 bool hasCharges = false;
455};
456
457#endif
458
Top