Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
UnitAI.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "Creature.h"
7#include "CreatureAIImpl.h"
8#include "Player.h"
9#include "Spell.h"
10#include "SpellAuraEffects.h"
11#include "SpellAuras.h"
12#include "SpellInfo.h"
13#include "SpellMgr.h"
14#include "UnitAI.h"
15
17{
18 if (victim && me->Attack(victim, true))
19 me->GetMotionMaster()->MoveChase(victim);
20}
21
22void UnitAI::AttackStartCaster(Unit* victim, float dist)
23{
24 if (victim && me->Attack(victim, false))
25 me->GetMotionMaster()->MoveChase(victim, dist);
26}
27
29{
30 if (me->HasUnitState(UNIT_STATE_CASTING))
31 return;
32
33 Unit* victim = me->GetVictim();
34 //Make sure our attack is ready and we aren't currently casting before checking distance
35 if (me->isAttackReady() && me->IsWithinMeleeRange(victim))
36 {
37 me->AttackerStateUpdate(victim);
38 me->resetAttackTimer();
39 }
40
41 if (me->haveOffhandWeapon() && me->isAttackReady(WeaponAttackType::OFF_ATTACK) && me->IsWithinMeleeRange(victim))
42 {
43 me->AttackerStateUpdate(victim, WeaponAttackType::OFF_ATTACK);
44 me->resetAttackTimer(WeaponAttackType::OFF_ATTACK);
45 }
46}
47
49{
50 if (me->HasUnitState(UNIT_STATE_CASTING) || !me->isAttackReady())
51 return true;
52
53 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell))
54 {
55 if (me->IsWithinCombatRange(me->GetVictim(), spellInfo->GetMaxRange(false)))
56 {
57 me->CastSpell(me->GetVictim(), spell, false);
58 me->resetAttackTimer();
59 return true;
60 }
61 }
62
63 return false;
64}
65
66Unit* UnitAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura)
67{
68 return SelectTarget(targetType, position, DefaultTargetSelector(me, dist, playerOnly, aura));
69}
70
71void UnitAI::SelectTargetList(std::list<Unit*>& targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura)
72{
73 SelectTargetList(targetList, DefaultTargetSelector(me, dist, playerOnly, aura), num, targetType);
74}
75
76float UnitAI::DoGetSpellMaxRange(uint32 spellId, bool positive)
77{
78 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
79 return spellInfo ? spellInfo->GetMaxRange(positive) : 0;
80}
81
83{
84 if (me->IsInCombat())
85 {
86 ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList();
87 for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
88 {
89 if (Unit* unit = Unit::GetUnit(*me, (*itr)->getUnitGuid()))
90 if (unit->GetTypeId() == TypeID::TYPEID_PLAYER)
91 me->AddAura(spellid, unit);
92 }
93 }
94}
95
96void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered)
97{
98 if (me->IsInCombat())
99 {
100 ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList();
101 for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
102 {
103 if (Unit* unit = Unit::GetUnit(*me, (*itr)->getUnitGuid()))
104 if (unit->GetTypeId() == TypeID::TYPEID_PLAYER)
105 me->CastSpell(unit, spellid, triggered);
106 }
107 }
108}
109
111{
112 Unit* target = NULL;
113
114 switch (AISpellInfo[spellId].target)
115 {
116 default:
117 case AITARGET_SELF:
118 target = me;
119 break;
120 case AITARGET_VICTIM:
121 target = me->GetVictim();
122 break;
123 case AITARGET_ENEMY:
124 {
125 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
126 {
127 bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS;
128 target = SelectTarget(SELECT_TARGET_RANDOM, 0, spellInfo->GetMaxRange(false), playerOnly);
129 }
130 break;
131 }
132 case AITARGET_ALLY:
133 target = me;
134 break;
135 case AITARGET_BUFF:
136 target = me;
137 break;
138 case AITARGET_DEBUFF:
139 {
140 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId))
141 {
142 bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_PLAYERS;
143 float range = spellInfo->GetMaxRange(false);
144
145 DefaultTargetSelector targetSelector(me, range, playerOnly, -(int32)spellId);
146 if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM)
147 && targetSelector(me->GetVictim()))
148 target = me->GetVictim();
149 else
150 target = SelectTarget(SELECT_TARGET_RANDOM, 0, targetSelector);
151 }
152 break;
153 }
154 }
155
156 if (target)
157 me->CastSpell(target, spellId, false);
158}
159
160void UnitAI::DoCast(Unit* victim, uint32 spellId, bool triggered)
161{
162 if (!victim || (me->HasUnitState(UNIT_STATE_CASTING) && !triggered))
163 return;
164
165 me->CastSpell(victim, spellId, triggered);
166}
167
168void UnitAI::DoCastVictim(uint32 spellId, bool triggered)
169{
170 if (!me->GetVictim() || (me->HasUnitState(UNIT_STATE_CASTING) && !triggered))
171 return;
172
173 me->CastSpell(me->GetVictim(), spellId, triggered);
174}
175
176void UnitAI::DoCastAOE(uint32 spellId, bool triggered)
177{
178 if (!triggered && me->HasUnitState(UNIT_STATE_CASTING))
179 return;
180
181 me->CastSpell((Unit*)NULL, spellId, triggered);
182}
183
184#define UPDATE_TARGET(a) {if (AIInfo->target<a) AIInfo->target=a;}
185
187{
188 AISpellInfo = new AISpellInfoType[sSpellMgr->GetSpellInfoStoreSize()];
189
191 const SpellInfo* spellInfo;
192
193 for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i, ++AIInfo)
194 {
195 spellInfo = sSpellMgr->GetSpellInfo(i);
196 if (!spellInfo)
197 continue;
198
200 AIInfo->condition = AICOND_DIE;
201 else if (spellInfo->IsPassive() || spellInfo->GetDuration() == -1)
202 AIInfo->condition = AICOND_AGGRO;
203 else
204 AIInfo->condition = AICOND_COMBAT;
205
206 if (AIInfo->cooldown < spellInfo->RecoveryTime)
207 AIInfo->cooldown = spellInfo->RecoveryTime;
208
209 if (!spellInfo->GetMaxRange(false))
211 else
212 {
213 for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
214 {
215 uint32 targetType = spellInfo->Effects[j].TargetA.GetTarget();
216
217 if (targetType == TARGET_UNIT_TARGET_ENEMY || targetType == TARGET_DEST_TARGET_ENEMY)
218 {
220 }
221 else if (targetType == TARGET_UNIT_DEST_AREA_ENEMY)
222 {
224 }
225
226 if (spellInfo->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA)
227 {
228 if (targetType == TARGET_UNIT_TARGET_ENEMY)
230 else if (spellInfo->IsPositive())
232 }
233 }
234 }
235 AIInfo->realCooldown = spellInfo->RecoveryTime + spellInfo->StartRecoveryTime;
236 AIInfo->maxRange = spellInfo->GetMaxRange(false) * 3 / 4;
237 }
238}
239
240//Enable PlayerAI when charmed
241void PlayerAI::OnCharmed(bool apply)
242{
243 me->IsAIEnabled = apply;
244}
245
247{
248 Creature* charmer = me->GetCharmer()->ToCreature();
249
250 //kill self if charm aura has infinite duration
251 if (charmer->IsInEvadeMode())
252 {
253 Unit::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM);
254 for (Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
255 if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent())
256 {
257 charmer->Kill(me);
258 return;
259 }
260 }
261
262 if (!charmer->IsInCombat())
263 me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle());
264
265 Unit* target = me->GetVictim();
266 if (!target || !charmer->IsValidAttackTarget(target))
268}
269
271 _caster(caster), _spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(sSpellMgr->GetSpellInfo(spellId), caster))
272{
274}
275
276bool SpellTargetSelector::operator()(Unit const* target) const
277{
278 if (!target)
279 return false;
280
281 if (_spellInfo->CheckTarget(_caster, target) != SpellCastResult::SPELL_CAST_OK)
282 return false;
283
284 // copypasta from Spell::CheckRange
285 uint32 range_type = _spellInfo->RangeEntry ? _spellInfo->RangeEntry->type : 0;
286 float max_range = _caster->GetSpellMaxRangeForTarget(target, _spellInfo);
287 float min_range = _caster->GetSpellMinRangeForTarget(target, _spellInfo);
288
289
290 if (target && target != _caster)
291 {
292 if (range_type == SPELL_RANGE_MELEE)
293 {
294 // Because of lag, we can not check too strictly here.
295 if (!_caster->IsWithinMeleeRange(target, max_range))
296 return false;
297 }
298 else if (!_caster->IsWithinCombatRange(target, max_range))
299 return false;
300
301 if (range_type == SPELL_RANGE_RANGED)
302 {
303 if (_caster->IsWithinMeleeRange(target))
304 return false;
305 }
306 else if (min_range && _caster->IsWithinCombatRange(target, min_range)) // skip this check if min_range = 0
307 return false;
308 }
309
310 return true;
311}
312
314{
315 if (!target)
316 return false;
317
318 if (_playerOnly && target->GetTypeId() != TypeID::TYPEID_PLAYER)
319 return false;
320
321 return target != _source->GetVictim();
322}
@ AITARGET_ALLY
@ AITARGET_BUFF
@ AITARGET_SELF
@ AITARGET_VICTIM
@ AITARGET_ENEMY
@ AITARGET_DEBUFF
@ AICOND_COMBAT
@ AICOND_AGGRO
@ AICOND_DIE
#define MAX_SPELL_EFFECTS
std::int32_t int32
Definition Define.h:73
std::uint32_t uint32
Definition Define.h:77
#define ASSERT
Definition Errors.h:29
@ TYPEID_PLAYER
Definition Object.h:55
#define PET_FOLLOW_DIST
Definition PetDefines.h:57
@ SPELL_ATTR0_CASTABLE_WHILE_DEAD
@ SPELL_EFFECT_APPLY_AURA
@ TARGET_UNIT_DEST_AREA_ENEMY
@ TARGET_DEST_TARGET_ENEMY
@ TARGET_UNIT_TARGET_ENEMY
@ SPELL_ATTR3_ONLY_TARGET_PLAYERS
@ SPELL_RANGE_MELEE
Definition Spell.h:69
@ SPELL_RANGE_RANGED
Definition Spell.h:70
@ SPELL_AURA_MOD_CHARM
#define sSpellMgr
Definition SpellMgr.h:744
@ AURA_INTERRUPT_FLAG_NOT_VICTIM
Definition Unit.h:68
@ UNIT_STATE_CASTING
Definition Unit.h:527
#define UPDATE_TARGET(a)
Definition UnitAI.cpp:184
SelectAggroTarget
Definition UnitAI.h:22
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
Unit * SelectNearestTargetInAttackDistance(float dist=0) const
bool IsInEvadeMode() const
Definition Creature.h:478
uint64 GetGUID() const
Definition Object.h:119
TypeID GetTypeId() const
Definition Object.h:131
void OnCharmed(bool apply) OVERRIDE
Definition UnitAI.cpp:241
Player *const me
Definition UnitAI.h:263
void UpdateAI(uint32 diff) OVERRIDE
Definition UnitAI.cpp:246
SpellImplicitTargetInfo TargetA
Definition SpellInfo.h:102
SpellEffectInfo Effects[MAX_SPELL_EFFECTS]
Definition SpellInfo.h:255
uint32 RecoveryTime
Definition SpellInfo.h:194
bool IsPassive() const
float GetMaxRange(bool positive=false, Unit *caster=NULL, Spell *spell=NULL) const
uint32 Attributes
Definition SpellInfo.h:164
int32 GetDuration() const
uint32 StartRecoveryTime
Definition SpellInfo.h:197
bool IsPositive() const
std::list< HostileReference * > StorageType
void AttackStartCaster(Unit *victim, float dist)
Definition UnitAI.cpp:22
static void FillAISpellInfo()
Definition UnitAI.cpp:186
void SelectTargetList(std::list< Unit * > &targetList, uint32 num, SelectAggroTarget targetType, float dist=0.0f, bool playerOnly=false, int32 aura=0)
Definition UnitAI.cpp:71
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:28
void DoCast(uint32 spellId)
Definition UnitAI.cpp:110
Unit * SelectTarget(SelectAggroTarget targetType, uint32 position=0, float dist=0.0f, bool playerOnly=false, int32 aura=0)
Definition UnitAI.cpp:66
void DoCastToAllHostilePlayers(uint32 spellid, bool triggered=false)
Definition UnitAI.cpp:96
float DoGetSpellMaxRange(uint32 spellId, bool positive=false)
Definition UnitAI.cpp:76
void DoAddAuraToAllHostilePlayers(uint32 spellid)
Definition UnitAI.cpp:82
bool DoSpellAttackIfReady(uint32 spell)
Definition UnitAI.cpp:48
Unit *const me
Definition UnitAI.h:109
void DoCastVictim(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:168
void DoCastAOE(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:176
static AISpellInfoType * AISpellInfo
Definition UnitAI.h:242
virtual void AttackStart(Unit *)
Definition UnitAI.cpp:16
Definition Unit.h:1367
void Kill(Unit *victim, bool durabilityLoss=true)
Definition Unit.cpp:6342
bool IsValidAttackTarget(Unit const *target) const
Definition Unit.cpp:3810
static Unit * GetUnit(WorldObject &object, uint64 guid)
Definition Unit.cpp:4895
std::list< AuraEffect * > AuraEffectList
Definition Unit.h:1383
bool IsInCombat() const
Definition Unit.h:1896
AICondition condition
Creature const * _source
Definition UnitAI.h:102
bool operator()(Unit const *target) const
Definition UnitAI.cpp:313
SpellInfo const * _spellInfo
Definition UnitAI.h:89
bool operator()(Unit const *target) const
Definition UnitAI.cpp:276
SpellTargetSelector(Unit *caster, uint32 spellId)
Definition UnitAI.cpp:270
Unit const * _caster
Definition UnitAI.h:88