OregonCore  revision fb2a440-git
Your Favourite TBC server
MotionMaster.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 "MotionMaster.h"
19 #include "CreatureAISelector.h"
20 #include "Creature.h"
23 #include "HomeMovementGenerator.h"
24 #include "IdleMovementGenerator.h"
25 #include "PointMovementGenerator.h"
29 #include "MoveSpline.h"
30 #include "MoveSplineInit.h"
31 
32 inline bool isStatic(MovementGenerator* mv)
33 {
34  return (mv == &si_idleMovement);
35 }
36 
37 void
39 {
40  // clear ALL movement generators (including default)
41  while (!empty())
42  {
43  MovementGenerator* curr = top();
44  pop();
45  if (curr) DirectDelete(curr);
46  }
47 
48  InitDefault();
49 }
50 
51 // set new default movement generator
53 {
54  if (i_owner->GetTypeId() == TYPEID_UNIT)
55  {
57  Mutate(movement == NULL ? &si_idleMovement : movement, MOTION_SLOT_IDLE);
58  }
59  else
61 }
62 
64 {
65  // clear ALL movement generators (including default)
66  while (!empty())
67  {
68  MovementGenerator* curr = top();
69  pop();
70  if (curr) DirectDelete(curr);
71  }
72 }
73 
74 void
76 {
78  return;
79  ASSERT(!empty());
81  if (!top()->Update(*i_owner, diff))
82  {
85  }
86  else
88 
89  if (m_expList)
90  {
91  for (uint32 i = 0; i < m_expList->size(); ++i)
92  {
93  MovementGenerator* mg = (*m_expList)[i];
94  DirectDelete(mg);
95  }
96 
97  delete m_expList;
98  m_expList = NULL;
99 
100  if (empty())
101  Initialize();
102  else if (needInitTop())
103  InitTop();
104  else if (m_cleanFlag & MMCF_RESET)
105  top()->Reset(*i_owner);
106 
107  m_cleanFlag &= ~MMCF_RESET;
108  }
109 }
110 
111 void
113 {
114  while (size() > 1)
115  {
116  MovementGenerator* curr = top();
117  pop();
118  if (curr) DirectDelete(curr);
119  }
120 
121  if (needInitTop())
122  InitTop();
123  else if (reset)
124  top()->Reset(*i_owner);
125 }
126 
127 void
129 {
130  while (size() > 1)
131  {
132  MovementGenerator* curr = top();
133  pop();
134  if (curr)
135  DelayedDelete(curr);
136  }
137 }
138 
139 void
141 {
142  if (size() > 1)
143  {
144  MovementGenerator* curr = top();
145  pop();
146  DirectDelete(curr);
147  }
148 
149  while (!empty() && !top())
150  --i_top;
151 
152  if (empty())
153  Initialize();
154  else if (needInitTop())
155  InitTop();
156  else if (reset)
157  top()->Reset(*i_owner);
158 }
159 
160 void
162 {
163  if (size() > 1)
164  {
165  MovementGenerator* curr = top();
166  pop();
167  DelayedDelete(curr);
168  }
169 
170  while (!top())
171  --i_top;
172 }
173 
175 {
176  //if (empty() || !isStatic(top()))
177  // push(&si_idleMovement);
178  if (!isStatic(Impl[slot]))
179  Mutate(&si_idleMovement, slot);
180 }
181 
182 void
183 MotionMaster::MoveRandom(float spawndist)
184 {
185  if (i_owner->GetTypeId() == TYPEID_UNIT)
186  {
187  DEBUG_LOG("Creature (GUID: %u) start moving random", i_owner->GetGUIDLow());
189  }
190 }
191 
192 void
194 {
195  //if (i_owner->HasUnitState(UNIT_STATE_FLEEING))
196  // return;
197 
198  Clear(false);
199 
200  if (i_owner->GetTypeId() == TYPEID_UNIT)
201  {
202  DEBUG_LOG("Creature (Entry: %u GUID: %u) targeted home", i_owner->GetEntry(), i_owner->GetGUIDLow());
204  }
205  else
206  sLog.outError("Player (GUID: %u) attempt targeted home", i_owner->GetGUIDLow());
207 }
208 
209 void
211 {
212  if (i_owner->GetTypeId() == TYPEID_PLAYER)
213  {
214  DEBUG_LOG("Player (GUID: %u) move confused", i_owner->GetGUIDLow());
216  }
217  else
218  {
219  DEBUG_LOG("Creature (Entry: %u GUID: %u) move confused",
222  }
223 }
224 
225 void
226 MotionMaster::MoveChase(Unit* target, float dist, float angle)
227 {
228  // ignore movement request if target not exist
229  if (!target || target == i_owner)
230  return;
231 
232  if (i_owner->GetTypeId() == TYPEID_PLAYER)
233  {
234  DEBUG_LOG("Player (GUID: %u) chase to %s (GUID: %u)",
235  i_owner->GetGUIDLow(),
236  target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
237  target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
238  Mutate(new ChaseMovementGenerator<Player>(*target, dist, angle), MOTION_SLOT_ACTIVE);
239  }
240  else
241  {
242  DEBUG_LOG("Creature (Entry: %u GUID: %u) chase to %s (GUID: %u)",
244  target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
245  target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
246  Mutate(new ChaseMovementGenerator<Creature>(*target, dist, angle), MOTION_SLOT_ACTIVE);
247  }
248 }
249 
250 void
251 MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlot slot)
252 {
253  // ignore movement request if target not exist
254  if (!target || target == i_owner)
255  return;
256 
257  if (i_owner->GetTypeId() == TYPEID_PLAYER)
258  {
259  DEBUG_LOG("Player (GUID: %u) follow to %s (GUID: %u)", i_owner->GetGUIDLow(),
260  target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
261  target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
262  Mutate(new FollowMovementGenerator<Player>(*target, dist, angle), slot);
263  }
264  else
265  {
266  DEBUG_LOG("Creature (Entry: %u GUID: %u) follow to %s (GUID: %u)",
268  target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
269  target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
270  Mutate(new FollowMovementGenerator<Creature>(*target, dist, angle), slot);
271  }
272 }
273 
274 void
275 MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool usePathfinding)
276 {
277  if (i_owner->GetTypeId() == TYPEID_PLAYER)
278  {
279  DEBUG_LOG("Player (GUID: %u) targeted point (Id: %u X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), id, x, y, z);
280  Mutate(new PointMovementGenerator<Player>(id, x, y, z, usePathfinding), MOTION_SLOT_ACTIVE);
281  }
282  else
283  {
284  DEBUG_LOG("Creature (Entry: %u GUID: %u) targeted point (ID: %u X: %f Y: %f Z: %f)",
285  i_owner->GetEntry(), i_owner->GetGUIDLow(), id, x, y, z);
286  Mutate(new PointMovementGenerator<Creature>(id, x, y, z, usePathfinding), MOTION_SLOT_ACTIVE);
287  }
288 }
289 
290 void
291 MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id, bool usePathfinding)
292 {
293  if (Impl[MOTION_SLOT_CONTROLLED] && Impl[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
294  return;
295 
297  if (i_owner->GetTypeId() == TYPEID_PLAYER)
298  {
299  DEBUG_LOG("Player (GUID: %u) charge point (X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), x, y, z);
300  Mutate(new PointMovementGenerator<Player>(id, x, y, z, usePathfinding, speed), MOTION_SLOT_CONTROLLED);
301  }
302  else
303  {
304  DEBUG_LOG("Creature (Entry: %u GUID: %u) charge point (X: %f Y: %f Z: %f)",
305  i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z);
306  Mutate(new PointMovementGenerator<Creature>(id, x, y, z, usePathfinding, speed), MOTION_SLOT_CONTROLLED);
307  }
308 }
309 
311 {
312  if (!z)
313  {
314  // use larger distance for vmap height search than in most other cases
316  if (z < INVALID_HEIGHT)
317  {
318  sLog.outDebug("MotionMaster::MoveFall: unable retrive a proper height at map %u (x: %f, y: %f, z: %f) Z: %f.",
320  return;
321  }
322 
323  // Abort too if the ground is very near
324  if (fabs(i_owner->GetPositionZ() - z) < 0.1f)
325  return;
326  }
327 
329 
330  // don't run spline movement for players
331  if (i_owner->GetTypeId() == TYPEID_PLAYER)
332  return;
333 
335  init.MoveTo(i_owner->GetPositionX(), i_owner->GetPositionY(), z, false);
336  init.SetFall();
337  init.Launch();
339 }
340 
341 void
342 MotionMaster::MoveSeekAssistance(float x, float y, float z)
343 {
344  if (i_owner->GetTypeId() == TYPEID_PLAYER)
345  sLog.outError("Player (GUID: %u) attempt to seek assistance", i_owner->GetGUIDLow());
346  else
347  {
348  DEBUG_LOG("Creature (Entry: %u GUID: %u) seek assistance (X: %f Y: %f Z: %f)",
349  i_owner->GetEntry(), i_owner->GetGUIDLow(), x, y, z);
350  i_owner->AttackStop();
351  i_owner->CastStop();
354  }
355 }
356 
357 void
359 {
360  if (i_owner->GetTypeId() == TYPEID_PLAYER)
361  sLog.outError("Player (GUID: %u) attempt to call distract after assistance", i_owner->GetGUIDLow());
362  else
363  {
364  DEBUG_LOG("Creature (Entry: %u GUID: %u) is distracted after assistance call (Time: %u)",
365  i_owner->GetEntry(), i_owner->GetGUIDLow(), time);
367  }
368 }
369 
370 void
372 {
373  if (!enemy)
374  return;
375 
377  return;
378 
379  if (i_owner->GetTypeId() == TYPEID_PLAYER)
380  {
381  DEBUG_LOG("Player (GUID: %u) flee from %s (GUID: %u)", i_owner->GetGUIDLow(),
382  enemy->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
383  enemy->GetTypeId() == TYPEID_PLAYER ? enemy->GetGUIDLow() : enemy->ToCreature()->GetDBTableGUIDLow());
385  }
386  else
387  {
388  DEBUG_LOG("Creature (Entry: %u GUID: %u) flee from %s (GUID: %u)",
390  enemy->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
391  enemy->GetTypeId() == TYPEID_PLAYER ? enemy->GetGUIDLow() : enemy->ToCreature()->GetDBTableGUIDLow());
392  if (time)
394  else
396  }
397 }
398 
399 void
401 {
402  if (i_owner->GetTypeId() == TYPEID_PLAYER)
403  {
404  if (path < sTaxiPathNodesByPath.size())
405  {
406  sLog.outDebug("%s taxi to (Path %u node %u)", i_owner->GetName(), path, pathnode);
409  }
410  else
411  {
412  sLog.outError("%s attempt taxi to (not existed Path %u node %u)",
413  i_owner->GetName(), path, pathnode);
414  }
415  }
416  else
417  {
418  sLog.outError("Creature (Entry: %u GUID: %u) attempt taxi to (Path %u node %u)",
419  i_owner->GetEntry(), i_owner->GetGUIDLow(), path, pathnode);
420  }
421 }
422 
423 void
425 {
427  return;
428 
429  if (i_owner->GetTypeId() == TYPEID_PLAYER)
430  DEBUG_LOG("Player (GUID: %u) distracted (timer: %u)", i_owner->GetGUIDLow(), timer);
431  else
432  {
433  DEBUG_LOG("Creature (Entry: %u GUID: %u) (timer: %u)",
434  i_owner->GetEntry(), i_owner->GetGUIDLow(), timer);
435  }
436 
438  Mutate(mgen, MOTION_SLOT_CONTROLLED);
439 }
440 
442 {
443  if (MovementGenerator* curr = Impl[slot])
444  {
445  Impl[slot] = NULL; // in case a new one is generated in this slot during directdelete
446 
447  if (i_top == slot && (m_cleanFlag & MMCF_UPDATE))
448  DelayedDelete(curr);
449  else
450  DirectDelete(curr);
451  }
452  else if (i_top < slot)
453  i_top = slot;
454 
455  Impl[slot] = m;
456  if (i_top > slot)
457  needInit[slot] = true;
458  else
459  {
460  needInit[slot] = false;
461  m->Initialize(*i_owner);
462  }
463 }
464 
465 void MotionMaster::MovePath(uint32 path_id, bool repeatable)
466 {
467  if (!path_id)
468  return;
469  //We set waypoint movement as new default movement generator
470  // clear ALL movement generators (including default)
471  /*while (!empty())
472  {
473  MovementGenerator *curr = top();
474  curr->Finalize(*i_owner);
475  pop();
476  if (!isStatic(curr))
477  delete curr;
478  }*/
479 
480  //i_owner->GetTypeId() == TYPEID_PLAYER ?
481  //Mutate(new WaypointMovementGenerator<Player>(path_id, repeatable)):
483 
484  DEBUG_LOG("%s (GUID: %u) start moving over path(Id:%u, repeatable: %s)",
485  i_owner->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature",
486  i_owner->GetGUIDLow(), path_id, repeatable ? "YES" : "NO");
487 }
488 
490 {
491  if (!time)
492  return;
493 
494  Mutate(new RotateMovementGenerator(time, direction), MOTION_SLOT_ACTIVE);
495 }
496 
498 {
499  /*Impl::container_type::iterator it = Impl::c.begin();
500  for (; it != end(); ++it)
501  {
502  (*it)->unitSpeedChanged();
503  }*/
504  for (int i = 0; i <= i_top; ++i)
505  {
506  if (Impl[i])
507  Impl[i]->unitSpeedChanged();
508  }
509 }
510 
512 {
513  if (empty())
514  return IDLE_MOTION_TYPE;
515 
516  return top()->GetMovementGeneratorType();
517 }
518 
520 {
521  if (!Impl[slot])
522  return NULL_MOTION_TYPE;
523  else
524  return Impl[slot]->GetMovementGeneratorType();
525 }
526 
528 {
529  top()->Initialize(*i_owner);
530  needInit[i_top] = false;
531 }
532 
534 {
535  if (isStatic(curr))
536  return;
537  curr->Finalize(*i_owner);
538  delete curr;
539 }
540 
542 {
543  if (isStatic(curr))
544  return;
545  if (!m_expList)
546  m_expList = new ExpireList();
547  m_expList->push_back(curr);
548 }
549 
550 bool MotionMaster::GetDestination(float& x, float& y, float& z)
551 {
552  if (i_owner->movespline->Finalized())
553  return false;
554 
555  const G3D::Vector3& dest = i_owner->movespline->FinalDestination();
556  x = dest.x;
557  y = dest.y;
558  z = dest.z;
559  return true;
560 }
void MoveTaxiFlight(uint32 path, uint32 pathnode)
bool AttackStop()
Definition: Unit.cpp:7484
void DirectClean(bool reset)
void MoveRandom(float spawndist=0.0f)
void MoveIdle(MovementSlot slot=MOTION_SLOT_ACTIVE)
#define MAX_FALL_DISTANCE
Definition: Map.h:260
Map * GetMap() const
Definition: Object.h:841
uint32 GetDBTableGUIDLow() const
Definition: Creature.h:476
void Clear(bool reset=true)
Definition: MotionMaster.h:145
void MoveFleeing(Unit *enemy, uint32 time=0)
const Vector3 FinalDestination() const
Definition: MoveSpline.h:120
void AddUnitState(uint32 f)
Definition: Unit.h:1026
pet will not attack
Definition: Unit.h:760
void MoveSeekAssistanceDistract(uint32 timer)
void MoveChase(Unit *target, float dist=0.0f, float angle=0.0f)
IdleMovementGenerator si_idleMovement
Movement::MoveSpline * movespline
Definition: Unit.h:1907
void DirectExpire(bool reset)
float GetHeight(float x, float y, float z, bool checkVMap=true, float maxSearchDist=DEFAULT_HEIGHT_SEARCH) const
Definition: Map.cpp:1591
#define sLog
Log class singleton.
Definition: Log.h:187
void MoveTargetedHome()
void propagateSpeedChange()
MovementGeneratorType GetCurrentMovementGeneratorType() const
virtual MovementGeneratorType GetMovementGeneratorType()=0
bool needInit[MAX_MOTION_SLOT]
Definition: MotionMaster.h:88
void MovePoint(uint32 id, const Position &pos, bool usePathfinding=true)
Definition: MotionMaster.h:179
void MoveFall(float z=0, uint32 id=0)
void CastStop(uint32 except_spellid=0)
Definition: Unit.cpp:1216
Unit * i_owner
Definition: MotionMaster.h:214
uint32 GetGUIDLow() const
Definition: Object.h:166
void DirectDelete(_Ty curr)
ExpireList * m_expList
Definition: MotionMaster.h:215
TaxiPathNodesByPath sTaxiPathNodesByPath
Definition: DBCStores.cpp:148
void MoveTo(const Vector3 &destination, bool generatePath=false, bool forceDestination=false)
virtual void Initialize(Unit &)=0
_Ty top() const
Definition: MotionMaster.h:132
bool isStatic(MovementGenerator *mv)
void AddUnitMovementFlag(uint32 f)
Definition: Unit.h:1901
void InitDefault()
uint32 GetId(void) const
Definition: Map.h:333
void Mutate(MovementGenerator *m, MovementSlot slot)
void DelayedDelete(_Ty curr)
uint8 GetTypeId() const
Definition: Object.h:210
void UpdateMotion(uint32 diff)
std::vector< _Ty > ExpireList
Definition: MotionMaster.h:89
void MoveConfused()
void MoveSeekAssistance(float x, float y, float z)
bool needInitTop() const
Definition: MotionMaster.h:103
float GetPositionY() const
Definition: Position.h:98
float GetPositionZ() const
Definition: Position.h:99
bool Finalized() const
Definition: MoveSpline.h:117
#define DEBUG_LOG(...)
Definition: Log.h:194
MovementGeneratorType GetMotionSlotType(int slot) const
const char * GetName() const
Definition: Object.h:704
MovementSlot
Definition: MotionMaster.h:58
int size() const
Definition: MotionMaster.h:124
virtual void unitSpeedChanged()
void MoveCharge(float x, float y, float z, float speed=SPEED_CHARGE, uint32 id=EVENT_CHARGE, bool usePathfinding=true)
RotateDirection
Definition: MotionMaster.h:73
Creature * ToCreature()
Definition: Object.h:395
virtual void Reset(Unit &)=0
uint8 m_cleanFlag
Definition: MotionMaster.h:216
void MovePath(uint32 path_id, bool repeatable)
virtual void Finalize(Unit &)=0
MovementGeneratorType
Definition: MotionMaster.h:33
bool HasUnitState(const uint32 f) const
Definition: Unit.h:1030
#define ASSERT
Definition: Errors.h:29
_Ty Impl[MAX_MOTION_SLOT]
Definition: MotionMaster.h:87
bool HasAuraType(AuraType auraType) const
Definition: Unit.cpp:832
#define INVALID_HEIGHT
Definition: Map.h:259
uint32 GetEntry() const
Definition: Object.h:192
void DelayedExpire()
void MoveRotate(uint32 time, RotateDirection direction)
ACE_UINT32 uint32
Definition: Define.h:71
void Initialize()
float GetPositionX() const
Definition: Position.h:97
void MoveDistract(uint32 time)
void MovementExpired(bool reset=true)
Definition: MotionMaster.h:158
void DelayedClean()
Definition: Unit.h:908
void SetReactState(ReactStates st)
Definition: Creature.h:495
MovementGenerator * selectMovementGenerator(Creature *creature)
bool GetDestination(float &x, float &y, float &z)
bool empty() const
Definition: MotionMaster.h:128
void MoveFollow(Unit *target, float dist, float angle, MovementSlot slot=MOTION_SLOT_ACTIVE)
const uint64 & GetGUID() const
Definition: Object.h:162