OregonCore  revision fb2a440-git
Your Favourite TBC server
ScriptedFollowerAI.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 /* ScriptData
19 SDName: FollowerAI
20 SD%Complete: 50
21 SDComment: This AI is under development
22 SDCategory: Npc
23 EndScriptData */
24 
25 #include "ScriptedCreature.h"
26 #include "ScriptedFollowerAI.h"
27 #include "Group.h"
28 #include "Player.h"
29 
30 const float MAX_PLAYER_DISTANCE = 100.0f;
31 
32 enum ePoints
33 {
34  POINT_COMBAT_START = 0xFFFFFF
35 };
36 
37 FollowerAI::FollowerAI(Creature* pCreature) : ScriptedAI(pCreature),
38  m_uiLeaderGUID(0),
39  m_uiUpdateFollowTimer(2500),
40  m_uiFollowState(STATE_FOLLOW_NONE),
41  m_pQuestForFollow(NULL)
42 {}
43 
45 {
46  if (!pWho)
47  return;
48 
49  if (me->Attack(pWho, true))
50  {
51  me->AddThreat(pWho, 0.0f);
52  me->SetInCombatWith(pWho);
53  pWho->SetInCombatWith(me);
54 
57 
58  if (IsCombatMovement())
59  me->GetMotionMaster()->MoveChase(pWho);
60  }
61 }
62 
63 //This part provides assistance to a player that are attacked by pWho, even if out of normal aggro range
64 //It will cause me to attack pWho that are attacking _any_ player (which has been confirmed may happen also on offi)
65 //The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate.
67 {
68  if (!pWho || !pWho->GetVictim())
69  return false;
70 
72  return false;
73 
74  //not a player
76  return false;
77 
78  //never attack friendly
79  if (me->IsFriendlyTo(pWho))
80  return false;
81 
82  //too far away and no free sight?
84  {
85  //already fighting someone?
86  if (!me->GetVictim())
87  {
88  AttackStart(pWho);
89  return true;
90  }
91  else
92  {
93  pWho->SetInCombatWith(me);
94  me->AddThreat(pWho, 0.0f);
95  return true;
96  }
97  }
98 
99  return false;
100 }
101 
103 {
105  {
107  return;
108 
109  if (!me->CanFly() && me->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE)
110  return;
111 
112  if (me->IsHostileTo(pWho))
113  {
114  float fAttackRadius = me->GetAttackDistance(pWho);
115  if (me->IsWithinDistInMap(pWho, fAttackRadius) && me->IsWithinLOSInMap(pWho))
116  {
117  if (!me->GetVictim())
118  {
119  // Clear distracted state on combat
121  {
123  me->GetMotionMaster()->Clear();
124  }
125 
126  AttackStart(pWho);
127  }
128  else if (me->GetMap()->IsDungeon())
129  {
130  pWho->SetInCombatWith(me);
131  me->AddThreat(pWho, 0.0f);
132  }
133  }
134  }
135  }
136 }
137 
138 void FollowerAI::JustDied(Unit* /*pKiller*/)
139 {
141  return;
142 
143  //@todo need a better check for quests with time limit.
144  if (Player* player = GetLeaderForFollower())
145  {
146  if (Group* pGroup = player->GetGroup())
147  {
148  for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next())
149  {
150  if (Player* member = pRef->GetSource())
151  {
152  if (member->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
153  if (member->IsInMap(player))
154  member->FailQuest(m_pQuestForFollow->GetQuestId());
155  }
156  }
157  }
158  else
159  {
160  if (player->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
161  player->FailQuest(m_pQuestForFollow->GetQuestId());
162  }
163  }
164 }
165 
167 {
169 
170  if (!IsCombatMovement())
171  SetCombatMovement(true);
172 
175 
176  Reset();
177 }
178 
180 {
181  me->RemoveAllAuras();
182  me->DeleteThreatList();
183  me->CombatStop(true);
184  me->SetLootRecipient(NULL);
185 
187  {
188  sLog.outDebug("OSCR: FollowerAI left combat, returning to CombatStartPosition.");
189 
191  {
192  float fPosX, fPosY, fPosZ;
193  me->GetPosition(fPosX, fPosY, fPosZ);
194  me->GetMotionMaster()->MovePoint(POINT_COMBAT_START, fPosX, fPosY, fPosZ);
195  }
196  }
197  else
198  {
201  }
202 
203  Reset();
204 }
205 
206 void FollowerAI::UpdateAI(const uint32 uiDiff)
207 {
209  {
210  if (m_uiUpdateFollowTimer <= uiDiff)
211  {
213  {
214  sLog.outDebug("OSCR: FollowerAI is set completed, despawns.");
215  me->ForcedDespawn();
216  return;
217  }
218 
219  bool bIsMaxRangeExceeded = true;
220 
221  if (Player* pPlayer = GetLeaderForFollower())
222  {
224  {
225  sLog.outDebug("OSCR: FollowerAI is returning to leader.");
226 
229  return;
230  }
231 
232  if (Group* pGroup = pPlayer->GetGroup())
233  {
234  for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next())
235  {
236  Player* pMember = pRef->GetSource();
237 
238  if (pMember && me->IsWithinDistInMap(pMember, MAX_PLAYER_DISTANCE))
239  {
240  bIsMaxRangeExceeded = false;
241  break;
242  }
243  }
244  }
245  else
246  {
248  bIsMaxRangeExceeded = false;
249  }
250  }
251 
252  if (bIsMaxRangeExceeded)
253  {
254  sLog.outDebug("OSCR: FollowerAI failed because player/group was to far away or not found");
255  me->ForcedDespawn();
256  return;
257  }
258 
259  m_uiUpdateFollowTimer = 1000;
260  }
261  else
262  m_uiUpdateFollowTimer -= uiDiff;
263  }
264 
265  UpdateFollowerAI(uiDiff);
266 }
267 
268 void FollowerAI::UpdateFollowerAI(const uint32 /*uiDiff*/)
269 {
270  if (!UpdateVictim())
271  return;
272 
274 }
275 
276 void FollowerAI::MovementInform(uint32 uiMotionType, uint32 uiPointId)
277 {
279  return;
280 
281  if (uiPointId == POINT_COMBAT_START)
282  {
283  if (GetLeaderForFollower())
284  {
287  }
288  else
289  me->ForcedDespawn();
290  }
291 }
292 
293 void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const Quest* pQuest)
294 {
295  if (me->GetVictim())
296  {
297  sLog.outDebug("OSCR: FollowerAI attempt to StartFollow while in combat.");
298  return;
299  }
300 
302  {
303  sLog.outError("OSCR: FollowerAI attempt to StartFollow while already following.");
304  return;
305  }
306 
307  //set variables
308  m_uiLeaderGUID = pLeader->GetGUID();
309 
310  if (uiFactionForFollower)
311  me->SetFaction(uiFactionForFollower);
312 
313  m_pQuestForFollow = pQuest;
314 
316  {
317  me->GetMotionMaster()->Clear();
319  sLog.outDebug("OSCR: FollowerAI start with WAYPOINT_MOTION_TYPE, set to MoveIdle.");
320  }
321 
323 
325 
327 
328  sLog.outDebug("OSCR: FollowerAI start follow %s (GUID " UI64FMTD ")", pLeader->GetName(), m_uiLeaderGUID);
329 }
330 
332 {
333  if (Player* pLeader = Unit::GetPlayer(*me, m_uiLeaderGUID))
334  {
335  if (pLeader->IsAlive())
336  return pLeader;
337  else
338  {
339  if (Group* pGroup = pLeader->GetGroup())
340  {
341  for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next())
342  {
343  Player* member = pRef->GetSource();
344 
345  if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE) && member->IsAlive())
346  {
347  sLog.outDebug("OSCR: FollowerAI GetLeader changed and returned new leader.");
348  m_uiLeaderGUID = member->GetGUID();
349  return member;
350  break;
351  }
352  }
353  }
354  }
355  }
356 
357  sLog.outDebug("OSCR: FollowerAI GetLeader can not find suitable leader.");
358  return NULL;
359 }
360 
361 void FollowerAI::SetFollowComplete(bool bWithEndEvent)
362 {
364  {
366 
367  me->StopMoving();
368  me->GetMotionMaster()->Clear();
370  }
371 
372  if (bWithEndEvent)
374  else
375  {
378  }
379 
381 }
382 
383 void FollowerAI::SetFollowPaused(bool bPaused)
384 {
386  return;
387 
388  if (bPaused)
389  {
391 
393  {
395 
396  me->StopMoving();
397  me->GetMotionMaster()->Clear();
399  }
400  }
401  else
402  {
404 
405  if (Player* pLeader = GetLeaderForFollower())
407  }
408 }
409 
void RemoveAllAuras()
Definition: Unit.cpp:4577
bool Attack(Unit *victim, bool meleeAttack)
Definition: Unit.cpp:7390
void MoveIdle(MovementSlot slot=MOTION_SLOT_ACTIVE)
bool UpdateVictim()
Definition: CreatureAI.cpp:276
Map * GetMap() const
Definition: Object.h:841
uint32 GetFaction() const
Definition: Unit.h:1116
void Clear(bool reset=true)
Definition: MotionMaster.h:145
void StartFollow(Player *pPlayer, uint32 uiFactionForFollower=0, const Quest *pQuest=NULL)
void AddThreat(Unit *victim, float threat, SpellSchoolMask schoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *threatSpell=NULL)
Definition: Unit.cpp:10208
void MoveChase(Unit *target, float dist=0.0f, float angle=0.0f)
#define CREATURE_Z_ATTACK_RANGE
Definition: Creature.h:451
MotionMaster * GetMotionMaster()
Definition: Unit.h:1890
#define PET_FOLLOW_ANGLE
void AddFollowState(uint32 uiFollowState)
bool CanFly() const
Definition: Creature.h:493
void MovementInform(uint32 uiMotionType, uint32 uiPointId)
bool AssistPlayerInCombat(Unit *pWho)
#define sLog
Log class singleton.
Definition: Log.h:187
void MoveTargetedHome()
MovementGeneratorType GetCurrentMovementGeneratorType() const
#define PET_FOLLOW_DIST
void SetUInt32Value(uint16 index, uint32 value)
Definition: Object.cpp:779
bool IsWithinLOSInMap(const WorldObject *obj) const
Definition: Object.cpp:1229
bool IsDungeon() const
Definition: Map.h:427
void MovePoint(uint32 id, const Position &pos, bool usePathfinding=true)
Definition: MotionMaster.h:179
void ForcedDespawn(uint32 timeMSToDespawn=0)
Definition: Creature.cpp:1702
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition: Object.h:774
void SetLootRecipient(Unit *unit)
Definition: Creature.cpp:1012
bool HasFollowState(uint32 uiFollowState)
void ClearUnitState(uint32 f)
Definition: Unit.h:1034
uint32 m_uiUpdateFollowTimer
#define UI64FMTD
Definition: Common.h:149
void MoveInLineOfSight(Unit *)
Player * GetLeaderForFollower()
uint32 faction
Definition: Creature.h:150
uint32 GetQuestId() const
Definition: QuestDef.h:186
bool IsAlive() const
Definition: Unit.h:1336
Unit * GetVictim() const
Definition: Unit.h:1013
void GetPosition(float &x, float &y) const
Definition: Position.h:102
bool IsFriendlyTo(Unit const *unit) const
Definition: Unit.cpp:7339
void CombatStop(bool cast=false)
Definition: Unit.cpp:7518
void RemoveFollowState(uint32 uiFollowState)
float GetAttackDistance(Unit const *pl) const
Definition: Creature.cpp:1537
const Quest * m_pQuestForFollow
bool isInAccessiblePlaceFor(Creature const *c) const
Definition: Unit.cpp:3646
GroupReference * next()
const char * GetName() const
Definition: Object.h:704
void SetFollowPaused(bool bPaused)
const float MAX_PLAYER_DISTANCE
void SetFollowComplete(bool bWithEndEvent=false)
uint32 m_uiFollowState
void SetCombatMovement(bool CombatMove)
uint64 m_uiLeaderGUID
CreatureInfo const * GetCreatureTemplate() const
Definition: Creature.h:557
void UpdateAI(const uint32)
void DeleteThreatList()
Definition: Unit.cpp:10226
void SetFaction(uint32 faction)
Definition: Unit.h:1117
virtual void UpdateFollowerAI(const uint32)
bool IsHostileTo(Unit const *unit) const
Definition: Unit.cpp:7334
void DoMeleeAttackIfReady()
Definition: UnitAI.cpp:45
bool HasUnitState(const uint32 f) const
Definition: Unit.h:1030
void AttackStart(Unit *)
Creature * me
bool IsCombatMovement()
uint32 type_flags
Definition: Creature.h:170
float GetDistanceZ(const WorldObject *obj) const
Definition: Object.cpp:1195
FollowerAI(Creature *pCreature)
ACE_UINT32 uint32
Definition: Define.h:71
Definition: Unit.h:908
void JustDied(Unit *)
void StopMoving()
Definition: Unit.cpp:11917
static Player * GetPlayer(WorldObject &object, uint64 guid)
Definition: Unit.cpp:10676
Definition: Player.h:922
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition: Unit.cpp:9495
void SetInCombatWith(Unit *enemy)
Definition: Unit.cpp:9329
Definition: Group.h:154
void MoveFollow(Unit *target, float dist, float angle, MovementSlot slot=MOTION_SLOT_ACTIVE)
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition: Unit.cpp:7641
const uint64 & GetGUID() const
Definition: Object.h:162