diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp index 9c2cde694..5291256a7 100644 --- a/src/server/game/Entities/Player/PlayerUpdates.cpp +++ b/src/server/game/Entities/Player/PlayerUpdates.cpp @@ -181,8 +181,8 @@ void Player::Update(uint32 p_time) m_swingErrorMsg = 1; } } - // 120 degrees of radiant range - else if (!HasInArc(2 * M_PI / 3, victim)) + // 120 degrees of radiant range, if player is not in boundary radius + else if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim)) { setAttackTimer(BASE_ATTACK, 100); if (m_swingErrorMsg != 2) // send single time (client auto repeat) @@ -211,8 +211,8 @@ void Player::Update(uint32 p_time) { if (!IsWithinMeleeRange(victim)) setAttackTimer(OFF_ATTACK, 100); - else if (!HasInArc(2 * M_PI / 3, victim)) - setAttackTimer(OFF_ATTACK, 100); + else if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim)) + setAttackTimer(BASE_ATTACK, 100); else { // prevent base and off attack in same time, delay attack at diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 5532033dd..318e50bf9 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -698,6 +698,16 @@ bool Unit::IsWithinRange(Unit const* obj, float dist) const return distsq <= dist * dist; } +bool Unit::IsWithinBoundaryRadius(const Unit* obj) const +{ + if (!obj || !IsInMap(obj) || !InSamePhase(obj)) + return false; + + float objBoundaryRadius = std::max(obj->GetBoundaryRadius(), MIN_MELEE_REACH); + + return IsInDist(obj, objBoundaryRadius); +} + bool Unit::GetRandomContactPoint(Unit const* obj, float& x, float& y, float& z, bool force) const { float combat_reach = GetCombatReach(); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index c5d655406..29344cb76 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -818,9 +818,11 @@ public: bool _IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) const; // Combat range + [[nodiscard]] float GetBoundaryRadius() const { return m_floatValues[UNIT_FIELD_BOUNDINGRADIUS]; } [[nodiscard]] float GetCombatReach() const override { return m_floatValues[UNIT_FIELD_COMBATREACH]; } [[nodiscard]] float GetMeleeReach() const { float reach = m_floatValues[UNIT_FIELD_COMBATREACH]; return reach > MIN_MELEE_REACH ? reach : MIN_MELEE_REACH; } [[nodiscard]] bool IsWithinRange(Unit const* obj, float dist) const; + bool IsWithinBoundaryRadius(const Unit* obj) const; bool IsWithinCombatRange(Unit const* obj, float dist2compare) const; bool IsWithinMeleeRange(Unit const* obj, float dist = 0.f) const; float GetMeleeRange(Unit const* target) const; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index a0f46e9a8..ca543c804 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -7126,7 +7126,7 @@ SpellCastResult Spell::CheckRange(bool strict) return SPELL_FAILED_TOO_CLOSE; } - if (m_caster->IsPlayer() && (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast(M_PI), target)) + if (m_caster->IsPlayer() && (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast(M_PI), target) && !m_caster->IsWithinBoundaryRadius(target)) return SPELL_FAILED_UNIT_NOT_INFRONT; } @@ -9129,7 +9129,7 @@ namespace Acore } else { - if (!_caster->isInFront(target, _coneAngle)) + if (!_caster->IsWithinBoundaryRadius(target->ToUnit()) && !_caster->isInFront(target, _coneAngle)) return false; } return WorldObjectSpellAreaTargetCheck::operator ()(target);