aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/AI/ScriptedAI/ScriptedCreature.h
blob: 0f46bf4e5648d7ba57f79b41252e50ec23d5f9d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
/*
 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef TRINITY_SCRIPTEDCREATURE_H
#define TRINITY_SCRIPTEDCREATURE_H

#include "CreatureAI.h"
#include "Creature.h"  // convenience include for scripts, all uses of ScriptedCreature also need Creature (except ScriptedCreature itself doesn't need Creature)
#include "DBCEnums.h"
#include "EventMap.h"
#include "TaskScheduler.h"

class InstanceScript;
enum SelectTargetType : uint8;
enum SelectEffect : uint8;

class TC_GAME_API SummonList
{
public:
    typedef GuidList StorageType;
    typedef StorageType::iterator iterator;
    typedef StorageType::const_iterator const_iterator;
    typedef StorageType::size_type size_type;
    typedef StorageType::value_type value_type;

    explicit SummonList(Creature* creature) : _me(creature) { }

    // And here we see a problem of original inheritance approach. People started
    // to exploit presence of std::list members, so I have to provide wrappers

    iterator begin()
    {
        return _storage.begin();
    }

    const_iterator begin() const
    {
        return _storage.begin();
    }

    iterator end()
    {
        return _storage.end();
    }

    const_iterator end() const
    {
        return _storage.end();
    }

    iterator erase(iterator i)
    {
        return _storage.erase(i);
    }

    bool empty() const
    {
        return _storage.empty();
    }

    size_type size() const
    {
        return _storage.size();
    }

    // Clear the underlying storage. This does NOT despawn the creatures - use DespawnAll for that!
    void clear()
    {
        _storage.clear();
    }

    void Summon(Creature const* summon);
    void Despawn(Creature const* summon);
    void DespawnEntry(uint32 entry);
    void DespawnAll();

    template <typename T>
    void DespawnIf(T const& predicate)
    {
        _storage.remove_if(predicate);
    }

    template <class Predicate>
    void DoAction(int32 info, Predicate&& predicate, uint16 max = 0)
    {
        // We need to use a copy of SummonList here, otherwise original SummonList would be modified
        StorageType listCopy;
        std::copy_if(std::begin(_storage), std::end(_storage), std::inserter(listCopy, std::end(listCopy)), predicate);
        DoActionImpl(info, listCopy, max);
    }

    void DoZoneInCombat(uint32 entry = 0);
    void RemoveNotExisting();
    bool HasEntry(uint32 entry) const;

private:
    void DoActionImpl(int32 action, StorageType& summons, uint16 max);

    Creature* _me;
    StorageType _storage;
};

class TC_GAME_API EntryCheckPredicate
{
    public:
        EntryCheckPredicate(uint32 entry) : _entry(entry) { }
        bool operator()(ObjectGuid const& guid) const { return guid.GetEntry() == _entry; }

    private:
        uint32 _entry;
};

class TC_GAME_API DummyEntryCheckPredicate
{
    public:
        bool operator()(ObjectGuid const&) const { return true; }
};

struct TC_GAME_API ScriptedAI : public CreatureAI
{
    public:
        explicit ScriptedAI(Creature* creature, uint32 scriptId = 0) noexcept;
        virtual ~ScriptedAI() { }

        // *************
        // CreatureAI Functions
        // *************

        void AttackStartNoMove(Unit* target);

        // Called at World update tick
        virtual void UpdateAI(uint32 diff) override;

        // *************
        // Variables
        // *************

        // *************
        // Pure virtual functions
        // *************

        // Called before JustEngagedWith even before the creature is in combat.
        void AttackStart(Unit* /*target*/) override;

        // *************
        // AI Helper Functions
        // *************

        // Start movement toward victim
        void DoStartMovement(Unit* target, float distance = 0.0f, float angle = 0.0f);

        // Start no movement on victim
        void DoStartNoMovement(Unit* target);

        // Stop attack of current victim
        void DoStopAttack();

        // Cast spell by spell info
        void DoCastSpell(Unit* target, SpellInfo const* spellInfo, bool triggered = false);

        // Plays a sound to all nearby players
        void DoPlaySoundToSet(WorldObject* source, uint32 soundId);

        // Add specified amount of threat directly to victim (ignores redirection effects) - also puts victim in combat and engages them if necessary
        void AddThreat(Unit* victim, float amount, Unit* who = nullptr);
        // Adds/removes the specified percentage from the specified victim's threat (to who, or me if not specified)
        void ModifyThreatByPercent(Unit* victim, int32 pct, Unit* who = nullptr);
        // Resets the victim's threat level to who (or me if not specified) to zero
        void ResetThreat(Unit* victim, Unit* who = nullptr);
        // Resets the specified unit's threat list (me if not specified) - does not delete entries, just sets their threat to zero
        void ResetThreatList(Unit* who = nullptr);
        // Returns the threat level of victim towards who (or me if not specified)
        float GetThreat(Unit const* victim, Unit const* who = nullptr);
        // Stops combat, ignoring restrictions, for the given creature
        void ForceCombatStop(Creature* who, bool reset = true);
        // Stops combat, ignoring restrictions, for the found creatures
        void ForceCombatStopForCreatureEntry(uint32 entry, float maxSearchRange = 250.0f, bool samePhase = true, bool reset = true);
        // Stops combat, ignoring restrictions, for the found creatures
        void ForceCombatStopForCreatureEntry(std::vector<uint32> creatureEntries, float maxSearchRange = 250.0f, bool samePhase = true, bool reset = true);

        void DoTeleportTo(float x, float y, float z, uint32 time = 0);
        void DoTeleportTo(float const pos[4]);

        // Teleports a player without dropping threat (only teleports to same map)
        void DoTeleportPlayer(Unit* unit, float x, float y, float z, float o);
        void DoTeleportAll(float x, float y, float z, float o);

        // Returns friendly unit with the most amount of hp missing from max hp
        Unit* DoSelectLowestHpFriendly(float range, uint32 minHPDiff = 1);

        // Returns friendly unit with hp pct below specified and with specified entry
        Unit* DoSelectBelowHpPctFriendlyWithEntry(uint32 entry, float range, uint8 hpPct = 1, bool excludeSelf = true);

        // Returns a list of friendly CC'd units within range
        std::list<Creature*> DoFindFriendlyCC(float range);

        // Returns a list of all friendly units missing a specific buff within range
        std::list<Creature*> DoFindFriendlyMissingBuff(float range, uint32 spellId);

        // Return a player with at least minimumRange from me
        Player* GetPlayerAtMinimumRange(float minRange);

        // Spawns a creature relative to me
        Creature* DoSpawnCreature(uint32 entry, float offsetX, float offsetY, float offsetZ, float angle, uint32 type, Milliseconds despawntime);

        bool HealthBelowPct(uint32 pct) const;
        bool HealthAbovePct(uint32 pct) const;

        // Returns spells that meet the specified criteria from the creatures spell list
        SpellInfo const* SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, float rangeMin, float rangeMax, SelectEffect effect);

        void SetEquipmentSlots(bool loadDefault, int32 mainHand = EQUIP_NO_CHANGE, int32 offHand = EQUIP_NO_CHANGE, int32 ranged = EQUIP_NO_CHANGE);

        // Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
        // NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart
        //       You should make the necessary to make it happen so.
        //       Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset().
        //       It will keep the last value you set.
        void SetCombatMovement(bool allowMovement);
        bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; }

        bool IsLFR() const;
        bool IsNormal() const;
        bool IsHeroic() const;
        bool IsMythic() const;
        bool IsMythicPlus() const;
        bool IsHeroicOrHigher() const;
        bool IsTimewalking() const;

        // return the dungeon or raid difficulty
        Difficulty GetDifficulty() const { return _difficulty; }

        // return true for 25 man or 25 man heroic mode
        bool Is25ManRaid() const { return _difficulty == DIFFICULTY_25_N || _difficulty == DIFFICULTY_25_HC; }

        template <class T>
        inline T const& DUNGEON_MODE(T const& normal5, T const& heroic10) const
        {
            switch (_difficulty)
            {
                case DIFFICULTY_NORMAL:
                    return normal5;
                case DIFFICULTY_HEROIC:
                    return heroic10;
                default:
                    break;
            }

            return heroic10;
        }

        template <class T>
        inline T const& RAID_MODE(T const& normal10, T const& normal25) const
        {
            switch (_difficulty)
            {
                case DIFFICULTY_10_N:
                    return normal10;
                case DIFFICULTY_25_N:
                    return normal25;
                default:
                    break;
            }

            return normal25;
        }

        template <class T>
        inline T const& RAID_MODE(T const& normal10, T const& normal25, T const& heroic10, T const& heroic25) const
        {
            switch (_difficulty)
            {
                case DIFFICULTY_10_N:
                    return normal10;
                case DIFFICULTY_25_N:
                    return normal25;
                case DIFFICULTY_10_HC:
                    return heroic10;
                case DIFFICULTY_25_HC:
                    return heroic25;
                default:
                    break;
            }

            return heroic25;
        }

    private:
        Difficulty _difficulty;
        bool _isCombatMovementAllowed;
};

class TC_GAME_API BossAI : public ScriptedAI
{
    public:
        explicit BossAI(Creature* creature, uint32 bossId) noexcept;
        virtual ~BossAI();

        InstanceScript* const instance;

        void JustSummoned(Creature* summon) override;
        void SummonedCreatureDespawn(Creature* summon) override;

        virtual void UpdateAI(uint32 diff) override;

        // Hook used to execute events scheduled into EventMap without the need
        // to override UpdateAI
        // note: You must re-schedule the event within this method if the event
        // is supposed to run more than once
        virtual void ExecuteEvent(uint32 /*eventId*/) { }

        virtual void ScheduleTasks() { }

        void Reset() override { _Reset(); }
        void JustEngagedWith(Unit* who) override { _JustEngagedWith(who); }
        void JustDied(Unit* /*killer*/) override { _JustDied(); }
        void JustReachedHome() override { _JustReachedHome(); }

        bool CanAIAttack(Unit const* target) const override;

        uint32 GetBossId() const { return _bossId; }

    protected:
        void _Reset();
        void _JustEngagedWith(Unit* who);
        void _JustDied();
        void _JustReachedHome();
        void _DespawnAtEvade(Seconds delayToRespawn = 30s, Creature* who = nullptr);

        void TeleportCheaters();

        EventMap events;
        SummonList summons;
        TaskScheduler scheduler;

    private:
        uint32 const _bossId;
};

class TC_GAME_API WorldBossAI : public ScriptedAI
{
    public:
        explicit WorldBossAI(Creature* creature) noexcept;
        virtual ~WorldBossAI();

        void JustSummoned(Creature* summon) override;
        void SummonedCreatureDespawn(Creature* summon) override;

        virtual void UpdateAI(uint32 diff) override;

        // Hook used to execute events scheduled into EventMap without the need
        // to override UpdateAI
        // note: You must re-schedule the event within this method if the event
        // is supposed to run more than once
        virtual void ExecuteEvent(uint32 /*eventId*/) { }

        void Reset() override { _Reset(); }
        void JustEngagedWith(Unit* /*who*/) override { _JustEngagedWith(); }
        void JustDied(Unit* /*killer*/) override { _JustDied(); }

    protected:
        void _Reset();
        void _JustEngagedWith();
        void _JustDied();

        EventMap events;
        SummonList summons;
};

// SD2 grid searchers.
inline Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive = true)
{
    return source->FindNearestCreature(entry, maxSearchRange, alive);
}

inline Creature* GetClosestCreatureWithOptions(WorldObject* source, float maxSearchRange, FindCreatureOptions const& options)
{
    return source->FindNearestCreatureWithOptions(maxSearchRange, options);
}

inline GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool spawnedOnly = true)
{
    return source->FindNearestGameObject(entry, maxSearchRange, spawnedOnly);
}

template <typename Container>
inline void GetCreatureListWithEntryInGrid(Container& container, WorldObject* source, uint32 entry, float maxSearchRange)
{
    source->GetCreatureListWithEntryInGrid(container, entry, maxSearchRange);
}

template <typename Container>
inline void GetCreatureListWithOptionsInGrid(Container& container, WorldObject* source, float maxSearchRange, FindCreatureOptions const& options)
{
    source->GetCreatureListWithOptionsInGrid(container, maxSearchRange, options);
}

template <typename Container>
inline void GetGameObjectListWithEntryInGrid(Container& container, WorldObject* source, uint32 entry, float maxSearchRange)
{
    source->GetGameObjectListWithEntryInGrid(container, entry, maxSearchRange);
}

template <typename Container>
inline void GetPlayerListInGrid(Container& container, WorldObject* source, float maxSearchRange, bool alive = true)
{
    source->GetPlayerListInGrid(container, maxSearchRange, alive);
}

#endif // TRINITY_SCRIPTEDCREATURE_H