aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Movement/MotionMaster.cpp
diff options
context:
space:
mode:
authorccrs <ccrs@users.noreply.github.com>2018-06-03 10:06:57 -0700
committerShauren <shauren.trinity@gmail.com>2021-09-28 00:15:13 +0200
commit426f9f2f92b26fbb68e7cda9290ccbd586c6af4e (patch)
treeede70b7865c2edb58964c7aa668eb1250a5816ab /src/server/game/Movement/MotionMaster.cpp
parent3e0af19b7767d6e71a7467874fdad566cea5ee87 (diff)
Core/Movement: MotionMaster reimplementation (#21888)
Internal structure and handling changes, nothing behavioural (or thats the intention at least). (cherry picked from commit 982643cd96790ffc54e7a3e507469649f3b074d2)
Diffstat (limited to 'src/server/game/Movement/MotionMaster.cpp')
-rw-r--r--src/server/game/Movement/MotionMaster.cpp846
1 files changed, 599 insertions, 247 deletions
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
index d2ebbf22faa..b03fbd08497 100644
--- a/src/server/game/Movement/MotionMaster.cpp
+++ b/src/server/game/Movement/MotionMaster.cpp
@@ -16,13 +16,15 @@
*/
#include "MotionMaster.h"
+#include "AbstractFollower.h"
#include "Creature.h"
#include "CreatureAISelector.h"
+#include "Containers.h"
#include "DB2Stores.h"
+#include "Errors.h"
#include "G3DPosition.hpp"
#include "Log.h"
#include "Map.h"
-#include "MovementGenerator.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
#include "PathGenerator.h"
@@ -31,6 +33,8 @@
#include "ScriptSystem.h"
#include "Unit.h"
#include "WaypointDefines.h"
+#include <algorithm>
+#include <iterator>
#include "ChaseMovementGenerator.h"
#include "ConfusedMovementGenerator.h"
@@ -56,144 +60,465 @@ inline bool IsStatic(MovementGenerator* movement)
return (movement == GetIdleMovementGenerator());
}
+inline void MovementGeneratorPointerDeleter(MovementGenerator* a)
+{
+ if (a != nullptr && !IsStatic(a))
+ delete a;
+}
+
+void MovementGeneratorDeleter::operator()(MovementGenerator * a)
+{
+ MovementGeneratorPointerDeleter(a);
+}
+
+bool MovementGeneratorComparator::operator()(MovementGenerator const* a, MovementGenerator const* b) const
+{
+ if (a->Mode > b->Mode)
+ return true;
+ else if (a->Mode == b->Mode)
+ return a->Priority > b->Priority;
+
+ return false;
+}
+
+MovementGeneratorInformation::MovementGeneratorInformation(MovementGeneratorType type, ObjectGuid targetGUID, std::string const& targetName) : Type(type), TargetGUID(targetGUID), TargetName(targetName) { }
+
+MotionMaster::MotionMaster(Unit* unit) : _owner(unit), _defaultGenerator(nullptr), _flags(MOTIONMASTER_FLAG_NONE) { }
+
MotionMaster::~MotionMaster()
{
- // clear ALL movement generators (including default)
- while (!empty())
+ _delayedActions.clear();
+
+ for (auto itr = _generators.begin(); itr != _generators.end(); itr = _generators.erase(itr))
+ MovementGeneratorPointerDeleter(*itr);
+}
+
+void MotionMaster::Initialize()
+{
+ if (HasFlag(MOTIONMASTER_FLAG_UPDATE))
{
- MovementGenerator* movement = top();
- pop();
- if (movement && !IsStatic(movement))
- delete movement;
+ std::function<void()> action = [this]()
+ {
+ Initialize();
+ };
+ _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_INITIALIZE);
+ return;
}
- while (!_expireList.empty())
+ DirectInitialize();
+}
+
+void MotionMaster::InitializeDefault()
+{
+ Add(FactorySelector::SelectMovementGenerator(_owner), MOTION_SLOT_DEFAULT);
+}
+
+bool MotionMaster::Empty() const
+{
+ return !_defaultGenerator && _generators.empty();
+}
+
+uint32 MotionMaster::Size() const
+{
+ return _defaultGenerator ? 1 : 0 + uint32(_generators.size());
+}
+
+std::vector<MovementGeneratorInformation> MotionMaster::GetMovementGeneratorsInformation() const
+{
+ std::vector<MovementGeneratorInformation> list;
+
+ if (_defaultGenerator)
+ list.emplace_back(_defaultGenerator->GetMovementGeneratorType(), ObjectGuid::Empty, std::string());
+
+ for (auto itr = _generators.begin(); itr != _generators.end(); ++itr)
{
- delete _expireList.back();
- _expireList.pop_back();
+ MovementGenerator* movement = *itr;
+ MovementGeneratorType const type = movement->GetMovementGeneratorType();
+ switch (type)
+ {
+ case CHASE_MOTION_TYPE:
+ case FOLLOW_MOTION_TYPE:
+ if (AbstractFollower* followInformation = dynamic_cast<AbstractFollower*>(movement))
+ {
+ if (Unit* target = followInformation->GetTarget())
+ list.emplace_back(type, target->GetGUID(), target->GetName());
+ else
+ list.emplace_back(type, ObjectGuid::Empty, std::string());
+ }
+ else
+ list.emplace_back(type, ObjectGuid::Empty, std::string());
+ break;
+ default:
+ list.emplace_back(type, ObjectGuid::Empty, std::string());
+ break;
+ }
}
+
+ return list;
}
-MovementGenerator* MotionMaster::top() const
+MovementSlot MotionMaster::GetCurrentSlot() const
{
- ASSERT(!empty());
+ if (!_generators.empty())
+ return MOTION_SLOT_ACTIVE;
- return _slot[_top];
+ if (_defaultGenerator)
+ return MOTION_SLOT_DEFAULT;
+
+ return MAX_MOTION_SLOT;
}
-void MotionMaster::Initialize()
+MovementGenerator* MotionMaster::GetCurrentMovementGenerator() const
+{
+ if (!_generators.empty())
+ return *_generators.begin();
+
+ if (_defaultGenerator)
+ return _defaultGenerator.get();
+
+ return nullptr;
+}
+
+MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const
+{
+ if (Empty())
+ return MAX_MOTION_TYPE;
+
+ MovementGenerator const* movement = GetCurrentMovementGenerator();
+ if (!movement)
+ return MAX_MOTION_TYPE;
+
+ return movement->GetMovementGeneratorType();
+}
+
+MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType(MovementSlot slot) const
+{
+ if (Empty() || IsInvalidMovementSlot(slot))
+ return MAX_MOTION_TYPE;
+
+ if (slot == MOTION_SLOT_ACTIVE && !_generators.empty())
+ return (*_generators.begin())->GetMovementGeneratorType();
+
+ if (slot == MOTION_SLOT_DEFAULT && _defaultGenerator)
+ return _defaultGenerator->GetMovementGeneratorType();
+
+ return MAX_MOTION_TYPE;
+}
+
+MovementGenerator* MotionMaster::GetCurrentMovementGenerator(MovementSlot slot) const
+{
+ if (Empty() || IsInvalidMovementSlot(slot))
+ return nullptr;
+
+ if (slot == MOTION_SLOT_ACTIVE && !_generators.empty())
+ return *_generators.begin();
+
+ if (slot == MOTION_SLOT_DEFAULT && _defaultGenerator)
+ return _defaultGenerator.get();
+
+ return nullptr;
+}
+
+MovementGenerator* MotionMaster::GetMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot) const
{
- // clear ALL movement generators (including default)
- while (!empty())
+ if (Empty() || IsInvalidMovementSlot(slot))
+ return nullptr;
+
+ MovementGenerator* movement = nullptr;
+ switch (slot)
{
- MovementGenerator* curr = top();
- pop();
- if (curr)
- DirectDelete(curr);
+ case MOTION_SLOT_DEFAULT:
+ if (_defaultGenerator && filter(_defaultGenerator.get()))
+ movement = _defaultGenerator.get();
+ break;
+ case MOTION_SLOT_ACTIVE:
+ if (!_generators.empty())
+ {
+ auto itr = std::find_if(_generators.begin(), _generators.end(), std::ref(filter));
+ if (itr != _generators.end())
+ movement = *itr;
+ }
+ break;
+ default:
+ break;
}
- InitDefault();
+ return movement;
}
-// set new default movement generator
-void MotionMaster::InitDefault()
+bool MotionMaster::HasMovementGenerator(std::function<bool(MovementGenerator const*)> const& filter, MovementSlot slot) const
{
- Mutate(FactorySelector::SelectMovementGenerator(_owner), MOTION_SLOT_IDLE);
+ if (Empty() || IsInvalidMovementSlot(slot))
+ return false;
+
+ bool value = false;
+ switch (slot)
+ {
+ case MOTION_SLOT_DEFAULT:
+ if (_defaultGenerator && filter(_defaultGenerator.get()))
+ value = true;
+ break;
+ case MOTION_SLOT_ACTIVE:
+ if (!_generators.empty())
+ {
+ auto itr = std::find_if(_generators.begin(), _generators.end(), std::ref(filter));
+ value = itr != _generators.end();
+ }
+ break;
+ default:
+ break;
+ }
+
+ return value;
}
-void MotionMaster::UpdateMotion(uint32 diff)
+void MotionMaster::Update(uint32 diff)
{
if (!_owner)
return;
- ASSERT(!empty());
+ ASSERT(!Empty(), "MotionMaster:Update: update called without Initializing! (%s)", _owner->GetGUID().ToString().c_str());
- _cleanFlag |= MOTIONMMASTER_CLEANFLAG_UPDATE;
- if (!top()->Update(_owner, diff))
+ AddFlag(MOTIONMASTER_FLAG_UPDATE);
+
+ MovementGenerator* top = GetCurrentMovementGenerator();
+ if (HasFlag(MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING) && IsStatic(top))
{
- _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_UPDATE;
- MovementExpired();
+ RemoveFlag(MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING);
+ top->Initialize(_owner);
}
- else
- _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_UPDATE;
+ if (top->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING))
+ top->Initialize(_owner);
+ if (top->HasFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED))
+ top->Reset(_owner);
+
+ 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);
+
+ if (!top->Update(_owner, diff))
+ {
+ ASSERT(top == GetCurrentMovementGenerator(), "MotionMaster::Update: top was modified while updating! (%s)", _owner->GetGUID().ToString().c_str());
+
+ // Since all the actions that modify any slot are delayed, this movement is guaranteed to be top
+ Pop(true, true); // Natural, and only, call to MovementInform
+ }
+
+ RemoveFlag(MOTIONMASTER_FLAG_UPDATE);
- if (!_expireList.empty())
- ClearExpireList();
+ while (!_delayedActions.empty())
+ {
+ _delayedActions.front().Resolve();
+ _delayedActions.pop_front();
+ }
}
-void MotionMaster::Clear(bool reset /*= true*/)
+void MotionMaster::Add(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
{
- if (_cleanFlag & MOTIONMMASTER_CLEANFLAG_UPDATE)
+ if (!movement)
+ return;
+
+ if (IsInvalidMovementSlot(slot))
{
- if (reset)
- _cleanFlag |= MOTIONMMASTER_CLEANFLAG_RESET;
- else
- _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_RESET;
- DelayedClean();
+ delete movement;
+ return;
+ }
+
+ if (HasFlag(MOTIONMASTER_FLAG_UPDATE))
+ {
+ std::function<void()> action = [this, movement, slot]()
+ {
+ Add(movement, slot);
+ };
+ _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_ADD);
}
else
- DirectClean(reset);
+ DirectAdd(movement, slot);
}
-void MotionMaster::Clear(MovementSlot slot)
+void MotionMaster::Remove(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
{
- if (empty() || IsInvalidMovementSlot(slot))
+ if (!movement || IsInvalidMovementSlot(slot))
return;
- if (_cleanFlag & MOTIONMMASTER_CLEANFLAG_UPDATE)
- DelayedClean(slot);
- else
- DirectClean(slot);
+ if (HasFlag(MOTIONMASTER_FLAG_UPDATE))
+ {
+ std::function<void()> action = [this, movement, slot]()
+ {
+ Remove(movement, slot);
+ };
+ _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_REMOVE);
+ return;
+ }
+
+ if (Empty())
+ return;
+
+ switch (slot)
+ {
+ case MOTION_SLOT_DEFAULT:
+ if (_defaultGenerator && _defaultGenerator.get() == movement)
+ DirectClearDefault();
+ break;
+ case MOTION_SLOT_ACTIVE:
+ if (!_generators.empty())
+ {
+ auto itr = _generators.find(movement);
+ if (itr != _generators.end())
+ {
+ MovementGenerator* pointer = *itr;
+ bool const top = GetCurrentMovementGenerator() == pointer;
+ _generators.erase(pointer);
+ Delete(pointer, top, false);
+ }
+ }
+ break;
+ default:
+ break;
+ }
}
-void MotionMaster::MovementExpired(bool reset /*= true*/)
+void MotionMaster::Remove(MovementGeneratorType type, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
{
- if (_cleanFlag & MOTIONMMASTER_CLEANFLAG_UPDATE)
+ if (IsInvalidMovementGeneratorType(type) || IsInvalidMovementSlot(slot))
+ return;
+
+ if (HasFlag(MOTIONMASTER_FLAG_UPDATE))
{
- if (reset)
- _cleanFlag |= MOTIONMMASTER_CLEANFLAG_RESET;
- else
- _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_RESET;
- DelayedExpire();
+ std::function<void()> action = [this, type, slot]()
+ {
+ Remove(type, slot);
+ };
+ _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_REMOVE_TYPE);
+ return;
+ }
+
+ if (Empty())
+ return;
+
+ switch (slot)
+ {
+ case MOTION_SLOT_DEFAULT:
+ if (_defaultGenerator && _defaultGenerator->GetMovementGeneratorType() == type)
+ DirectClearDefault();
+ break;
+ case MOTION_SLOT_ACTIVE:
+ if (!_generators.empty())
+ {
+ auto itr = std::find_if(_generators.begin(), _generators.end(), [type](MovementGenerator const* a) -> bool
+ {
+ return a->GetMovementGeneratorType() == type;
+ });
+
+ if (itr != _generators.end())
+ {
+ MovementGenerator* pointer = *itr;
+ bool const top = GetCurrentMovementGenerator() == pointer;
+ _generators.erase(pointer);
+ Delete(pointer, top, false);
+ }
+ }
+ break;
+ default:
+ break;
}
- else
- DirectExpire(reset);
}
-MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const
+void MotionMaster::Clear()
{
- if (empty())
- return MAX_MOTION_TYPE;
+ if (HasFlag(MOTIONMASTER_FLAG_UPDATE))
+ {
+ std::function<void()> action = [this]()
+ {
+ Clear();
+ };
+ _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR);
+ return;
+ }
- MovementGenerator* movement = top();
- if (!movement)
- return MAX_MOTION_TYPE;
+ if (!Empty())
+ DirectClear();
+}
- return movement->GetMovementGeneratorType();
+void MotionMaster::Clear(MovementSlot slot)
+{
+ if (IsInvalidMovementSlot(slot))
+ return;
+
+ if (HasFlag(MOTIONMASTER_FLAG_UPDATE))
+ {
+ std::function<void()> action = [this, slot]()
+ {
+ Clear(slot);
+ };
+ _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_SLOT);
+ return;
+ }
+
+ if (Empty())
+ return;
+
+ switch (slot)
+ {
+ case MOTION_SLOT_DEFAULT:
+ DirectClearDefault();
+ break;
+ case MOTION_SLOT_ACTIVE:
+ DirectClear();
+ break;
+ default:
+ break;
+ }
}
-MovementGeneratorType MotionMaster::GetMotionSlotType(MovementSlot slot) const
+void MotionMaster::Clear(MovementGeneratorMode mode)
{
- if (empty() || IsInvalidMovementSlot(slot) || !_slot[slot])
- return MAX_MOTION_TYPE;
+ if (HasFlag(MOTIONMASTER_FLAG_UPDATE))
+ {
+ std::function<void()> action = [this, mode]()
+ {
+ Clear(mode);
+ };
+ _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_MODE);
+ return;
+ }
+
+ if (Empty())
+ return;
- return _slot[slot]->GetMovementGeneratorType();
+ std::function<bool(MovementGenerator*)> criteria = [mode](MovementGenerator* a) -> bool
+ {
+ return a->Mode == mode;
+ };
+ DirectClear(criteria);
}
-MovementGenerator* MotionMaster::GetMotionSlot(MovementSlot slot) const
+void MotionMaster::Clear(MovementGeneratorPriority priority)
{
- if (empty() || IsInvalidMovementSlot(slot) || !_slot[slot])
- return nullptr;
+ if (HasFlag(MOTIONMASTER_FLAG_UPDATE))
+ {
+ std::function<void()> action = [this, priority]()
+ {
+ Clear(priority);
+ };
+ _delayedActions.emplace_back(std::move(action), MOTIONMASTER_DELAYED_CLEAR_PRIORITY);
+ return;
+ }
- return _slot[slot];
+ if (Empty())
+ return;
+
+ std::function<bool(MovementGenerator*)> criteria = [priority](MovementGenerator* a) -> bool
+ {
+ return a->Priority == priority;
+ };
+ DirectClear(criteria);
}
void MotionMaster::PropagateSpeedChange()
{
- if (empty())
+ if (Empty())
return;
- MovementGenerator* movement = top();
+ MovementGenerator* movement = GetCurrentMovementGenerator();
if (!movement)
return;
@@ -214,9 +539,7 @@ bool MotionMaster::GetDestination(float &x, float &y, float &z)
void MotionMaster::MoveIdle()
{
- //! Should be preceded by MovementExpired or Clear if there's an overlying movementgenerator active
- if (empty() || !IsStatic(top()))
- Mutate(GetIdleMovementGenerator(), MOTION_SLOT_IDLE);
+ Add(GetIdleMovementGenerator(), MOTION_SLOT_DEFAULT);
}
void MotionMaster::MoveTargetedHome()
@@ -228,18 +551,18 @@ void MotionMaster::MoveTargetedHome()
return;
}
- Clear(false);
+ Clear();
Unit* target = owner->GetCharmerOrOwner();
if (!target)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTargetedHome: '%s', targeted home.", _owner->GetGUID().ToString().c_str());
- Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE);
+ Add(new HomeMovementGenerator<Creature>());
}
else
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTargetedHome: '%s', starts following '%s'", _owner->GetGUID().ToString().c_str(), target->GetGUID().ToString().c_str());
- Mutate(new FollowMovementGenerator(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE);
+ Add(new FollowMovementGenerator(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE));
}
}
@@ -248,28 +571,28 @@ void MotionMaster::MoveRandom(float spawndist)
if (_owner->GetTypeId() == TYPEID_UNIT)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRandom: '%s', started random movement (spawnDist: %f)", _owner->GetGUID().ToString().c_str(), spawndist);
- Mutate(new RandomMovementGenerator<Creature>(spawndist), MOTION_SLOT_IDLE);
+ Add(new RandomMovementGenerator<Creature>(spawndist), MOTION_SLOT_DEFAULT);
}
}
-void MotionMaster::MoveFollow(Unit* target, float dist, ChaseAngle angle, MovementSlot slot)
+void MotionMaster::MoveFollow(Unit* target, float dist, ChaseAngle angle, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
{
- // ignore movement request if target not exist
+ // Ignore movement request if target not exist
if (!target || target == _owner)
return;
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFollow: '%s', starts following '%s'", _owner->GetGUID().ToString().c_str(), target->GetGUID().ToString().c_str());
- Mutate(new FollowMovementGenerator(target, dist, angle), slot);
+ Add(new FollowMovementGenerator(target, dist, angle), slot);
}
void MotionMaster::MoveChase(Unit* target, Optional<ChaseRange> dist, Optional<ChaseAngle> angle)
{
- // ignore movement request if target not exist
+ // Ignore movement request if target not exist
if (!target || target == _owner)
return;
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveChase: '%s', starts chasing '%s'", _owner->GetGUID().ToString().c_str(), target->GetGUID().ToString().c_str());
- Mutate(new ChaseMovementGenerator(target, dist, angle), MOTION_SLOT_ACTIVE);
+ Add(new ChaseMovementGenerator(target, dist, angle));
}
void MotionMaster::MoveConfused()
@@ -277,12 +600,12 @@ void MotionMaster::MoveConfused()
if (_owner->GetTypeId() == TYPEID_PLAYER)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveConfused: '%s', started confused movement.", _owner->GetGUID().ToString().c_str());
- Mutate(new ConfusedMovementGenerator<Player>(), MOTION_SLOT_CONTROLLED);
+ Add(new ConfusedMovementGenerator<Player>());
}
else
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveConfused: '%s', started confused movement.", _owner->GetGUID().ToString().c_str());
- Mutate(new ConfusedMovementGenerator<Creature>(), MOTION_SLOT_CONTROLLED);
+ Add(new ConfusedMovementGenerator<Creature>());
}
}
@@ -295,12 +618,12 @@ void MotionMaster::MoveFleeing(Unit* enemy, uint32 time)
if (_owner->GetTypeId() == TYPEID_UNIT)
{
if (time)
- Mutate(new TimedFleeingMovementGenerator(enemy->GetGUID(), time), MOTION_SLOT_CONTROLLED);
+ Add(new TimedFleeingMovementGenerator(enemy->GetGUID(), time));
else
- Mutate(new FleeingMovementGenerator<Creature>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED);
+ Add(new FleeingMovementGenerator<Creature>(enemy->GetGUID()));
}
else
- Mutate(new FleeingMovementGenerator<Player>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED);
+ Add(new FleeingMovementGenerator<Player>(enemy->GetGUID()));
}
void MotionMaster::MovePoint(uint32 id, Position const& pos, bool generatePath/* = true*/, Optional<float> finalOrient/* = {}*/)
@@ -313,12 +636,12 @@ void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generate
if (_owner->GetTypeId() == TYPEID_PLAYER)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePoint: '%s', targeted point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, x, y, z);
- Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, 0.0f, nullptr, nullptr, finalOrient), MOTION_SLOT_ACTIVE);
+ Add(new PointMovementGenerator<Player>(id, x, y, z, generatePath, 0.0f, finalOrient));
}
else
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePoint: '%s', targeted point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, x, y, z);
- Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, 0.0f, nullptr, nullptr, finalOrient), MOTION_SLOT_ACTIVE);
+ Add(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, 0.0f, finalOrient));
}
}
@@ -334,11 +657,11 @@ void MotionMaster::MoveCloserAndStop(uint32 id, Unit* target, float distance)
}
else
{
- // we are already close enough. We just need to turn toward the target without changing position.
+ // We are already close enough. We just need to turn toward the target without changing position.
Movement::MoveSplineInit init(_owner);
init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ());
init.SetFacing(target);
- Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id), MOTION_SLOT_ACTIVE);
+ Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id));
}
}
@@ -349,7 +672,7 @@ void MotionMaster::MoveLand(uint32 id, Position const& pos)
Movement::MoveSplineInit init(_owner);
init.MoveTo(PositionToVector3(pos));
init.SetAnimation(Movement::ToGround);
- Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id), MOTION_SLOT_ACTIVE);
+ Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id));
}
void MotionMaster::MoveTakeoff(uint32 id, Position const& pos)
@@ -359,24 +682,31 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos)
Movement::MoveSplineInit init(_owner);
init.MoveTo(PositionToVector3(pos));
init.SetAnimation(Movement::ToFly);
- Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id), MOTION_SLOT_ACTIVE);
+ Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id));
}
void MotionMaster::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*/)
{
+/*
if (_slot[MOTION_SLOT_CONTROLLED] && _slot[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
return;
-
+*/
if (_owner->GetTypeId() == TYPEID_PLAYER)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveCharge: '%s', charging point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, x, y, z);
- Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed, target, spellEffectExtraData), MOTION_SLOT_CONTROLLED);
+ PointMovementGenerator<Player>* movement = new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed, {}, target, spellEffectExtraData);
+ movement->Priority = MOTION_PRIORITY_HIGHEST;
+ movement->BaseUnitState = UNIT_STATE_CHARGING;
+ Add(movement);
}
else
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveCharge: '%s', charging point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, x, y, z);
- Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed, target, spellEffectExtraData), MOTION_SLOT_CONTROLLED);
+ PointMovementGenerator<Creature>* movement = new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed, {}, target, spellEffectExtraData);
+ movement->Priority = MOTION_PRIORITY_HIGHEST;
+ movement->BaseUnitState = UNIT_STATE_CHARGING;
+ Add(movement);
}
}
@@ -400,7 +730,7 @@ void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_C
void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
{
- // this function may make players fall below map
+ // This function may make players fall below map
if (_owner->GetTypeId() == TYPEID_PLAYER)
return;
@@ -422,12 +752,14 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa
if (spellEffectExtraData)
init.SetSpellEffectExtraData(*spellEffectExtraData);
- Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0), MOTION_SLOT_CONTROLLED);
+ GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0);
+ movement->Priority = MOTION_PRIORITY_HIGHEST;
+ Add(movement);
}
void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ)
{
- // this function may make players fall below map
+ // This function may make players fall below map
if (_owner->GetTypeId() == TYPEID_PLAYER)
return;
@@ -475,7 +807,10 @@ void MotionMaster::MoveJump(float x, float y, float z, float o, float speedXY, f
arrivalSpellTargetGuid = arrivalCast->Target;
}
- Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id, arrivalSpellId, arrivalSpellTargetGuid), MOTION_SLOT_CONTROLLED);
+ GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id, arrivalSpellId, arrivalSpellTargetGuid);
+ movement->Priority = MOTION_PRIORITY_HIGHEST;
+ movement->BaseUnitState = UNIT_STATE_JUMPING;
+ Add(movement);
}
void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount)
@@ -512,7 +847,7 @@ void MotionMaster::MoveCirclePath(float x, float y, float z, float radius, bool
init.SetCyclic();
}
- Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0), MOTION_SLOT_ACTIVE);
+ Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, 0));
}
void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, size_t pathSize, bool walk, bool fly)
@@ -535,9 +870,9 @@ void MotionMaster::MoveSmoothPath(uint32 pointId, Position const* pathPoints, si
init.SetWalk(walk);
// This code is not correct
- // GenericMovementGenerator does not affect UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE
+ // GenericMovementGenerator does not affect UNIT_STATE_ROAMING_MOVE
// need to call PointMovementGenerator with various pointIds
- Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, pointId), MOTION_SLOT_ACTIVE);
+ Add(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, pointId));
}
void MotionMaster::MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
@@ -559,7 +894,7 @@ void MotionMaster::MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool w
void MotionMaster::MoveAlongSplineChain(uint32 pointId, std::vector<SplineChainLink> const& chain, bool walk)
{
- Mutate(new SplineChainMovementGenerator(pointId, chain, walk), MOTION_SLOT_ACTIVE);
+ Add(new SplineChainMovementGenerator(pointId, chain, walk));
}
void MotionMaster::ResumeSplineChain(SplineChainResumeInfo const& info)
@@ -569,12 +904,12 @@ void MotionMaster::ResumeSplineChain(SplineChainResumeInfo const& info)
TC_LOG_ERROR("movement.motionmaster", "MotionMaster::ResumeSplineChain: '%s', tried to resume a spline chain from empty info.", _owner->GetGUID().ToString().c_str());
return;
}
- Mutate(new SplineChainMovementGenerator(info), MOTION_SLOT_ACTIVE);
+ Add(new SplineChainMovementGenerator(info));
}
void MotionMaster::MoveFall(uint32 id/* = 0*/)
{
- // use larger distance for vmap height search than in most other cases
+ // Use larger distance for vmap height search than in most other cases
float tz = _owner->GetMapHeight(_owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ(), true, MAX_FALL_DISTANCE);
if (tz <= INVALID_HEIGHT)
{
@@ -589,7 +924,7 @@ void MotionMaster::MoveFall(uint32 id/* = 0*/)
_owner->SetFall(true);
- // don't run spline movement for players
+ // Don't run spline movement for players
if (_owner->GetTypeId() == TYPEID_PLAYER)
{
_owner->ToPlayer()->SetFallInformation(0, _owner->GetPositionZ());
@@ -599,7 +934,10 @@ void MotionMaster::MoveFall(uint32 id/* = 0*/)
Movement::MoveSplineInit init(_owner);
init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz + _owner->GetHoverOffset(), false);
init.SetFall();
- Mutate(new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id), MOTION_SLOT_CONTROLLED);
+
+ GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(init), EFFECT_MOTION_TYPE, id);
+ movement->Priority = MOTION_PRIORITY_HIGHEST;
+ Add(movement);
}
void MotionMaster::MoveSeekAssistance(float x, float y, float z)
@@ -610,7 +948,7 @@ void MotionMaster::MoveSeekAssistance(float x, float y, float z)
_owner->AttackStop();
_owner->CastStop();
_owner->ToCreature()->SetReactState(REACT_PASSIVE);
- Mutate(new AssistanceMovementGenerator(x, y, z), MOTION_SLOT_ACTIVE);
+ Add(new AssistanceMovementGenerator(EVENT_ASSIST_MOVE, x, y, z));
}
else
TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistance: '%s', attempted to seek assistance.", _owner->GetGUID().ToString().c_str());
@@ -621,7 +959,7 @@ void MotionMaster::MoveSeekAssistanceDistract(uint32 time)
if (_owner->GetTypeId() == TYPEID_UNIT)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '%s', is distracted after assistance call (Time: %u)", _owner->GetGUID().ToString().c_str(), time);
- Mutate(new AssistanceDistractMovementGenerator(time), MOTION_SLOT_ACTIVE);
+ Add(new AssistanceDistractMovementGenerator(time, _owner->GetOrientation()));
}
else
TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveSeekAssistanceDistract: '%s', attempted to call distract assistance.", _owner->GetGUID().ToString().c_str());
@@ -634,9 +972,13 @@ void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode)
if (path < sTaxiPathNodesByPath.size())
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '%s', taxi to path Id: %u (node %u)", _owner->GetGUID().ToString().c_str(), path, pathnode);
+
+ // Only one FLIGHT_MOTION_TYPE is allowed
+ Remove(FLIGHT_MOTION_TYPE);
+
FlightPathMovementGenerator* movement = new FlightPathMovementGenerator();
movement->LoadPath(_owner->ToPlayer(), pathnode);
- Mutate(movement, MOTION_SLOT_CONTROLLED);
+ Add(movement);
}
else
TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '%s', attempted taxi to non-existing path Id: %u (node: %u)", _owner->GetGUID().ToString().c_str(), path, pathnode);
@@ -645,17 +987,14 @@ void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode)
TC_LOG_ERROR("movement.motionmaster", "MotionMaster::MoveTaxiFlight: '%s', attempted taxi to path Id: %u (node: %u)", _owner->GetGUID().ToString().c_str(), path, pathnode);
}
-void MotionMaster::MoveDistract(uint32 timer)
+void MotionMaster::MoveDistract(uint32 timer, float orientation)
{
+/*
if (_slot[MOTION_SLOT_CONTROLLED])
return;
-
- if (_owner->GetTypeId() == TYPEID_PLAYER)
- TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveDistract: '%s', distracted (timer: %u)", _owner->GetGUID().ToString().c_str(), timer);
- else
- TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveDistract: '%s', distracted (timer: %u)", _owner->GetGUID().ToString().c_str(), timer);
-
- Mutate(new DistractMovementGenerator(timer), MOTION_SLOT_CONTROLLED);
+*/
+ TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveDistract: '%s', distracted (timer: %u, orientation: %f)", _owner->GetGUID().ToString().c_str(), timer, orientation);
+ Add(new DistractMovementGenerator(timer, orientation));
}
void MotionMaster::MovePath(uint32 pathId, bool repeatable)
@@ -664,22 +1003,22 @@ void MotionMaster::MovePath(uint32 pathId, bool repeatable)
return;
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '%s', starts moving over path Id: %u (repeatable: %s)", _owner->GetGUID().ToString().c_str(), pathId, repeatable ? "YES" : "NO");
- Mutate(new WaypointMovementGenerator<Creature>(pathId, repeatable), MOTION_SLOT_IDLE);
+ Add(new WaypointMovementGenerator<Creature>(pathId, repeatable), MOTION_SLOT_DEFAULT);
}
void MotionMaster::MovePath(WaypointPath& path, bool repeatable)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '%s', starts moving over path Id: %u (repeatable: %s)", _owner->GetGUID().ToString().c_str(), path.id, repeatable ? "YES" : "NO");
- Mutate(new WaypointMovementGenerator<Creature>(path, repeatable), MOTION_SLOT_IDLE);
+ Add(new WaypointMovementGenerator<Creature>(path, repeatable), MOTION_SLOT_DEFAULT);
}
-void MotionMaster::MoveRotate(uint32 time, RotateDirection direction)
+void MotionMaster::MoveRotate(uint32 id, uint32 time, RotateDirection direction)
{
if (!time)
return;
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRotate: '%s', starts rotate (time: %u, direction: %u)", _owner->GetGUID().ToString().c_str(), time, direction);
- Mutate(new RotateMovementGenerator(time, direction), MOTION_SLOT_ACTIVE);
+ Add(new RotateMovementGenerator(id, time, direction));
}
void MotionMaster::MoveFormation(uint32 id, Position destination, uint32 moveType, bool forceRun /*= false*/, bool forceOrientation /*= false*/)
@@ -687,49 +1026,85 @@ void MotionMaster::MoveFormation(uint32 id, Position destination, uint32 moveTyp
if (_owner->GetTypeId() == TYPEID_UNIT)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveFormation: '%s', targeted point Id: %u (X: %f, Y: %f, Z: %f)", _owner->GetGUID().ToString().c_str(), id, destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
- Mutate(new FormationMovementGenerator(id, destination, moveType, forceRun, forceOrientation), MOTION_SLOT_ACTIVE);
+ Add(new FormationMovementGenerator(id, destination, moveType, forceRun, forceOrientation));
}
}
-void MotionMaster::LaunchMoveSpline(Movement::MoveSplineInit&& init, uint32 id/*= 0*/, MovementSlot slot/*= MOTION_SLOT_ACTIVE*/, MovementGeneratorType type/*= EFFECT_MOTION_TYPE*/)
+void MotionMaster::LaunchMoveSpline(Movement::MoveSplineInit&& init, uint32 id/*= 0*/, MovementGeneratorPriority priority/* = MOTION_PRIORITY_NORMAL*/, MovementGeneratorType type/*= EFFECT_MOTION_TYPE*/)
{
if (IsInvalidMovementGeneratorType(type))
{
- TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '%s', tried to launch a spline with an invalid MovementGeneratorType: %u (Id: %u, Slot: %u)", _owner->GetGUID().ToString().c_str(), type, id, slot);
+ TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '%s', tried to launch a spline with an invalid MovementGeneratorType: %u (Id: %u, Priority: %u)", _owner->GetGUID().ToString().c_str(), type, id, priority);
return;
}
- TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '%s', initiates spline Id: %u (Type: %u, Slot: %u)", _owner->GetGUID().ToString().c_str(), id, type, slot);
- Mutate(new GenericMovementGenerator(std::move(init), type, id), slot);
+ TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::LaunchMoveSpline: '%s', initiates spline Id: %u (Type: %u, Priority: %u)", _owner->GetGUID().ToString().c_str(), id, type, priority);
+
+ GenericMovementGenerator* movement = new GenericMovementGenerator(std::move(init), type, id);
+ movement->Priority = priority;
+ Add(movement);
}
/******************** Private methods ********************/
-void MotionMaster::pop()
+void MotionMaster::Pop(bool active, bool movementInform)
{
- if (empty())
- return;
+ MovementGenerator* pointer = *_generators.begin();
+ _generators.erase(pointer);
+ Delete(pointer, active, movementInform);
+}
+
+void MotionMaster::DirectInitialize()
+{
+ // Clear ALL movement generators (including default)
+ DirectClearDefault();
+ DirectClear();
- _slot[_top] = nullptr;
- while (!empty() && !top())
- --_top;
+ InitializeDefault();
}
-bool MotionMaster::NeedInitTop() const
+void MotionMaster::DirectClear()
{
- if (empty())
- return false;
- return _initialize[_top];
+ // First delete Top
+ if (!_generators.empty())
+ Pop(true, false);
+
+ // Then the rest
+ while (!_generators.empty())
+ Pop(false, false);
+
+ // Make sure the storage is empty
+ ClearBaseUnitStates();
}
-void MotionMaster::InitTop()
+void MotionMaster::DirectClearDefault()
{
- top()->Initialize(_owner);
- _initialize[_top] = false;
+ if (_defaultGenerator)
+ DeleteDefault(_generators.empty(), false);
}
-void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot)
+void MotionMaster::DirectClear(std::function<bool(MovementGenerator*)> const& filter)
{
+ if (_generators.empty())
+ return;
+
+ MovementGenerator const* top = GetCurrentMovementGenerator();
+ for (auto itr = _generators.begin(); itr != _generators.end();)
+ {
+ if (filter(*itr))
+ {
+ MovementGenerator* movement = *itr;
+ itr = _generators.erase(itr);
+ Delete(movement, movement == top, false);
+ }
+ else
+ ++itr;
+ }
+}
+
+void MotionMaster::DirectAdd(MovementGenerator* movement, MovementSlot slot/* = MOTION_SLOT_ACTIVE*/)
+{
+/*
if (MovementGenerator* curr = _slot[slot])
{
_slot[slot] = nullptr; // in case a new one is generated in this slot during directdelete
@@ -751,131 +1126,108 @@ void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot)
_initialize[slot] = false;
m->Initialize(_owner);
}
-}
+*/
-void MotionMaster::DirectClean(bool reset)
-{
- while (size() > 1)
- {
- MovementGenerator* curr = top();
- pop();
- if (curr)
- DirectDelete(curr);
- }
+ /*
+ * NOTE: This mimics old behaviour: only one MOTION_SLOT_IDLE, MOTION_SLOT_ACTIVE, MOTION_SLOT_CONTROLLED
+ * On future changes support for multiple will be added
+ */
- if (empty())
- return;
-
- if (NeedInitTop())
- InitTop();
- else if (reset)
- top()->Reset(_owner);
-}
-
-void MotionMaster::DelayedClean()
-{
- while (size() > 1)
- {
- MovementGenerator* curr = top();
- pop();
- if (curr)
- DelayedDelete(curr);
- }
-}
-
-void MotionMaster::DirectClean(MovementSlot slot)
-{
- if (MovementGenerator* motion = GetMotionSlot(slot))
- {
- _slot[slot] = nullptr;
- DirectDelete(motion);
- }
-
- while (!empty() && !top())
- --_top;
-
- if (empty())
- Initialize();
- else if (NeedInitTop())
- InitTop();
-}
-
-void MotionMaster::DelayedClean(MovementSlot slot)
-{
- if (MovementGenerator* motion = GetMotionSlot(slot))
+ switch (slot)
{
- _slot[slot] = nullptr;
- DelayedDelete(motion);
+ case MOTION_SLOT_DEFAULT:
+ if (_defaultGenerator)
+ _defaultGenerator->Finalize(_owner, _generators.empty(), false);
+
+ _defaultGenerator = MovementGeneratorPointer(movement);
+ if (IsStatic(movement))
+ AddFlag(MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING);
+ break;
+ case MOTION_SLOT_ACTIVE:
+ if (!_generators.empty())
+ {
+ if (movement->Priority >= (*_generators.begin())->Priority)
+ {
+ MovementGenerator* pointer = *_generators.begin();
+ if (movement->Priority == pointer->Priority)
+ {
+ _generators.erase(pointer);
+ Delete(pointer, true, false);
+ }
+ else
+ pointer->Deactivate(_owner);
+ }
+ else
+ {
+ auto itr = std::find_if(_generators.begin(), _generators.end(), [movement](MovementGenerator const* a) -> bool
+ {
+ return a->Priority == movement->Priority;
+ });
+
+ if (itr != _generators.end())
+ {
+ MovementGenerator* pointer = *itr;
+ _generators.erase(pointer);
+ Delete(pointer, false, false);
+ }
+ }
+ }
+ else
+ _defaultGenerator->Deactivate(_owner);
+
+ _generators.emplace(movement);
+ AddBaseUnitState(movement);
+ break;
+ default:
+ break;
}
-
- while (!empty() && !top())
- --_top;
}
-void MotionMaster::DirectExpire(bool reset)
+void MotionMaster::Delete(MovementGenerator* movement, bool active, bool movementInform)
{
- if (size() > 1)
- {
- MovementGenerator* curr = top();
- pop();
- DirectDelete(curr);
- }
-
- while (!empty() && !top())
- --_top;
+ TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::Delete: deleting generator (Priority: %u, Flags: %u, BaseUnitState: %u, Type: %u), owner: '%s'",
+ movement->Priority, movement->Flags, movement->BaseUnitState, movement->GetMovementGeneratorType(), _owner->GetGUID().ToString().c_str());
- if (empty())
- Initialize();
- else if (NeedInitTop())
- InitTop();
- else if (reset)
- top()->Reset(_owner);
+ movement->Finalize(_owner, active, movementInform);
+ ClearBaseUnitState(movement);
+ MovementGeneratorPointerDeleter(movement);
}
-void MotionMaster::DelayedExpire()
+void MotionMaster::DeleteDefault(bool active, bool movementInform)
{
- if (size() > 1)
- {
- MovementGenerator* curr = top();
- pop();
- DelayedDelete(curr);
- }
+ TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::DeleteDefault: deleting generator (Priority: %u, Flags: %u, BaseUnitState: %u, Type: %u), owner: '%s'",
+ _defaultGenerator->Priority, _defaultGenerator->Flags, _defaultGenerator->BaseUnitState, _defaultGenerator->GetMovementGeneratorType(), _owner->GetGUID().ToString().c_str());
- while (!empty() && !top())
- --_top;
+ _defaultGenerator->Finalize(_owner, active, movementInform);
+ _defaultGenerator = MovementGeneratorPointer(GetIdleMovementGenerator());
+ AddFlag(MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING);
}
-void MotionMaster::DirectDelete(MovementGenerator* curr)
+void MotionMaster::AddBaseUnitState(MovementGenerator const* movement)
{
- if (IsStatic(curr))
+ if (!movement || !movement->BaseUnitState)
return;
- curr->Finalize(_owner);
- delete curr;
+ _baseUnitStatesMap.emplace(movement->BaseUnitState, movement);
+ _owner->AddUnitState(movement->BaseUnitState);
}
-void MotionMaster::DelayedDelete(MovementGenerator* curr)
+void MotionMaster::ClearBaseUnitState(MovementGenerator const* movement)
{
- TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::DelayedDelete: '%s', delayed deleting movement generator (type: %u)", _owner->GetGUID().ToString().c_str(), curr->GetMovementGeneratorType());
- if (IsStatic(curr))
+ if (!movement || !movement->BaseUnitState)
return;
- _expireList.push_back(curr);
+ Trinity::Containers::MultimapErasePair(_baseUnitStatesMap, movement->BaseUnitState, movement);
+ if (_baseUnitStatesMap.count(movement->BaseUnitState) == 0)
+ _owner->ClearUnitState(movement->BaseUnitState);
}
-void MotionMaster::ClearExpireList()
+void MotionMaster::ClearBaseUnitStates()
{
- for (auto itr : _expireList)
- DirectDelete(itr);
-
- _expireList.clear();
-
- if (empty())
- Initialize();
- else if (NeedInitTop())
- InitTop();
- else if (_cleanFlag & MOTIONMMASTER_CLEANFLAG_RESET)
- top()->Reset(_owner);
+ uint32 unitState = 0;
+ for (auto itr = _baseUnitStatesMap.begin(); itr != _baseUnitStatesMap.end(); ++itr)
+ unitState |= itr->first;
- _cleanFlag &= ~MOTIONMMASTER_CLEANFLAG_RESET;
+ _owner->ClearUnitState(unitState);
+ _baseUnitStatesMap.clear();
}