OregonCore  revision be9e804-git
Your Favourite TBC server
UnitAI.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore 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 <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "UnitAI.h"
19 #include "Player.h"
20 #include "Creature.h"
21 #include "SpellAuras.h"
22 #include "SpellMgr.h"
23 #include "CreatureAIImpl.h"
24 
26 {
27  if (victim && me->Attack(victim, true))
28  {
29  // Clear distracted state on attacking
31  {
33  me->GetMotionMaster()->Clear();
34  }
35  me->GetMotionMaster()->MoveChase(victim);
36  }
37 }
38 
39 void UnitAI::AttackStartCaster(Unit* victim, float dist)
40 {
41  if (victim && me->Attack(victim, false))
42  me->GetMotionMaster()->MoveChase(victim, dist);
43 }
44 
46 {
48  return;
49 
50  //Make sure our attack is ready and we aren't currently casting before checking distance
51  if (me->isAttackReady())
52  {
53  //If we are within range melee the target
55  {
58  }
59  }
61  {
62  //If we are within range melee the target
64  {
67  }
68  }
69 }
70 
72 {
74  return true;
75 
76  if (me->isAttackReady())
77  {
78  const SpellEntry* spellInfo = GetSpellStore()->LookupEntry(spell);
79  if (me->IsWithinCombatRange(me->GetVictim(), GetSpellMaxRange(spellInfo)))
80  {
81  me->CastSpell(me->GetVictim(), spell, false);
83  }
84  else
85  return false;
86  }
87  return true;
88 }
89 
90 inline bool SelectTargetHelper(const Unit* me, const Unit* target, const bool& playerOnly, const float& dist, const int32& aura)
91 {
92  if (playerOnly && (!target || target->GetTypeId() != TYPEID_PLAYER))
93  return false;
94 
95  if (dist && (!me || !target || !me->IsWithinCombatRange(target, dist)))
96  return false;
97 
98  if (aura)
99  {
100  if (aura > 0)
101  {
102  if (!target->HasAura(aura, 0))
103  return false;
104  }
105  else
106  {
107  if (target->HasAura(aura, 0))
108  return false;
109  }
110  }
111 
112  return true;
113 }
114 
115 struct TargetDistanceOrder : public std::binary_function<const Unit*, const Unit*, bool>
116 {
117  const Unit* me;
118  TargetDistanceOrder(const Unit* Target) : me(Target) {};
119  // functor for operator ">"
120  bool operator()(const Unit* _Left, const Unit* _Right) const
121  {
122  return (me->GetExactDistSq(_Left) < me->GetExactDistSq(_Right));
123  }
124 };
125 
126 Unit* UnitAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura)
127 {
128  const std::list<HostileReference*>& threatlist = me->getThreatManager().getThreatList();
129  std::list<Unit*> targetList;
130 
131  for (std::list<HostileReference*>::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
132  if (SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura))
133  targetList.push_back((*itr)->getTarget());
134 
135  if (position >= targetList.size())
136  return NULL;
137 
138  if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
139  targetList.sort(TargetDistanceOrder(me));
140 
141  switch (targetType)
142  {
145  {
146  std::list<Unit*>::iterator itr = targetList.begin();
147  advance(itr, position);
148  return *itr;
149  }
150  break;
151 
154  {
155  std::list<Unit*>::reverse_iterator ritr = targetList.rbegin();
156  advance(ritr, position);
157  return *ritr;
158  }
159  break;
160 
162  return SelectRandomContainerElement(targetList);
163  break;
164  }
165 
166  return NULL;
167 }
168 
169 void UnitAI::SelectTargetList(std::list<Unit*>& targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura)
170 {
171  const std::list<HostileReference*>& threatlist = me->getThreatManager().getThreatList();
172  if (threatlist.empty())
173  return;
174 
175  for (std::list<HostileReference*>::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
176  if (SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura))
177  targetList.push_back((*itr)->getTarget());
178 
179  if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
180  targetList.sort(TargetDistanceOrder(me));
181 
182  if (targetType == SELECT_TARGET_FARTHEST || targetType == SELECT_TARGET_BOTTOMAGGRO)
183  targetList.reverse();
184 
185  if (targetType == SELECT_TARGET_RANDOM)
186  {
187  while (num < targetList.size())
188  {
189  std::list<Unit*>::iterator itr = targetList.begin();
190  advance(itr, urand(0, targetList.size() - 1));
191  targetList.erase(itr);
192  }
193  }
194  else
195  targetList.resize(num);
196 }
197 
198 float UnitAI::DoGetSpellMaxRange(uint32 spellId, bool /*positive*/)
199 {
200  return GetSpellMaxRange(spellId);
201 }
202 
203 void UnitAI::DoCast(uint32 spellId)
204 {
205  Unit* target = NULL;
206  //sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target);
207  switch (AISpellInfo[spellId].target)
208  {
209  default:
210  case AITARGET_SELF:
211  target = me;
212  break;
213  case AITARGET_VICTIM:
214  target = me->GetVictim();
215  break;
216  case AITARGET_ENEMY:
217  {
218  const SpellEntry* spellInfo = GetSpellStore()->LookupEntry(spellId);
219  bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR3_PLAYERS_ONLY;
220  target = SelectTarget(SELECT_TARGET_RANDOM, 0, GetSpellMaxRange(spellInfo), playerOnly);
221  break;
222  }
223  case AITARGET_ALLY:
224  target = me;
225  break;
226  case AITARGET_BUFF:
227  target = me;
228  break;
229  case AITARGET_DEBUFF:
230  {
231  const SpellEntry* spellInfo = GetSpellStore()->LookupEntry(spellId);
232  bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR3_PLAYERS_ONLY;
233  float range = GetSpellMaxRange(spellInfo);
236  && SelectTargetHelper(me, me->GetVictim(), playerOnly, range, -(int32)spellId))
237  target = me->GetVictim();
238  else
239  target = SelectTarget(SELECT_TARGET_RANDOM, 0, range, playerOnly, -(int32)spellId);
240  break;
241  }
242  }
243 
244  if (target)
245  me->CastSpell(target, spellId, false);
246 }
247 
248 void UnitAI::DoCast(Unit* victim, uint32 spellId, bool triggered)
249 {
250  if (!victim || (me->HasUnitState(UNIT_STATE_CASTING) && !triggered))
251  return;
252 
253  me->CastSpell(victim, spellId, triggered);
254 }
255 
256 void UnitAI::DoCastVictim(uint32 spellId, bool triggered)
257 {
258  // Why don't we check for casting unit_state and existing target as we do in DoCast(.. ?
259  DoCast(me->GetVictim(), spellId, triggered);
260 }
261 
262 void UnitAI::DoCastAOE(uint32 spellId, bool triggered)
263 {
264  if (!triggered && me->HasUnitState(UNIT_STATE_CASTING))
265  return;
266 
267  me->CastSpell((Unit*)NULL, spellId, triggered);
268 }
269 
270 #define UPDATE_TARGET(a) {if (AIInfo->target<a) AIInfo->target=a;}
271 
273 {
274  AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()];
275 
276  AISpellInfoType* AIInfo = AISpellInfo;
277  const SpellEntry* spellInfo;
278 
279  for (uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo)
280  {
281  spellInfo = GetSpellStore()->LookupEntry(i);
282  if (!spellInfo)
283  continue;
284 
286  AIInfo->condition = AICOND_DIE;
287  else if (IsPassiveSpell(i) || GetSpellDuration(spellInfo) == -1)
288  AIInfo->condition = AICOND_AGGRO;
289  else
290  AIInfo->condition = AICOND_COMBAT;
291 
292  if (AIInfo->cooldown < spellInfo->RecoveryTime)
293  AIInfo->cooldown = spellInfo->RecoveryTime;
294 
295  if (!GetSpellMaxRange(spellInfo))
297  else
298  {
299  for (uint32 j = 0; j < 3; ++j)
300  {
301  uint32 targetType = spellInfo->EffectImplicitTargetA[j];
302 
303  if (targetType == TARGET_UNIT_TARGET_ENEMY
304  || targetType == TARGET_DST_TARGET_ENEMY)
306  else if (targetType == TARGET_UNIT_AREA_ENEMY_DST)
308 
309  if (spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA)
310  {
311  if (targetType == TARGET_UNIT_TARGET_ENEMY)
313  else if (IsPositiveSpell(i))
315  }
316  }
317  }
318  AIInfo->realCooldown = spellInfo->RecoveryTime + spellInfo->StartRecoveryTime;
319  SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(spellInfo->rangeIndex);
320  if (srange)
321  AIInfo->maxRange = srange->maxRange * 3 / 4;
322  }
323 }
324 
326 {
327  delete[] AISpellInfo;
328  AISpellInfo = NULL;
329 }
330 
331 //Enable PlayerAI when charmed
333 {
334  me->IsAIEnabled = apply;
335 }
336 
337 void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
338 {
339  Creature* charmer = me->GetCharmer()->ToCreature();
340 
341  //kill self if charm aura has infinite duration
342  if (charmer->IsInEvadeMode())
343  {
345  for (Unit::AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
346  if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->IsPermanent())
347  {
348  charmer->Kill(me);
349  return;
350  }
351  }
352 
353  if (!charmer->IsInCombat())
355 
356  Unit* target = me->GetVictim();
357  if (!target || !charmer->IsValidAttackTarget(target))
359 }
360 
Unit * GetCharmer() const
Definition: Unit.cpp:7668
uint32 AuraInterruptFlags
Definition: DBCStructure.h:700
bool IsWithinCombatRange(const Unit *obj, float dist2compare) const
Definition: Unit.cpp:672
static AISpellInfoType * AISpellInfo
Definition: UnitAI.h:121
void Kill(Unit *victim, bool durabilityLoss=true)
Definition: Unit.cpp:12672
bool Attack(Unit *victim, bool meleeAttack)
Definition: Unit.cpp:7425
DBCStorage< SpellEntry > const * GetSpellStore()
Definition: DBCStores.cpp:776
void DoCastAOE(uint32 spellId, bool triggered=false)
Definition: UnitAI.cpp:262
Unit * SelectNearestTargetInAttackDistance(float dist=0) const
Definition: Creature.cpp:1882
static void ClearAISpellInfo()
Definition: UnitAI.cpp:325
bool IsPassiveSpell(uint32 spellId)
Definition: SpellMgr.cpp:278
void AttackerStateUpdate(Unit *victim, WeaponAttackType attType=BASE_ATTACK, bool extra=false)
Definition: Unit.cpp:2367
void Clear(bool reset=true)
Definition: MotionMaster.h:145
void MoveChase(Unit *target, float dist=0.0f, float angle=0.0f)
void SelectTargetList(std::list< Unit * > &targetList, uint32 num, SelectAggroTarget target, float dist=0, bool playerOnly=false, int32 aura=0)
Definition: UnitAI.cpp:169
MotionMaster * GetMotionMaster()
Definition: Unit.h:1893
bool IsInCombat() const
Definition: Unit.h:1243
#define UPDATE_TARGET(a)
Definition: UnitAI.cpp:270
bool IsValidAttackTarget(Unit const *target) const
Definition: Unit.cpp:9545
#define PET_FOLLOW_DIST
ThreatContainer::StorageType const & getThreatList() const
ACE_INT32 int32
Definition: Define.h:67
AICondition condition
std::list< Aura * > AuraList
Definition: Unit.h:917
bool IsInEvadeMode() const
Definition: Creature.cpp:2297
uint32 Effect[MAX_SPELL_EFFECTS]
Definition: DBCStructure.h:724
Unit *const me
Definition: UnitAI.h:44
void UpdateAI(const uint32 diff) override
Definition: UnitAI.cpp:337
bool operator()(const Unit *_Left, const Unit *_Right) const
Definition: UnitAI.cpp:120
bool DoSpellAttackIfReady(uint32 spell)
Definition: UnitAI.cpp:71
void apply(T *val)
Definition: ByteConverter.h:41
bool IsAIEnabled
Definition: Unit.h:1993
uint32 rangeIndex
Definition: DBCStructure.h:714
const Unit * me
Definition: UnitAI.cpp:117
uint32 Attributes
Definition: DBCStructure.h:679
uint64 GetGUID() const
Definition: Object.h:177
void ClearUnitState(uint32 f)
Definition: Unit.h:1034
uint8 GetTypeId() const
Definition: Object.h:192
uint32 AttributesEx3
Definition: DBCStructure.h:682
TargetDistanceOrder(const Unit *Target)
Definition: UnitAI.cpp:118
Unit * GetVictim() const
Definition: Unit.h:1013
SelectAggroTarget
Definition: UnitAI.h:32
void CastSpell(Unit *Victim, uint32 spellId, bool triggered, Item *castItem=NULL, Aura *triggeredByAura=NULL, uint64 originalCaster=0)
Definition: Unit.cpp:1260
float GetExactDistSq(float x, float y, float z) const
Definition: Position.h:145
uint32 EffectImplicitTargetA[MAX_SPELL_EFFECTS]
Definition: DBCStructure.h:731
void DoCast(uint32 spellId)
Definition: UnitAI.cpp:203
bool SelectTargetHelper(const Unit *me, const Unit *target, const bool &playerOnly, const float &dist, const int32 &aura)
Definition: UnitAI.cpp:90
bool haveOffhandWeapon() const
Definition: Unit.cpp:628
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition: Unit.h:952
void OnCharmed(bool apply) override
Definition: UnitAI.cpp:332
static void FillAISpellInfo()
Definition: UnitAI.cpp:272
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition: Unit.cpp:644
bool IsPositiveSpell(uint32 spellId)
Definition: SpellMgr.cpp:773
Target
uint32 RecoveryTime
Definition: DBCStructure.h:697
Creature * ToCreature()
Definition: Object.h:371
ThreatManager & getThreatManager()
Definition: Unit.h:1721
void DoMeleeAttackIfReady()
Definition: UnitAI.cpp:45
bool HasUnitState(const uint32 f) const
Definition: Unit.h:1030
bool IsWithinMeleeRange(Unit *obj, float dist=MELEE_RANGE) const
Definition: Unit.cpp:688
void DoCastVictim(uint32 spellId, bool triggered=false)
Definition: UnitAI.cpp:256
uint32 StartRecoveryTime
Definition: DBCStructure.h:758
AuraList const & GetAurasByType(AuraType type) const
Definition: Unit.h:1747
ACE_UINT32 uint32
Definition: Define.h:71
Definition: Unit.h:908
Unit * SelectTarget(SelectAggroTarget target, uint32 position=0, float dist=0, bool playerOnly=false, int32 aura=0)
Definition: UnitAI.cpp:126
virtual void AttackStart(Unit *)
Definition: UnitAI.cpp:25
DBCStorage< SpellRangeEntry > sSpellRangeStore(SpellRangefmt)
int32 GetSpellDuration(SpellEntry const *spellInfo)
Definition: SpellMgr.cpp:228
C::value_type const & SelectRandomContainerElement(C const &container)
Definition: Util.h:352
virtual float GetFollowAngle() const
Definition: Unit.h:1974
void MoveFollow(Unit *target, float dist, float angle, MovementSlot slot=MOTION_SLOT_ACTIVE)
float DoGetSpellMaxRange(uint32 spellId, bool positive=false)
Definition: UnitAI.cpp:198
uint32 urand(uint32 min, uint32 max)
Definition: Util.cpp:33
void AttackStartCaster(Unit *victim, float dist)
Definition: UnitAI.cpp:39
bool HasAura(uint32 spellId, uint8 effIndex=0) const
Definition: Unit.h:1262
float GetSpellMaxRange(SpellRangeEntry const *range)
Definition: SpellMgr.h:143