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_MONSTER_H_9F5EEFE64314418CA7DA41D1B9409DD0
21#define FS_MONSTER_H_9F5EEFE64314418CA7DA41D1B9409DD0
22
23#include "monsters.h"
24#include "tile.h"
25
26class Creature;
27class Game;
28class Spawn;
29
30using CreatureHashSet = std::unordered_set<Creature *>;
31using CreatureList = std::list<Creature *>;
32
33enum TargetSearchType_t {
34 TARGETSEARCH_DEFAULT,
35 TARGETSEARCH_RANDOM,
36 TARGETSEARCH_ATTACKRANGE,
37 TARGETSEARCH_NEAREST,
38};
39
40class Monster final : public Creature {
41public:
42 static Monster *createMonster(const std::string &name);
43 static int32_t despawnRange;
44 static int32_t despawnRadius;
45
46 explicit Monster(MonsterType *mType);
47 ~Monster();
48
49 // non-copyable
50 Monster(const Monster &) = delete;
51 Monster &operator=(const Monster &) = delete;
52
53 Monster *getMonster() override { return this; }
54 const Monster *getMonster() const override { return this; }
55
56 void setID() override {
57 if (id == 0) {
58 id = monsterAutoID++;
59 }
60 }
61
62 void removeList() override;
63 void addList() override;
64
65 std::string name, nameDescription, altStrDesc;
66 const std::string &getName() const final {
67 if (!name.empty()) {
68 return name;
69 }
70 return mType->name;
71 }
72 const std::string &getNameDescription() const final {
73 if (nameDescription.empty()) {
74 return mType->nameDescription;
75 }
76 return nameDescription;
77 }
78 std::string getDescription(int32_t) const final {
79 if (!altStrDesc.empty()) {
80 return altStrDesc + '.';
81 }
82 return strDescription + '.';
83 }
84 void setName(std::string n) { name = n; }
85 void setDescription(std::string desc) { nameDescription = desc; }
86 void setStrDescription(std::string altdesc) { altStrDesc = altdesc; }
87 CreatureType_t getType() const override { return CREATURETYPE_MONSTER; }
88
89 const Position &getMasterPos() const { return masterPos; }
90 void setMasterPos(Position pos) { masterPos = pos; }
91
92 RaceType_t getRace() const override { return mType->info.race; }
93 int32_t getArmor() const override { return mType->info.armor; }
94 int32_t getDefense() const override { return mType->info.defense; }
95 bool isPushable() const override {
96 return mType->info.pushable && baseSpeed != 0;
97 }
98 bool isAttackable() const override { return mType->info.isAttackable; }
99
100 bool canPushItems() const { return mType->info.canPushItems; }
101 bool canPushCreatures() const { return mType->info.canPushCreatures; }
102 bool isHostile() const { return mType->info.isHostile; }
103 bool canSee(const Position &pos) const override;
104 bool canSeeInvisibility() const override {
105 return isImmune(CONDITION_INVISIBLE);
106 }
107 uint32_t getManaCost() const { return mType->info.manaCost; }
108 void setSpawn(Spawn *spawn) { this->spawn = spawn; }
109 bool canWalkOnFieldType(CombatType_t combatType) const;
110
111 void onAttackedCreatureDisappear(bool isLogout) override;
112
113 void onCreatureAppear(Creature *creature, bool isLogin) override;
114 void onRemoveCreature(Creature *creature, bool isLogout) override;
115 void onCreatureMove(Creature *creature, const Tile *newTile,
116 const Position &newPos, const Tile *oldTile,
117 const Position &oldPos, bool teleport) override;
118 void onCreatureSay(Creature *creature, SpeakClasses type,
119 const std::string &text) override;
120
121 void drainHealth(Creature *attacker, int32_t damage) override;
122 void changeHealth(int32_t healthChange,
123 bool sendHealthChange = true) override;
124 void onWalk() override;
125 bool getNextStep(Direction &direction, uint32_t &flags) override;
126 void onFollowCreatureComplete(const Creature *creature) override;
127
128 void onThink(uint32_t interval) override;
129
130 bool challengeCreature(Creature *creature) override;
131
132 void setNormalCreatureLight() override;
133 bool getCombatValues(int32_t &min, int32_t &max) override;
134
135 void doAttacking(uint32_t interval) override;
136 uint16_t getAttackOutfitLookType() const override;
137 bool hasExtraSwing() override { return extraMeleeAttack; }
138
139 bool searchTarget(TargetSearchType_t searchType = TARGETSEARCH_DEFAULT);
140 bool selectTarget(Creature *creature);
141
142 const CreatureList &getTargetList() const { return targetList; }
143 const CreatureHashSet &getFriendList() const { return friendList; }
144
145 bool isTarget(const Creature *creature) const;
146 bool isFleeing() const {
147 return !isSummon() && getHealth() <= mType->info.runAwayHealth &&
148 challengeFocusDuration <= 0;
149 }
150
151 bool getDistanceStep(const Position &targetPos, Direction &direction,
152 bool flee = false);
153 bool isTargetNearby() const { return stepDuration >= 1; }
154 bool isIgnoringFieldDamage() const { return ignoreFieldDamage; }
155
156 BlockType_t blockHit(Creature *attacker, CombatType_t combatType,
157 int32_t &damage, bool checkDefense = false,
158 bool checkArmor = false, bool field = false) override;
159
160 static uint32_t monsterAutoID;
161
162private:
163 CreatureHashSet friendList;
164 CreatureList targetList;
165
166 std::string strDescription;
167
168 MonsterType *mType;
169 Spawn *spawn = nullptr;
170
171 int64_t lastMeleeAttack = 0;
172
173 uint32_t attackTicks = 0;
174 uint32_t targetTicks = 0;
175 uint32_t targetChangeTicks = 0;
176 uint32_t defenseTicks = 0;
177 uint32_t yellTicks = 0;
178 int32_t minCombatValue = 0;
179 int32_t maxCombatValue = 0;
180 int32_t targetChangeCooldown = 0;
181 int32_t challengeFocusDuration = 0;
182 int32_t stepDuration = 0;
183
184 Position masterPos;
185
186 bool isIdle = true;
187 bool extraMeleeAttack = false;
188 bool isMasterInRange = false;
189 bool randomStepping = false;
190 bool ignoreFieldDamage = false;
191
192 void onCreatureEnter(Creature *creature);
193 void onCreatureLeave(Creature *creature);
194 void onCreatureFound(Creature *creature, bool pushFront = false);
195
196 void updateLookDirection();
197
198 void addFriend(Creature *creature);
199 void removeFriend(Creature *creature);
200 void addTarget(Creature *creature, bool pushFront = false);
201 void removeTarget(Creature *creature);
202
203 void updateTargetList();
204 void clearTargetList();
205 void clearFriendList();
206
207 void death(Creature *lastHitCreature) override;
208 Item *getCorpse(Creature *lastHitCreature,
209 Creature *mostDamageCreature) override;
210
211 void setIdle(bool idle);
212 void updateIdleStatus();
213 bool getIdleStatus() const { return isIdle; }
214
215 void onAddCondition(ConditionType_t type) override;
216 void onEndCondition(ConditionType_t type) override;
217
218 bool canUseAttack(const Position &pos, const Creature *target) const;
219 bool canUseSpell(const Position &pos, const Position &targetPos,
220 const spellBlock_t &sb, uint32_t interval, bool &inRange,
221 bool &resetTicks);
222 bool getRandomStep(const Position &creaturePos, Direction &direction) const;
223 bool getDanceStep(const Position &creaturePos, Direction &direction,
224 bool keepAttack = true, bool keepDistance = true);
225 bool isInSpawnRange(const Position &pos) const;
226 bool canWalkTo(Position pos, Direction direction) const;
227
228 static bool pushItem(Item *item);
229 static void pushItems(Tile *tile);
230 static bool pushCreature(Creature *creature);
231 static void pushCreatures(Tile *tile);
232
233 void onThinkTarget(uint32_t interval);
234 void onThinkYell(uint32_t interval);
235 void onThinkDefense(uint32_t interval);
236
237 bool isFriend(const Creature *creature) const;
238 bool isOpponent(const Creature *creature) const;
239
240 uint64_t getLostExperience() const override {
241 return skillLoss ? mType->info.experience : 0;
242 }
243 uint16_t getLookCorpse() const override { return mType->info.lookcorpse; }
244 void dropLoot(Container *corpse, Creature *lastHitCreature) override;
245 uint32_t getDamageImmunities() const override {
246 return mType->info.damageImmunities;
247 }
248 uint32_t getConditionImmunities() const override {
249 return mType->info.conditionImmunities;
250 }
251 void getPathSearchParams(const Creature *creature,
252 FindPathParams &fpp) const override;
253 bool useCacheMap() const override { return !randomStepping; }
254
255 friend class LuaScriptInterface;
256};
257
258#endif
259