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_CREATURE_H_5363C04015254E298F84E6D59A139508
21#define FS_CREATURE_H_5363C04015254E298F84E6D59A139508
22
23#include "condition.h"
24#include "const.h"
25#include "creatureevent.h"
26#include "enums.h"
27#include "map.h"
28#include "position.h"
29#include "tile.h"
30#include <list>
31#include <map>
32
33using ConditionList = std::list<Condition *>;
34using CreatureEventList = std::list<CreatureEvent *>;
35
36enum slots_t : uint8_t {
37 CONST_SLOT_WHEREEVER = 0,
38 CONST_SLOT_HEAD = 1,
39 CONST_SLOT_NECKLACE = 2,
40 CONST_SLOT_BACKPACK = 3,
41 CONST_SLOT_ARMOR = 4,
42 CONST_SLOT_RIGHT = 5,
43 CONST_SLOT_LEFT = 6,
44 CONST_SLOT_LEGS = 7,
45 CONST_SLOT_FEET = 8,
46 CONST_SLOT_RING = 9,
47 CONST_SLOT_AMMO = 10,
48
49 CONST_SLOT_FIRST = CONST_SLOT_HEAD,
50 CONST_SLOT_LAST = CONST_SLOT_AMMO,
51};
52
53struct FindPathParams {
54 bool fullPathSearch = true;
55 bool clearSight = true;
56 bool allowDiagonal = true;
57 bool keepDistance = false;
58 int32_t maxSearchDist = 0;
59 int32_t minTargetDist = -1;
60 int32_t maxTargetDist = -1;
61};
62
63class Map;
64class Thing;
65class Container;
66class Player;
67class Monster;
68class Npc;
69class Item;
70class Tile;
71
72static constexpr int32_t EVENT_CREATURECOUNT = 10;
73static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000;
74static constexpr int32_t EVENT_CHECK_CREATURE_INTERVAL =
75 (EVENT_CREATURE_THINK_INTERVAL / EVENT_CREATURECOUNT);
76
77class FrozenPathingConditionCall {
78public:
79 explicit FrozenPathingConditionCall(Position targetPos)
80 : targetPos(std::move(targetPos)) {}
81
82 bool operator()(const Position &startPos, const Position &testPos,
83 const FindPathParams &fpp, int32_t &bestMatchDist) const;
84
85 bool isInRange(const Position &startPos, const Position &testPos,
86 const FindPathParams &fpp) const;
87
88private:
89 Position targetPos;
90};
91
92//////////////////////////////////////////////////////////////////////
93// Defines the Base class for all creatures and base functions which
94// every creature has
95
96class Creature : virtual public Thing {
97protected:
98 Creature();
99
100public:
101 static double speedA, speedB, speedC;
102
103 virtual ~Creature();
104
105 // non-copyable
106 Creature(const Creature &) = delete;
107 Creature &operator=(const Creature &) = delete;
108
109 Creature *getCreature() override final { return this; }
110 const Creature *getCreature() const override final { return this; }
111 virtual Player *getPlayer() { return nullptr; }
112 virtual const Player *getPlayer() const { return nullptr; }
113 virtual Npc *getNpc() { return nullptr; }
114 virtual const Npc *getNpc() const { return nullptr; }
115 virtual Monster *getMonster() { return nullptr; }
116 virtual const Monster *getMonster() const { return nullptr; }
117
118 virtual const std::string &getName() const = 0;
119 virtual const std::string &getNameDescription() const = 0;
120
121 virtual CreatureType_t getType() const = 0;
122
123 virtual void setID() = 0;
124 void setRemoved() { isInternalRemoved = true; }
125
126 uint32_t getID() const { return id; }
127 virtual void removeList() = 0;
128 virtual void addList() = 0;
129
130 virtual bool canSee(const Position &pos) const;
131 virtual bool canSeeCreature(const Creature *creature) const;
132
133 virtual RaceType_t getRace() const { return RACE_NONE; }
134 virtual Skulls_t getSkull() const { return skull; }
135 virtual Skulls_t getSkullClient(const Creature *creature) const {
136 return creature->getSkull();
137 }
138 void setSkull(Skulls_t newSkull);
139 Direction getDirection() const { return direction; }
140 void setDirection(Direction dir) { direction = dir; }
141
142 bool isHealthHidden() const { return hiddenHealth; }
143 void setHiddenHealth(bool b) { hiddenHealth = b; }
144
145 int32_t getThrowRange() const override final { return 1; }
146 bool isPushable() const override { return getWalkDelay() <= 0; }
147 bool isRemoved() const override final { return isInternalRemoved; }
148 virtual bool canSeeInvisibility() const { return false; }
149 virtual bool isInGhostMode() const { return false; }
150
151 int32_t getWalkDelay(Direction dir) const;
152 int32_t getWalkDelay() const;
153 int64_t getTimeSinceLastMove() const;
154
155 int64_t getEventStepTicks() const;
156 int64_t getStepDuration(Direction dir) const;
157 int64_t getStepDuration(bool forAnimation = false) const;
158 virtual int32_t getStepSpeed() const { return getSpeed(); }
159 int32_t getSpeed() const { return baseSpeed + varSpeed; }
160 void setSpeed(int32_t varSpeedDelta) {
161 int32_t oldSpeed = getSpeed();
162 varSpeed = varSpeedDelta;
163
164 if (getSpeed() <= 0) {
165 stopEventWalk();
166 cancelNextWalk = true;
167 } else if (oldSpeed <= 0 && !listWalkDir.empty()) {
168 addEventWalk();
169 }
170 }
171
172 void setBaseSpeed(uint32_t newBaseSpeed) { baseSpeed = newBaseSpeed; }
173 uint32_t getBaseSpeed() const { return baseSpeed; }
174
175 int32_t getHealth() const { return health; }
176 virtual int32_t getMaxHealth() const { return healthMax; }
177
178 const Outfit_t getCurrentOutfit() const { return currentOutfit; }
179 void setCurrentOutfit(Outfit_t outfit) { currentOutfit = outfit; }
180 const Outfit_t getDefaultOutfit() const { return defaultOutfit; }
181 bool isInvisible() const;
182
183 ZoneType_t getZone() const { return getTile()->getZone(); }
184
185 // walk functions
186 void startAutoWalk(const std::list<Direction> &listDir);
187 void addEventWalk();
188 void stopEventWalk();
189 virtual void goToFollowCreature();
190
191 // walk events
192 virtual void onWalk(Direction &dir);
193 virtual void onWalkAborted() {}
194 virtual void onWalkComplete() {}
195
196 // follow functions
197 Creature *getFollowCreature() const { return followCreature; }
198 virtual bool setFollowCreature(Creature *creature);
199
200 // follow events
201 virtual void onFollowCreature(const Creature *) {}
202 virtual void onFollowCreatureComplete(const Creature *) {}
203
204 // combat functions
205 Creature *getAttackedCreature() { return attackedCreature; }
206 virtual bool setAttackedCreature(Creature *creature);
207 virtual BlockType_t blockHit(Creature *attacker, CombatType_t combatType,
208 int32_t &damage, bool checkDefense = false,
209 bool checkArmor = false, bool field = false);
210
211 bool setMaster(Creature *newMaster);
212
213 void removeMaster() {
214 if (master) {
215 master = nullptr;
216 decrementReferenceCounter();
217 }
218 }
219
220 bool isSummon() const { return master != nullptr; }
221 Creature *getMaster() const { return master; }
222
223 virtual uint32_t getMana() const { return 0; }
224 virtual uint32_t getMaxMana() const { return 0; }
225
226 const std::list<Creature *> &getSummons() const { return summons; }
227
228 virtual int32_t getArmor() const { return 0; }
229 virtual int32_t getDefense() const { return 0; }
230 virtual float getAttackFactor() const { return 1.0f; }
231 virtual float getDefenseFactor() const { return 1.0f; }
232
233 virtual uint8_t getSpeechBubble() const { return SPEECHBUBBLE_NONE; }
234
235 bool addCondition(Condition *condition, bool force = false);
236 bool addCombatCondition(Condition *condition);
237 void removeCondition(ConditionType_t type, ConditionId_t conditionId,
238 bool force = false);
239 void removeCondition(ConditionType_t type, bool force = false);
240 void removeCondition(Condition *condition, bool force = false);
241 void removeCombatCondition(ConditionType_t type);
242 Condition *getCondition(ConditionType_t type) const;
243 Condition *getCondition(ConditionType_t type, ConditionId_t conditionId,
244 uint32_t subId = 0) const;
245 void executeConditions(uint32_t interval);
246 bool hasCondition(ConditionType_t type, uint32_t subId = 0) const;
247 virtual bool isImmune(ConditionType_t type) const;
248 virtual bool isImmune(CombatType_t type) const;
249 virtual bool isSuppress(ConditionType_t type) const;
250 virtual uint32_t getDamageImmunities() const { return 0; }
251 virtual uint32_t getConditionImmunities() const { return 0; }
252 virtual uint32_t getConditionSuppressions() const { return 0; }
253 virtual bool isAttackable() const { return true; }
254
255 virtual void changeHealth(int32_t healthChange, bool sendHealthChange = true);
256
257 void gainHealth(Creature *healer, int32_t healthGain);
258 virtual void drainHealth(Creature *attacker, int32_t damage);
259
260 virtual bool challengeCreature(Creature *) { return false; }
261
262 void onDeath();
263 virtual uint64_t getGainedExperience(Creature *attacker) const;
264 void addDamagePoints(Creature *attacker, int32_t damagePoints);
265 bool hasBeenAttacked(uint32_t attackerId);
266
267 // combat event functions
268 virtual void onAddCondition(ConditionType_t type);
269 virtual void onAddCombatCondition(ConditionType_t type);
270 virtual void onEndCondition(ConditionType_t type);
271 void onTickCondition(ConditionType_t type, bool &bRemove);
272 virtual void onCombatRemoveCondition(Condition *condition);
273 virtual void onAttackedCreature(Creature *, bool = true) {}
274 virtual void onAttacked();
275 virtual void onAttackedCreatureDrainHealth(Creature *target, int32_t points);
276 virtual void onTargetCreatureGainHealth(Creature *, int32_t) {}
277 virtual bool onKilledCreature(Creature *target, bool lastHit = true);
278 virtual void onGainExperience(uint64_t gainExp, Creature *target);
279 virtual void onAttackedCreatureBlockHit(BlockType_t) {}
280 virtual void onBlockHit() {}
281 virtual void onChangeZone(ZoneType_t zone);
282 virtual void onAttackedCreatureChangeZone(ZoneType_t zone);
283 virtual void onIdleStatus();
284
285 virtual LightInfo getCreatureLight() const;
286 virtual void setNormalCreatureLight();
287 void setCreatureLight(LightInfo lightInfo);
288
289 virtual void onThink(uint32_t interval);
290 void onAttacking(uint32_t interval);
291 virtual void onWalk();
292 virtual bool getNextStep(Direction &dir, uint32_t &flags);
293
294 virtual void onAddTileItem(const Tile *tile, const Position &pos);
295 virtual void onUpdateTileItem(const Tile *tile, const Position &pos,
296 const Item *oldItem, const ItemType &oldType,
297 const Item *newItem, const ItemType &newType);
298 virtual void onRemoveTileItem(const Tile *tile, const Position &pos,
299 const ItemType &iType, const Item *item);
300
301 virtual void onCreatureAppear(Creature *creature, bool isLogin);
302 virtual void onRemoveCreature(Creature *creature, bool isLogout);
303 virtual void onCreatureMove(Creature *creature, const Tile *newTile,
304 const Position &newPos, const Tile *oldTile,
305 const Position &oldPos, bool teleport);
306
307 virtual void onAttackedCreatureDisappear(bool) {}
308 virtual void onFollowCreatureDisappear(bool) {}
309
310 virtual void onCreatureSay(Creature *, SpeakClasses, const std::string &) {}
311
312 virtual void onPlacedCreature() {}
313
314 virtual bool getCombatValues(int32_t &, int32_t &) { return false; }
315
316 size_t getSummonCount() const { return summons.size(); }
317 void setDropLoot(bool lootDrop) { this->lootDrop = lootDrop; }
318 void setSkillLoss(bool skillLoss) { this->skillLoss = skillLoss; }
319 void setUseDefense(bool useDefense) { canUseDefense = useDefense; }
320
321 // creature script events
322 bool registerCreatureEvent(const std::string &name);
323 bool unregisterCreatureEvent(const std::string &name);
324
325 Cylinder *getParent() const override final { return tile; }
326 void setParent(Cylinder *cylinder) override final {
327 tile = static_cast<Tile *>(cylinder);
328 position = tile->getPosition();
329 }
330
331 const Position &getPosition() const override final { return position; }
332
333 Tile *getTile() override final { return tile; }
334 const Tile *getTile() const override final { return tile; }
335
336 int32_t getWalkCache(const Position &pos) const;
337
338 const Position &getLastPosition() const { return lastPosition; }
339 void setLastPosition(Position newLastPos) { lastPosition = newLastPos; }
340
341 static bool canSee(const Position &myPos, const Position &pos,
342 int32_t viewRangeX, int32_t viewRangeY);
343
344 double getDamageRatio(Creature *attacker) const;
345
346 bool getPathTo(const Position &targetPos, std::list<Direction> &dirList,
347 const FindPathParams &fpp) const;
348 bool getPathTo(const Position &targetPos, std::list<Direction> &dirList,
349 int32_t minTargetDist, int32_t maxTargetDist,
350 bool fullPathSearch = true, bool clearSight = true,
351 int32_t maxSearchDist = 0) const;
352
353 void incrementReferenceCounter() { ++referenceCounter; }
354 void decrementReferenceCounter() {
355 if (--referenceCounter == 0) {
356 delete this;
357 }
358 }
359
360 std::list<Direction> &getListWalkDir() { return listWalkDir; }
361 bool tryToFixAutoWalk(Direction dir);
362
363protected:
364 virtual bool useCacheMap() const { return false; }
365
366 struct CountBlock_t {
367 int32_t total;
368 int64_t ticks;
369 };
370
371 static constexpr int32_t mapWalkWidth = Map::maxViewportX * 2 + 1;
372 static constexpr int32_t mapWalkHeight = Map::maxViewportY * 2 + 1;
373 static constexpr int32_t maxWalkCacheWidth = (mapWalkWidth - 1) / 2;
374 static constexpr int32_t maxWalkCacheHeight = (mapWalkHeight - 1) / 2;
375
376 Position position;
377
378 using CountMap = std::map<uint32_t, CountBlock_t>;
379 CountMap damageMap;
380
381 std::list<Creature *> summons;
382 CreatureEventList eventsList;
383 ConditionList conditions;
384
385 std::list<Direction> listWalkDir;
386
387 Tile *tile = nullptr;
388 Creature *attackedCreature = nullptr;
389 Creature *master = nullptr;
390 Creature *followCreature = nullptr;
391
392 uint64_t lastStep = 0;
393 uint32_t referenceCounter = 0;
394 uint32_t id = 0;
395 uint32_t scriptEventsBitField = 0;
396 uint32_t eventWalk = 0;
397 uint32_t walkUpdateTicks = 0;
398 uint32_t lastHitCreatureId = 0;
399 uint32_t blockCount = 0;
400 uint32_t blockTicks = 0;
401 uint32_t lastStepCost = 1;
402 uint32_t baseSpeed = 220;
403 int32_t varSpeed = 0;
404 int32_t health = 1000;
405 int32_t healthMax = 1000;
406
407 Outfit_t currentOutfit;
408 Outfit_t defaultOutfit;
409 Position lastPosition;
410 LightInfo internalLight;
411
412 Direction direction = DIRECTION_SOUTH;
413 Skulls_t skull = SKULL_NONE;
414
415 bool localMapCache[mapWalkHeight][mapWalkWidth] = {{false}};
416 bool isInternalRemoved = false;
417 bool isMapLoaded = false;
418 bool isUpdatingPath = false;
419 bool creatureCheck = false;
420 bool inCheckCreaturesVector = false;
421 bool skillLoss = true;
422 bool lootDrop = true;
423 bool cancelNextWalk = false;
424 bool hasFollowPath = false;
425 bool forceUpdateFollowPath = false;
426 bool hiddenHealth = false;
427 bool canUseDefense = true;
428
429 // creature script events
430 bool hasEventRegistered(CreatureEventType_t event) const {
431 return (0 != (scriptEventsBitField & (static_cast<uint32_t>(1) << event)));
432 }
433 CreatureEventList getCreatureEvents(CreatureEventType_t type);
434
435 void updateMapCache();
436 void updateTileCache(const Tile *tile, int32_t dx, int32_t dy);
437 void updateTileCache(const Tile *tile, const Position &pos);
438 void onCreatureDisappear(const Creature *creature, bool isLogout);
439 virtual void doAttacking(uint32_t) {}
440 virtual bool hasExtraSwing() { return false; }
441
442 virtual uint64_t getLostExperience() const { return 0; }
443 virtual void dropLoot(Container *, Creature *) {}
444 virtual uint16_t getLookCorpse() const { return 0; }
445 virtual void getPathSearchParams(const Creature *creature,
446 FindPathParams &fpp) const;
447 virtual void death(Creature *) {}
448 virtual bool dropCorpse(Creature *lastHitCreature,
449 Creature *mostDamageCreature, bool lastHitUnjustified,
450 bool mostDamageUnjustified);
451 virtual Item *getCorpse(Creature *lastHitCreature,
452 Creature *mostDamageCreature);
453
454 friend class Game;
455 friend class Map;
456 friend class LuaScriptInterface;
457
458 // Attack outfit animation members (added at the end for binary compatibility)
459 Outfit_t attackOutfit; // outfit temporal durante el ataque
460 uint32_t attackOutfitEventId = 0; // ID del evento de reversión programado
461 Outfit_t originalOutfit; // outfit base antes del pulso
462 bool isAttackPulsing = false; // si está en un pulso de ataque
463
464public:
465 // Attack outfit animation methods (added at the end for binary compatibility)
466 void pulseAttackOutfit(const Outfit_t &outfit, uint32_t durationMs = 1000);
467 void revertAttackOutfit();
468 virtual uint16_t getAttackOutfitLookType() const {
469 return attackOutfit.lookType;
470 }
471 void setAttackOutfitLookType(uint16_t lookType) {
472 attackOutfit.lookType = lookType;
473 }
474};
475
476#endif
477