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
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)
649 {
650 if (time > 0ms)
651 Add(new TimedFleeingMovementGenerator(enemy->GetGUID(), time));
652 else
654 }
655 else
657}
658
659void MotionMaster::MovePoint(uint32 id, Position const& pos, bool generatePath/* = true*/, Optional<float> finalOrient/* = {}*/, Optional<float> speed /*= {}*/,
660 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, Optional<float> closeEnoughDistance /*= {}*/)
661{
662 MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ, generatePath, finalOrient, speed, speedSelectionMode, closeEnoughDistance);
663}
664
665void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generatePath /*= true*/, Optional<float> finalOrient /*= {}*/, Optional<float> speed /*= {}*/,
666 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/, Optional<float> closeEnoughDistance /*= {}*/)
667{
668 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePoint: '{}', targeted point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
669 Add(new PointMovementGenerator(id, x, y, z, generatePath, speed, finalOrient, nullptr, nullptr, speedSelectionMode, closeEnoughDistance));
670}
671
672void MotionMaster::MoveCloserAndStop(uint32 id, Unit* target, float distance)
673{
674 float distanceToTravel = _owner->GetExactDist2d(target) - distance;
675 if (distanceToTravel > 0.0f)
676 {
677 float angle = _owner->GetAbsoluteAngle(target);
678 float destx = _owner->GetPositionX() + distanceToTravel * std::cos(angle);
679 float desty = _owner->GetPositionY() + distanceToTravel * std::sin(angle);
680 MovePoint(id, destx, desty, target->GetPositionZ());
681 }
682 else
683 {
684 // We are already close enough. We just need to turn toward the target without changing position.
685 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this, target = target->GetGUID()](Movement::MoveSplineInit& init)
686 {
688 if (Unit const* refreshedTarget = ObjectAccessor::GetUnit(*_owner, target))
689 init.SetFacing(refreshedTarget);
690 };
691 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id));
692 }
693}
694
695void MotionMaster::MoveLand(uint32 id, Position const& pos, Optional<int32> tierTransitionId /*= {}*/, Optional<float> velocity /*= {}*/,
696 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/)
697{
698 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveLand: '{}', landing point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
699
700 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
701 {
702 init.MoveTo(PositionToVector3(pos), false);
703 init.SetAnimation(AnimTier::Ground, tierTransitionId.value_or(0));
704 switch (speedSelectionMode)
705 {
707 init.SetWalk(false);
708 break;
710 init.SetWalk(true);
711 break;
713 default:
714 break;
715 }
716 if (velocity)
717 init.SetVelocity(*velocity);
718 };
719 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id));
720}
721
722void MotionMaster::MoveTakeoff(uint32 id, Position const& pos, Optional<int32> tierTransitionId /*= {}*/, Optional<float> velocity /*= {}*/,
723 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/)
724{
725 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTakeoff: '{}', landing point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
726
727 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
728 {
729 init.MoveTo(PositionToVector3(pos), false);
730 init.SetAnimation(AnimTier::Hover, tierTransitionId.value_or(0));
731 switch (speedSelectionMode)
732 {
734 init.SetWalk(false);
735 break;
737 init.SetWalk(true);
738 break;
740 default:
741 break;
742 }
743 if (velocity)
744 init.SetVelocity(*velocity);
745 };
746 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id));
747}
748
749void MotionMaster::MoveCharge(float x, float y, float z, float speed /*= SPEED_CHARGE*/, uint32 id /*= EVENT_CHARGE*/, bool generatePath /*= false*/,
750 Unit const* target /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
751{
752/*
753 if (_slot[MOTION_SLOT_CONTROLLED] && _slot[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
754 return;
755*/
756 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveCharge: '{}', charging point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
757 PointMovementGenerator* movement = new PointMovementGenerator(id, x, y, z, generatePath, speed, {}, target, spellEffectExtraData);
760 Add(movement);
761}
762
763void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_CHARGE*/, Unit const* target /*= nullptr*/,
764 Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
765{
766 G3D::Vector3 dest = path.GetActualEndPosition();
767
768 MoveCharge(dest.x, dest.y, dest.z, speed, EVENT_CHARGE_PREPATH);
769
770 // If this is ever changed to not happen immediately then all spell effect handlers that use this must be updated
771
772 // Charge movement is not started when using EVENT_CHARGE_PREPATH
774 init.MovebyPath(path.GetPath());
775 init.SetVelocity(speed);
776 if (target)
777 init.SetFacing(target);
778 if (spellEffectExtraData)
779 init.SetSpellEffectExtraData(*spellEffectExtraData);
780 init.Launch();
781}
782
783void MotionMaster::MoveKnockbackFrom(Position const& origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
784{
785 // This function may make players fall below map
787 return;
788
789 if (speedXY < 0.01f)
790 return;
791
792 Position dest = _owner->GetPosition();
793 float moveTimeHalf = speedZ / Movement::gravity;
794 float dist = 2 * moveTimeHalf * speedXY;
795 float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ);
796
797 // Use a mmap raycast to get a valid destination.
798 _owner->MovePositionToFirstCollision(dest, dist, _owner->GetRelativeAngle(origin) + float(M_PI));
799
800 std::function<void(Movement::MoveSplineInit&)> initializer = [=, effect = (spellEffectExtraData ? Optional<Movement::SpellEffectExtraData>(*spellEffectExtraData) : Optional<Movement::SpellEffectExtraData>())](Movement::MoveSplineInit& init)
801 {
802 init.MoveTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), false);
803 init.SetParabolic(max_height, 0);
804 init.SetOrientationFixed(true);
805 init.SetVelocity(speedXY);
806 if (effect)
807 init.SetSpellEffectExtraData(*effect);
808 };
809
810 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, 0);
813 Add(movement);
814}
815
816void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ)
817{
818 // This function may make players fall below map
820 return;
821
822 float x, y, z = _owner->GetPositionZ();
823
824 float moveTimeHalf = speedZ / Movement::gravity;
825 float dist = 2 * moveTimeHalf * speedXY;
826
827 _owner->GetNearPoint2D(nullptr, x, y, dist, _owner->GetOrientation() + angle);
829
830 MoveJump(x, y, z, 0.0f, speedXY, speedZ);
831}
832
833void MotionMaster::MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id/* = EVENT_JUMP*/, bool hasOrientation/* = false*/,
834 JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
835{
836 MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), speedXY, speedZ, id, hasOrientation, arrivalCast, spellEffectExtraData);
837}
838
839void MotionMaster::MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id /*= EVENT_JUMP*/, bool hasOrientation /* = false*/,
840 JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
841{
842 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveJump: '{}', jumps to point Id: {} (X: {}, Y: {}, Z: {})", _owner->GetGUID().ToString(), id, x, y, z);
843 if (speedXY < 0.01f)
844 return;
845
846 float moveTimeHalf = speedZ / Movement::gravity;
847 float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ);
848
849 std::function<void(Movement::MoveSplineInit&)> initializer = [=, effect = (spellEffectExtraData ? Optional<Movement::SpellEffectExtraData>(*spellEffectExtraData) : Optional<Movement::SpellEffectExtraData>())](Movement::MoveSplineInit& init)
850 {
851 init.MoveTo(x, y, z, false);
852 init.SetParabolic(max_height, 0);
853 init.SetVelocity(speedXY);
854 if (hasOrientation)
855 init.SetFacing(o);
856 if (effect)
857 init.SetSpellEffectExtraData(*effect);
858 };
859
860 uint32 arrivalSpellId = 0;
861 ObjectGuid arrivalSpellTargetGuid;
862 if (arrivalCast)
863 {
864 arrivalSpellId = arrivalCast->SpellId;
865 arrivalSpellTargetGuid = arrivalCast->Target;
866 }
867
868 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id,
869 { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid });
872 Add(movement);
873}
874
875void MotionMaster::MoveJumpWithGravity(Position const& pos, float speedXY, float gravity, uint32 id/* = EVENT_JUMP*/, bool hasOrientation/* = false*/,
876 JumpArrivalCastArgs const* arrivalCast /*= nullptr*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
877{
878 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveJumpWithGravity: '{}', jumps to point Id: {} ({})", _owner->GetGUID().ToString(), id, pos.ToString());
879 if (speedXY < 0.01f)
880 return;
881
882 std::function<void(Movement::MoveSplineInit&)> initializer = [=, effect = (spellEffectExtraData ? Optional<Movement::SpellEffectExtraData>(*spellEffectExtraData) : Optional<Movement::SpellEffectExtraData>())](Movement::MoveSplineInit& init)
883 {
884 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false);
886 init.SetUncompressed();
887 init.SetVelocity(speedXY);
888 init.SetUnlimitedSpeed();
889 if (hasOrientation)
890 init.SetFacing(pos.GetOrientation());
891 if (effect)
892 init.SetSpellEffectExtraData(*effect);
893 };
894
895 uint32 arrivalSpellId = 0;
896 ObjectGuid arrivalSpellTargetGuid;
897 if (arrivalCast)
898 {
899 arrivalSpellId = arrivalCast->SpellId;
900 arrivalSpellTargetGuid = arrivalCast->Target;
901 }
902
903 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id,
904 { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid });
908 Add(movement);
909}
910
911void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount,
912 Optional<Milliseconds> duration /*= {}*/, Optional<float> speed /*= {}*/,
913 MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/)
914{
915 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this](Movement::MoveSplineInit& init)
916 {
917 float step = 2 * float(M_PI) / stepCount * (clockwise ? -1.0f : 1.0f);
918 Position const& pos = { x, y, z, 0.0f };
919 float angle = pos.GetAbsoluteAngle(_owner->GetPositionX(), _owner->GetPositionY());
920
921 // add the owner's current position as starting point as it gets removed after entering the cycle
922 init.Path().emplace_back(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ());
923
924 for (uint8 i = 0; i < stepCount; angle += step, ++i)
925 {
926 G3D::Vector3& point = init.Path().emplace_back();
927 point.x = x + radius * cosf(angle);
928 point.y = y + radius * sinf(angle);
929
930 if (_owner->IsFlying())
931 point.z = z;
932 else
933 point.z = _owner->GetMapHeight(point.x, point.y, z) + _owner->GetHoverOffset();
934 }
935
936 init.SetCyclic();
937 if (_owner->IsFlying())
938 {
939 init.SetFly();
940 init.SetAnimation(AnimTier::Hover);
941 }
942 else
943 init.SetWalk(true);
944
945 switch (speedSelectionMode)
946 {
948 init.SetWalk(false);
949 break;
951 init.SetWalk(true);
952 break;
954 default:
955 break;
956 }
957 if (speed)
958 init.SetVelocity(*speed);
959 };
960
961 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, 0, { .Duration = duration }));
962}
963
964void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk, bool fly)
965{
967 path.reserve(pathSize);
968 std::transform(pathPoints, pathPoints + pathSize, std::back_inserter(path), [](Position const& point)
969 {
970 return G3D::Vector3(point.GetPositionX(), point.GetPositionY(), point.GetPositionZ());
971 });
972 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
973 {
974 init.MovebyPath(path);
975 init.SetWalk(walk);
976 if (fly)
977 {
978 init.SetFly();
979 init.SetUncompressed();
980 init.SetSmooth();
981 }
982 };
983
984 // This code is not correct
985 // GenericMovementGenerator does not affect UNIT_STATE_ROAMING_MOVE
986 // need to call PointMovementGenerator with various pointIds
987 Add(new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, pointId));
988}
989
990void MotionMaster::MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
991{
992 Creature* owner = _owner->ToCreature();
993 if (!owner)
994 {
995 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveAlongSplineChain: '{}', tried to walk along DB spline chain. Ignoring.", _owner->GetGUID().ToString());
996 return;
997 }
998 std::vector<SplineChainLink> const* chain = sScriptSystemMgr->GetSplineChain(owner, dbChainId);
999 if (!chain)
1000 {
1001 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveAlongSplineChain: '{}', tried to walk along non-existing spline chain with DB Id: {}.", _owner->GetGUID().ToString(), dbChainId);
1002 return;
1003 }
1004 MoveAlongSplineChain(pointId, *chain, walk);
1005}
1006
1007void MotionMaster::MoveAlongSplineChain(uint32 pointId, std::vector<SplineChainLink> const& chain, bool walk)
1008{
1009 Add(new SplineChainMovementGenerator(pointId, chain, walk));
1010}
1011
1013{
1014 if (info.Empty())
1015 {
1016 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::ResumeSplineChain: '{}', tried to resume a spline chain from empty info.", _owner->GetGUID().ToString());
1017 return;
1018 }
1020}
1021
1023{
1024 // Use larger distance for vmap height search than in most other cases
1026 if (tz <= INVALID_HEIGHT)
1027 {
1028 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFall: '{}', unable to retrieve a proper height at map Id: {} (X: {}, Y: {}, Z: {})",
1030 return;
1031 }
1032
1033 // Abort too if the ground is very near
1034 if (std::fabs(_owner->GetPositionZ() - tz) < 0.1f)
1035 return;
1036
1037 // rooted units don't move (also setting falling+root flag causes client freezes)
1039 return;
1040
1041 _owner->SetFall(true);
1042
1043 // Don't run spline movement for players
1044 if (_owner->GetTypeId() == TYPEID_PLAYER)
1045 {
1047 return;
1048 }
1049
1050 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this](Movement::MoveSplineInit& init)
1051 {
1052 init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz + _owner->GetHoverOffset(), false);
1053 init.SetFall();
1054 };
1055
1056 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), EFFECT_MOTION_TYPE, id);
1058 Add(movement);
1059}
1060
1061void MotionMaster::MoveSeekAssistance(float x, float y, float z)
1062{
1063 if (Creature* creature = _owner->ToCreature())
1064 {
1065 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveSeekAssistance: '{}', seeks assistance (X: {}, Y: {}, Z: {})", creature->GetGUID().ToString(), x, y, z);
1066 creature->AttackStop();
1067 creature->CastStop();
1068 creature->DoNotReacquireSpellFocusTarget();
1069 creature->SetReactState(REACT_PASSIVE);
1071 }
1072 else
1073 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistance: '{}', attempted to seek assistance.", _owner->GetGUID().ToString());
1074}
1075
1077{
1078 if (_owner->GetTypeId() == TYPEID_UNIT)
1079 {
1080 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '{}', is distracted after assistance call (Time: {})", _owner->GetGUID().ToString(), time);
1082 }
1083 else
1084 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '{}', attempted to call distract assistance.", _owner->GetGUID().ToString());
1085}
1086
1088{
1089 if (_owner->GetTypeId() == TYPEID_PLAYER)
1090 {
1091 if (path < sTaxiPathNodesByPath.size())
1092 {
1093 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '{}', taxi to path Id: {} (node {})", _owner->GetGUID().ToString(), path, pathnode);
1094
1095 // Only one FLIGHT_MOTION_TYPE is allowed
1096 bool hasExisting = HasMovementGenerator([](MovementGenerator const* gen) { return gen->GetMovementGeneratorType() == FLIGHT_MOTION_TYPE; });
1097 ASSERT(!hasExisting, "Duplicate flight path movement generator");
1098
1100 movement->LoadPath(_owner->ToPlayer(), pathnode);
1101 Add(movement);
1102 }
1103 else
1104 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '{}', attempted taxi to non-existing path Id: {} (node: {})", _owner->GetGUID().ToString(), path, pathnode);
1105 }
1106 else
1107 TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '{}', attempted taxi to path Id: {} (node: {})", _owner->GetGUID().ToString(), path, pathnode);
1108}
1109
1110void MotionMaster::MoveDistract(uint32 timer, float orientation)
1111{
1112/*
1113 if (_slot[MOTION_SLOT_CONTROLLED])
1114 return;
1115*/
1116 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveDistract: '{}', distracted (timer: {}, orientation: {})", _owner->GetGUID().ToString(), timer, orientation);
1117 Add(new DistractMovementGenerator(timer, orientation));
1118}
1119
1120void MotionMaster::MovePath(uint32 pathId, bool repeatable, Optional<Milliseconds> duration, Optional<float> speed,
1121 MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
1122 Optional<float> wanderDistanceAtPathEnds, bool followPathBackwardsFromEndToStart, bool generatePath)
1123{
1124 if (!pathId)
1125 return;
1126
1127 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
1128 _owner->GetGUID().ToString(), pathId, repeatable ? "YES" : "NO");
1129 Add(new WaypointMovementGenerator<Creature>(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
1130 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT);
1131}
1132
1133void MotionMaster::MovePath(WaypointPath const& path, bool repeatable, Optional<Milliseconds> duration, Optional<float> speed,
1134 MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
1135 Optional<float> wanderDistanceAtPathEnds, bool followPathBackwardsFromEndToStart, bool generatePath)
1136{
1137 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
1138 _owner->GetGUID().ToString(), path.Id, repeatable ? "YES" : "NO");
1139 Add(new WaypointMovementGenerator<Creature>(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
1140 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT);
1141}
1142
1144{
1145 if (!time)
1146 return;
1147
1148 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRotate: '{}', starts rotate (time: {}, direction: {})", _owner->GetGUID().ToString(), time, direction);
1149 Add(new RotateMovementGenerator(id, time, direction));
1150}
1151
1152void MotionMaster::MoveFormation(Unit* leader, float range, float angle, uint32 point1, uint32 point2)
1153{
1154 if (_owner->GetTypeId() == TYPEID_UNIT && leader)
1155 {
1156 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFormation: '{}', started to move in a formation with leader {}", _owner->GetGUID().ToString(), leader->GetGUID().ToString());
1157 Add(new FormationMovementGenerator(leader, range, angle, point1, point2), MOTION_SLOT_DEFAULT);
1158 }
1159}
1160
1161void MotionMaster::LaunchMoveSpline(std::function<void(Movement::MoveSplineInit& init)>&& initializer, uint32 id/*= 0*/, MovementGeneratorPriority priority/* = MOTION_PRIORITY_NORMAL*/, MovementGeneratorType type/*= EFFECT_MOTION_TYPE*/)
1162{
1164 {
1165 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '{}', tried to launch a spline with an invalid MovementGeneratorType: {} (Id: {}, Priority: {})", _owner->GetGUID().ToString(), type, id, priority);
1166 return;
1167 }
1168
1169 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '{}', initiates spline Id: {} (Type: {}, Priority: {})", _owner->GetGUID().ToString(), id, type, priority);
1170
1171 GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(initializer), type, id);
1172 movement->Priority = priority;
1173 Add(movement);
1174}
1175
1176void MotionMaster::CalculateJumpSpeeds(float dist, UnitMoveType moveType, float speedMultiplier, float minHeight, float maxHeight, float& speedXY, float& speedZ) const
1177{
1178 float baseSpeed = _owner->IsControlledByPlayer() ? playerBaseMoveSpeed[moveType] : baseMoveSpeed[moveType];
1179 if (Creature* creature = _owner->ToCreature())
1180 baseSpeed *= creature->GetCreatureTemplate()->speed_run;
1181
1182 speedXY = std::min(baseSpeed * 3.0f * speedMultiplier, std::max(28.0f, _owner->GetSpeed(moveType) * 4.0f));
1183
1184 float duration = dist / speedXY;
1185 float durationSqr = duration * duration;
1186 float height;
1187 if (durationSqr < minHeight * 8 / Movement::gravity)
1188 height = minHeight;
1189 else if (durationSqr > maxHeight * 8 / Movement::gravity)
1190 height = maxHeight;
1191 else
1192 height = Movement::gravity * durationSqr / 8;
1193
1194 speedZ = std::sqrt(2 * Movement::gravity * height);
1195}
1196
1197/******************** Private methods ********************/
1198
1200{
1201 while (!_delayedActions.empty())
1202 {
1203 _delayedActions.front().Resolve();
1204 _delayedActions.pop_front();
1205 }
1206}
1207
1208void MotionMaster::Remove(MotionMasterContainer::iterator iterator, bool active, bool movementInform)
1209{
1210 MovementGenerator* pointer = *iterator;
1211 _generators.erase(iterator);
1212 Delete(pointer, active, movementInform);
1213}
1214
1215void MotionMaster::Pop(bool active, bool movementInform)
1216{
1217 if (!_generators.empty())
1218 Remove(_generators.begin(), active, movementInform);
1219}
1220
1222{
1223 // Clear ALL movement generators (including default)
1225 DirectClear();
1226
1228}
1229
1231{
1232 // First delete Top
1233 if (!_generators.empty())
1234 Pop(true, false);
1235
1236 // Then the rest
1237 while (!_generators.empty())
1238 Pop(false, false);
1239
1240 // Make sure the storage is empty
1242}
1243
1245{
1247 DeleteDefault(_generators.empty(), false);
1248}
1249
1250void MotionMaster::DirectClear(std::function<bool(MovementGenerator*)> const& filter)
1251{
1252 if (_generators.empty())
1253 return;
1254
1256 for (auto itr = _generators.begin(); itr != _generators.end();)
1257 {
1258 if (filter(*itr))
1259 {
1260 MovementGenerator* movement = *itr;
1261 itr = _generators.erase(itr);
1262 Delete(movement, movement == top, false);
1263 }
1264 else
1265 ++itr;
1266 }
1267}
1268
1269void MotionMaster::DirectAdd(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
1270{
1271/*
1272 if (MovementGenerator* curr = _slot[slot])
1273 {
1274 _slot[slot] = nullptr; // in case a new one is generated in this slot during directdelete
1275 if (_top == slot && (_cleanFlag & MOTIONMMASTER_CLEANFLAG_UPDATE))
1276 DelayedDelete(curr);
1277 else
1278 DirectDelete(curr);
1279 }
1280 else if (_top < slot)
1281 {
1282 _top = slot;
1283 }
1284
1285 _slot[slot] = m;
1286 if (_top > slot)
1287 _initialize[slot] = true;
1288 else
1289 {
1290 _initialize[slot] = false;
1291 m->Initialize(_owner);
1292 }
1293*/
1294
1295 /*
1296 * NOTE: This mimics old behaviour: only one MOTION_SLOT_IDLE, MOTION_SLOT_ACTIVE, MOTION_SLOT_CONTROLLED
1297 * On future changes support for multiple will be added
1298 */
1299
1300 switch (slot)
1301 {
1304 _defaultGenerator->Finalize(_owner, _generators.empty(), false);
1305
1307 if (IsStatic(movement))
1309 break;
1310 case MOTION_SLOT_ACTIVE:
1311 if (!_generators.empty())
1312 {
1313 if (movement->Priority >= (*_generators.begin())->Priority)
1314 {
1315 auto itr = _generators.begin();
1316 if (movement->Priority == (*itr)->Priority)
1317 Remove(itr, true, false);
1318 else
1319 (*itr)->Deactivate(_owner);
1320 }
1321 else
1322 {
1323 auto itr = std::find_if(_generators.begin(), _generators.end(), [movement](MovementGenerator const* a) -> bool
1324 {
1325 return a->Priority == movement->Priority;
1326 });
1327
1328 if (itr != _generators.end())
1329 Remove(itr, false, false);
1330 }
1331 }
1332 else
1333 _defaultGenerator->Deactivate(_owner);
1334
1335 _generators.emplace(movement);
1336 AddBaseUnitState(movement);
1337 break;
1338 default:
1339 break;
1340 }
1341}
1342
1343void MotionMaster::Delete(MovementGenerator* movement, bool active, bool movementInform)
1344{
1345 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::Delete: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1346 movement->Priority, movement->Flags, movement->BaseUnitState, movement->GetMovementGeneratorType(), _owner->GetGUID().ToString());
1347
1348 movement->Finalize(_owner, active, movementInform);
1349 ClearBaseUnitState(movement);
1351}
1352
1353void MotionMaster::DeleteDefault(bool active, bool movementInform)
1354{
1355 TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::DeleteDefault: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1356 _defaultGenerator->Priority, _defaultGenerator->Flags, _defaultGenerator->BaseUnitState, _defaultGenerator->GetMovementGeneratorType(), _owner->GetGUID().ToString());
1357
1358 _defaultGenerator->Finalize(_owner, active, movementInform);
1361}
1362
1364{
1365 if (!movement || !movement->BaseUnitState)
1366 return;
1367
1368 _baseUnitStatesMap.emplace(movement->BaseUnitState, movement);
1369 _owner->AddUnitState(movement->BaseUnitState);
1370}
1371
1373{
1374 if (!movement || !movement->BaseUnitState)
1375 return;
1376
1378 if (_baseUnitStatesMap.count(movement->BaseUnitState) == 0)
1380}
1381
1383{
1384 uint32 unitState = 0;
1385 for (auto itr = _baseUnitStatesMap.begin(); itr != _baseUnitStatesMap.end(); ++itr)
1386 unitState |= itr->first;
1387
1388 _owner->ClearUnitState(unitState);
1389 _baseUnitStatesMap.clear();
1390}
#define M_PI
Definition: Common.h:115
TaxiPathNodesByPath sTaxiPathNodesByPath
Definition: DB2Stores.cpp:382
uint8_t uint8
Definition: Define.h:145
uint16_t uint16
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:143
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:95
float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition: Unit.cpp:108
@ UNIT_STATE_ROOT
Definition: Unit.h:260
@ UNIT_STATE_CHARGING
Definition: Unit.h:267
@ UNIT_STATE_STUNNED
Definition: Unit.h:253
@ UNIT_STATE_JUMPING
Definition: Unit.h:268
void LoadPath(Player *owner, uint32 startNode=0)
uint32 GetId() const
Definition: Map.cpp:3195
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:222
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 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)
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:217
void AddFlag(uint8 const flag)
Definition: MotionMaster.h:221
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:243
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:223
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:244
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:241
MotionMaster(Unit *unit)
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={}, bool followPathBackwardsFromEndToStart=false, bool generatePath=true)
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 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:242
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:272
std::string ToString() const
Definition: ObjectGuid.cpp:554
static Creature * ToCreature(Object *o)
Definition: Object.h:206
bool IsInWorld() const
Definition: Object.h:153
TypeID GetTypeId() const
Definition: Object.h:172
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:158
static Player * ToPlayer(Object *o)
Definition: Object.h:200
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:26557
Definition: Unit.h:622
void ClearUnitState(uint32 f)
Definition: Unit.h:728
float GetSpeed(UnitMoveType mtype) const
Definition: Unit.cpp:8488
bool SetFall(bool enable)
Definition: Unit.cpp:12698
void StopMoving()
Definition: Unit.cpp:9983
void AddUnitState(uint32 f)
Definition: Unit.h:726
Unit * GetCharmerOrOwner() const
Definition: Unit.h:1186
float GetHoverOffset() const
Definition: Unit.h:1724
bool HasUnitState(const uint32 f) const
Definition: Unit.h:727
std::unique_ptr< Movement::MoveSpline > movespline
Definition: Unit.h:1753
bool IsControlledByPlayer() const
Definition: Unit.h:1179
bool IsFlying() const
Definition: Unit.h:1719
ObjectGuid GetTarget() const
Definition: Unit.h:1746
Map * GetMap() const
Definition: Object.h:604
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition: Object.cpp:1359
float GetMapHeight(float x, float y, float z, bool vmap=true, float distanceToSearch=50.0f) const
Definition: Object.cpp:3749
void MovePositionToFirstCollision(Position &pos, float dist, float angle)
Definition: Object.cpp:3470
void GetNearPoint2D(WorldObject const *searcher, float &x, float &y, float distance, float absAngle) const
Definition: Object.cpp:3327
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)
float m_positionZ
Definition: Position.h:55
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 GetPositionZ() const
Definition: Position.h:78
float m_positionY
Definition: Position.h:54
float GetOrientation() const
Definition: Position.h:79
float GetAbsoluteAngle(float x, float y) const
Definition: Position.h:125
float GetPositionX() const
Definition: Position.h:76
void GetPosition(float &x, float &y) const
Definition: Position.h:81
float GetPositionY() const
Definition: Position.h:77
bool Empty() const
Definition: SplineChain.h:40