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