TrinityCore
pet_mage.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Ordered alphabetically using scriptname.
20 * Scriptnames of files in this file should be prefixed with "npc_pet_mag_".
21 */
22
23#include "ScriptMgr.h"
24#include "CellImpl.h"
25#include "CombatAI.h"
26#include "GridNotifiersImpl.h"
27#include "MotionMaster.h"
28#include "Pet.h"
29#include "ScriptedCreature.h"
30
32{
37};
38
40{
42};
43
45{
46 const float CHASE_DISTANCE = 35.0f;
47
49
50 void InitializeAI() override
51 {
52 Unit* owner = me->GetOwner();
53 if (!owner)
54 return;
55
56 // here mirror image casts on summoner spell (not present in client dbc) 49866
57 // here should be auras (not present in client dbc): 35657, 35658, 35659, 35660 selfcast by mirror images (stats related?)
58 // Clone Me!
59 owner->CastSpell(me, SPELL_MAGE_CLONE_ME, true);
60 }
61
62 // custom UpdateVictim implementation to handle special target selection
63 // we prioritize between things that are in combat with owner based on the owner's threat to them
65 {
66 Unit* owner = me->GetOwner();
67 if (!owner)
68 return false;
69
70 if (!me->HasUnitState(UNIT_STATE_CASTING) && !me->IsInCombat() && !owner->IsInCombat())
71 return false;
72
73 Unit* currentTarget = me->GetVictim();
74 if (currentTarget && !CanAIAttack(currentTarget))
75 {
76 me->InterruptNonMeleeSpells(true); // do not finish casting on invalid targets
77 me->AttackStop();
78 currentTarget = nullptr;
79 }
80
81 // don't reselect if we're currently casting anyway
82 if (currentTarget && me->HasUnitState(UNIT_STATE_CASTING))
83 return true;
84
85 Unit* selectedTarget = nullptr;
86 CombatManager const& mgr = owner->GetCombatManager();
87 if (mgr.HasPvPCombat())
88 { // select pvp target
89 float minDistance = 0.0f;
90 for (auto const& pair : mgr.GetPvPCombatRefs())
91 {
92 Unit* target = pair.second->GetOther(owner);
93 if (target->GetTypeId() != TYPEID_PLAYER)
94 continue;
95 if (!CanAIAttack(target))
96 continue;
97
98 float dist = owner->GetDistance(target);
99 if (!selectedTarget || dist < minDistance)
100 {
101 selectedTarget = target;
102 minDistance = dist;
103 }
104 }
105 }
106
107 if (!selectedTarget)
108 { // select pve target
109 float maxThreat = 0.0f;
110 for (auto const& pair : mgr.GetPvECombatRefs())
111 {
112 Unit* target = pair.second->GetOther(owner);
113 if (!CanAIAttack(target))
114 continue;
115
116 float threat = target->GetThreatManager().GetThreat(owner);
117 if (threat >= maxThreat)
118 {
119 selectedTarget = target;
120 maxThreat = threat;
121 }
122 }
123 }
124
125 if (!selectedTarget)
126 {
128 return false;
129 }
130
131 if (selectedTarget != me->GetVictim())
132 AttackStartCaster(selectedTarget, CHASE_DISTANCE);
133 return true;
134 }
135
136 void UpdateAI(uint32 diff) override
137 {
138 Unit* owner = me->GetOwner();
139 if (!owner)
140 {
142 return;
143 }
144
145 if (_fireBlastTimer)
146 {
147 if (_fireBlastTimer <= diff)
148 _fireBlastTimer = 0;
149 else
150 _fireBlastTimer -= diff;
151 }
152
153 if (!UpdateVictim())
154 return;
155
157 return;
158
159 if (!_fireBlastTimer)
160 {
163 }
164 else
166 }
167
168 bool CanAIAttack(Unit const* who) const override
169 {
170 Unit* owner = me->GetOwner();
171 return owner && who->IsAlive() && me->IsValidAttackTarget(who) &&
173 who->IsInCombatWith(owner) && ScriptedAI::CanAIAttack(who);
174 }
175
176 // Do not reload Creature templates on evade mode enter - prevent visual lost
177 void EnterEvadeMode(EvadeReason /*why*/) override
178 {
179 if (me->IsInEvadeMode() || !me->IsAlive())
180 return;
181
182 Unit* owner = me->GetCharmerOrOwner();
183
184 me->CombatStop(true);
185 if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW))
186 {
189 }
190 }
191
193};
194
196{
198}
uint32_t uint32
Definition: Define.h:142
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
#define PET_FOLLOW_DIST
Definition: PetDefines.h:97
#define RegisterCreatureAI(ai_name)
Definition: ScriptMgr.h:1380
EvadeReason
Definition: UnitAICommon.h:30
@ UNIT_STATE_FOLLOW
Definition: Unit.h:264
@ UNIT_STATE_CASTING
Definition: Unit.h:270
std::unordered_map< ObjectGuid, PvPCombatReference * > const & GetPvPCombatRefs() const
std::unordered_map< ObjectGuid, CombatReference * > const & GetPvECombatRefs() const
bool HasPvPCombat() const
Creature *const me
Definition: CreatureAI.h:61
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
Definition: Creature.cpp:2415
bool IsInEvadeMode() const
Definition: Creature.h:203
void MoveFollow(Unit *target, float dist, ChaseAngle angle, Optional< Milliseconds > duration={}, MovementSlot slot=MOTION_SLOT_ACTIVE)
TypeID GetTypeId() const
Definition: Object.h:173
float GetThreat(Unit const *who, bool includeOffline=false) const
void AttackStartCaster(Unit *victim, float dist)
Definition: UnitAI.cpp:55
virtual bool CanAIAttack(Unit const *) const
Definition: UnitAI.h:57
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.cpp:180
Definition: Unit.h:627
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition: Unit.cpp:5827
ThreatManager & GetThreatManager()
Definition: Unit.h:1063
bool HasBreakableByDamageCrowdControlAura(Unit *excludeCasterChannel=nullptr) const
Definition: Unit.cpp:734
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3089
MotionMaster * GetMotionMaster()
Definition: Unit.h:1652
bool IsAlive() const
Definition: Unit.h:1164
bool IsInCombatWith(Unit const *who) const
Definition: Unit.h:1044
Unit * GetCharmerOrOwner() const
Definition: Unit.h:1200
virtual float GetFollowAngle() const
Definition: Unit.h:1744
Unit * GetVictim() const
Definition: Unit.h:715
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
CombatManager & GetCombatManager()
Definition: Unit.h:1023
bool AttackStop()
Definition: Unit.cpp:5781
bool IsInCombat() const
Definition: Unit.h:1043
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:2991
Unit * GetOwner() const
Definition: Object.cpp:2229
float GetDistance(WorldObject const *obj) const
Definition: Object.cpp:1078
MirrorImageTimers
Definition: pet_mage.cpp:40
@ TIMER_MIRROR_IMAGE_FIRE_BLAST
Definition: pet_mage.cpp:41
void AddSC_mage_pet_scripts()
Definition: pet_mage.cpp:195
@ SPELL_MAGE_FIRE_BLAST
Definition: pet_mage.cpp:36
@ SPELL_MAGE_CLONE_ME
Definition: pet_mage.cpp:33
@ SPELL_MAGE_FROST_BOLT
Definition: pet_mage.cpp:35
@ SPELL_MAGE_MASTERS_THREAT_LIST
Definition: pet_mage.cpp:34
npc_pet_mage_mirror_image(Creature *creature)
Definition: pet_mage.cpp:48
void InitializeAI() override
Definition: pet_mage.cpp:50
void EnterEvadeMode(EvadeReason) override
Definition: pet_mage.cpp:177
void UpdateAI(uint32 diff) override
Definition: pet_mage.cpp:136
const float CHASE_DISTANCE
Definition: pet_mage.cpp:46
bool CanAIAttack(Unit const *who) const override
Definition: pet_mage.cpp:168