OregonCore  revision fb2a440-git
Your Favourite TBC server
PetAI.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 <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "PetAI.h"
19 #include "Errors.h"
20 #include "Pet.h"
21 #include "Player.h"
22 #include "Spell.h"
23 #include "ObjectAccessor.h"
24 #include "SpellMgr.h"
25 #include "Creature.h"
26 #include "Utilities/Util.h"
27 
28 int PetAI::Permissible(const Creature* creature)
29 {
30  if (creature->IsPet())
31  return PERMIT_BASE_SPECIAL;
32 
33  return PERMIT_BASE_NO;
34 }
35 
37 {
38  m_AllySet.clear();
39  UpdateAllies();
40 }
41 
42 bool PetAI::_needToStop() const
43 {
44  // This is needed for charmed creatures, as once their target was reset other effects can trigger threat
45  if (me->isCharmed() && me->GetVictim() == me->GetCharmer())
46  return true;
47 
48  // dont allow pets to follow targets far away from owner
49  if (Unit* owner = me->GetCharmerOrOwner())
50  if (owner->GetExactDist(me) >= (owner->GetVisibilityRange() - 10.0f))
51  return true;
52 
53  return !me->IsValidAttackTarget(me->GetVictim());
54 }
55 
57 {
58  if (!me->IsAlive())
59  {
60  DEBUG_LOG("Creature stoped attacking because he is dead [guid=%u]", me->GetGUIDLow());
61  me->GetMotionMaster()->Clear();
63  me->CombatStop();
65 
66  return;
67  }
68 
69  me->AttackStop();
74 }
75 
76 void PetAI::UpdateAI(const uint32 diff)
77 {
78  if (!me->IsAlive() || !me->GetCharmInfo())
79  return;
80 
81  Unit* owner = me->GetCharmerOrOwner();
82 
83  if (m_updateAlliesTimer <= diff)
84  // UpdateAllies self set update timer
85  UpdateAllies();
86  else
87  m_updateAlliesTimer -= diff;
88 
89  // i_pet.GetVictim() can't be used for check in case stop fighting, i_pet.GetVictim() clear at Unit death etc.
90  if (me->GetVictim() && me->GetVictim()->IsAlive())
91  {
92  if (_needToStop())
93  {
94  DEBUG_LOG("Pet AI stoped attacking [guid=%u]", me->GetGUIDLow());
95  _stopAttack();
96  return;
97  }
98 
100  }
101  else if (owner) //no victim
102  {
103  if (Unit* nextTarget = SelectNextTarget())
104  AttackStart(nextTarget);
105  else
106  {
107  // Cancels the attack command so the pet stops chasing the
108  // target it is attacking, and returns the pet to his owner
111  }
112  }
113  else if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) // no charm info and no victim
115 
116  // Autocast (casted only in combat or persistent spells in any state)
118  {
119  typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
120  TargetSpellList targetSpellStore;
121 
122  for (uint8 i = 0; i < me->GetPetAutoSpellSize(); ++i)
123  {
124  uint32 spellID = me->GetPetAutoSpellOnPos(i);
125  if (!spellID)
126  continue;
127 
128  SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellID);
129  if (!spellInfo)
130  continue;
131 
132  // ignore some combinations of combat state and combat/noncombat spells
133  if (!me->GetVictim())
134  {
135  // ignore attacking spells, and allow only self/around spells
136  if (!IsPositiveSpell(spellInfo->Id))
137  continue;
138 
139  // non combat spells allowed
140  // only pet spells have IsNonCombatSpell and not fit this reqs:
141  // Consume Shadows, Lesser Invisibility, so ignore checks for its
142  if (!IsNonCombatSpell(spellInfo))
143  {
144  // allow only spell without spell cost or with spell cost but not duration limit
145  int32 duration = GetSpellDuration(spellInfo);
146  if ((spellInfo->manaCost || spellInfo->ManaCostPercentage || spellInfo->manaPerSecond) && duration > 0)
147  continue;
148 
149  // allow only spell without cooldown > duration
150  int32 cooldown = GetSpellRecoveryTime(spellInfo);
151  if (cooldown >= 0 && duration >= 0 && cooldown > duration)
152  continue;
153  }
154  }
155  else
156  {
157  // just ignore non-combat spells
158  if (IsNonCombatSpell(spellInfo))
159  continue;
160  }
161 
162  Spell* spell = new Spell(me, spellInfo, false, 0);
163 
164  // Fix to allow pets on STAY to autocast
165  if (me->GetVictim() && CanAttack(me->GetVictim()) && spell->CanAutoCast(me->GetVictim()))
166  {
167  targetSpellStore.push_back(std::pair<Unit*, Spell*>(me->GetVictim(), spell));
168  continue;
169  }
170  else
171  {
172  bool spellUsed = false;
173  for (std::set<uint64>::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar)
174  {
176 
177  //only buff targets that are in combat, unless the spell can only be cast while out of combat
178  if (!Target)
179  continue;
180 
181  if (spell->CanAutoCast(Target))
182  {
183  targetSpellStore.push_back(std::pair<Unit*, Spell*>(Target, spell));
184  spellUsed = true;
185  break;
186  }
187  }
188  if (!spellUsed)
189  delete spell;
190  }
191  }
192 
193  //found units to cast on to
194  if (!targetSpellStore.empty())
195  {
196  uint32 index = urand(0, targetSpellStore.size() - 1);
197 
198  Spell* spell = targetSpellStore[index].second;
199  Unit* target = targetSpellStore[index].first;
200 
201  targetSpellStore.erase(targetSpellStore.begin() + index);
202 
203  SpellCastTargets targets;
204  targets.setUnitTarget(target);
205 
206  if (!me->HasInArc(float(M_PI), target))
207  {
208  me->SetInFront(target);
209  if (target->GetTypeId() == TYPEID_PLAYER)
210  me->SendUpdateToPlayer(target->ToPlayer());
211 
212  if (owner && owner->GetTypeId() == TYPEID_PLAYER)
213  me->SendUpdateToPlayer(owner->ToPlayer());
214  }
215 
216  me->AddCreatureSpellCooldown(spell->m_spellInfo->Id);
217  if (me->IsPet())
218  ((Pet*)me)->CheckLearning(spell->m_spellInfo->Id);
219 
220  spell->prepare(&targets);
221  }
222 
223  // deleted cached Spell objects
224  for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr)
225  delete itr->second;
226  }
227 }
228 
229 void PetAI::DamageDealt(Unit* victim, uint32& damage, DamageEffectType damageType)
230 {
231  if (!victim)
232  return;
233 
234  Unit* owner = me->GetCharmerOrOwner();
235  if (!owner || !me->GetVictim())
236  return;
237 
238  if (!(me->GetVictim() == victim) && !me->GetVictim()->IsAlive())
239  return;
240 
241  owner->SetInCombatWith(victim);
242 }
243 
245 {
246  m_updateAlliesTimer = 10 * IN_MILLISECONDS; //update friendly targets every 10 seconds, lesser checks increase performance
247 
248  Unit* owner = me->GetCharmerOrOwner();
249  if (!owner)
250  return;
251 
252  Group* group = NULL;
253  if (Player* player = owner->ToPlayer())
254  group = player->GetGroup();
255 
256  //only pet and owner/not in group->ok
257  if (m_AllySet.size() == 2 && !group)
258  return;
259 
260  //owner is in group; group members filled in already (no raid -> subgroupcount = whole count)
261  if (group && !group->isRaidGroup() && m_AllySet.size() == (group->GetMembersCount() + 2))
262  return;
263 
264  m_AllySet.clear();
265  m_AllySet.insert(me->GetGUID());
266  if (group) //add group
267  {
268  for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
269  {
270  Player* Target = itr->GetSource();
271  if (!Target || !Target->IsInMap(owner) || !group->SameSubGroup(owner->ToPlayer(), Target))
272  continue;
273 
274  if (Target->GetGUID() == owner->GetGUID())
275  continue;
276 
277  m_AllySet.insert(Target->GetGUID());
278  }
279  }
280  else //remove group
281  m_AllySet.insert(owner->GetGUID());
282 }
283 
284 void PetAI::KilledUnit(Unit* victim)
285 {
286  // Called from Unit::Kill() in case where pet or owner kills something
287  // if owner killed this victim, pet may still be attacking something else
288  if (me == victim || (me->GetVictim() && me->GetVictim() != victim))
289  return;
290 
291  // Clear target just in case. May help problem where health / focus / mana
292  // regen gets stuck. Also resets attack command.
293  // Can't use _stopAttack() because that activates movement handlers and ignores
294  // next target selection
295  me->AttackStop();
296  me->InterruptNonMeleeSpells(false);
297  me->SendMeleeAttackStop(); // Stops the pet's 'Attack' button from flashing
298 
299  // Before returning to owner, see if there are more things to attack
300  if (Unit* nextTarget = SelectNextTarget())
301  AttackStart(nextTarget);
302  else
303  {
304  // Cancels the attack command so the pet stops chasing the
305  // target it is attacking, and returns the pet to his owner
308  }
309 }
310 
312 {
313  // Overrides Unit::AttackStart to correctly evaluate Pet states
314 
315  // Check all pet states to decide if we can attack this target
316  if (!me->GetCharmInfo() || !CanAttack(target))
317  return;
318 
319  // Only chase if not commanded to stay or if stay but commanded to attack
321 }
322 
324 {
325  // Provides next target selection after current target death
326 
327  // Passive pets don't do next target selection
329  return NULL;
330 
331  // Check pet attackers first so we don't drag a bunch of targets to the owner
332  if (Unit* myAttacker = me->getAttackerForHelper())
333  return myAttacker;
334 
335  // Not sure why we wouldn't have an owner but just in case...
336  if (!me->GetCharmerOrOwner())
337  return NULL;
338 
339  // Check owner attackers
340  if (Unit* ownerAttacker = me->GetCharmerOrOwner()->getAttackerForHelper())
341  return ownerAttacker;
342 
343  // Default - no valid targets
344  return NULL;
345 }
346 
348 {
349  // Handles moving the pet back to stay or owner
350 
351  // Prevent activating movement when under control of spells
352  // such as "Eyes of the Beast"
353  if (me->isCharmed())
354  return;
355 
357  {
358  if (!me->GetCharmInfo()->IsAtStay() && !me->GetCharmInfo()->IsReturning())
359  {
360  float x, y, z;
361 
362  me->GetCharmInfo()->GetStayPosition(x, y, z);
364  me->GetCharmInfo()->SetIsReturning(true);
365  me->GetMotionMaster()->Clear();
366  me->GetMotionMaster()->MovePoint(me->GetGUIDLow(), x, y, z);
367  }
368  }
369  else // COMMAND_FOLLOW
370  {
371  if (!me->GetCharmInfo()->IsFollowing() && !me->GetCharmInfo()->IsReturning())
372  {
374  me->GetCharmInfo()->SetIsReturning(true);
375  me->GetMotionMaster()->Clear();
377  }
378  }
379 
380  me->ClearInPetCombat();
381 }
382 
383 void PetAI::DoAttack(Unit* target, bool chase)
384 {
385  // Handles attack with or without chase and also resets flags
386  // for next update / creature kill
387 
388  if (me->Attack(target, true))
389  {
390  // properly fix fake combat after pet is sent to attack
391  if (Unit* owner = me->GetOwner())
392  owner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
393 
395 
396  // Play sound to let the player know the pet is attacking something it picked on its own
399 
400  if (chase)
401  {
402  bool oldCmdAttack = me->GetCharmInfo()->IsCommandAttack(); // This needs to be reset after other flags are cleared
404  me->GetCharmInfo()->SetIsCommandAttack(oldCmdAttack); // For passive pets commanded to attack so they will use spells
405  me->GetMotionMaster()->Clear();
406  me->GetMotionMaster()->MoveChase(target);
407  }
408  else // (Stay && ((Aggressive || Defensive) && In Melee Range)))
409  {
411  me->GetCharmInfo()->SetIsAtStay(true);
412  me->GetMotionMaster()->Clear();
414  }
415  }
416 }
417 
419 void PetAI::MovementInform(uint32 moveType, uint32 data)
420 {
421  if (!me->GetCharmInfo())
422  return;
423 
424  switch (moveType)
425  {
426  case POINT_MOTION_TYPE:
427  {
428  // Pet is returning to where stay was clicked. data should be
429  // pet's GUIDLow since we set that as the waypoint ID
430  if (data == me->GetGUIDLow() && me->GetCharmInfo()->IsReturning())
431  {
433  me->GetCharmInfo()->SetIsAtStay(true);
434  me->GetMotionMaster()->Clear();
436  }
437  break;
438  }
439  case FOLLOW_MOTION_TYPE:
440  {
441  // If data is owner's GUIDLow then we've reached follow point
443  {
445  me->GetCharmInfo()->SetIsFollowing(true);
447  }
448  break;
449  }
450  default:
451  break;
452  }
453 }
454 
455 bool PetAI::CanAttack(Unit* target)
456 {
457  // Evaluates wether a pet can attack a specific target based on CommandState, ReactState and other flags
458 
459  if (!target)
460  return false;
461 
462  if (!target->IsAlive())
463  {
464  // if target is invalid, pet should evade automaticly
465  // Clear target to prevent getting stuck on dead targets
466  //me->AttackStop();
467  //me->InterruptNonMeleeSpells(false);
468  return false;
469  }
470 
471  // Passive - passive pets can attack if told to
473  return me->GetCharmInfo()->IsCommandAttack();
474 
475  // Returning - pets ignore attacks only if owner clicked follow
476  if (me->GetCharmInfo()->IsReturning())
477  return false;
478 
479  // Is owner on a mount
481  return false;
482 
483  // Stay - can attack if target is within range or commanded to
485  return (me->IsWithinMeleeRange(target, MELEE_RANGE) || me->GetCharmInfo()->IsCommandAttack());
486 
487  // Pets attacking something (or chasing) should only switch targets if owner tells them to
488  if (me->GetVictim() && me->GetVictim() != target)
489  {
490  // Check if our owner selected this target and clicked "attack"
491  Unit* ownerTarget = NULL;
492  if (Player* owner = me->GetCharmerOrOwner()->ToPlayer())
493  ownerTarget = owner->GetSelectedUnit();
494  else
495  ownerTarget = me->GetCharmerOrOwner()->GetVictim();
496 
497  if (ownerTarget && me->GetCharmInfo()->IsCommandAttack())
498  return (target->GetGUID() == ownerTarget->GetGUID());
499  }
500 
501  // Follow
503  return true;
504 
505  // default, though we shouldn't ever get here
506  return false;
507 }
508 
510 {
511  // Called when owner takes damage. This function helps keep pets from running off
512  // simply due to owner gaining aggro.
513 
514  if (!attacker)
515  return;
516 
517  // Passive pets don't do anything
519  return;
520 
521  // Prevent pet from disengaging from current target
522  if (me->GetVictim() && me->GetVictim()->IsAlive())
523  return;
524 
525  // Continue to evaluate and attack if necessary
526  AttackStart(attacker);
527 }
528 
530 {
531  // Called when owner attacks something. Allows defensive pets to know
532  // that they need to assist
533 
534  // Target might be NULL if called from spell with invalid cast targets
535  if (!target)
536  return;
537 
538  // Passive pets don't do anything
540  return;
541 
542  // Prevent pet from disengaging from current target
543  if (me->GetVictim() && me->GetVictim()->IsAlive())
544  return;
545 
546  // Continue to evaluate and attack if necessary
547  AttackStart(target);
548 }
549 
550 void PetAI::AttackedBy(Unit* attacker)
551 {
552  // Called when pet takes damage. This function helps keep pets from running off
553  // simply due to gaining aggro.
554 
555  if (!attacker)
556  return;
557 
558  // Passive pets don't do anything
560  return;
561 
562  if (Unit* owner = me->GetOwner())
563  owner->SetInCombatWith(attacker);
564 
565  // Prevent pet from disengaging from current target
566  if (me->GetVictim() && me->GetVictim()->IsAlive())
567  return;
568 
569  // Continue to evaluate and attack if necessary
570  AttackStart(attacker);
571 }
572 
574 {
575  // Quick access to set all flags to FALSE
576 
577  CharmInfo* ci = me->GetCharmInfo();
578 
579  if (ci)
580  {
581  ci->SetIsAtStay(false);
582  ci->SetIsCommandAttack(false);
583  ci->SetIsFollowing(false);
584  ci->SetIsReturning(false);
585  }
586 }
Unit * GetCharmer() const
Definition: Unit.cpp:7633
void ClearInPetCombat()
Definition: Unit.cpp:9488
bool AttackStop()
Definition: Unit.cpp:7484
uint32 m_updateAlliesTimer
Definition: PetAI.h:62
bool Attack(Unit *victim, bool meleeAttack)
Definition: Unit.cpp:7390
bool SameSubGroup(uint64 guid1, const uint64 &guid2) const
Definition: Group.h:275
void SendPetAIReaction(uint64 guid)
Definition: Unit.cpp:11904
void MoveIdle(MovementSlot slot=MOTION_SLOT_ACTIVE)
virtual uint8 GetPetAutoSpellSize() const
Definition: Creature.h:707
void Clear(bool reset=true)
Definition: MotionMaster.h:145
void SetIsFollowing(bool val)
Definition: Unit.cpp:13580
void ClearCharmInfoFlags()
Definition: PetAI.cpp:573
bool HasCommandState(CommandStates state)
Definition: Unit.h:817
void SendMeleeAttackStop(Unit *victim=NULL)
Definition: Unit.cpp:2642
void AddUnitState(uint32 f)
Definition: Unit.h:1026
pet will not attack
Definition: Unit.h:760
bool isRaidGroup() const
Definition: Group.h:210
void MoveChase(Unit *target, float dist=0.0f, float angle=0.0f)
Pet * ToPet()
Definition: Unit.h:1054
void DamageDealt(Unit *victim, uint32 &damage, DamageEffectType damageType)
Definition: PetAI.cpp:229
void UpdateAI(const uint32)
Definition: PetAI.cpp:76
MotionMaster * GetMotionMaster()
Definition: Unit.h:1890
void DoAttack(Unit *target, bool chase)
Definition: PetAI.cpp:383
bool IsValidAttackTarget(Unit const *target) const
Definition: Unit.cpp:9510
#define PET_FOLLOW_DIST
ACE_INT32 int32
Definition: Define.h:67
bool HasReactState(ReactStates state) const
Definition: Creature.h:497
void setUnitTarget(Unit *target)
Definition: Spell.cpp:83
void MovePoint(uint32 id, const Position &pos, bool usePathfinding=true)
Definition: MotionMaster.h:179
uint32 GetGUIDLow() const
Definition: Object.h:166
void SetFlag(uint16 index, uint32 newFlag)
Definition: Object.cpp:985
void OwnerAttacked(Unit *target)
Definition: PetAI.cpp:529
void KilledUnit(Unit *victim)
Definition: PetAI.cpp:284
bool IsAtStay()
Definition: Unit.cpp:13575
CharmInfo * GetCharmInfo()
Definition: Unit.h:1458
DBCStorage< SpellEntry > sSpellStore(SpellEntryfmt)
Player * ToPlayer()
Definition: Object.h:392
void SetInFront(Unit const *target)
Definition: Unit.h:1675
void HandleReturnMovement()
Definition: PetAI.cpp:347
Unit * SelectNextTarget()
Definition: PetAI.cpp:323
void _stopAttack(void)
Definition: PetAI.cpp:56
#define TIME_INTERVAL_LOOK
Definition: CreatureAI.h:31
bool IsReturning()
Definition: Unit.cpp:13595
Creature *const me
Definition: CreatureAI.h:68
uint8 GetTypeId() const
Definition: Object.h:210
ACE_UINT8 uint8
Definition: Define.h:73
bool IsCommandAttack()
Definition: Unit.cpp:13543
uint32 manaPerSecond
Definition: DBCStructure.h:712
bool IsFollowing()
Definition: Unit.cpp:13585
HostileRefManager & getHostileRefManager()
Definition: Unit.h:1733
void SetIsReturning(bool val)
Definition: Unit.cpp:13590
bool IsAlive() const
Definition: Unit.h:1336
Unit * GetVictim() const
Definition: Unit.h:1013
DamageEffectType
Definition: Unit.h:537
TimeTracker i_tracker
Definition: PetAI.h:59
uint32 GetGlobalCooldown() const
Definition: Creature.h:736
void CombatStop(bool cast=false)
Definition: Unit.cpp:7518
#define DEBUG_LOG(...)
Definition: Log.h:194
void UpdateAllies()
Definition: PetAI.cpp:244
virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
Definition: Creature.h:711
GroupReference * GetFirstMember()
Definition: Group.h:304
bool IsInMap(const WorldObject *obj) const
Definition: Object.h:745
PetModeFlags GetModeFlags() const
Definition: Pet.h:224
void SetIsAtStay(bool val)
Definition: Unit.cpp:13570
GroupReference * next()
bool IsPositiveSpell(uint32 spellId)
Definition: SpellMgr.cpp:773
bool IsPet() const
Definition: Unit.h:1048
void SetIsCommandAttack(bool val)
Definition: Unit.cpp:13538
std::set< uint64 > m_AllySet
Definition: PetAI.h:61
void AttackStart(Unit *target)
Definition: PetAI.cpp:311
Target
void GetStayPosition(float &x, float &y, float &z)
Definition: Unit.cpp:13563
bool HasInArc(float arcangle, const Position *pos) const
Definition: Object.cpp:1393
Unit * GetCharmerOrOwner() const
Definition: Unit.h:1410
orders pet to follow
Definition: Unit.h:769
uint32 GetMembersCount() const
Definition: Group.h:309
Unit * GetOwner() const
Definition: Unit.cpp:7625
bool _needToStop(void) const
Definition: PetAI.cpp:42
void AttackedBy(Unit *attacker)
Definition: PetAI.cpp:550
bool IsNonCombatSpell(SpellEntry const *spellInfo)
Definition: SpellMgr.h:315
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3576
static int Permissible(const Creature *)
Definition: PetAI.cpp:28
void DoMeleeAttackIfReady()
Definition: UnitAI.cpp:45
Unit * getAttackerForHelper() const
Definition: Unit.cpp:7370
bool HasUnitState(const uint32 f) const
Definition: Unit.h:1030
static Unit * GetUnit(WorldObject const &, uint64 guid)
bool IsWithinMeleeRange(Unit *obj, float dist=MELEE_RANGE) const
Definition: Unit.cpp:653
#define MELEE_RANGE
Definition: Object.h:48
uint32 ManaCostPercentage
Definition: DBCStructure.h:756
bool CanAttack(Unit *target)
Definition: PetAI.cpp:455
bool isCharmed() const
Definition: Unit.h:1434
ACE_UINT32 uint32
Definition: Define.h:71
orders pet to stop moving
Definition: Unit.h:768
bool CanAutoCast(Unit *target)
Definition: Spell.cpp:5161
void AddCreatureSpellCooldown(uint32 spellid)
Definition: Creature.cpp:2247
Definition: Unit.h:908
void MovementInform(uint32 moveType, uint32 data)
Receives notification when pet reaches stay or follow owner.
Definition: PetAI.cpp:419
Definition: Player.h:922
void OwnerAttackedBy(Unit *attacker)
Definition: PetAI.cpp:509
void SendUpdateToPlayer(Player *player)
Definition: Object.cpp:207
int32 GetSpellDuration(SpellEntry const *spellInfo)
Definition: SpellMgr.cpp:228
Definition: Pet.h:146
void SetInCombatWith(Unit *enemy)
Definition: Unit.cpp:9329
Definition: Group.h:154
PetAI(Creature *c)
Definition: PetAI.cpp:36
virtual float GetFollowAngle() const
Definition: Unit.h:1971
uint32 manaCost
Definition: DBCStructure.h:710
void MoveFollow(Unit *target, float dist, float angle, MovementSlot slot=MOTION_SLOT_ACTIVE)
uint32 GetSpellRecoveryTime(SpellEntry const *spellInfo)
Definition: SpellMgr.h:151
uint32 urand(uint32 min, uint32 max)
Definition: Util.cpp:33
const uint64 & GetGUID() const
Definition: Object.h:162
Definition: Spell.h:249