TrinityCore
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 "DB2Stores.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 "ObjectAccessor.h"
31#include "PathGenerator.h"
32#include "PetDefines.h"
33#include "Player.h"
34#include "ScriptSystem.h"
35#include "Unit.h"
36#include "WaypointDefines.h"
37#include <algorithm>
38#include <iterator>
39
53
55{
56 return sMovementGeneratorRegistry->GetRegistryItem(IDLE_MOTION_TYPE)->Create();
57}
58
59inline bool IsStatic(MovementGenerator* movement)
60{
61 return (movement == GetIdleMovementGenerator());
62}
63
65{
66 if (a != nullptr && !IsStatic(a))
67 delete a;
68}
69
71{
73}
74
76{
77 if (a->Mode > b->Mode)
78 return true;
79 else if (a->Mode == b->Mode)
80 return a->Priority > b->Priority;
81
82 return false;
83}
84
85MovementGeneratorInformation::MovementGeneratorInformation(MovementGeneratorType type, ObjectGuid targetGUID, std::string const& targetName) : Type(type), TargetGUID(targetGUID), TargetName(targetName) { }
86
87MotionMaster::MotionMaster(Unit* unit) : _owner(unit), _defaultGenerator(nullptr), _flags(MOTIONMASTER_FLAG_INITIALIZATION_PENDING) { }
88
90{
91 _delayedActions.clear();
92
93 for (auto itr = _generators.begin(); itr != _generators.end(); itr = _generators.erase(itr))
95}
96
98{
100 return;
101
103 {
104 DelayedActionDefine action = [this]()
105 {
106 Initialize();
107 };
108 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_INITIALIZE);
109 return;
110 }
111
113}
114
116{
118}
119
121{
123 return;
124
127
130
132}
133
135{
136 return !_defaultGenerator && _generators.empty();
137}
138
140{
141 return (_defaultGenerator ? 1 : 0) + uint32(_generators.size());
142}
143
144std::vector<MovementGeneratorInformation> MotionMaster::GetMovementGeneratorsInformation() const
145{
146 std::vector<MovementGeneratorInformation> list;
147
149 list.emplace_back(_defaultGenerator->GetMovementGeneratorType(), ObjectGuid::Empty, std::string());
150
151 for (auto itr = _generators.begin(); itr != _generators.end(); ++itr)
152 {
153 MovementGenerator* movement = *itr;
154 MovementGeneratorType const type = movement->GetMovementGeneratorType();
155 switch (type)
156 {
159 if (AbstractFollower* followInformation = dynamic_cast<AbstractFollower*>(movement))
160 {
161 if (Unit* target = followInformation->GetTarget())
162 list.emplace_back(type, target->GetGUID(), target->GetName());
163 else
164 list.emplace_back(type, ObjectGuid::Empty, std::string());
165 }
166 else
167 list.emplace_back(type, ObjectGuid::Empty, std::string());
168 break;
169 default:
170 list.emplace_back(type, ObjectGuid::Empty, std::string());
171 break;
172 }
173 }
174
175 return list;
176}
177
179{
180 if (!_generators.empty())
181 return MOTION_SLOT_ACTIVE;
182
184 return MOTION_SLOT_DEFAULT;
185
186 return MAX_MOTION_SLOT;
187}
188
190{
191 if (!_generators.empty())
192 return *_generators.begin();
193
195 return _defaultGenerator.get();
196
197 return nullptr;
198}
199
201{
202 if (Empty())
203 return MAX_MOTION_TYPE;
204
206 if (!movement)
207 return MAX_MOTION_TYPE;
208
209 return movement->GetMovementGeneratorType();
210}
211
213{
214 if (Empty() || IsInvalidMovementSlot(slot))
215 return MAX_MOTION_TYPE;
216
217 if (slot == MOTION_SLOT_ACTIVE && !_generators.empty())
218 return (*_generators.begin())->GetMovementGeneratorType();
219
221 return _defaultGenerator->GetMovementGeneratorType();
222
223 return MAX_MOTION_TYPE;
224}
225
227{
228 if (Empty() || IsInvalidMovementSlot(slot))
229 return nullptr;
230
231 if (slot == MOTION_SLOT_ACTIVE && !_generators.empty())
232 return *_generators.begin();
233
235 return _defaultGenerator.get();
236
237 return nullptr;
238}
239
240MovementGenerator* MotionMaster::GetMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot) const
241{
242 if (Empty() || IsInvalidMovementSlot(slot))
243 return nullptr;
244
245 MovementGenerator* movement = nullptr;
246 switch (slot)
247 {
249 if (_defaultGenerator && filter(_defaultGenerator.get()))
250 movement = _defaultGenerator.get();
251 break;
253 if (!_generators.empty())
254 {
255 auto itr = std::find_if(_generators.begin(), _generators.end(), std::ref(filter));
256 if (itr != _generators.end())
257 movement = *itr;
258 }
259 break;
260 default:
261 break;
262 }
263
264 return movement;
265}
266
267bool MotionMaster::HasMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot) const
268{
269 if (Empty() || IsInvalidMovementSlot(slot))
270 return false;
271
272 bool value = false;
273 switch (slot)
274 {
276 if (_defaultGenerator && filter(_defaultGenerator.get()))
277 value = true;
278 break;
280 if (!_generators.empty())
281 {
282 auto itr = std::find_if(_generators.begin(), _generators.end(), std::ref(filter));
283 value = itr != _generators.end();
284 }
285 break;
286 default:
287 break;
288 }
289
290 return value;
291}
292
294{
295 if (!_owner)
296 return;
297
299 return;
300
301 ASSERT(!Empty(), "MotionMaster:Update: update called without Initializing! (%s)", _owner->GetGUID().ToString().c_str());
302
304
307 {
309 top->Initialize(_owner);
310 }
312 top->Initialize(_owner);
314 top->Reset(_owner);
315
316 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);
317
318 if (!top->Update(_owner, diff))
319 {
320 ASSERT(top == GetCurrentMovementGenerator(), "MotionMaster::Update: top was modified while updating! (%s)", _owner->GetGUID().ToString().c_str());
321
322 // Since all the actions that modify any slot are delayed, this movement is guaranteed to be top
323 Pop(true, true); // Natural, and only, call to MovementInform
324 }
325
327
329}
330
331void MotionMaster::Add(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
332{
333 if (!movement)
334 return;
335
336 if (IsInvalidMovementSlot(slot))
337 {
338 delete movement;
339 return;
340 }
341
343 {
344 DelayedActionDefine action = [this, movement, slot]()
345 {
346 Add(movement, slot);
347 };
348 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_ADD);
349 }
350 else
351 DirectAdd(movement, slot);
352}
353
354void MotionMaster::Remove(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
355{
356 if (!movement || IsInvalidMovementSlot(slot))
357 return;
358
360 {
361 DelayedActionDefine action = [this, movement, slot]()
362 {
363 Remove(movement, slot);
364 };
365 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_REMOVE);
366 return;
367 }
368
369 if (Empty())
370 return;
371
372 switch (slot)
373 {
375 if (_defaultGenerator && _defaultGenerator.get() == movement)
377 break;
379 if (!_generators.empty())
380 {
381 auto bounds = _generators.equal_range(movement);
382 auto itr = std::find(bounds.first, bounds.second, movement);
383 if (itr != _generators.end())
384 Remove(itr, GetCurrentMovementGenerator() == *itr, false);
385 }
386 break;
387 default:
388 break;
389 }
390}
391
392void MotionMaster::Remove(MovementGeneratorType type, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
393{
395 return;
396
398 {
399 DelayedActionDefine action = [this, type, slot]()
400 {
401 Remove(type, slot);
402 };
403 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_REMOVE_TYPE);
404 return;
405 }
406
407 if (Empty())
408 return;
409
410 switch (slot)
411 {
413 if (_defaultGenerator && _defaultGenerator->GetMovementGeneratorType() == type)
415 break;
417 if (!_generators.empty())
418 {
419 auto itr = std::find_if(_generators.begin(), _generators.end(), [type](MovementGenerator const* a) -> bool
420 {
421 return a->GetMovementGeneratorType() == type;
422 });
423
424 if (itr != _generators.end())
425 Remove(itr, GetCurrentMovementGenerator() == *itr, false);
426 }
427 break;
428 default:
429 break;
430 }
431}
432
434{
436 {
437 DelayedActionDefine action = [this]()
438 {
439 Clear();
440 };
441 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR);
442 return;
443 }
444
445 if (!Empty())
446 DirectClear();
447}
448
450{
451 if (IsInvalidMovementSlot(slot))
452 return;
453
455 {
456 DelayedActionDefine action = [this, slot]()
457 {
458 Clear(slot);
459 };
460 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_SLOT);
461 return;
462 }
463
464 if (Empty())
465 return;
466
467 switch (slot)
468 {
471 break;
473 DirectClear();
474 break;
475 default:
476 break;
477 }
478}
479
481{
483 {
484 DelayedActionDefine action = [this, mode]()
485 {
486 Clear(mode);
487 };
488 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_MODE);
489 return;
490 }
491
492 if (Empty())
493 return;
494
495 std::function<bool(MovementGenerator*)> criteria = [mode](MovementGenerator* a) -> bool
496 {
497 return a->Mode == mode;
498 };
499 DirectClear(criteria);
500}
501
503{
505 {
506 DelayedActionDefine action = [this, priority]()
507 {
508 Clear(priority);
509 };
510 _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_PRIORITY);
511 return;
512 }
513
514 if (Empty())
515 return;
516
517 std::function<bool(MovementGenerator*)> criteria = [priority](MovementGenerator* a) -> bool
518 {
519 return a->Priority == priority;
520 };
521 DirectClear(criteria);
522}
523
525{
526 if (Empty())
527 return;
528
530 if (!movement)
531 return;
532
533 movement->UnitSpeedChanged();
534}
535
536bool MotionMaster::GetDestination(float &x, float &y, float &z)
537{
538 if (_owner->movespline->Finalized())
539 return false;
540
541 G3D::Vector3 const& dest = _owner->movespline->FinalDestination();
542 x = dest.x;
543 y = dest.y;
544 z = dest.z;
545 return true;
546}
547
549{
550 if (MovementGenerator* movementGenerator = GetCurrentMovementGenerator())
551 if (movementGenerator->HasFlag(MOVEMENTGENERATOR_FLAG_PERSIST_ON_DEATH))
552 return false;
553
554 if (_owner->IsInWorld())
555 {
556 // Only clear MotionMaster for entities that exists in world
557 // Avoids crashes in the following conditions :
558 // * Using 'call pet' on dead pets
559 // * Using 'call stabled pet'
560 // * Logging in with dead pets
561 Clear();
562 MoveIdle();
563 }
564
566
567 return true;
568}
569
571{
573}
574
576{
577 Creature* owner = _owner->ToCreature();
578 if (!owner)
579 {
580 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTargetedHome: '{}', attempted to move towards target home.", _owner->GetGUID().ToString());
581 return;
582 }
583
584 Clear();
585
586 Unit* target = owner->GetCharmerOrOwner();
587 if (!target)
588 {
589 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTargetedHome: '{}', targeted home.", _owner->GetGUID().ToString());
591 }
592 else
593 {
594 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTargetedHome: '{}', starts following '{}'", _owner->GetGUID().ToString(), target->GetGUID().ToString());
596 }
597}
598
599void MotionMaster::MoveRandom(float wanderDistance, Optional<Milliseconds> duration, MovementSlot slot /*= MOTION_SLOT_DEFAULT*/)
600{
601 if (_owner->GetTypeId() == TYPEID_UNIT)
602 {
603 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRandom: '{}', started random movement (spawnDist: {})", _owner->GetGUID().ToString(), wanderDistance);
604 Add(new RandomMovementGenerator<Creature>(wanderDistance, duration), slot);
605 }
606}
607
608void MotionMaster::MoveFollow(Unit* target, float dist, ChaseAngle angle, Optional<Milliseconds> duration /*= {}*/, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
609{
610 // Ignore movement request if target not exist
611 if (!target || target == _owner)
612 return;
613
614 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFollow: '{}', starts following '{}'", _owner->GetGUID().ToString(), target->GetGUID().ToString());
615 Add(new FollowMovementGenerator(target, dist, angle, duration), slot);
616}
617
619{
620 // Ignore movement request if target not exist
621 if (!target || target == _owner)
622 return;
623
624 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveChase: '{}', starts chasing '{}'", _owner->GetGUID().ToString(), target->GetGUID().ToString());
625 Add(new ChaseMovementGenerator(target, dist, angle));
626}
627
629{
631 {
632 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveConfused: '{}', started confused movement.", _owner->GetGUID().ToString());
634 }
635 else
636 {
637 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveConfused: '{}', started confused movement.", _owner->GetGUID().ToString());
639 }
640}
641
642void MotionMaster::MoveFleeing(Unit* enemy, Milliseconds time /*= 0ms*/)
643{
644 if (!enemy)
645 return;
646
647 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFleeing: '{}', flees from '{}' (time: {}ms)", _owner->GetGUID().ToString(), enemy->GetGUID().ToString(), time.count());
648 if (_owner->GetTypeId() == TYPEID_UNIT && time > 0ms)
649 Add(new TimedFleeingMovementGenerator(enemy->GetGUID(), time));
650 else
651 Add(new FleeingMovementGenerator(enemy->GetGUID()));
652}
653
654void MotionMaster::MovePoint(uint32 id, Position const& pos, bool generatePath/* = true*/, Optional<float> finalOrient/* = {}*/, Optional<float> speed /*= {}*/,
655 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, Optional<float> closeEnoughDistance /*= {}*/)
656{
657 MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ, generatePath, finalOrient, speed, speedSelectionMode, closeEnoughDistance);
658}
659
660void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generatePath /*= true*/, Optional<float> finalOrient /*= {}*/, Optional<float> speed /*= {}*/,
661 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, Optional<float> closeEnoughDistance /*= {}*/)
662{
663 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePoint: '{}', targeted point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
664 Add(new PointMovementGenerator(id, x, y, z, generatePath, speed, finalOrient, nullptr, nullptr, speedSelectionMode, closeEnoughDistance));
665}
666
667void MotionMaster::MoveCloserAndStop(uint32 id, Unit* target, float distance)
668{
669 float distanceToTravel = _owner->GetExactDist2d(target) - distance;
670 if (distanceToTravel > 0.0f)
671 {
672 float angle = _owner->GetAbsoluteAngle(target);
673 float destx = _owner->GetPositionX() + distanceToTravel * std::cos(angle);
674 float desty = _owner->GetPositionY() + distanceToTravel * std::sin(angle);
675 MovePoint(id, destx, desty, target->GetPositionZ());
676 }
677 else
678 {
679 // We are already close enough. We just need to turn toward the target without changing position.
680 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this, target = target->GetGUID()](Movement::MoveSplineInit& init)
681 {
683 if (Unit const* refreshedTarget = ObjectAccessor::GetUnit(*_owner, target))
684 init.SetFacing(refreshedTarget);
685 };
686 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id));
687 }
688}
689
690void MotionMaster::MoveLand(uint32 id, Position const& pos, Optional<int32> tierTransitionId /*= {}*/, Optional<float> velocity /*= {}*/,
691 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/)
692{
693 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveLand: '{}', landing point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
694
695 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
696 {
697 init.MoveTo(PositionToVector3(pos), false);
698 init.SetAnimation(AnimTier::Ground, tierTransitionId.value_or(0));
699 switch (speedSelectionMode)
700 {
702 init.SetWalk(false);
703 break;
705 init.SetWalk(true);
706 break;
708 default:
709 break;
710 }
711 if (velocity)
712 init.SetVelocity(*velocity);
713 };
714 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id));
715}
716
717void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, Optional<int32> tierTransitionId /*= {}*/, Optional<float> velocity /*= {}*/,
718 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/)
719{
720 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTakeoff: '{}', landing point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
721
722 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
723 {
724 init.MoveTo(PositionToVector3(pos), false);
725 init.SetAnimation(AnimTier::Hover, tierTransitionId.value_or(0));
726 switch (speedSelectionMode)
727 {
729 init.SetWalk(false);
730 break;
732 init.SetWalk(true);
733 break;
735 default:
736 break;
737 }
738 if (velocity)
739 init.SetVelocity(*velocity);
740 };
741 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id));
742}
743
744void MotionMaster::MoveCharge(float x, float y, float z, float speed /*= SPEED_CHARGE*/, uint32 id /*= EVENT_CHARGE*/, bool generatePath /*= false*/,
745 Unit const* target /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
746{
747/*
748 if (_slot[MOTION_SLOT_CONTROLLED] && _slot[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
749 return;
750*/
751 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveCharge: '{}', charging point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
752 PointMovementGenerator* movement = new PointMovementGenerator(id, x, y, z, generatePath, speed, {}, target, spellEffectExtraData);
755 Add(movement);
756}
757
758void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_CHARGE*/, Unit const* target /*= nullptr*/,
759 Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
760{
761 G3D::Vector3 dest = path.GetActualEndPosition();
762
763 MoveCharge(dest.x, dest.y, dest.z, speed, EVENT_CHARGE_PREPATH);
764
765 // If this is ever changed to not happen immediately then all spell effect handlers that use this must be updated
766
767 // Charge movement is not started when using EVENT_CHARGE_PREPATH
769 init.MovebyPath(path.GetPath());
770 init.SetVelocity(speed);
771 if (target)
772 init.SetFacing(target);
773 if (spellEffectExtraData)
774 init.SetSpellEffectExtraData(*spellEffectExtraData);
775 init.Launch();
776}
777
778void MotionMaster::MoveKnockbackFrom(Position const& origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
779{
780 // This function may make players fall below map
782 return;
783
784 if (speedXY < 0.01f)
785 return;
786
787 Position dest = _owner->GetPosition();
788 float moveTimeHalf = speedZ / Movement::gravity;
789 float dist = 2 * moveTimeHalf * speedXY;
790 float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ);
791
792 // Use a mmap raycast to get a valid destination.
793 _owner->MovePositionToFirstCollision(dest, dist, _owner->GetRelativeAngle(origin) + float(M_PI));
794
795 std::function<void(Movement::MoveSplineInit&)> initializer = [=, effect = (spellEffectExtraData ? Optional<Movement::SpellEffectExtraData>(*spellEffectExtraData) : Optional<Movement::SpellEffectExtraData>())](Movement::MoveSplineInit& init)
796 {
797 init.MoveTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), false);
798 init.SetParabolic(max_height, 0);
799 init.SetOrientationFixed(true);
800 init.SetVelocity(speedXY);
801 if (effect)
802 init.SetSpellEffectExtraData(*effect);
803 };
804
805 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, 0);
808 Add(movement);
809}
810
811void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ)
812{
813 // This function may make players fall below map
815 return;
816
817 float x, y, z = _owner->GetPositionZ();
818
819 float moveTimeHalf = speedZ / Movement::gravity;
820 float dist = 2 * moveTimeHalf * speedXY;
821
822 _owner->GetNearPoint2D(nullptr, x, y, dist, _owner->GetOrientation() + angle);
824
825 MoveJump(x, y, z, 0.0f, speedXY, speedZ);
826}
827
828void MotionMaster::MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id/* = EVENT_JUMP*/, bool hasOrientation/* = false*/,
829 JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
830{
831 MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), speedXY, speedZ, id, hasOrientation, arrivalCast, spellEffectExtraData);
832}
833
834void MotionMaster::MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id /*= EVENT_JUMP*/, bool hasOrientation /* = false*/,
835 JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
836{
837 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveJump: '{}', jumps to point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
838 if (speedXY < 0.01f)
839 return;
840
841 float moveTimeHalf = speedZ / Movement::gravity;
842 float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ);
843
844 std::function<void(Movement::MoveSplineInit&)> initializer = [=, effect = (spellEffectExtraData ? Optional<Movement::SpellEffectExtraData>(*spellEffectExtraData) : Optional<Movement::SpellEffectExtraData>())](Movement::MoveSplineInit& init)
845 {
846 init.MoveTo(x, y, z, false);
847 init.SetParabolic(max_height, 0);
848 init.SetVelocity(speedXY);
849 if (hasOrientation)
850 init.SetFacing(o);
851 if (effect)
852 init.SetSpellEffectExtraData(*effect);
853 };
854
855 uint32 arrivalSpellId = 0;
856 ObjectGuid arrivalSpellTargetGuid;
857 if (arrivalCast)
858 {
859 arrivalSpellId = arrivalCast->SpellId;
860 arrivalSpellTargetGuid = arrivalCast->Target;
861 }
862
863 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id,
864 { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid });
867 Add(movement);
868}
869
870void MotionMaster::MoveJumpWithGravity(Position const& pos, float speedXY, float gravity, uint32 id/* = EVENT_JUMP*/, bool hasOrientation/* = false*/,
871 JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
872{
873 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveJumpWithGravity: '{}', jumps to point Id: {} ({})", _owner->GetGUID().ToString(), id, pos.ToString());
874 if (speedXY < 0.01f)
875 return;
876
877 std::function<void(Movement::MoveSplineInit&)> initializer = [=, effect = (spellEffectExtraData ? Optional<Movement::SpellEffectExtraData>(*spellEffectExtraData) : Optional<Movement::SpellEffectExtraData>())](Movement::MoveSplineInit& init)
878 {
879 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false);
881 init.SetUncompressed();
882 init.SetVelocity(speedXY);
883 init.SetUnlimitedSpeed();
884 if (hasOrientation)
885 init.SetFacing(pos.GetOrientation());
886 if (effect)
887 init.SetSpellEffectExtraData(*effect);
888 };
889
890 uint32 arrivalSpellId = 0;
891 ObjectGuid arrivalSpellTargetGuid;
892 if (arrivalCast)
893 {
894 arrivalSpellId = arrivalCast->SpellId;
895 arrivalSpellTargetGuid = arrivalCast->Target;
896 }
897
898 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id,
899 { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid });
903 Add(movement);
904}
905
906void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount,
907 Optional<Milliseconds> duration /*= {}*/, Optional<float> speed /*= {}*/,
908 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/)
909{
910 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this](Movement::MoveSplineInit& init)
911 {
912 float step = 2 * float(M_PI) / stepCount * (clockwise ? -1.0f : 1.0f);
913 Position const& pos = { x, y, z, 0.0f };
914 float angle = pos.GetAbsoluteAngle(_owner->GetPositionX(), _owner->GetPositionY());
915
916 // add the owner's current position as starting point as it gets removed after entering the cycle
917 init.Path().emplace_back(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ());
918
919 for (uint8 i = 0; i < stepCount; angle += step, ++i)
920 {
921 G3D::Vector3& point = init.Path().emplace_back();
922 point.x = x + radius * cosf(angle);
923 point.y = y + radius * sinf(angle);
924
925 if (_owner->IsFlying())
926 point.z = z;
927 else
928 point.z = _owner->GetMapHeight(point.x, point.y, z) + _owner->GetHoverOffset();
929 }
930
931 init.SetCyclic();
932 if (_owner->IsFlying())
933 {
934 init.SetFly();
935 init.SetAnimation(AnimTier::Hover);
936 }
937 else
938 init.SetWalk(true);
939
940 switch (speedSelectionMode)
941 {
943 init.SetWalk(false);
944 break;
946 init.SetWalk(true);
947 break;
949 default:
950 break;
951 }
952 if (speed)
953 init.SetVelocity(*speed);
954 };
955
956 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, 0, { .Duration = duration }));
957}
958
959void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk, bool fly)
960{
962 path.reserve(pathSize);
963 std::transform(pathPoints, pathPoints + pathSize, std::back_inserter(path), [](Position const& point)
964 {
965 return G3D::Vector3(point.GetPositionX(), point.GetPositionY(), point.GetPositionZ());
966 });
967 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
968 {
969 init.MovebyPath(path);
970 init.SetWalk(walk);
971 if (fly)
972 {
973 init.SetFly();
974 init.SetUncompressed();
975 init.SetSmooth();
976 }
977 };
978
979 // This code is not correct
980 // GenericMovementGenerator does not affect UNIT_STATE_ROAMING_MOVE
981 // need to call PointMovementGenerator with various pointIds
982 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, pointId));
983}
984
985void MotionMaster::MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
986{
987 Creature* owner = _owner->ToCreature();
988 if (!owner)
989 {
990 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveAlongSplineChain: '{}', tried to walk along DB spline chain. Ignoring.", _owner->GetGUID().ToString());
991 return;
992 }
993 std::vector<SplineChainLink> const* chain = sScriptSystemMgr->GetSplineChain(owner, dbChainId);
994 if (!chain)
995 {
996 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveAlongSplineChain: '{}', tried to walk along non-existing spline chain with DB Id: {}.", _owner->GetGUID().ToString(), dbChainId);
997 return;
998 }
999 MoveAlongSplineChain(pointId, *chain, walk);
1000}
1001
1002void MotionMaster::MoveAlongSplineChain(uint32 pointId, std::vector<SplineChainLink> const& chain, bool walk)
1003{
1004 Add(new SplineChainMovementGenerator(pointId, chain, walk));
1005}
1006
1008{
1009 if (info.Empty())
1010 {
1011 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::ResumeSplineChain: '{}', tried to resume a spline chain from empty info.", _owner->GetGUID().ToString());
1012 return;
1013 }
1015}
1016
1018{
1019 // Use larger distance for vmap height search than in most other cases
1021 if (tz <= INVALID_HEIGHT)
1022 {
1023 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFall: '{}', unable to retrieve a proper height at map Id: {} (X: {}, Y: {}, Z: {})",
1025 return;
1026 }
1027
1028 // Abort too if the ground is very near
1029 if (std::fabs(_owner->GetPositionZ() - tz) < 0.1f)
1030 return;
1031
1032 // rooted units don't move (also setting falling+root flag causes client freezes)
1034 return;
1035
1036 _owner->SetFall(true);
1037
1038 // Don't run spline movement for players
1039 if (_owner->GetTypeId() == TYPEID_PLAYER)
1040 {
1042 return;
1043 }
1044
1045 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this](Movement::MoveSplineInit& init)
1046 {
1047 init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz + _owner->GetHoverOffset(), false);
1048 init.SetFall();
1049 };
1050
1051 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id);
1053 Add(movement);
1054}
1055
1056void MotionMaster::MoveSeekAssistance(float x, float y, float z)
1057{
1058 if (Creature* creature = _owner->ToCreature())
1059 {
1060 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveSeekAssistance: '{}', seeks assistance (X: {}, Y: {}, Z: {})", creature->GetGUID().ToString(), x, y, z);
1061 creature->AttackStop();
1062 creature->CastStop();
1063 creature->DoNotReacquireSpellFocusTarget();
1064 creature->SetReactState(REACT_PASSIVE);
1066 }
1067 else
1068 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistance: '{}', attempted to seek assistance.", _owner->GetGUID().ToString());
1069}
1070
1072{
1073 if (_owner->GetTypeId() == TYPEID_UNIT)
1074 {
1075 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '{}', is distracted after assistance call (Time: {})", _owner->GetGUID().ToString(), time);
1077 }
1078 else
1079 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '{}', attempted to call distract assistance.", _owner->GetGUID().ToString());
1080}
1081
1083{
1084 if (_owner->GetTypeId() == TYPEID_PLAYER)
1085 {
1086 if (path < sTaxiPathNodesByPath.size())
1087 {
1088 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '{}', taxi to path Id: {} (node {})", _owner->GetGUID().ToString(), path, pathnode);
1089
1090 // Only one FLIGHT_MOTION_TYPE is allowed
1091 bool hasExisting = HasMovementGenerator([](MovementGenerator const* gen) { return gen->GetMovementGeneratorType() == FLIGHT_MOTION_TYPE; });
1092 ASSERT(!hasExisting, "Duplicate flight path movement generator");
1093
1095 movement->LoadPath(_owner->ToPlayer(), pathnode);
1096 Add(movement);
1097 }
1098 else
1099 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '{}', attempted taxi to non-existing path Id: {} (node: {})", _owner->GetGUID().ToString(), path, pathnode);
1100 }
1101 else
1102 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '{}', attempted taxi to path Id: {} (node: {})", _owner->GetGUID().ToString(), path, pathnode);
1103}
1104
1105void MotionMaster::MoveDistract(uint32 timer, float orientation)
1106{
1107/*
1108 if (_slot[MOTION_SLOT_CONTROLLED])
1109 return;
1110*/
1111 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveDistract: '{}', distracted (timer: {}, orientation: {})", _owner->GetGUID().ToString(), timer, orientation);
1112 Add(new DistractMovementGenerator(timer, orientation));
1113}
1114
1115void MotionMaster::MovePath(uint32 pathId, bool repeatable, Optional<Milliseconds> duration, Optional<float> speed,
1116 MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
1117 Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, bool generatePath)
1118{
1119 if (!pathId)
1120 return;
1121
1122 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
1123 _owner->GetGUID().ToString(), pathId, repeatable ? "YES" : "NO");
1124 Add(new WaypointMovementGenerator<Creature>(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
1125 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT);
1126}
1127
1128void MotionMaster::MovePath(WaypointPath const& path, bool repeatable, Optional<Milliseconds> duration, Optional<float> speed,
1129 MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
1130 Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, bool generatePath)
1131{
1132 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
1133 _owner->GetGUID().ToString(), path.Id, repeatable ? "YES" : "NO");
1134 Add(new WaypointMovementGenerator<Creature>(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
1135 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT);
1136}
1137
1139 Optional<float> turnSpeed /*= {}*/, Optional<float> totalTurnAngle /*= {}*/)
1140{
1141 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRotate: '{}', starts rotate (time: {}ms, turnSpeed: {}, totalTurnAngle: {}, direction: {})",
1142 _owner->GetGUID().ToString(), time.value_or(0ms).count(), turnSpeed, totalTurnAngle, direction);
1143
1144 Add(new RotateMovementGenerator(id, direction, time, turnSpeed, totalTurnAngle));
1145}
1146
1147void MotionMaster::MoveFormation(Unit* leader, float range, float angle, uint32 point1, uint32 point2)
1148{
1149 if (_owner->GetTypeId() == TYPEID_UNIT && leader)
1150 {
1151 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFormation: '{}', started to move in a formation with leader {}", _owner->GetGUID().ToString(), leader->GetGUID().ToString());
1152 Add(new FormationMovementGenerator(leader, range, angle, point1, point2), MOTION_SLOT_DEFAULT);
1153 }
1154}
1155
1156void MotionMaster::LaunchMoveSpline(std::function<void(Movement::MoveSplineInit& init)>&& initializer, uint32 id/*= 0*/, MovementGeneratorPriority priority/* = MOTION_PRIORITY_NORMAL*/, MovementGeneratorType type/*= EFFECT_MOTION_TYPE*/)
1157{
1159 {
1160 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '{}', tried to launch a spline with an invalid MovementGeneratorType: {} (Id: {}, Priority: {})", _owner->GetGUID().ToString(), type, id, priority);
1161 return;
1162 }
1163
1164 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '{}', initiates spline Id: {} (Type: {}, Priority: {})", _owner->GetGUID().ToString(), id, type, priority);
1165
1166 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), type, id);
1167 movement->Priority = priority;
1168 Add(movement);
1169}
1170
1171void MotionMaster::CalculateJumpSpeeds(float dist, UnitMoveType moveType, float speedMultiplier, float minHeight, float maxHeight, float& speedXY, float& speedZ) const
1172{
1173 float baseSpeed = _owner->IsControlledByPlayer() ? playerBaseMoveSpeed[moveType] : baseMoveSpeed[moveType];
1174 if (Creature* creature = _owner->ToCreature())
1175 baseSpeed *= creature->GetCreatureTemplate()->speed_run;
1176
1177 speedXY = std::min(baseSpeed * 3.0f * speedMultiplier, std::max(28.0f, _owner->GetSpeed(moveType) * 4.0f));
1178
1179 float duration = dist / speedXY;
1180 float durationSqr = duration * duration;
1181 float height;
1182 if (durationSqr < minHeight * 8 / Movement::gravity)
1183 height = minHeight;
1184 else if (durationSqr > maxHeight * 8 / Movement::gravity)
1185 height = maxHeight;
1186 else
1187 height = Movement::gravity * durationSqr / 8;
1188
1189 speedZ = std::sqrt(2 * Movement::gravity * height);
1190}
1191
1192/******************** Private methods ********************/
1193
1195{
1196 while (!_delayedActions.empty())
1197 {
1198 _delayedActions.front().Resolve();
1199 _delayedActions.pop_front();
1200 }
1201}
1202
1203void MotionMaster::Remove(MotionMasterContainer::iterator iterator, bool active, bool movementInform)
1204{
1205 MovementGenerator* pointer = *iterator;
1206 _generators.erase(iterator);
1207 Delete(pointer, active, movementInform);
1208}
1209
1210void MotionMaster::Pop(bool active, bool movementInform)
1211{
1212 if (!_generators.empty())
1213 Remove(_generators.begin(), active, movementInform);
1214}
1215
1217{
1218 // Clear ALL movement generators (including default)
1220 DirectClear();
1221
1223}
1224
1226{
1227 // First delete Top
1228 if (!_generators.empty())
1229 Pop(true, false);
1230
1231 // Then the rest
1232 while (!_generators.empty())
1233 Pop(false, false);
1234
1235 // Make sure the storage is empty
1237}
1238
1240{
1242 DeleteDefault(_generators.empty(), false);
1243}
1244
1245void MotionMaster::DirectClear(std::function<bool(MovementGenerator*)> const& filter)
1246{
1247 if (_generators.empty())
1248 return;
1249
1251 for (auto itr = _generators.begin(); itr != _generators.end();)
1252 {
1253 if (filter(*itr))
1254 {
1255 MovementGenerator* movement = *itr;
1256 itr = _generators.erase(itr);
1257 Delete(movement, movement == top, false);
1258 }
1259 else
1260 ++itr;
1261 }
1262}
1263
1264void MotionMaster::DirectAdd(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
1265{
1266/*
1267 if (MovementGenerator* curr = _slot[slot])
1268 {
1269 _slot[slot] = nullptr; // in case a new one is generated in this slot during directdelete
1270 if (_top == slot && (_cleanFlag & MOTIONMMASTER_CLEANFLAG_UPDATE))
1271 DelayedDelete(curr);
1272 else
1273 DirectDelete(curr);
1274 }
1275 else if (_top < slot)
1276 {
1277 _top = slot;
1278 }
1279
1280 _slot[slot] = m;
1281 if (_top > slot)
1282 _initialize[slot] = true;
1283 else
1284 {
1285 _initialize[slot] = false;
1286 m->Initialize(_owner);
1287 }
1288*/
1289
1290 /*
1291 * NOTE: This mimics old behaviour: only one MOTION_SLOT_IDLE, MOTION_SLOT_ACTIVE, MOTION_SLOT_CONTROLLED
1292 * On future changes support for multiple will be added
1293 */
1294
1295 switch (slot)
1296 {
1299 _defaultGenerator->Finalize(_owner, _generators.empty(), false);
1300
1302 if (IsStatic(movement))
1304 break;
1305 case MOTION_SLOT_ACTIVE:
1306 if (!_generators.empty())
1307 {
1308 if (movement->Priority >= (*_generators.begin())->Priority)
1309 {
1310 auto itr = _generators.begin();
1311 if (movement->Priority == (*itr)->Priority)
1312 Remove(itr, true, false);
1313 else
1314 (*itr)->Deactivate(_owner);
1315 }
1316 else
1317 {
1318 auto itr = std::find_if(_generators.begin(), _generators.end(), [movement](MovementGenerator const* a) -> bool
1319 {
1320 return a->Priority == movement->Priority;
1321 });
1322
1323 if (itr != _generators.end())
1324 Remove(itr, false, false);
1325 }
1326 }
1327 else
1328 _defaultGenerator->Deactivate(_owner);
1329
1330 _generators.emplace(movement);
1331 AddBaseUnitState(movement);
1332 break;
1333 default:
1334 break;
1335 }
1336}
1337
1338void MotionMaster::Delete(MovementGenerator* movement, bool active, bool movementInform)
1339{
1340 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::Delete: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1341 movement->Priority, movement->Flags, movement->BaseUnitState, movement->GetMovementGeneratorType(), _owner->GetGUID().ToString());
1342
1343 movement->Finalize(_owner, active, movementInform);
1344 ClearBaseUnitState(movement);
1346}
1347
1348void MotionMaster::DeleteDefault(bool active, bool movementInform)
1349{
1350 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::DeleteDefault: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1351 _defaultGenerator->Priority, _defaultGenerator->Flags, _defaultGenerator->BaseUnitState, _defaultGenerator->GetMovementGeneratorType(), _owner->GetGUID().ToString());
1352
1353 _defaultGenerator->Finalize(_owner, active, movementInform);
1356}
1357
1359{
1360 if (!movement || !movement->BaseUnitState)
1361 return;
1362
1363 _baseUnitStatesMap.emplace(movement->BaseUnitState, movement);
1364 _owner->AddUnitState(movement->BaseUnitState);
1365}
1366
1368{
1369 if (!movement || !movement->BaseUnitState)
1370 return;
1371
1373 if (_baseUnitStatesMap.count(movement->BaseUnitState) == 0)
1375}
1376
1378{
1379 uint32 unitState = 0;
1380 for (auto itr = _baseUnitStatesMap.begin(); itr != _baseUnitStatesMap.end(); ++itr)
1381 unitState |= itr->first;
1382
1383 _owner->ClearUnitState(unitState);
1384 _baseUnitStatesMap.clear();
1385}
#define M_PI
Definition: Common.h:115
TaxiPathNodesByPath sTaxiPathNodesByPath
Definition: DB2Stores.cpp:383
uint8_t uint8
Definition: Define.h:144
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
#define ASSERT
Definition: Errors.h:68
#define MAX_FALL_DISTANCE
Definition: GridDefines.h:62
#define INVALID_HEIGHT
Definition: GridDefines.h:61
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
void MovementGeneratorPointerDeleter(MovementGenerator *a)
MovementGenerator * GetIdleMovementGenerator()
bool IsStatic(MovementGenerator *movement)
@ MOTIONMASTER_DELAYED_ADD
Definition: MotionMaster.h:65
@ MOTIONMASTER_DELAYED_REMOVE
Definition: MotionMaster.h:66
@ MOTIONMASTER_DELAYED_REMOVE_TYPE
Definition: MotionMaster.h:67
@ MOTIONMASTER_DELAYED_INITIALIZE
Definition: MotionMaster.h:68
@ MOTIONMASTER_DELAYED_CLEAR_PRIORITY
Definition: MotionMaster.h:64
@ MOTIONMASTER_DELAYED_CLEAR
Definition: MotionMaster.h:61
@ MOTIONMASTER_DELAYED_CLEAR_SLOT
Definition: MotionMaster.h:62
@ MOTIONMASTER_DELAYED_CLEAR_MODE
Definition: MotionMaster.h:63
@ MOTIONMASTER_FLAG_DELAYED
Definition: MotionMaster.h:56
@ MOTIONMASTER_FLAG_INITIALIZING
Definition: MotionMaster.h:54
@ MOTIONMASTER_FLAG_UPDATE
Definition: MotionMaster.h:51
@ MOTIONMASTER_FLAG_INITIALIZATION_PENDING
Definition: MotionMaster.h:53
@ MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING
Definition: MotionMaster.h:52
bool IsInvalidMovementSlot(uint8 const slot)
MovementGeneratorMode
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
@ FLIGHT_MOTION_TYPE
@ FOLLOW_MOTION_TYPE
@ EFFECT_MOTION_TYPE
MovementWalkRunSpeedSelectionMode
bool IsInvalidMovementGeneratorType(uint8 const type)
@ MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING
@ MOVEMENTGENERATOR_FLAG_DEACTIVATED
@ MOVEMENTGENERATOR_FLAG_PERSIST_ON_DEATH
#define sMovementGeneratorRegistry
@ TYPEID_UNIT
Definition: ObjectGuid.h:40
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
#define PET_FOLLOW_ANGLE
Definition: PetDefines.h:98
#define PET_FOLLOW_DIST
Definition: PetDefines.h:97
#define sScriptSystemMgr
Definition: ScriptSystem.h:53
@ EVENT_ASSIST_MOVE
@ EVENT_CHARGE_PREPATH
UnitMoveType
Definition: UnitDefines.h:116
@ REACT_PASSIVE
Definition: UnitDefines.h:506
float baseMoveSpeed[MAX_MOVE_TYPE]
Definition: Unit.cpp:97
float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition: Unit.cpp:110
@ UNIT_STATE_ROOT
Definition: Unit.h:265
@ UNIT_STATE_CHARGING
Definition: Unit.h:272
@ UNIT_STATE_STUNNED
Definition: Unit.h:258
@ UNIT_STATE_JUMPING
Definition: Unit.h:273
void LoadPath(Player *owner, uint32 startNode=0)
uint32 GetId() const
Definition: Map.cpp:3228
void Initialize()
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
Definition: MotionMaster.h:231
void MoveJumpWithGravity(Position const &pos, float speedXY, float gravity, uint32 id=EVENT_JUMP, bool hasOrientation=false, JumpArrivalCastArgs const *arrivalCast=nullptr, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MoveRotate(uint32 id, RotateDirection direction, Optional< Milliseconds > time={}, Optional< float > turnSpeed={}, Optional< float > totalTurnAngle={})
Makes the Unit turn in place.
void ClearBaseUnitState(MovementGenerator const *movement)
void ResolveDelayedActions()
void MoveJump(Position const &pos, float speedXY, float speedZ, uint32 id=EVENT_JUMP, bool hasOrientation=false, JumpArrivalCastArgs const *arrivalCast=nullptr, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MovePath(uint32 pathId, bool repeatable, Optional< Milliseconds > duration={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< std::pair< Milliseconds, Milliseconds > > waitTimeRangeAtPathEnd={}, Optional< float > wanderDistanceAtPathEnds={}, Optional< bool > followPathBackwardsFromEndToStart={}, bool generatePath=true)
MovementGeneratorType GetCurrentMovementGeneratorType() const
void MoveFleeing(Unit *enemy, Milliseconds time=0ms)
std::vector< MovementGeneratorInformation > GetMovementGeneratorsInformation() const
void CalculateJumpSpeeds(float dist, UnitMoveType moveType, float speedMultiplier, float minHeight, float maxHeight, float &speedXY, float &speedZ) const
void Pop(bool active, bool movementInform)
bool StopOnDeath()
void PropagateSpeedChange()
void MoveSmoothPath(uint32 pointId, Position const *pathPoints, size_t pathSize, bool walk=false, bool fly=false)
void Delete(MovementGenerator *movement, bool active, bool movementInform)
void MoveConfused()
void MoveChase(Unit *target, Optional< ChaseRange > dist={}, Optional< ChaseAngle > angle={})
void MoveFormation(Unit *leader, float range, float angle, uint32 point1, uint32 point2)
void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
void DirectAdd(MovementGenerator *movement, MovementSlot slot)
std::unique_ptr< MovementGenerator, MovementGeneratorDeleter > MovementGeneratorPointer
Definition: MotionMaster.h:226
void AddFlag(uint8 const flag)
Definition: MotionMaster.h:230
void MoveTakeoff(uint32 id, Position const &pos, Optional< int32 > tierTransitionId={}, Optional< float > velocity={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default)
void MoveSeekAssistance(float x, float y, float z)
void MoveRandom(float wanderDistance=0.0f, Optional< Milliseconds > duration={}, MovementSlot slot=MOTION_SLOT_DEFAULT)
void MoveKnockbackFrom(Position const &origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MoveSeekAssistanceDistract(uint32 timer)
void DirectClearDefault()
MotionMasterUnitStatesContainer _baseUnitStatesMap
Definition: MotionMaster.h:252
void ResumeSplineChain(SplineChainResumeInfo const &info)
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< float > closeEnoughDistance={})
void RemoveFlag(uint8 const flag)
Definition: MotionMaster.h:232
void MoveLand(uint32 id, Position const &pos, Optional< int32 > tierTransitionId={}, Optional< float > velocity={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default)
void Add(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
bool GetDestination(float &x, float &y, float &z)
std::function< void()> DelayedActionDefine
Definition: MotionMaster.h:99
void MoveFollow(Unit *target, float dist, ChaseAngle angle, Optional< Milliseconds > duration={}, MovementSlot slot=MOTION_SLOT_ACTIVE)
void Update(uint32 diff)
MovementGenerator * GetCurrentMovementGenerator() const
std::deque< DelayedAction > _delayedActions
Definition: MotionMaster.h:253
void MoveCharge(float x, float y, float z, float speed=SPEED_CHARGE, uint32 id=EVENT_CHARGE, bool generatePath=false, Unit const *target=nullptr, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MoveTargetedHome()
MovementSlot GetCurrentSlot() const
MovementGeneratorPointer _defaultGenerator
Definition: MotionMaster.h:250
MotionMaster(Unit *unit)
void MoveCloserAndStop(uint32 id, Unit *target, float distance)
void MoveJumpTo(float angle, float speedXY, float speedZ)
void DirectInitialize()
void MoveFall(uint32 id=0)
void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount, Optional< Milliseconds > duration={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default)
void MoveDistract(uint32 time, float orientation)
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()
MotionMasterContainer _generators
Definition: MotionMaster.h:251
void AddBaseUnitState(MovementGenerator const *movement)
virtual void Initialize(Unit *owner)=0
virtual bool Update(Unit *owner, uint32 diff)=0
void AddFlag(uint16 const flag)
virtual void Finalize(Unit *owner, bool active, bool movementInform)=0
bool HasFlag(uint16 const flag) const
virtual void Reset(Unit *owner)=0
virtual void UnitSpeedChanged()
virtual MovementGeneratorType GetMovementGeneratorType() const =0
void MoveTo(Vector3 const &destination, bool generatePath=true, bool forceDestination=false)
void SetParabolic(float amplitude, float start_time)
void SetVelocity(float velocity)
void SetFacing(float angle)
void SetSpellEffectExtraData(SpellEffectExtraData const &spellEffectExtraData)
void MovebyPath(PointsArray const &path, int32 pointId=0)
void SetParabolicVerticalAcceleration(float vertical_acceleration, float time_shift)
void SetOrientationFixed(bool enable)
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
std::string ToString() const
Definition: ObjectGuid.cpp:554
static Creature * ToCreature(Object *o)
Definition: Object.h:219
bool IsInWorld() const
Definition: Object.h:154
TypeID GetTypeId() const
Definition: Object.h:173
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
static Player * ToPlayer(Object *o)
Definition: Object.h:213
Movement::PointsArray const & GetPath() const
Definition: PathGenerator.h:81
G3D::Vector3 const & GetActualEndPosition() const
Definition: PathGenerator.h:79
void SetFallInformation(uint32 time, float z)
Definition: Player.cpp:26672
Definition: Unit.h:627
void ClearUnitState(uint32 f)
Definition: Unit.h:733
float GetSpeed(UnitMoveType mtype) const
Definition: Unit.cpp:8515
bool SetFall(bool enable)
Definition: Unit.cpp:12785
void StopMoving()
Definition: Unit.cpp:10049
void AddUnitState(uint32 f)
Definition: Unit.h:731
Unit * GetCharmerOrOwner() const
Definition: Unit.h:1200
float GetHoverOffset() const
Definition: Unit.h:1740
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
std::unique_ptr< Movement::MoveSpline > movespline
Definition: Unit.h:1766
bool IsControlledByPlayer() const
Definition: Unit.h:1193
bool IsFlying() const
Definition: Unit.h:1735
ObjectGuid GetTarget() const
Definition: Unit.h:1759
Map * GetMap() const
Definition: Object.h:624
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition: Object.cpp:1371
float GetMapHeight(float x, float y, float z, bool vmap=true, float distanceToSearch=50.0f) const
Definition: Object.cpp:3777
void MovePositionToFirstCollision(Position &pos, float dist, float angle)
Definition: Object.cpp:3482
void GetNearPoint2D(WorldObject const *searcher, float &x, float &y, float distance, float absAngle) const
Definition: Object.cpp:3339
MovementGenerator * SelectMovementGenerator(Unit *unit)
float constexpr gravity
std::vector< Vector3 > PointsArray
float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity=0.0f)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
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)
constexpr float GetPositionX() const
Definition: Position.h:76
float m_positionZ
Definition: Position.h:55
constexpr float GetPositionY() const
Definition: Position.h:77
float GetExactDist2d(const float x, const float y) const
Definition: Position.h:106
float GetRelativeAngle(float x, float y) const
Definition: Position.h:136
std::string ToString() const
Definition: Position.cpp:128
float m_positionX
Definition: Position.h:53
float m_positionY
Definition: Position.h:54
float GetAbsoluteAngle(float x, float y) const
Definition: Position.h:125
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
bool Empty() const
Definition: SplineChain.h:40