OregonCore  revision 3611e8a-git
Your Favourite TBC server
ScriptedEscortAI.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: Npc_EscortAI
20 SD%Complete: 100
21 SDComment:
22 SDCategory: Npc
23 EndScriptData */
24 
25 #include "ScriptedCreature.h"
26 #include "ScriptedEscortAI.h"
27 #include "Group.h"
28 #include "Player.h"
29 
30 enum ePoints
31 {
32  POINT_LAST_POINT = 0xFFFFFF,
33  POINT_HOME = 0xFFFFFE
34 };
35 
37  m_uiPlayerGUID(0),
38  m_uiWPWaitTimer(2500),
39  m_uiPlayerCheckTimer(1000),
40  m_uiEscortState(STATE_ESCORT_NONE),
41  MaxPlayerDistance(DEFAULT_MAX_PLAYER_DISTANCE),
42  m_pQuestForEscort(NULL),
43  m_bIsActiveAttacker(true),
44  m_bIsRunning(false),
45  m_bCanInstantRespawn(false),
46  m_bCanReturnToStart(false),
47  DespawnAtEnd(true),
48  DespawnAtFar(true),
49  ScriptWP(false),
50  ClearWP(false)
51 {}
52 
54 {
55  if (!pWho)
56  return;
57 
58  if (me->Attack(pWho, true))
59  {
62 
63  if (IsCombatMovement())
64  me->GetMotionMaster()->MoveChase(pWho);
65  }
66 }
67 
68 //see followerAI
70 {
71  if (!pWho || !pWho->GetVictim())
72  return false;
73 
75  return false;
76 
77  //not a player
79  return false;
80 
81  //never attack friendly
82  if (me->IsFriendlyTo(pWho))
83  return false;
84 
85  //too far away and no free sight?
87  {
88  //already fighting someone?
89  if (!me->GetVictim())
90  {
91  AttackStart(pWho);
92  return true;
93  }
94  else
95  {
96  pWho->SetInCombatWith(me);
97  me->AddThreat(pWho, 0.0f);
98  return true;
99  }
100  }
101 
102  return false;
103 }
104 
106 {
108  {
110  return;
111 
112  if (!me->canFly() && me->GetDistanceZ(pWho) > CREATURE_Z_ATTACK_RANGE)
113  return;
114 
115  if (me->IsHostileTo(pWho))
116  {
117  float fAttackRadius = me->GetAttackDistance(pWho);
118  if (me->IsWithinDistInMap(pWho, fAttackRadius) && me->IsWithinLOSInMap(pWho))
119  {
120  if (!me->GetVictim())
121  {
122  // Clear distracted state on combat
124  {
126  me->GetMotionMaster()->Clear();
127  }
128 
129  AttackStart(pWho);
130  }
131  else if (me->GetMap()->IsDungeon())
132  {
133  pWho->SetInCombatWith(me);
134  me->AddThreat(pWho, 0.0f);
135  }
136  }
137  }
138  }
139 }
140 
141 void npc_escortAI::JustDied(Unit* /*pKiller*/)
142 {
144  return;
145 
146  if (Player* player = GetPlayerForEscort())
147  {
148  if (Group* pGroup = player->GetGroup())
149  {
150  for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next())
151  {
152  if (Player* member = pRef->GetSource())
153  {
154  if (member->GetQuestStatus(m_pQuestForEscort->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
155  if (member->IsInMap(player))
156  member->FailQuest(m_pQuestForEscort->GetQuestId());
157  }
158  }
159  }
160  else
161  {
162  if (player->GetQuestStatus(m_pQuestForEscort->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
163  player->FailQuest(m_pQuestForEscort->GetQuestId());
164  }
165  }
166 }
167 
169 {
171 
172  if (!IsCombatMovement())
173  SetCombatMovement(true);
174 
175  //add a small delay before going to first waypoint, normal in near all cases
176  m_uiWPWaitTimer = 2500;
177 
179  me->RestoreFaction();
180 
181  Reset();
182 }
183 
185 {
186  float x, y, z, o;
187  me->GetHomePosition(x, y, z, o);
189 }
190 
192 {
193  me->RemoveAllAuras();
194  me->DeleteThreatList();
195  me->CombatStop(true);
196  me->SetLootRecipient(NULL);
197 
199  {
202  debug_log("OSCR: EscortAI has left combat and is now returning to last point");
203  }
204  else
205  {
207  if (HasPassiveFlag)
209  Reset();
210  }
211 }
212 
214 {
215  if (Player* pPlayer = GetPlayerForEscort())
216  {
217  if (Group* pGroup = pPlayer->GetGroup())
218  {
219  for (GroupReference* pRef = pGroup->GetFirstMember(); pRef != NULL; pRef = pRef->next())
220  {
221  Player* pMember = pRef->GetSource();
222 
223  if (pMember && me->IsWithinDistInMap(pMember, GetMaxPlayerDistance()))
224  {
225  return true;
226  break;
227  }
228  }
229  }
230  else
231  {
232  if (me->IsWithinDistInMap(pPlayer, GetMaxPlayerDistance()))
233  return true;
234  }
235  }
236  return false;
237 }
238 
239 void npc_escortAI::UpdateAI(const uint32 uiDiff)
240 {
241  //Waypoint Updating
243  {
244  if (m_uiWPWaitTimer <= uiDiff)
245  {
246  //End of the line
247  if (CurrentWP == WaypointList.end())
248  {
249  if (DespawnAtEnd)
250  {
251  debug_log("OSCR: EscortAI reached end of waypoints");
252 
254  {
255  float fRetX, fRetY, fRetZ;
256  me->GetRespawnPosition(fRetX, fRetY, fRetZ);
257 
258  me->GetMotionMaster()->MovePoint(POINT_HOME, fRetX, fRetY, fRetZ);
259 
260  m_uiWPWaitTimer = 0;
261 
262  debug_log("OSCR: EscortAI are returning home to spawn location: %u, %f, %f, %f", POINT_HOME, fRetX, fRetY, fRetZ);
263  return;
264  }
265 
267  {
269  me->Respawn();
270  }
271  else
272  me->ForcedDespawn();
273 
274  return;
275  }
276  else
277  {
278  if (ClearWP)
279  {
280  WaypointList.clear();
282  }
283 
284  debug_log("OSCR: EscortAI reached end of waypoints with Despawn off");
285 
286  return;
287  }
288  }
289 
291  {
293  debug_log("OSCR: EscortAI start waypoint %u (%f, %f, %f).", CurrentWP->id, CurrentWP->x, CurrentWP->y, CurrentWP->z);
294 
296 
297  m_uiWPWaitTimer = 0;
298  }
299  }
300  else
301  m_uiWPWaitTimer -= uiDiff;
302  }
303 
304  //Check if player or any member of his group is within range
306  {
307  if (m_uiPlayerCheckTimer <= uiDiff)
308  {
310  {
311  debug_log("OSCR: EscortAI failed because player/group was to far away or not found");
312 
314  {
316  me->Respawn();
317  }
318  else
319  me->ForcedDespawn();
320 
321  return;
322  }
323 
324  m_uiPlayerCheckTimer = 1000;
325  }
326  else
327  m_uiPlayerCheckTimer -= uiDiff;
328  }
329 
330  UpdateEscortAI(uiDiff);
331 }
332 
333 void npc_escortAI::UpdateEscortAI(const uint32 /*uiDiff*/)
334 {
335  if (!UpdateVictim())
336  return;
337 
339 }
340 
341 void npc_escortAI::MovementInform(uint32 uiMoveType, uint32 uiPointId)
342 {
344  return;
345 
346  //Combat start position reached, continue waypoint movement
347  if (uiPointId == POINT_LAST_POINT)
348  {
349  debug_log("OSCR: EscortAI has returned to original position before combat");
350 
352  me->SetWalk(false);
354  me->SetWalk(true);
355 
357 
358  if (!m_uiWPWaitTimer)
359  m_uiWPWaitTimer = 1;
360  }
361  else if (uiPointId == POINT_HOME)
362  {
363  debug_log("OSCR: EscortAI has returned to original home location and will continue from beginning of waypoint list.");
364 
365  CurrentWP = WaypointList.begin();
366  m_uiWPWaitTimer = 1;
367  }
368  else
369  {
370  //Make sure that we are still on the right waypoint
371  if (CurrentWP->id != uiPointId)
372  {
373  error_log("OSCR ERROR: EscortAI reached waypoint out of order %u, expected %u", uiPointId, CurrentWP->id);
374  return;
375  }
376 
377  debug_log("OSCR: EscortAI Waypoint %u reached", CurrentWP->id);
378 
379  //Call WP function
381 
382  m_uiWPWaitTimer = CurrentWP->WaitTimeMs + 1;
383 
384  ++CurrentWP;
385  }
386 }
387 
388 /*
389 void npc_escortAI::OnPossess(bool apply)
390 {
391  // We got possessed in the middle of being escorted, store the point
392  // where we left off to come back to when possess is removed
393  if (HasEscortState(STATE_ESCORT_ESCORTING))
394  {
395  if (apply)
396  me->GetPosition(LastPos.x, LastPos.y, LastPos.z);
397  else
398  {
399  Returning = true;
400  me->GetMotionMaster()->MovementExpired();
401  me->GetMotionMaster()->MovePoint(WP_LAST_POINT, LastPos.x, LastPos.y, LastPos.z);
402  }
403  }
404 }
405 */
406 
407 void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs)
408 {
409  Escort_Waypoint t(id, x, y, z, WaitTimeMs);
410 
411  WaypointList.push_back(t);
412 
413  // i think SD2 no longer uses this function
414  ScriptWP = true;
415  /*PointMovement wp;
416  wp.m_uiCreatureEntry = me->GetEntry();
417  wp.m_uiPointId = id;
418  wp.m_fX = x;
419  wp.m_fY = y;
420  wp.m_fZ = z;
421  wp.m_uiWaitTime = WaitTimeMs;
422  PointMovementMap[wp.m_uiCreatureEntry].push_back(wp);*/
423 }
424 
426 {
427  std::vector<ScriptPointMove> const& pPointsEntries = pSystemMgr.GetPointMoveList(me->GetEntry());
428 
429  if (pPointsEntries.empty())
430  return;
431 
432  std::vector<ScriptPointMove>::const_iterator itr;
433 
434  for (itr = pPointsEntries.begin(); itr != pPointsEntries.end(); ++itr)
435  {
436  Escort_Waypoint pPoint(itr->uiPointId, itr->fX, itr->fY, itr->fZ, itr->uiWaitTime);
437  WaypointList.push_back(pPoint);
438  }
439 }
440 
441 void npc_escortAI::SetRun(bool bRun)
442 {
443  if (bRun)
444  {
445  if (!m_bIsRunning)
446  me->SetWalk(false);
447  else
448  debug_log("OSCR: EscortAI attempt to set run mode, but is already running.");
449  }
450  else
451  {
452  if (m_bIsRunning)
453  me->SetWalk(true);
454  else
455  debug_log("OSCR: EscortAI attempt to set walk mode, but is already walking.");
456  }
457  m_bIsRunning = bRun;
458 }
459 
460 //@todo get rid of this many variables passed in function.
461 void npc_escortAI::Start(bool bIsActiveAttacker, bool bRun, uint64 uiPlayerGUID, const Quest* pQuest, bool bInstantRespawn, bool bCanLoopPath)
462 {
463  if (me->GetVictim())
464  {
465  error_log("OSCR ERROR: EscortAI attempt to Start while in combat. Scriptname: %s, creature entry: %u", me->GetScriptName().c_str(), me->GetEntry());
466  return;
467  }
468 
470  {
471  error_log("OSCR: EscortAI attempt to Start while already escorting.");
472  return;
473  }
474 
475  if (!ScriptWP) // sd2 never adds wp in script, but tc does
476  {
477 
478  if (!WaypointList.empty())
479  WaypointList.clear();
480 
482 
483  }
484 
485  if (WaypointList.empty())
486  {
487  error_db_log("OSCR: EscortAI Start with 0 waypoints (possible missing entry in script_waypoint. Quest: %u).", pQuest ? pQuest->GetQuestId() : 0);
488  return;
489  }
490 
491  //set variables
492  m_bIsActiveAttacker = bIsActiveAttacker;
493  m_bIsRunning = bRun;
494 
495  m_uiPlayerGUID = uiPlayerGUID;
496  m_pQuestForEscort = pQuest;
497 
498  m_bCanInstantRespawn = bInstantRespawn;
499  m_bCanReturnToStart = bCanLoopPath;
500 
502  debug_log("OSCR: EscortAI is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn.");
503 
505  {
508  debug_log("OSCR: EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle.");
509  }
510 
511  //disable npcflags
514  {
515  HasPassiveFlag = true;
517  }
518 
519  debug_log("OSCR: EscortAI started with %lu waypoints. ActiveAttacker = %d, Run = %d, PlayerGUID = " UI64FMTD, WaypointList.size(), m_bIsActiveAttacker, m_bIsRunning, m_uiPlayerGUID);
520 
521  CurrentWP = WaypointList.begin();
522 
523  //Set initial speed
524  if (m_bIsRunning)
525  me->SetWalk(false);
526  else
527  me->SetWalk(true);
528 
530 }
531 
533 {
535  return;
536 
537  if (bPaused)
539  else
541 }
542 
bool SetWalk(bool enable) override
Definition: Creature.cpp:2514
void RemoveAllAuras()
Definition: Unit.cpp:4522
uint32 m_uiEscortState
bool Attack(Unit *victim, bool meleeAttack)
Definition: Unit.cpp:7315
bool HasUnitMovementFlag(uint32 f) const
Definition: Unit.h:2014
void MoveIdle(MovementSlot slot=MOTION_SLOT_ACTIVE)
bool UpdateVictim()
Definition: CreatureAI.cpp:276
Map * GetMap() const
Definition: Object.h:829
uint32 m_uiPlayerCheckTimer
void MovementInform(uint32, uint32)
void Clear(bool reset=true)
Definition: MotionMaster.h:145
uint32 getFaction() const
Definition: Unit.h:1111
std::list< Escort_Waypoint > WaypointList
void GetHomePosition(float &x, float &y, float &z, float &ori)
Definition: Creature.h:802
void AddEscortState(uint32 uiEscortState)
void JustDied(Unit *)
void AddThreat(Unit *victim, float threat, SpellSchoolMask schoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *threatSpell=NULL)
Definition: Unit.cpp:10129
void MoveChase(Unit *target, float dist=0.0f, float angle=0.0f)
#define CREATURE_Z_ATTACK_RANGE
Definition: Creature.h:451
Player * GetPlayerForEscort()
virtual void WaypointReached(uint32 uiPointId)=0
MotionMaster * GetMotionMaster()
Definition: Unit.h:2001
void FillPointMovementListForCreature()
void MoveTargetedHome()
MovementGeneratorType GetCurrentMovementGeneratorType() const
void SetUInt32Value(uint16 index, uint32 value)
Definition: Object.cpp:779
bool AssistPlayerInCombat(Unit *pWho)
bool IsWithinLOSInMap(const WorldObject *obj) const
Definition: Object.cpp:1226
void AttackStart(Unit *who)
void SetRun(bool bRun=true)
NULL Dbg ErrDB Arena Chat Char Map MMap false
Definition: Log.cpp:556
bool IsDungeon() const
Definition: Map.h:427
void AddWaypoint(uint32 id, float x, float y, float z, uint32 WaitTimeMs=0)
const Quest * m_pQuestForEscort
void MovePoint(uint32 id, const Position &pos, bool usePathfinding=true)
Definition: MotionMaster.h:179
#define debug_log
Definition: Log.h:201
void SetFlag(uint16 index, uint32 newFlag)
Definition: Object.cpp:985
npc_escortAI(Creature *pCreature)
void ForcedDespawn(uint32 timeMSToDespawn=0)
Definition: Creature.cpp:1681
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition: Object.h:762
void SetLootRecipient(Unit *unit)
Definition: Creature.cpp:1006
void ClearUnitState(uint32 f)
Definition: Unit.h:1006
bool canFly() const
Definition: Creature.h:520
void setDeathState(DeathState s) override
Definition: Creature.cpp:1558
#define UI64FMTD
Definition: Common.h:149
uint32 faction
Definition: Creature.h:150
float GetMaxPlayerDistance()
uint32 GetQuestId() const
Definition: QuestDef.h:186
bool HasEscortState(uint32 uiEscortState)
Unit * GetVictim() const
Definition: Unit.h:985
void RestoreFaction()
Definition: Unit.cpp:13237
std::list< Escort_Waypoint >::iterator CurrentWP
void UpdateAI(const uint32)
#define pSystemMgr
Definition: ScriptSystem.h:67
void SetEscortPaused(bool uPaused)
virtual void WaypointStart(uint32)
void RemoveEscortState(uint32 uiEscortState)
bool IsFriendlyTo(Unit const *unit) const
Definition: Unit.cpp:7284
void CombatStop(bool cast=false)
Definition: Unit.cpp:7442
float GetAttackDistance(Unit const *pl) const
Definition: Creature.cpp:1520
bool isInAccessiblePlaceFor(Creature const *c) const
Definition: Unit.cpp:3592
GroupReference * next()
void MoveInLineOfSight(Unit *who)
void RemoveFlag(uint16 index, uint32 oldFlag)
Definition: Object.cpp:1006
ACE_UINT64 uint64
Definition: Define.h:70
#define error_db_log
Definition: Log.h:203
void Respawn(bool force=false)
Definition: Creature.cpp:1630
void SetCombatMovement(bool CombatMove)
#define error_log
Definition: Log.h:202
CreatureInfo const * GetCreatureTemplate() const
Definition: Creature.h:598
void DeleteThreatList()
Definition: Unit.cpp:10147
uint32 m_uiWPWaitTimer
bool IsPlayerOrGroupInRange()
virtual void UpdateEscortAI(const uint32)
bool IsHostileTo(Unit const *unit) const
Definition: Unit.cpp:7279
void DoMeleeAttackIfReady()
Definition: UnitAI.cpp:45
bool HasUnitState(const uint32 f) const
Definition: Unit.h:1002
Creature * me
#define DEFAULT_MAX_PLAYER_DISTANCE
uint32 GetEntry() const
Definition: Object.h:186
bool IsCombatMovement()
uint32 type_flags
Definition: Creature.h:174
float GetDistanceZ(const WorldObject *obj) const
Definition: Object.cpp:1192
bool HasFlag(uint16 index, uint32 flag) const
Definition: Object.h:299
ACE_UINT32 uint32
Definition: Define.h:71
void GetRespawnPosition(float &x, float &y, float &z, float *ori=NULL, float *dist=NULL) const
Definition: Creature.cpp:2307
void MovementExpired(bool reset=true)
Definition: MotionMaster.h:158
true
Definition: Log.cpp:534
Definition: Unit.h:884
std::string GetScriptName()
Definition: Creature.cpp:2374
Definition: Player.h:922
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition: Unit.cpp:9418
void Start(bool bIsActiveAttacker=true, bool bRun=false, uint64 uiPlayerGUID=0, const Quest *pQuest=NULL, bool bInstantRespawn=false, bool bCanLoopPath=false)
void SetInCombatWith(Unit *enemy)
Definition: Unit.cpp:9255
Definition: Group.h:154
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition: Unit.cpp:7565