TrinityCore
Loading...
Searching...
No Matches
MotionMaster.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore 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 "AbstractFollower.h"
20#include "Creature.h"
21#include "CreatureAISelector.h"
22#include "Containers.h"
23#include "DBCStores.h"
24#include "Errors.h"
25#include "G3DPosition.hpp"
26#include "Log.h"
27#include "Map.h"
28#include "MoveSpline.h"
29#include "MoveSplineInit.h"
30#include "PathGenerator.h"
31#include "Player.h"
32#include "ScriptSystem.h"
33#include "Unit.h"
34#include "WaypointDefines.h"
35#include <algorithm>
36#include <iterator>
37
51
53{
54 return sMovementGeneratorRegistry->GetRegistryItem(IDLE_MOTION_TYPE)->Create();
55}
56
57inline bool IsStatic(MovementGenerator* movement)
58{
59 return (movement == GetIdleMovementGenerator());
60}
61
63{
64 if (a != nullptr && !IsStatic(a))
65 delete a;
66}
67
72
74{
75 return a->Priority > b->Priority;
76}
77
78MovementGeneratorInformation::MovementGeneratorInformation(MovementGeneratorType type, ObjectGuid targetGUID, std::string const& targetName) : Type(type), TargetGUID(targetGUID), TargetName(targetName) { }
79
80MotionMaster::MotionMaster(Unit* unit) : _owner(unit), _defaultGenerator(nullptr), _flags(MOTIONMASTER_FLAG_INITIALIZATION_PENDING) { }
81
89
91{
93 return;
94
96 {
97 DelayedActionDefine action = [this]()
98 {
99 Initialize();
100 };
101 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_INITIALIZE);
102 return;
103 }
104
106}
107
112
126
128{
129 return !_defaultGenerator && _generators.empty();
130}
131
133{
134 return (_defaultGenerator ? 1 : 0) + uint32(_generators.size());
135}
136
137std::vector<MovementGeneratorInformation> MotionMaster::GetMovementGeneratorsInformation() const
138{
139 std::vector<MovementGeneratorInformation> list;
140
142 list.emplace_back(_defaultGenerator->GetMovementGeneratorType(), ObjectGuid::Empty, std::string());
143
144 for (auto itr = _generators.begin(); itr != _generators.end(); ++itr)
145 {
146 MovementGenerator* movement = *itr;
147 MovementGeneratorType const type = movement->GetMovementGeneratorType();
148 switch (type)
149 {
152 if (AbstractFollower* followInformation = dynamic_cast<AbstractFollower*>(movement))
153 {
154 if (Unit* target = followInformation->GetTarget())
155 list.emplace_back(type, target->GetGUID(), target->GetName());
156 else
157 list.emplace_back(type, ObjectGuid::Empty, std::string());
158 }
159 else
160 list.emplace_back(type, ObjectGuid::Empty, std::string());
161 break;
162 default:
163 list.emplace_back(type, ObjectGuid::Empty, std::string());
164 break;
165 }
166 }
167
168 return list;
169}
170
172{
173 if (!_generators.empty())
174 return MOTION_SLOT_ACTIVE;
175
177 return MOTION_SLOT_DEFAULT;
178
179 return MAX_MOTION_SLOT;
180}
181
183{
184 if (!_generators.empty())
185 return *_generators.begin();
186
188 return _defaultGenerator.get();
189
190 return nullptr;
191}
192
194{
195 if (Empty())
196 return MAX_MOTION_TYPE;
197
199 if (!movement)
200 return MAX_MOTION_TYPE;
201
202 return movement->GetMovementGeneratorType();
203}
204
206{
207 if (Empty() || IsInvalidMovementSlot(slot))
208 return MAX_MOTION_TYPE;
209
210 if (slot == MOTION_SLOT_ACTIVE && !_generators.empty())
211 return (*_generators.begin())->GetMovementGeneratorType();
212
214 return _defaultGenerator->GetMovementGeneratorType();
215
216 return MAX_MOTION_TYPE;
217}
218
220{
221 if (Empty() || IsInvalidMovementSlot(slot))
222 return nullptr;
223
224 if (slot == MOTION_SLOT_ACTIVE && !_generators.empty())
225 return *_generators.begin();
226
228 return _defaultGenerator.get();
229
230 return nullptr;
231}
232
233MovementGenerator* MotionMaster::GetMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot) const
234{
235 if (Empty() || IsInvalidMovementSlot(slot))
236 return nullptr;
237
238 MovementGenerator* movement = nullptr;
239 switch (slot)
240 {
242 if (_defaultGenerator && filter(_defaultGenerator.get()))
243 movement = _defaultGenerator.get();
244 break;
246 {
247 auto itr = std::ranges::find_if(_generators, std::ref(filter));
248 if (itr != _generators.end())
249 movement = *itr;
250 break;
251 }
252 default:
253 break;
254 }
255
256 return movement;
257}
258
259bool MotionMaster::HasMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot) const
260{
261 if (Empty() || IsInvalidMovementSlot(slot))
262 return false;
263
264 bool value = false;
265 switch (slot)
266 {
268 value = _defaultGenerator && filter(_defaultGenerator.get());
269 break;
271 value = std::ranges::any_of(_generators, std::ref(filter));
272 break;
273 default:
274 break;
275 }
276
277 return value;
278}
279
281{
282 if (!_owner)
283 return;
284
286 return;
287
288 ASSERT(!Empty(), "MotionMaster:Update: update called without Initializing! (%s)", _owner->GetGUID().ToString().c_str());
289
291
292 enum class InitState : uint8
293 {
294 Failed,
295 Success,
296 AlreadyInitialized
297 } initializationState = InitState::AlreadyInitialized;
298
301 {
303 initializationState = top->Initialize(_owner) ? InitState::Success : InitState::Failed;
304 }
306 initializationState = top->Initialize(_owner) ? InitState::Success : InitState::Failed;
308 initializationState = top->Reset(_owner) ? InitState::Success : InitState::Failed;
309
310 ASSERT(!top->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING | MOVEMENTGENERATOR_FLAG_DEACTIVATED), "MotionMaster:Update: update called on an uninitialized top! (%s) (type: %u, flags: %u)", _owner->GetGUID().ToString().c_str(), top->GetMovementGeneratorType(), top->Flags);
311
312 if (initializationState == InitState::Failed || !top->Update(_owner, initializationState == InitState::AlreadyInitialized ? diff : 0))
313 {
314 ASSERT(top == GetCurrentMovementGenerator(), "MotionMaster::Update: top was modified while updating! (%s)", _owner->GetGUID().ToString().c_str());
315
316 // Since all the actions that modify any slot are delayed, this movement is guaranteed to be top
317 Pop(true, true); // Natural, and only, call to MovementInform
318 }
319
321
323}
324
325void MotionMaster::Add(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
326{
327 if (!movement)
328 return;
329
330 if (IsInvalidMovementSlot(slot))
331 {
332 delete movement;
333 return;
334 }
335
337 {
338 bool wouldBecomeTop = _generators.lower_bound(movement) == _generators.begin();
339 if (!wouldBecomeTop || !movement->Initialize(_owner))
340 {
341 delete movement;
342 return;
343 }
344 }
345
347 {
348 DelayedActionDefine action = [this, movement, slot]()
349 {
350 Add(movement, slot);
351 };
352 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_ADD);
353 }
354 else
355 DirectAdd(movement, slot);
356}
357
358void MotionMaster::Remove(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
359{
360 if (!movement || IsInvalidMovementSlot(slot))
361 return;
362
364 {
365 DelayedActionDefine action = [this, movement, slot]()
366 {
367 Remove(movement, slot);
368 };
369 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_REMOVE);
370 return;
371 }
372
373 if (Empty())
374 return;
375
376 switch (slot)
377 {
379 if (_defaultGenerator && _defaultGenerator.get() == movement)
381 break;
383 {
384 auto itr = _generators.find(movement);
385 if (itr != _generators.end())
386 Remove(itr, GetCurrentMovementGenerator() == *itr, false);
387 break;
388 }
389 default:
390 break;
391 }
392}
393
394void MotionMaster::Remove(MovementGeneratorType type, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
395{
397 return;
398
400 {
401 DelayedActionDefine action = [this, type, slot]()
402 {
403 Remove(type, slot);
404 };
405 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_REMOVE_TYPE);
406 return;
407 }
408
409 if (Empty())
410 return;
411
412 switch (slot)
413 {
415 if (_defaultGenerator && _defaultGenerator->GetMovementGeneratorType() == type)
417 break;
419 DirectClear([type](MovementGenerator const* a) { return a->GetMovementGeneratorType() == type; });
420 break;
421 default:
422 break;
423 }
424}
425
427{
429 {
430 DelayedActionDefine action = [this]()
431 {
432 Clear();
433 };
434 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR);
435 return;
436 }
437
438 if (!Empty())
439 DirectClear();
440}
441
443{
444 if (IsInvalidMovementSlot(slot))
445 return;
446
448 {
449 DelayedActionDefine action = [this, slot]()
450 {
451 Clear(slot);
452 };
453 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_SLOT);
454 return;
455 }
456
457 if (Empty())
458 return;
459
460 switch (slot)
461 {
464 break;
466 DirectClear();
467 break;
468 default:
469 break;
470 }
471}
472
474{
476 {
477 DelayedActionDefine action = [this, priority]()
478 {
479 Clear(priority);
480 };
481 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_PRIORITY);
482 return;
483 }
484
485 if (Empty())
486 return;
487
488 DirectClear([priority](MovementGenerator const* a) { return a->Priority == priority; });
489}
490
492{
493 if (Empty())
494 return;
495
497 if (!movement)
498 return;
499
500 movement->UnitSpeedChanged();
501}
502
503bool MotionMaster::GetDestination(float &x, float &y, float &z)
504{
506 return false;
507
508 G3D::Vector3 const& dest = _owner->movespline->FinalDestination();
509 x = dest.x;
510 y = dest.y;
511 z = dest.z;
512 return true;
513}
514
516{
517 if (MovementGenerator* movementGenerator = GetCurrentMovementGenerator())
518 if (movementGenerator->HasFlag(MOVEMENTGENERATOR_FLAG_PERSIST_ON_DEATH))
519 return false;
520
521 if (_owner->IsInWorld())
522 {
523 // Only clear MotionMaster for entities that exists in world
524 // Avoids crashes in the following conditions :
525 // * Using 'call pet' on dead pets
526 // * Using 'call stabled pet'
527 // * Logging in with dead pets
528 Clear();
529 MoveIdle();
530 }
531
533
534 return true;
535}
536
538{
541 top->Deactivate(_owner); // only deactivate top, don't remove it. non-resumable generators will clean up themselves on next update
542}
543
548
550{
551 Creature* owner = _owner->ToCreature();
552 if (!owner)
553 {
554 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTargetedHome: '{}', attempted to move towards target home.", _owner->GetGUID().ToString());
555 return;
556 }
557
558 Clear();
559
560 Unit* target = owner->GetCharmerOrOwner();
561 if (!target)
562 {
563 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTargetedHome: '{}', targeted home.", _owner->GetGUID().ToString());
565 }
566 else
567 {
568 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTargetedHome: '{}', starts following '{}'", _owner->GetGUID().ToString(), target->GetGUID().ToString());
570 }
571}
572
573void MotionMaster::MoveRandom(float wanderDistance)
574{
575 if (_owner->GetTypeId() == TYPEID_UNIT)
576 {
577 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRandom: '{}', started random movement (spawnDist: {})", _owner->GetGUID().ToString(), wanderDistance);
579 }
580}
581
582void MotionMaster::MoveFollow(Unit* target, float dist, ChaseAngle angle, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
583{
584 // Ignore movement request if target not exist
585 if (!target || target == _owner)
586 return;
587
588 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFollow: '{}', starts following '{}'", _owner->GetGUID().ToString(), target->GetGUID().ToString());
589 Add(new FollowMovementGenerator(target, dist, angle), slot);
590}
591
593{
594 // Ignore movement request if target not exist
595 if (!target || target == _owner)
596 return;
597
598 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveChase: '{}', starts chasing '{}'", _owner->GetGUID().ToString(), target->GetGUID().ToString());
599 Add(new ChaseMovementGenerator(target, dist, angle));
600}
601
603{
605 {
606 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveConfused: '{}', started confused movement.", _owner->GetGUID().ToString());
608 }
609 else
610 {
611 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveConfused: '{}', started confused movement.", _owner->GetGUID().ToString());
613 }
614}
615
617{
618 if (!enemy)
619 return;
620
621 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFleeing: '{}', flees from '{}' (time: {})", _owner->GetGUID().ToString(), enemy->GetGUID().ToString(), time);
622 if (_owner->GetTypeId() == TYPEID_UNIT)
623 {
624 if (time)
625 Add(new TimedFleeingMovementGenerator(enemy->GetGUID(), time));
626 else
628 }
629 else
631}
632
633void MotionMaster::MovePoint(uint32 id, Position const& pos, bool generatePath/* = true*/, Optional<float> finalOrient/* = {}*/)
634{
635 MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ, generatePath, finalOrient);
636}
637
638void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generatePath, Optional<float> finalOrient)
639{
641 {
642 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePoint: '{}', targeted point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
643 Add(new PointMovementGenerator<Player>(id, x, y, z, generatePath, 0.0f, finalOrient));
644 }
645 else
646 {
647 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePoint: '{}', targeted point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
648 Add(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, 0.0f, finalOrient));
649 }
650}
651
652void MotionMaster::MoveCloserAndStop(uint32 id, Unit* target, float distance)
653{
654 float distanceToTravel = _owner->GetExactDist2d(target) - distance;
655 if (distanceToTravel > 0.0f)
656 {
657 float angle = _owner->GetAbsoluteAngle(target);
658 float destx = _owner->GetPositionX() + distanceToTravel * std::cos(angle);
659 float desty = _owner->GetPositionY() + distanceToTravel * std::sin(angle);
660 MovePoint(id, destx, desty, target->GetPositionZ());
661 }
662 else
663 {
664 // We are already close enough. We just need to turn toward the target without changing position.
665 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this, target = target->GetGUID()](Movement::MoveSplineInit& init)
666 {
668 init.SetFacing(target);
669 };
670 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id));
671 }
672}
673
674void MotionMaster::MoveLand(uint32 id, Position const& pos, Optional<float> velocity /*= {}*/)
675{
676 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveLand: '{}', landing point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
677
678 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
679 {
680 init.MoveTo(PositionToVector3(pos), false);
681 init.SetAnimation(AnimTier::Ground);
682 if (velocity)
683 init.SetVelocity(*velocity);
684 };
685 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id));
686}
687
688void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, Optional<float> velocity /*= {}*/)
689{
690 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTakeoff: '{}', landing point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
691
692 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
693 {
694 init.MoveTo(PositionToVector3(pos), false);
695 init.SetAnimation(AnimTier::Hover);
696 if (velocity)
697 init.SetVelocity(*velocity);
698 };
699 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id));
700}
701
702void MotionMaster::MoveCharge(float x, float y, float z, float speed /*= SPEED_CHARGE*/, uint32 id /*= EVENT_CHARGE*/, bool generatePath /*= false*/)
703{
704/*
705 if (_slot[MOTION_SLOT_CONTROLLED] && _slot[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
706 return;
707*/
709 {
710 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveCharge: '{}', charging point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
711 PointMovementGenerator<Player>* movement = new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed);
714 Add(movement);
715 }
716 else
717 {
718 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveCharge: '{}', charging point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
719 PointMovementGenerator<Creature>* movement = new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed);
722 Add(movement);
723 }
724}
725
726void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_CHARGE*/)
727{
728 G3D::Vector3 dest = path.GetActualEndPosition();
729
730 MoveCharge(dest.x, dest.y, dest.z, speed, EVENT_CHARGE_PREPATH);
731
732 // Charge movement is not started when using EVENT_CHARGE_PREPATH
734 init.MovebyPath(path.GetPath());
735 init.SetVelocity(speed);
736 init.Launch();
737}
738
739void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
740{
741 // This function may make players fall below map
743 return;
744
745 if (speedXY < 0.01f)
746 return;
747
748 Position dest = _owner->GetPosition();
749 float moveTimeHalf = speedZ / Movement::gravity;
750 float dist = 2 * moveTimeHalf * speedXY;
751 float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ);
752
753 // Use a mmap raycast to get a valid destination.
754 _owner->MovePositionToFirstCollision(dest, dist, _owner->GetRelativeAngle(srcX, srcY) + float(M_PI));
755
756 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
757 {
758 init.MoveTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), false);
759 init.SetParabolic(max_height, 0);
760 init.SetOrientationFixed(true);
761 init.SetVelocity(speedXY);
762 };
763
764 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, 0);
767 Add(movement);
768}
769
770void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ)
771{
772 // This function may make players fall below map
774 return;
775
776 float x, y, z = _owner->GetPositionZ();
777
778 float moveTimeHalf = speedZ / Movement::gravity;
779 float dist = 2 * moveTimeHalf * speedXY;
780
781 _owner->GetNearPoint2D(nullptr, x, y, dist, _owner->GetOrientation() + angle);
783
784 MoveJump(x, y, z, 0.0f, speedXY, speedZ);
785}
786
787void MotionMaster::MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id/* = EVENT_JUMP*/, bool hasOrientation/* = false*/)
788{
789 MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), speedXY, speedZ, id, hasOrientation);
790}
791
792void MotionMaster::MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id, bool hasOrientation /* = false*/)
793{
794 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveJump: '{}', jumps to point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
795 if (speedXY < 0.01f)
796 return;
797
798 float moveTimeHalf = speedZ / Movement::gravity;
799 float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ);
800
801 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
802 {
803 init.MoveTo(x, y, z, false);
804 init.SetParabolic(max_height, 0);
805 init.SetVelocity(speedXY);
806 if (hasOrientation)
807 init.SetFacing(o);
808 };
809
810 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id);
814 Add(movement);
815}
816
817void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount)
818{
819 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this](Movement::MoveSplineInit& init)
820 {
821 float step = 2 * float(M_PI) / stepCount * (clockwise ? -1.0f : 1.0f);
822 Position const& pos = { x, y, z, 0.0f };
823 float angle = pos.GetAbsoluteAngle(_owner->GetPositionX(), _owner->GetPositionY());
824
825 // add the owner's current position as starting point as it gets removed after entering the cycle
826 init.Path().push_back(G3D::Vector3(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()));
827
828 for (uint8 i = 0; i < stepCount; angle += step, ++i)
829 {
830 G3D::Vector3 point;
831 point.x = x + radius * cosf(angle);
832 point.y = y + radius * sinf(angle);
833
834 if (_owner->IsFlying())
835 point.z = z;
836 else
837 point.z = _owner->GetMapHeight(point.x, point.y, z) + _owner->GetHoverOffset();
838
839 init.Path().push_back(point);
840 }
841
842 if (_owner->IsFlying())
843 {
844 init.SetFly();
845 init.SetCyclic();
846 init.SetAnimation(AnimTier::Hover);
847 }
848 else
849 {
850 init.SetWalk(true);
851 init.SetCyclic();
852 }
853 };
854
855 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, 0));
856}
857
858void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk)
859{
861 path.reserve(pathSize);
862 std::transform(pathPoints, pathPoints + pathSize, std::back_inserter(path), [](Position const& point)
863 {
864 return G3D::Vector3(point.GetPositionX(), point.GetPositionY(), point.GetPositionZ());
865 });
866
867 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
868 {
869 init.MovebyPath(path);
870 init.SetSmooth();
871 init.SetWalk(walk);
872 };
873
874 // This code is not correct
875 // GenericMovementGenerator does not affect UNIT_STATE_ROAMING_MOVE
876 // need to call PointMovementGenerator with various pointIds
877 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, pointId));
878}
879
880void MotionMaster::MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
881{
882 Creature* owner = _owner->ToCreature();
883 if (!owner)
884 {
885 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveAlongSplineChain: '{}', tried to walk along DB spline chain. Ignoring.", _owner->GetGUID().ToString());
886 return;
887 }
888 std::vector<SplineChainLink> const* chain = sScriptSystemMgr->GetSplineChain(owner, dbChainId);
889 if (!chain)
890 {
891 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveAlongSplineChain: '{}', tried to walk along non-existing spline chain with DB Id: {}.", _owner->GetGUID().ToString(), dbChainId);
892 return;
893 }
894 MoveAlongSplineChain(pointId, *chain, walk);
895}
896
897void MotionMaster::MoveAlongSplineChain(uint32 pointId, std::vector<SplineChainLink> const& chain, bool walk)
898{
899 Add(new SplineChainMovementGenerator(pointId, chain, walk));
900}
901
903{
904 if (info.Empty())
905 {
906 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::ResumeSplineChain: '{}', tried to resume a spline chain from empty info.", _owner->GetGUID().ToString());
907 return;
908 }
910}
911
913{
914 // Use larger distance for vmap height search than in most other cases
916 if (tz <= INVALID_HEIGHT)
917 {
918 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFall: '{}', unable to retrieve a proper height at map Id: {} (X: {}, Y: {}, Z: {})",
920 return;
921 }
922
923 // Abort too if the ground is very near
924 if (std::fabs(_owner->GetPositionZ() - tz) < 0.1f)
925 return;
926
927 // rooted units don't move (also setting falling+root flag causes client freezes)
929 return;
930
931 _owner->SetFall(true);
932
933 // Don't run spline movement for players
935 {
937 return;
938 }
939
940 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this](Movement::MoveSplineInit& init)
941 {
942 init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz + _owner->GetHoverOffset(), false);
943 init.SetFall();
944 };
945
946 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id);
948 Add(movement);
949}
950
951void MotionMaster::MoveSeekAssistance(float x, float y, float z)
952{
953 if (Creature* creature = _owner->ToCreature())
954 {
955 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveSeekAssistance: '{}', seeks assistance (X: {}, Y: {}, Z: {})", creature->GetGUID().ToString(), x, y, z);
956 creature->AttackStop();
957 creature->CastStop();
958 creature->DoNotReacquireSpellFocusTarget();
959 creature->SetReactState(REACT_PASSIVE);
961 }
962 else
963 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistance: '{}', attempted to seek assistance.", _owner->GetGUID().ToString());
964}
965
967{
968 if (_owner->GetTypeId() == TYPEID_UNIT)
969 {
970 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '{}', is distracted after assistance call (Time: {})", _owner->GetGUID().ToString(), time);
972 }
973 else
974 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '{}', attempted to call distract assistance.", _owner->GetGUID().ToString());
975}
976
978{
980 {
981 if (path < sTaxiPathNodesByPath.size())
982 {
983 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '{}', taxi to path Id: {} (node {})", _owner->GetGUID().ToString(), path, pathnode);
984
985 // Only one FLIGHT_MOTION_TYPE is allowed
986 bool hasExisting = HasMovementGenerator([](MovementGenerator const* gen) { return gen->GetMovementGeneratorType() == FLIGHT_MOTION_TYPE; });
987 ASSERT(!hasExisting, "Duplicate flight path movement generator");
988
990 movement->LoadPath(_owner->ToPlayer());
991 Add(movement);
992 }
993 else
994 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '{}', attempted taxi to non-existing path Id: {} (node: {})", _owner->GetGUID().ToString(), path, pathnode);
995 }
996 else
997 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '{}', attempted taxi to path Id: {} (node: {})", _owner->GetGUID().ToString(), path, pathnode);
998}
999
1000void MotionMaster::MoveDistract(uint32 timer, float orientation)
1001{
1002/*
1003 if (_slot[MOTION_SLOT_CONTROLLED])
1004 return;
1005*/
1006 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveDistract: '{}', distracted (timer: {}, orientation: {})", _owner->GetGUID().ToString(), timer, orientation);
1007 Add(new DistractMovementGenerator(timer, orientation));
1008}
1009
1010void MotionMaster::MovePath(uint32 pathId, bool repeatable)
1011{
1012 if (!pathId)
1013 return;
1014
1015 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})", _owner->GetGUID().ToString(), pathId, repeatable ? "YES" : "NO");
1017}
1018
1019void MotionMaster::MovePath(WaypointPath& path, bool repeatable)
1020{
1021 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})", _owner->GetGUID().ToString(), path.id, repeatable ? "YES" : "NO");
1023}
1024
1026{
1027 if (!time)
1028 return;
1029
1030 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRotate: '{}', starts rotate (time: {}, direction: {})", _owner->GetGUID().ToString(), time, direction);
1031 Add(new RotateMovementGenerator(id, time, direction));
1032}
1033
1034void MotionMaster::MoveFormation(Unit* leader, float range, float angle, uint32 point1, uint32 point2)
1035{
1036 if (_owner->GetTypeId() == TYPEID_UNIT && leader)
1037 {
1038 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFormation: '{}', started to move in a formation with leader {}", _owner->GetGUID().ToString(), leader->GetGUID().ToString());
1039 Add(new FormationMovementGenerator(leader, range, angle, point1, point2), MOTION_SLOT_DEFAULT);
1040 }
1041}
1042
1043void MotionMaster::MoveFace(float orientation, uint32 id /*= EVENT_FACE*/)
1044{
1045 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFace: '{}', faces '{}'", _owner->GetGUID(), orientation);
1046
1047 std::function<void(Movement::MoveSplineInit&)> initializer = [owner = _owner, orientation](Movement::MoveSplineInit& init)
1048 {
1049 init.MoveTo(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), false);
1050 if (owner->GetTransport())
1051 init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
1052 init.SetFacing(orientation);
1053 };
1054
1055 Add(new ImmediateMovementGenerator(std::move(initializer), FACE_MOTION_TYPE, id));
1056}
1057
1058void MotionMaster::MoveFace(WorldObject const* object, uint32 id /*= EVENT_FACE*/)
1059{
1060 if (!object)
1061 return;
1062
1063 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFace: '{}', faces '{}'", _owner->GetGUID(), object->GetGUID());
1064
1065 std::function<void(Movement::MoveSplineInit&)> initializer = [owner = _owner, object](Movement::MoveSplineInit& init)
1066 {
1067 init.MoveTo(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), false);
1068 init.SetFacing(owner->GetAbsoluteAngle(object)); // when on transport, GetAbsoluteAngle will still return global coordinates (and angle) that needs transforming
1069 };
1070
1071 Add(new ImmediateMovementGenerator(std::move(initializer), FACE_MOTION_TYPE, id));
1072}
1073
1074void MotionMaster::LaunchMoveSpline(std::function<void(Movement::MoveSplineInit& init)>&& initializer, uint32 id/*= 0*/, MovementGeneratorPriority priority/* = MOTION_PRIORITY_NORMAL*/, MovementGeneratorType type/*= EFFECT_MOTION_TYPE*/)
1075{
1077 {
1078 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '{}', tried to launch a spline with an invalid MovementGeneratorType: {} (Id: {}, Priority: {})", _owner->GetGUID().ToString(), type, id, priority);
1079 return;
1080 }
1081
1082 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '{}', initiates spline Id: {} (Type: {}, Priority: {})", _owner->GetGUID().ToString(), id, type, priority);
1083
1084 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), type, id);
1085 movement->Priority = priority;
1086 Add(movement);
1087}
1088
1089/******************** Private methods ********************/
1090
1092{
1093 while (!_delayedActions.empty())
1094 {
1095 _delayedActions.front().Resolve();
1096 _delayedActions.pop_front();
1097 }
1098}
1099
1100void MotionMaster::Remove(MotionMasterContainer::iterator& iterator, bool active, bool movementInform)
1101{
1102 MovementGenerator* pointer = *iterator;
1103 iterator = _generators.erase(iterator);
1104 Delete(pointer, active, movementInform);
1105}
1106
1107void MotionMaster::Pop(bool active, bool movementInform)
1108{
1109 auto itr = _generators.begin();
1110 if (itr != _generators.end())
1111 Remove(itr, active, movementInform);
1112}
1113
1115{
1116 // Clear ALL movement generators (including default)
1118 DirectClear();
1119
1121}
1122
1124{
1125 // First delete Top
1126 if (!_generators.empty())
1127 Pop(true, false);
1128
1129 // Then the rest
1130 while (!_generators.empty())
1131 Pop(false, false);
1132
1133 // Make sure the storage is empty
1135}
1136
1138{
1140 DeleteDefault(_generators.empty(), false);
1141}
1142
1143void MotionMaster::DirectClear(std::function<bool(MovementGenerator*)> const& filter)
1144{
1146 for (auto itr = _generators.begin(); itr != _generators.end();)
1147 {
1148 if (filter(*itr))
1149 Remove(itr, *itr == top, false);
1150 else
1151 ++itr;
1152 }
1153}
1154
1155void MotionMaster::DirectAdd(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
1156{
1157 switch (slot)
1158 {
1161 _defaultGenerator->Finalize(_owner, _generators.empty(), false);
1162
1164 if (IsStatic(movement))
1166 break;
1167 case MOTION_SLOT_ACTIVE:
1168 {
1169 if (!_generators.empty())
1170 {
1171 auto where = _generators.find(movement); // find movement with equal priority
1172 bool replacesExisting = !movement->HasFlag(MOVEMENTGENERATOR_FLAG_IMMEDIATE)
1173 && where != _generators.end();
1174 auto top = _generators.begin();
1175 if (replacesExisting)
1176 Remove(where, where == top, false);
1177 else if (where == top)
1178 (*top)->Deactivate(_owner);
1179 }
1180 else
1181 _defaultGenerator->Deactivate(_owner);
1182
1184 {
1185 _generators.insert(movement);
1186 AddBaseUnitState(movement);
1187 }
1188 else
1189 {
1190 movement->Finalize(_owner, true, true);
1191 delete movement;
1192 }
1193 break;
1194 }
1195 default:
1196 break;
1197 }
1198}
1199
1200void MotionMaster::Delete(MovementGenerator* movement, bool active, bool movementInform)
1201{
1202 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::Delete: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1203 movement->Priority, movement->Flags, movement->BaseUnitState, movement->GetMovementGeneratorType(), _owner->GetGUID().ToString());
1204
1205 movement->Finalize(_owner, active, movementInform);
1206 ClearBaseUnitState(movement);
1208}
1209
1210void MotionMaster::DeleteDefault(bool active, bool movementInform)
1211{
1212 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::DeleteDefault: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1213 _defaultGenerator->Priority, _defaultGenerator->Flags, _defaultGenerator->BaseUnitState, _defaultGenerator->GetMovementGeneratorType(), _owner->GetGUID().ToString());
1214
1215 _defaultGenerator->Finalize(_owner, active, movementInform);
1218}
1219
1221{
1222 if (!movement || !movement->BaseUnitState)
1223 return;
1224
1225 _baseUnitStatesMap.emplace(movement->BaseUnitState, movement);
1226 _owner->AddUnitState(movement->BaseUnitState);
1227}
1228
1230{
1231 if (!movement || !movement->BaseUnitState)
1232 return;
1233
1235 if (_baseUnitStatesMap.count(movement->BaseUnitState) == 0)
1237}
1238
1240{
1241 uint32 unitState = 0;
1242 for (auto itr = _baseUnitStatesMap.begin(); itr != _baseUnitStatesMap.end(); ++itr)
1243 unitState |= itr->first;
1244
1245 _owner->ClearUnitState(unitState);
1246 _baseUnitStatesMap.clear();
1247}
#define M_PI
Definition Common.h:72
TaxiPathNodesByPath sTaxiPathNodesByPath
uint8_t uint8
Definition Define.h:135
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
#define ASSERT
Definition Errors.h:68
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define MAX_FALL_DISTANCE
Definition Map.h:242
#define INVALID_HEIGHT
Definition Map.h:241
void MovementGeneratorPointerDeleter(MovementGenerator *a)
MovementGenerator * GetIdleMovementGenerator()
bool IsStatic(MovementGenerator *movement)
@ MOTIONMASTER_DELAYED_ADD
@ MOTIONMASTER_DELAYED_REMOVE
@ MOTIONMASTER_DELAYED_REMOVE_TYPE
@ MOTIONMASTER_DELAYED_INITIALIZE
@ MOTIONMASTER_DELAYED_CLEAR_PRIORITY
@ MOTIONMASTER_DELAYED_CLEAR
@ MOTIONMASTER_DELAYED_CLEAR_SLOT
@ MOTIONMASTER_FLAG_DELAYED
@ MOTIONMASTER_FLAG_INITIALIZING
@ MOTIONMASTER_FLAG_UPDATE
@ MOTIONMASTER_FLAG_INITIALIZATION_PENDING
@ MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING
bool IsInvalidMovementSlot(uint8 const slot)
RotateDirection
MovementGeneratorPriority
@ MOTION_PRIORITY_HIGHEST
MovementSlot
@ MOTION_SLOT_ACTIVE
@ MAX_MOTION_SLOT
@ MOTION_SLOT_DEFAULT
MovementGeneratorType
@ IDLE_MOTION_TYPE
@ CHASE_MOTION_TYPE
@ MAX_MOTION_TYPE
@ FACE_MOTION_TYPE
@ FLIGHT_MOTION_TYPE
@ FOLLOW_MOTION_TYPE
@ EFFECT_MOTION_TYPE
bool IsInvalidMovementGeneratorType(uint8 const type)
@ MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING
@ MOVEMENTGENERATOR_FLAG_DEACTIVATED
@ MOVEMENTGENERATOR_FLAG_FINALIZED
@ MOVEMENTGENERATOR_FLAG_IMMEDIATE
@ MOVEMENTGENERATOR_FLAG_PERSIST_ON_DEATH
#define sMovementGeneratorRegistry
@ TYPEID_UNIT
Definition ObjectGuid.h:38
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
#define PET_FOLLOW_ANGLE
Definition PetDefines.h:86
#define PET_FOLLOW_DIST
Definition PetDefines.h:85
#define sScriptSystemMgr
@ EVENT_ASSIST_MOVE
@ EVENT_CHARGE_PREPATH
@ REACT_PASSIVE
@ UNIT_STATE_ROOT
Definition Unit.h:230
@ UNIT_STATE_CHARGING
Definition Unit.h:237
@ UNIT_STATE_STUNNED
Definition Unit.h:223
@ UNIT_STATE_JUMPING
Definition Unit.h:238
uint32 const pathSize
uint32 GetId() const
Definition Map.cpp:4216
uint32 Size() const
bool HasMovementGenerator(std::function< bool(MovementGenerator const *)> const &filter, MovementSlot slot=MOTION_SLOT_ACTIVE) const
void ClearBaseUnitStates()
void DeleteDefault(bool active, bool movementInform)
void MoveTaxiFlight(uint32 path, uint32 pathnode)
void LaunchMoveSpline(std::function< void(Movement::MoveSplineInit &init)> &&initializer, uint32 id=0, MovementGeneratorPriority priority=MOTION_PRIORITY_NORMAL, MovementGeneratorType type=EFFECT_MOTION_TYPE)
bool HasFlag(uint8 const flag) const
void MoveSmoothPath(uint32 pointId, Position const *pathPoints, size_t pathSize, bool walk)
void ClearBaseUnitState(MovementGenerator const *movement)
void ResolveDelayedActions()
MovementGeneratorType GetCurrentMovementGeneratorType() const
void MoveJump(Position const &pos, float speedXY, float speedZ, uint32 id=EVENT_JUMP, bool hasOrientation=false)
std::vector< MovementGeneratorInformation > GetMovementGeneratorsInformation() const
void Pop(bool active, bool movementInform)
void PropagateSpeedChange()
void Delete(MovementGenerator *movement, bool active, bool movementInform)
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
void MoveChase(Unit *target, Optional< ChaseRange > dist={}, Optional< ChaseAngle > angle={})
void MoveFormation(Unit *leader, float range, float angle, uint32 point1, uint32 point2)
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={})
void MoveCharge(float x, float y, float z, float speed=SPEED_CHARGE, uint32 id=EVENT_CHARGE, bool generatePath=false)
void InterruptOnTeleport()
void MoveTakeoff(uint32 id, Position const &pos, Optional< float > velocity={})
void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
void DirectAdd(MovementGenerator *movement, MovementSlot slot)
std::unique_ptr< MovementGenerator, MovementGeneratorDeleter > MovementGeneratorPointer
void AddFlag(uint8 const flag)
void MoveSeekAssistance(float x, float y, float z)
void MoveSeekAssistanceDistract(uint32 timer)
void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount)
void MovePath(uint32 pathId, bool repeatable)
void DirectClearDefault()
MotionMasterUnitStatesContainer _baseUnitStatesMap
void ResumeSplineChain(SplineChainResumeInfo const &info)
void RemoveFlag(uint8 const flag)
void Add(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
bool GetDestination(float &x, float &y, float &z)
std::function< void()> DelayedActionDefine
void Update(uint32 diff)
MovementGenerator * GetCurrentMovementGenerator() const
std::deque< DelayedAction > _delayedActions
void MoveFollow(Unit *target, float dist, ChaseAngle angle, MovementSlot slot=MOTION_SLOT_ACTIVE)
void MoveTargetedHome()
MovementSlot GetCurrentSlot() const
MovementGeneratorPointer _defaultGenerator
MotionMaster(Unit *unit)
void MoveCloserAndStop(uint32 id, Unit *target, float distance)
void MoveRotate(uint32 id, uint32 time, RotateDirection direction)
void MoveJumpTo(float angle, float speedXY, float speedZ)
void DirectInitialize()
void MoveFall(uint32 id=0)
void MoveDistract(uint32 time, float orientation)
void MoveLand(uint32 id, Position const &pos, Optional< float > velocity={})
MovementGenerator * GetMovementGenerator(std::function< bool(MovementGenerator const *)> const &filter, MovementSlot slot=MOTION_SLOT_ACTIVE) const
bool Empty() const
void Remove(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
void InitializeDefault()
void MoveFace(float orientation, uint32 id=EVENT_FACE)
MotionMasterContainer _generators
void AddBaseUnitState(MovementGenerator const *movement)
void MoveFleeing(Unit *enemy, uint32 time=0)
void MoveRandom(float wanderDistance=0.0f)
void AddFlag(uint16 const flag)
virtual bool Update(Unit *, uint32 diff)=0
bool HasFlag(uint16 const flag) const
virtual void UnitSpeedChanged()
virtual bool Initialize(Unit *)=0
virtual bool Reset(Unit *)=0
virtual MovementGeneratorType GetMovementGeneratorType() const =0
virtual void Finalize(Unit *, bool, bool)=0
void SetVelocity(float velocity)
void MovebyPath(PointsArray const &path, int32 pointId=0)
bool Finalized() const
Definition MoveSpline.h:121
Vector3 FinalDestination() const
Definition MoveSpline.h:124
static ObjectGuid const Empty
Definition ObjectGuid.h:140
std::string ToString() const
static Creature * ToCreature(Object *o)
Definition Object.h:186
bool IsInWorld() const
Definition Object.h:73
TypeID GetTypeId() const
Definition Object.h:93
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
static Player * ToPlayer(Object *o)
Definition Object.h:180
Movement::PointsArray const & GetPath() const
G3D::Vector3 const & GetActualEndPosition() const
void SetFallInformation(uint32 time, float z)
Definition Player.cpp:24853
Definition Unit.h:769
void ClearUnitState(uint32 f)
Definition Unit.h:877
Movement::MoveSpline * movespline
Definition Unit.h:1804
bool SetFall(bool enable)
Definition Unit.cpp:13339
void StopMoving(bool force=false)
Definition Unit.cpp:10312
void AddUnitState(uint32 f)
Definition Unit.h:875
Unit * GetCharmerOrOwner() const
Definition Unit.h:1265
float GetHoverOffset() const
Definition Unit.h:1767
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
bool IsFlying() const
Definition Unit.h:1762
ObjectGuid GetTarget() const
Definition Unit.h:1797
Map * GetMap() const
Definition Object.h:449
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition Object.cpp:1416
float GetMapHeight(float x, float y, float z, bool vmap=true, float distanceToSearch=50.0f) const
Definition Object.cpp:3606
void MovePositionToFirstCollision(Position &pos, float dist, float angle)
Definition Object.cpp:3323
void GetNearPoint2D(WorldObject const *searcher, float &x, float &y, float distance, float absAngle) const
Definition Object.cpp:3180
MovementGenerator * SelectMovementGenerator(Unit *unit)
TC_GAME_API float gravity
std::vector< Vector3 > PointsArray
float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity=0.0f)
void MultimapErasePair(M< K, V, Rest... > &multimap, K const &key, V const &value)
Definition MapUtils.h:39
bool operator()(MovementGenerator const *a, MovementGenerator const *b) const
void operator()(MovementGenerator *a)
MovementGeneratorInformation(MovementGeneratorType type, ObjectGuid targetGUID, std::string const &targetName)
float m_positionZ
Definition Position.h:58
float GetExactDist2d(const float x, const float y) const
Definition Position.h:109
float GetRelativeAngle(float x, float y) const
Definition Position.h:139
float m_positionX
Definition Position.h:56
float GetPositionZ() const
Definition Position.h:81
float m_positionY
Definition Position.h:57
float GetOrientation() const
Definition Position.h:82
float GetAbsoluteAngle(float x, float y) const
Definition Position.h:128
float GetPositionX() const
Definition Position.h:79
void GetPosition(float &x, float &y) const
Definition Position.h:84
float GetPositionY() const
Definition Position.h:80