diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index 1dd66d7699..8683884b25 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -350,6 +350,40 @@ void CreatureAI::SetBoundary(CreatureBoundary const* boundary, bool negateBounda me->DoImmediateBoundaryCheck(); } +bool CreatureAI::CheckMeleeRepositionRequirements() +{ + if (Unit* victim = me->GetVictim()) + { + Position victimPos = victim->GetPosition(); + + // If we are closer than 50% of the combat reach we are going to reposition ourself + // Dont call if we have more than one attacker because Circling Target will take place. + float reach = CalculatePct(me->GetCombatReach() + victim->GetCombatReach(), 50); + float moveDist = CalculatePct(me->GetCombatReach() + victim->GetCombatReach(), 100); + if (me->IsFreeToMove() && victim->getAttackers().size() == 1 && me->GetDistance(victimPos) < reach) + { + me->GetMotionMaster()->MoveBackwards(victim, moveDist); + return true; + } + } + return false; +} + +bool CreatureAI::CheckCircleRepositionRequirements() +{ + if (Unit* victim = me->GetVictim()) + { + Position victimPos = victim->GetPosition(); + + if (me->IsFreeToMove() && victim->getAttackers().size() > 1) + { + me->GetMotionMaster()->MoveCircleTarget(victim); + return true; + } + } + return false; +} + Creature* CreatureAI::DoSummon(uint32 entry, Position const& pos, uint32 despawnTime, TempSummonType summonType) { return me->SummonCreature(entry, pos, summonType, despawnTime); diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index d7cfec7b0b..25284740d3 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -226,6 +226,9 @@ class TC_GAME_API CreatureAI : public UnitAI static bool IsInBounds(CreatureBoundary const& boundary, Position const* who); bool IsInBoundary(Position const* who = nullptr) const; + bool CheckMeleeRepositionRequirements(); + bool CheckCircleRepositionRequirements(); + protected: virtual void MoveInLineOfSight(Unit* /*who*/); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 0ac2b3be02..6a0b813a15 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -779,6 +779,25 @@ void Creature::Update(uint32 diff) m_boundaryCheckTime -= diff; } + // Moving back from the target. + if (diff >= m_moveBackMovementTime) + { + AI()->CheckMeleeRepositionRequirements(); + m_moveBackMovementTime = MOVE_BACK_CHECK_INTERVAL; + } + else + m_moveBackMovementTime -= diff; + + // Circling the target. + if (diff >= m_moveCircleMovementTime) + { + AI()->CheckCircleRepositionRequirements(); + m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL; + } + else + m_moveCircleMovementTime -= diff; + + // if periodic combat pulse is enabled and we are both in combat and in a dungeon, do this now if (m_combatPulseDelay > 0 && IsEngaged() && GetMap()->IsDungeon()) { @@ -3272,3 +3291,15 @@ bool Creature::IsEscortNPC(bool onlyIfActive) return AI()->IsEscortNPC(onlyIfActive); } + +bool Creature::IsFreeToMove() +{ + uint32 moveFlags = m_movementInfo.GetMovementFlags(); + // Do not reposition ourself when we are not allowed to move + if ((IsMovementPreventedByCasting() || isMoving() || !CanFreeMove()) && + GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE || + moveFlags & MOVEMENTFLAG_SPLINE_ENABLED) + return false; + + return true; +} diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 23e567f733..ff1dde1039 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -348,6 +348,7 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma void ReleaseFocus(Spell const* focusSpell = nullptr, bool withDelay = true); bool IsMovementPreventedByCasting() const override; + bool IsFreeToMove(); // Part of Evade mechanics time_t GetLastDamagedTime() const { return _lastDamagedTime; } @@ -386,6 +387,11 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma uint32 m_combatPulseTime; // (msecs) remaining time for next zone-in-combat pulse uint32 m_combatPulseDelay; // (secs) how often the creature puts the entire zone in combat (only works in dungeons) + static constexpr uint32 MOVE_BACK_CHECK_INTERVAL = 3000; + static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000; + uint32 m_moveBackMovementTime = MOVE_BACK_CHECK_INTERVAL; + uint32 m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL; + ReactStates m_reactState; // for AI, not charmInfo void RegenerateHealth(); void Regenerate(Powers power); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 09f5ef01a5..1d39fd9cdc 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -287,6 +287,7 @@ bool DispelableAura::RollDispel() const return roll_chance_i(_chance); } + Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject), m_playerMovingMe(nullptr), m_lastSanctuaryTime(0), IsAIEnabled(false), NeedChangeAI(false), LastCharmerGUID(), m_ControlledByPlayer(false), @@ -294,7 +295,8 @@ Unit::Unit(bool isWorldObject) : m_AutoRepeatFirstCast(false), m_procDeep(0), m_removedAurasCount(0), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr), m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this), - m_threatManager(this), m_comboTarget(nullptr), m_comboPoints(0), m_spellHistory(new SpellHistory(this)) + m_threatManager(this), m_comboTarget(nullptr), m_comboPoints(0), m_spellHistory(new SpellHistory(this)), + m_attackPosition(NULL) { m_objectType |= TYPEMASK_UNIT; m_objectTypeId = TYPEID_UNIT; @@ -451,6 +453,16 @@ void Unit::Update(uint32 p_time) ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, HealthAbovePct(75)); } + if (_attackPointCheckTimer > p_time) + { + _attackPointCheckTimer -= p_time; + } + else + { + _attackPointCheckTimer = ATTACK_POINT_CHECK_INTERVAL; + SetMeleeAttackPoints(); + } + UpdateSplineMovement(p_time); i_motionMaster->Update(p_time); } @@ -554,6 +566,20 @@ bool Unit::IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const return distsq <= maxdist * maxdist; } +bool Unit::IsWithinRange(Unit const* obj, float dist) const +{ + if (!obj || !IsInMap(obj) || !InSamePhase(obj)) + return false; + + float dx = GetPositionX() - obj->GetPositionX(); + float dy = GetPositionY() - obj->GetPositionY(); + float dz = GetPositionZ() - obj->GetPositionZ(); + float distsq = dx * dx + dy * dy + dz * dz; + + return distsq <= dist * dist; +} + + float Unit::GetMeleeRange(Unit const* target) const { float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f; @@ -2005,7 +2031,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr if (GetTypeId() == TYPEID_UNIT && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED) && !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN)) SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells) - + // melee attack spell cast at main hand attack only - no normal melee dmg dealt if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra) m_currentSpells[CURRENT_MELEE_SPELL]->cast(); @@ -13501,3 +13527,91 @@ float Unit::GetCollisionHeight() const float const collisionHeight = scaleMod * modelData->CollisionHeight * modelData->Scale * displayInfo->scale; return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight; } + + +struct AttackDistance { + AttackDistance(uint8 index, AttackPosition attackPos) : _index(index), _attackPos(attackPos) {} + uint8 _index; + AttackPosition _attackPos; +}; + +void Unit::SetMeleeAttackPoints() +{ + if (getAttackers().size() <= 1) + { + return; + } + + // Delete the attack positions each iteration. + attackMeleePositions.clear(); + + // Calculate the attack positions. + // radius (Melee range unknown so use default). + float radius = MIN_MELEE_REACH; + uint8 attackPoints = getAttackers().size() * 3; + for (uint8 i = 0; i < attackPoints; ++i) + { + int8 anglePosition = ceil((i+1)/2) * ((i+1) % 2 ? -1 : 1); + float step = float(M_PI*2) / attackPoints; + Position const& pos = GetPosition(); + float angle = GetOrientation() + float(M_PI * 2) + (step * anglePosition); + //TC_LOG_DEBUG("server", "AttackPosition (z,y,z)=(%4.1f,%4.1f,%4.1f)", pos.m_positionX + radius * cosf(angle), pos.m_positionY + radius * sinf(angle), pos.m_positionZ); + attackMeleePositions.push_back(AttackPosition(Position(pos.m_positionX + radius * cosf(angle), pos.m_positionY + radius * sinf(angle), pos.m_positionZ))); + } + m_previousAttackerCount = getAttackers().size(); + m_previousPosition = GetPosition(); +} + +Position Unit::GetMeleeAttackPoint(Unit* attacker) +{ + if (getAttackers().size() <= 1) + return NULL; + + // If already on an attack Position and close to Target abort. + if (attacker->GetDistance(GetPosition()) < GetCombatReach() && !(attacker->m_attackPosition == NULL) && attacker->GetDistance(attacker->m_attackPosition._pos) < 0.25f) + return NULL; + attacker->m_attackPosition = NULL; + + // Get all the distances. + std::vector distances; + distances.reserve( attackMeleePositions.size()); + for (uint8 i = 0; i < attackMeleePositions.size(); ++i) + { + // If the spot has been taken. + if (!attackMeleePositions[i]._taken) + distances.push_back(AttackDistance(i,attackMeleePositions[i])); + } + + if (distances.size() == 0) + return NULL; + + // Get the shortest point. + uint8 shortestIndex = 0; + float shortestLength = 100.0f; + for (uint8 i = 0; i < distances.size(); ++i) + { + float dist = attacker->GetDistance2d(distances[i]._attackPos._pos.m_positionX, distances[i]._attackPos._pos.m_positionY); // +GetDistance(distances[i]._attackPos._pos); + //TC_LOG_DEBUG("server", "dist=(%4.1f)", dist); + if (shortestLength > dist) + { + shortestLength = dist; + shortestIndex = i; + } + } + //TC_LOG_DEBUG("server", "shortestLength=(%4.1f)", shortestLength); + + // Create closest Position. + Position closestPos(distances[shortestIndex]._attackPos._pos); + + // Too close mark point taken and find another spot. + for (uint8 i = 0; i < attackMeleePositions.size(); ++i) + { + float dist = closestPos.GetExactDist(attackMeleePositions[i]._pos); + //TC_LOG_DEBUG("server", "points_dist=(%4.1f)", dist); + if (dist < GetCombatReach()/2) + attackMeleePositions[i]._taken = true; + } + attacker->m_attackPosition = distances[shortestIndex]._attackPos; + + return closestPos; +} diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index dfd1c1e020..6bd4005951 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -702,6 +702,26 @@ struct TC_GAME_API CharmInfo float _stayZ; }; +struct AttackPosition { + AttackPosition(Position pos) : _pos(pos), _taken(false) {} + bool operator==(const int val) + { + return val == NULL; + }; + int operator=(const int val) + { + if (val == NULL) + { + _pos = NULL; + _taken = false; + return NULL; + } + return NULL; + }; + Position _pos; + bool _taken; +}; + // for clearing special attacks #define REACTIVE_TIMER_START 4000 @@ -789,6 +809,7 @@ class TC_GAME_API Unit : public WorldObject bool CanDualWield() const { return m_canDualWield; } virtual void SetCanDualWield(bool value) { m_canDualWield = value; } float GetCombatReach() const override { return m_floatValues[UNIT_FIELD_COMBATREACH]; } + bool IsWithinRange(Unit const* obj, float dist) const; bool IsWithinCombatRange(Unit const* obj, float dist2compare) const; bool IsWithinMeleeRange(Unit const* obj) const { return IsWithinMeleeRangeAt(GetPosition(), obj); } bool IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const; @@ -805,6 +826,10 @@ class TC_GAME_API Unit : public WorldObject bool AttackStop(); void RemoveAllAttackers(); AttackerSet const& getAttackers() const { return m_attackers; } + + void Unit::SetMeleeAttackPoints(); + Position GetMeleeAttackPoint(Unit* attacker); + bool isAttackingPlayer() const; Unit* GetVictim() const { return m_attacking; } // Use this only when 100% sure there is a victim @@ -1676,6 +1701,9 @@ class TC_GAME_API Unit : public WorldObject virtual void Whisper(uint32 textId, Player* target, bool isBossWhisper = false); float GetCollisionHeight() const override; + + AttackPosition getAttackPosition() { return m_attackPosition; } + protected: explicit Unit (bool isWorldObject); @@ -1756,6 +1784,10 @@ class TC_GAME_API Unit : public WorldObject virtual void AtEnterCombat() { } virtual void AtExitCombat(); + std::vector attackMeleePositions; + Position m_previousPosition; + uint8 m_previousAttackerCount; + AttackPosition m_attackPosition; private: void UpdateSplineMovement(uint32 t_diff); @@ -1799,6 +1831,9 @@ class TC_GAME_API Unit : public WorldObject bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed? SpellHistory* m_spellHistory; + + static constexpr uint32 ATTACK_POINT_CHECK_INTERVAL = 200; + uint32 _attackPointCheckTimer = ATTACK_POINT_CHECK_INTERVAL; }; namespace Trinity diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index ebccc6fa48..2712c85cf8 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -595,6 +595,54 @@ void MotionMaster::MoveChase(Unit* target, Optional dist, OptionalGetMeleeAttackPoint(_owner); + if (point == NULL) + return; + + if (_owner->IsFlying()) + ; // Dont do anything yet might add later. + else + point.m_positionZ = _owner->GetMapHeight(point.m_positionX, point.m_positionY, point.m_positionZ); + + Movement::MoveSplineInit init(_owner); + init.MoveTo(point.m_positionX, point.m_positionY, point.m_positionZ, true, true); + init.SetFacing(target); + init.Launch(); +} + +void MotionMaster::MoveBackwards(Unit* target, float dist) +{ + if (!target) + return; + + //TC_LOG_DEBUG("server", "MoveBackwards"); + + Position const& pos = target->GetPosition(); + float angle = pos.GetOrientation() + (M_PI*2); + G3D::Vector3 point; + point.x = pos.m_positionX + dist * cosf(angle); + point.y = pos.m_positionY + dist * sinf(angle); + point.z = pos.m_positionZ; + + //if (_owner->IsFlying()) + // point.z = pos.m_positionZ; + //else + // point.z = _owner->GetMapHeight(point.x, point.y, point.z); + + Movement::MoveSplineInit init(_owner); + init.MoveTo(point.x, point.y, point.z); + init.SetFacing(target); + init.SetBackward(); + init.Launch(); +} + void MotionMaster::MoveConfused() { if (_owner->GetTypeId() == TYPEID_PLAYER) diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 3be8d735a2..592fec1c92 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -142,6 +142,8 @@ class TC_GAME_API MotionMaster void MoveFollow(Unit* target, float dist, ChaseAngle angle, MovementSlot slot = MOTION_SLOT_ACTIVE); void MoveChase(Unit* target, Optional dist = {}, Optional angle = {}); void MoveChase(Unit* target, float dist, float angle = 0.0f) { MoveChase(target, Optional(dist), Optional(angle)); } + void MoveCircleTarget(Unit* target); + void MoveBackwards(Unit* target, float dist); void MoveConfused(); void MoveFleeing(Unit* enemy, uint32 time = 0); void MovePoint(uint32 id, Position const& pos, bool generatePath = true, Optional finalOrient = {}); diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp index f83c7e8b16..f6554e932a 100644 --- a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp @@ -73,7 +73,7 @@ void ChaseMovementGenerator::Initialize(Unit* owner) owner->SetWalk(false); _path = nullptr; - _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); + //_lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); } void ChaseMovementGenerator::Reset(Unit* owner) @@ -121,7 +121,8 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff) else { _rangeCheckTimer = RANGE_CHECK_INTERVAL; - if (PositionOkay(owner, target, _movingTowards ? Optional() : minTarget, _movingTowards ? maxTarget : Optional(), angle)) + if (PositionOkay(owner, target, _movingTowards ? Optional() : minTarget, _movingTowards ? maxTarget : Optional(), angle) && + owner->getAttackPosition() == NULL) { _path = nullptr; owner->StopMoving(); @@ -141,73 +142,100 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff) DoMovementInform(owner, target); } - // if the target moved, we have to consider whether to adjust - if (_lastTargetPosition != target->GetPosition() || mutualChase != _mutualChase) + //if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE)) + //{ + if (_pathCheckTimer > diff) { - _lastTargetPosition = target->GetPosition(); - _mutualChase = mutualChase; - if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) || !PositionOkay(owner, target, minRange, maxRange, angle)) + _pathCheckTimer -= diff; + return true; + } + else + { + _pathCheckTimer = PATH_CHECK_INTERVAL; + } + //} + + if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) || !PositionOkay(owner, target, minRange, maxRange, angle)) + { + Creature* const cOwner = owner->ToCreature(); + // can we get to the target? + if (cOwner && !target->isInAccessiblePlaceFor(cOwner)) { - Creature* const cOwner = owner->ToCreature(); - // can we get to the target? - if (cOwner && !target->isInAccessiblePlaceFor(cOwner)) - { - cOwner->SetCannotReachTarget(true); - cOwner->StopMoving(); - _path = nullptr; - return true; - } + cOwner->SetCannotReachTarget(true); + cOwner->StopMoving(); + _path = nullptr; + return true; + } - // figure out which way we want to move - bool const moveToward = !owner->IsInDist(target, maxRange); + // Fan Creatures around target if there are more than one. + Unit * target = GetTarget(); + int chaserCount = target->getAttackers().size(); + // Only start fanning if its within a certain distance. + if (chaserCount > 1) + { + owner->GetMotionMaster()->MoveCircleTarget(target); + return true; + } - // make a new path if we have to... - if (!_path || moveToward != _movingTowards) - _path = std::make_unique(owner); + // figure out which way we want to move + bool const moveToward = !owner->IsInDist(target, maxRange); - float x, y, z; - bool shortenPath; - // if we want to move toward the target and there's no fixed angle... - if (moveToward && !angle) - { - // ...we'll pathfind to the center, then shorten the path - target->GetPosition(x, y, z); - shortenPath = true; - } - else - { - // otherwise, we fall back to nearpoint finding - target->GetNearPoint(owner, x, y, z, (moveToward ? maxTarget : minTarget) - hitboxSum, angle ? target->ToAbsoluteAngle(angle->RelativeAngle) : target->GetAbsoluteAngle(owner)); - shortenPath = false; - } + // make a new path if we have to... + if (!_path || moveToward != _movingTowards) + _path = std::make_unique(owner); - if (owner->IsHovering()) - owner->UpdateAllowedPositionZ(x, y, z); + float x, y, z; + bool shortenPath; + // if we want to move toward the target and there's no fixed angle... + if (moveToward && !angle) + { + // ...we'll pathfind to the center, then shorten the path + target->GetPosition(x, y, z); + shortenPath = true; + } + else + { + // otherwise, we fall back to nearpoint finding + target->GetNearPoint(owner, x, y, z, (moveToward ? maxTarget : minTarget) - hitboxSum, angle ? target->ToAbsoluteAngle(angle->RelativeAngle) : target->GetAbsoluteAngle(owner)); + shortenPath = false; + } - bool success = _path->CalculatePath(x, y, z); - if (!success || (_path->GetPathType() & PATHFIND_NOPATH)) - { - if (cOwner) - cOwner->SetCannotReachTarget(true); - owner->StopMoving(); - return true; - } + if (owner->IsHovering()) + owner->UpdateAllowedPositionZ(x, y, z); - if (shortenPath) - _path->ShortenPathUntilDist(PositionToVector3(target), maxTarget); + bool success = _path->CalculatePath(x, y, z); + // Special case where Enemy cant get close to player to Melee because of height difference. + float floorZ; + bool canReach = true; + if (target && target->IsFlying() && !owner->IsFlying()) + { + target->UpdateAllowedPositionZ(_path->GetEndPosition().x, _path->GetEndPosition().y, floorZ); + if (abs(floorZ - _path->GetStartPosition().z) > MELEE_RANGE) + canReach = false; + } + + if ((!success || (!canReach && success)) || (_path->GetPathType() & PATHFIND_NOPATH)) + { if (cOwner) - cOwner->SetCannotReachTarget(false); + cOwner->SetCannotReachTarget(true); + owner->StopMoving(); + return true; + } + + if (shortenPath) + _path->ShortenPathUntilDist(PositionToVector3(target), maxTarget); - owner->AddUnitState(UNIT_STATE_CHASE_MOVE); + if (cOwner) + cOwner->SetCannotReachTarget(false); - Movement::MoveSplineInit init(owner); - init.MovebyPath(_path->GetPath()); - init.SetWalk(false); - init.SetFacing(target); + owner->AddUnitState(UNIT_STATE_CHASE_MOVE); - init.Launch(); - } + Movement::MoveSplineInit moveSplineInit(owner); + moveSplineInit.MovebyPath(_path->GetPath()); + moveSplineInit.SetWalk(false); + moveSplineInit.SetFacing(target); + moveSplineInit.Launch(); } // and then, finally, we're done for the tick diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h index 48d828b760..aef1a9c166 100644 --- a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h @@ -40,19 +40,21 @@ class ChaseMovementGenerator : public MovementGenerator, public AbstractFollower void Finalize(Unit*, bool, bool) override; MovementGeneratorType GetMovementGeneratorType() const override { return CHASE_MOTION_TYPE; } - void UnitSpeedChanged() override { _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); } + //void UnitSpeedChanged() override { _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); } private: - static constexpr uint32 RANGE_CHECK_INTERVAL = 100; // time (ms) until we attempt to recalculate + static constexpr uint32 RANGE_CHECK_INTERVAL = 500; // time (ms) until we attempt to recalculate + static constexpr uint32 PATH_CHECK_INTERVAL = 500; Optional const _range; Optional const _angle; std::unique_ptr _path; - Position _lastTargetPosition; + //Position _lastTargetPosition; uint32 _rangeCheckTimer = RANGE_CHECK_INTERVAL; + uint32 _pathCheckTimer = PATH_CHECK_INTERVAL; bool _movingTowards = true; - bool _mutualChase = true; + //bool _mutualChase = true; }; #endif