diff --git a/Source/Game/AI/AISelector.cs b/Source/Game/AI/AISelector.cs index 1c80dea25..f30b2a10c 100644 --- a/Source/Game/AI/AISelector.cs +++ b/Source/Game/AI/AISelector.cs @@ -97,10 +97,11 @@ namespace Game.AI return new NullCreatureAI(creature); } - public static IMovementGenerator SelectMovementAI(Creature creature) + public static IMovementGenerator SelectMovementAI(Unit unit) { - MovementGeneratorType type = MovementGeneratorType.Idle; - if (creature.GetPlayerMovingMe() == null) + MovementGeneratorType type = unit.GetDefaultMovementType(); + Creature creature = unit.ToCreature(); + if (creature != null && creature.GetPlayerMovingMe() == null) type = creature.GetDefaultMovementType(); return type switch diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 0079dbb85..a9ba5ee2c 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -3189,7 +3189,7 @@ namespace Game.Entities public void SetNoSearchAssistance(bool val) { m_AlreadySearchedAssistance = val; } public bool HasSearchedAssistance() { return m_AlreadySearchedAssistance; } - public MovementGeneratorType GetDefaultMovementType() { return DefaultMovementType; } + public override MovementGeneratorType GetDefaultMovementType() { return DefaultMovementType; } public void SetDefaultMovementType(MovementGeneratorType mgt) { DefaultMovementType = mgt; } public long GetRespawnTime() { return m_respawnTime; } diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index 242ec53fc..6a13c8f4e 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -150,6 +150,11 @@ namespace Game.Entities public float GetSpeedRate(UnitMoveType mtype) { return m_speed_rate[(int)mtype]; } + public virtual MovementGeneratorType GetDefaultMovementType() + { + return MovementGeneratorType.Idle; + } + public void StopMoving() { ClearUnitState(UnitState.Moving); @@ -523,10 +528,9 @@ namespace Game.Entities if (creature.HasUnitTypeMask(UnitTypeMask.Minion) && !creature.IsInCombat()) { - var top = creature.GetMotionMaster().TopOrNull(); - if (top != null && top.GetMovementGeneratorType() == MovementGeneratorType.Follow) + if (GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Follow) { - Unit followed = ((AbstractFollower)top).GetTarget(); + Unit followed = ((AbstractFollower)GetMotionMaster().Top()).GetTarget(); if (followed != null && followed.GetGUID() == GetOwnerGUID() && !followed.IsInCombat()) { float ownerSpeed = followed.GetSpeedRate(mtype); diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 03825df57..976676345 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -3319,7 +3319,7 @@ namespace Game data.phaseGroup = result.Read(25); data.terrainSwapMap = result.Read(26); data.ScriptId = GetScriptId(result.Read(27)); - data.spawnGroupData = _spawnGroupDataStorage[IsTransportMap(data.spawnPoint.GetMapId()) ? 1 : 0]; // transport spawns default to compatibility group + data.spawnGroupData = _spawnGroupDataStorage[IsTransportMap(data.spawnPoint.GetMapId()) ? 1 : 0u]; // transport spawns default to compatibility group var mapEntry = CliDB.MapStorage.LookupByKey(data.spawnPoint.GetMapId()); if (mapEntry == null) @@ -4063,7 +4063,7 @@ namespace Game data.rotation.Z = result.Read(9); data.rotation.W = result.Read(10); data.spawntimesecs = result.Read(11); - data.spawnGroupData = _spawnGroupDataStorage[IsTransportMap(data.spawnPoint.GetMapId()) ? 1 : 0]; // transport spawns default to compatibility group + data.spawnGroupData = _spawnGroupDataStorage[IsTransportMap(data.spawnPoint.GetMapId()) ? 1 : 0u]; // transport spawns default to compatibility group var mapEntry = CliDB.MapStorage.LookupByKey(data.spawnPoint.GetMapId()); if (mapEntry == null) diff --git a/Source/Game/Movement/Generators/ChaseMovementGenerator.cs b/Source/Game/Movement/Generators/ChaseMovementGenerator.cs index e66c0ed4f..5042ec18d 100644 --- a/Source/Game/Movement/Generators/ChaseMovementGenerator.cs +++ b/Source/Game/Movement/Generators/ChaseMovementGenerator.cs @@ -49,6 +49,7 @@ namespace Game.Movement { owner.AddUnitState(UnitState.Chase); owner.SetWalk(false); + _path = null; } public bool Update(Unit owner, uint diff) @@ -187,18 +188,18 @@ namespace Game.Movement cOwner.SetCannotReachTarget(false); } - public MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Chase; } - public void Reset(Unit owner) { Initialize(owner); } + public MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Chase; } + public void UnitSpeedChanged() { _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); } static bool IsMutualChase(Unit owner, Unit target) { - IMovementGenerator gen = target.GetMotionMaster().TopOrNull(); - if (gen == null || gen.GetMovementGeneratorType() != MovementGeneratorType.Chase) + if (target.GetMotionMaster().GetCurrentMovementGeneratorType() != MovementGeneratorType.Chase) return false; - return ((ChaseMovementGenerator)gen).GetTarget() == owner; + + return ((ChaseMovementGenerator)target.GetMotionMaster().Top()).GetTarget() == owner; } static bool PositionOkay(Unit owner, Unit target, float? minDistance, float? maxDistance, ChaseAngle? angle) diff --git a/Source/Game/Movement/Generators/ConfusedGenerator.cs b/Source/Game/Movement/Generators/ConfusedGenerator.cs index 6f682116e..ec228bdc8 100644 --- a/Source/Game/Movement/Generators/ConfusedGenerator.cs +++ b/Source/Game/Movement/Generators/ConfusedGenerator.cs @@ -39,6 +39,7 @@ namespace Game.Movement _timer.Reset(0); _reference = owner.GetPosition(); + _path = null; } public override void DoReset(T owner) @@ -55,6 +56,7 @@ namespace Game.Movement { _interrupt = true; owner.StopMoving(); + _path = null; return true; } else @@ -73,9 +75,11 @@ namespace Game.Movement owner.MovePositionToFirstCollision(destination, distance, angle); if (_path == null) + { _path = new PathGenerator(owner); + _path.SetPathLengthLimit(30.0f); + } - _path.SetPathLengthLimit(30.0f); bool result = _path.CalculatePath(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ()); if (!result || _path.GetPathType().HasAnyFlag(PathType.NoPath)) { diff --git a/Source/Game/Movement/Generators/FleeingGenerator.cs b/Source/Game/Movement/Generators/FleeingGenerator.cs index bf21758ff..a7ec92ef9 100644 --- a/Source/Game/Movement/Generators/FleeingGenerator.cs +++ b/Source/Game/Movement/Generators/FleeingGenerator.cs @@ -40,6 +40,7 @@ namespace Game.Movement owner.AddUnitFlag(UnitFlags.Fleeing); owner.AddUnitState(UnitState.Fleeing); SetTargetLocation(owner); + _path = null; } public override void DoReset(T owner) @@ -56,6 +57,7 @@ namespace Game.Movement { _interrupt = true; owner.StopMoving(); + _path = null; return true; } else @@ -94,6 +96,7 @@ namespace Game.Movement { _interrupt = true; owner.StopMoving(); + _path = null; return; } @@ -110,9 +113,11 @@ namespace Game.Movement } if (_path == null) + { _path = new PathGenerator(owner); + _path.SetPathLengthLimit(30.0f); + } - _path.SetPathLengthLimit(30.0f); bool result = _path.CalculatePath(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ()); if (!result || _path.GetPathType().HasAnyFlag(PathType.NoPath)) { @@ -218,6 +223,11 @@ namespace Game.Movement return base.Update(owner, diff); } + public override MovementGeneratorType GetMovementGeneratorType() + { + return MovementGeneratorType.TimedFleeing; + } + TimeTracker _totalFleeTime; } } diff --git a/Source/Game/Movement/Generators/FollowMovementGenerator.cs b/Source/Game/Movement/Generators/FollowMovementGenerator.cs index 6b17082c5..3991ce78b 100644 --- a/Source/Game/Movement/Generators/FollowMovementGenerator.cs +++ b/Source/Game/Movement/Generators/FollowMovementGenerator.cs @@ -44,6 +44,7 @@ namespace Game.Movement { owner.AddUnitState(UnitState.Follow); UpdatePetSpeed(owner); + _path = null; } public bool Update(Unit owner, uint diff) diff --git a/Source/Game/Movement/Generators/MovementGenerators.cs b/Source/Game/Movement/Generators/MovementGenerators.cs index d8d38c36c..87d7d7979 100644 --- a/Source/Game/Movement/Generators/MovementGenerators.cs +++ b/Source/Game/Movement/Generators/MovementGenerators.cs @@ -55,14 +55,17 @@ namespace Game.Movement DoInitialize((T)owner); IsActive = true; } + public virtual void Finalize(Unit owner) { DoFinalize((T)owner); } + public virtual void Reset(Unit owner) { DoReset((T)owner); } + public virtual bool Update(Unit owner, uint diff) { return DoUpdate((T)owner, diff); diff --git a/Source/Game/Movement/Generators/RandomMovement.cs b/Source/Game/Movement/Generators/RandomMovement.cs index e5406058e..0835877fb 100644 --- a/Source/Game/Movement/Generators/RandomMovement.cs +++ b/Source/Game/Movement/Generators/RandomMovement.cs @@ -43,6 +43,7 @@ namespace Game.Movement _wanderDistance = owner.GetRespawnRadius(); _timer.Reset(0); + _path = null; } public override void DoReset(Creature owner) @@ -59,6 +60,7 @@ namespace Game.Movement { _interrupt = true; owner.StopMoving(); + _path = null; return true; } else @@ -87,6 +89,7 @@ namespace Game.Movement { _interrupt = true; owner.StopMoving(); + _path = null; return; } @@ -100,9 +103,11 @@ namespace Game.Movement uint resetTimer = RandomHelper.randChance(50) ? RandomHelper.URand(5000, 10000) : RandomHelper.URand(1000, 2000); if (_path == null) + { _path = new PathGenerator(owner); + _path.SetPathLengthLimit(30.0f); + } - _path.SetPathLengthLimit(30.0f); bool result = _path.CalculatePath(position.GetPositionX(), position.GetPositionY(), position.GetPositionZ()); if (!result || _path.GetPathType().HasAnyFlag(PathType.NoPath)) { diff --git a/Source/Game/Movement/Generators/WaypointMovement.cs b/Source/Game/Movement/Generators/WaypointMovement.cs index add5be7d4..fc3407f2c 100644 --- a/Source/Game/Movement/Generators/WaypointMovement.cs +++ b/Source/Game/Movement/Generators/WaypointMovement.cs @@ -257,7 +257,7 @@ namespace Game.Movement // check if there is a wait time for the next movement if (!_nextMoveTime.Passed()) { - // dont update wait timer while moving + // update timer since it's not moving _nextMoveTime.Update((int)diff); if (_nextMoveTime.Passed()) { @@ -268,7 +268,7 @@ namespace Game.Movement else // if it's not moving and there is no timer, assume node is reached { OnArrived(creature); // hooks and wait timer reset (if necessary) - _isArrivalDone = true; // signals that the next move will happen after reaching a node + _isArrivalDone = true; // signals to future StartMove that it reached a node if (_nextMoveTime.Passed()) StartMove(creature); // check path status, get next point and move if necessary & can diff --git a/Source/Game/Movement/MotionMaster.cs b/Source/Game/Movement/MotionMaster.cs index ba2763c60..7aa675501 100644 --- a/Source/Game/Movement/MotionMaster.cs +++ b/Source/Game/Movement/MotionMaster.cs @@ -35,7 +35,7 @@ namespace Game.Movement { _owner = me; _top = -1; - _cleanFlag = MMCleanFlag.None; + _cleanFlag = MotionMasterCleanFlag.None; for (byte i = 0; i < (int)MovementSlot.Max; ++i) { @@ -44,6 +44,12 @@ namespace Game.Movement } } + public IMovementGenerator Top() + { + Cypher.Assert(!Empty()); + return _slot[_top]; + } + public void Initialize() { while (!Empty()) @@ -61,7 +67,7 @@ namespace Game.Movement { if (_owner.IsTypeId(TypeId.Unit)) { - IMovementGenerator movement = AISelector.SelectMovementAI(_owner.ToCreature()); + IMovementGenerator movement = AISelector.SelectMovementAI(_owner); StartMovement(movement ?? staticIdleMovement, MovementSlot.Idle); } else @@ -75,14 +81,14 @@ namespace Game.Movement Cypher.Assert(!Empty()); - _cleanFlag |= MMCleanFlag.Update; + _cleanFlag |= MotionMasterCleanFlag.Update; if (!Top().Update(_owner, diff)) { - _cleanFlag &= ~MMCleanFlag.Update; + _cleanFlag &= ~MotionMasterCleanFlag.Update; MovementExpired(); } else - _cleanFlag &= ~MMCleanFlag.Update; + _cleanFlag &= ~MotionMasterCleanFlag.Update; if (!_expireList.Empty()) ClearExpireList(); @@ -90,12 +96,12 @@ namespace Game.Movement public void Clear(bool reset = true) { - if (Convert.ToBoolean(_cleanFlag & MMCleanFlag.Update)) + if (Convert.ToBoolean(_cleanFlag & MotionMasterCleanFlag.Update)) { if (reset) - _cleanFlag |= MMCleanFlag.Reset; + _cleanFlag |= MotionMasterCleanFlag.Reset; else - _cleanFlag &= ~MMCleanFlag.Reset; + _cleanFlag &= ~MotionMasterCleanFlag.Reset; DelayedClean(); } else @@ -107,7 +113,7 @@ namespace Game.Movement if (Empty() || slot >= MovementSlot.Max) return; - if (_cleanFlag.HasAnyFlag(MMCleanFlag.Update)) + if (_cleanFlag.HasAnyFlag(MotionMasterCleanFlag.Update)) DelayedClean(slot); else DirectClean(slot); @@ -115,12 +121,12 @@ namespace Game.Movement public void MovementExpired(bool reset = true) { - if (Convert.ToBoolean(_cleanFlag & MMCleanFlag.Update)) + if (Convert.ToBoolean(_cleanFlag & MotionMasterCleanFlag.Update)) { if (reset) - _cleanFlag |= MMCleanFlag.Reset; + _cleanFlag |= MotionMasterCleanFlag.Reset; else - _cleanFlag &= ~MMCleanFlag.Reset; + _cleanFlag &= ~MotionMasterCleanFlag.Reset; DelayedExpire(); } else @@ -130,7 +136,11 @@ namespace Game.Movement public MovementGeneratorType GetCurrentMovementGeneratorType() { if (Empty()) - return MovementGeneratorType.Idle; + return MovementGeneratorType.Max; + + IMovementGenerator movement = Top(); + if (movement == null) + return MovementGeneratorType.Max; return Top().GetMovementGeneratorType(); } @@ -654,7 +664,7 @@ namespace Game.Movement if (curr != null) { _slot[(int)slot] = null; // in case a new one is generated in this slot during directdelete - if (_top == (int)slot && Convert.ToBoolean(_cleanFlag & MMCleanFlag.Update)) + if (_top == (int)slot && Convert.ToBoolean(_cleanFlag & MotionMasterCleanFlag.Update)) DelayedDelete(curr); else DirectDelete(curr); @@ -794,27 +804,16 @@ namespace Game.Movement Initialize(); else if (NeedInitTop()) InitTop(); - else if (_cleanFlag.HasAnyFlag(MMCleanFlag.Reset)) + else if (_cleanFlag.HasAnyFlag(MotionMasterCleanFlag.Reset)) Top().Reset(_owner); - _cleanFlag &= ~MMCleanFlag.Reset; + _cleanFlag &= ~MotionMasterCleanFlag.Reset; } public bool Empty() { return (_top < 0); } int Size() { return _top + 1; } - public IMovementGenerator TopOrNull() - { - return Empty() ? null : Top(); - } - - public IMovementGenerator Top() - { - Cypher.Assert(!Empty()); - return _slot[_top]; - } - public static uint SplineId { get { return splineId++; } @@ -829,7 +828,7 @@ namespace Game.Movement Unit _owner { get; } IMovementGenerator[] _slot = new IMovementGenerator[(int)MovementSlot.Max]; - MMCleanFlag _cleanFlag; + MotionMasterCleanFlag _cleanFlag; bool[] _initialize = new bool[(int)MovementSlot.Max]; int _top; List _expireList = new(); @@ -841,7 +840,7 @@ namespace Game.Movement public ObjectGuid Target; } - enum MMCleanFlag + enum MotionMasterCleanFlag { None = 0, Update = 1, // Clear or Expire called from update