mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-22 18:15:31 +01:00
Core/Units: Fixed melee range check (#17693)
* Split Spell::CheckRange() into 2 methods since that method had more than one responsibility.
* Moved melee range logic into its own function
* Moved melee range logic method GetMeleeRange from Spell to Unit class. Unit::IsWithinMeleeRange() and Spell::GetMinMaxRange() both use that method.
(cherry picked from commit d7600f1126)
# Conflicts:
# src/server/game/Entities/Unit/Unit.cpp
# src/server/game/Entities/Unit/Unit.h
# src/server/game/Spells/Spell.cpp
This commit is contained in:
@@ -511,11 +511,17 @@ bool Unit::IsWithinMeleeRange(Unit const* obj) const
|
||||
float dz = GetPositionZMinusOffset() - obj->GetPositionZMinusOffset();
|
||||
float distsq = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
float maxdist = GetCombatReach() + obj->GetCombatReach() + 4.0f / 3.0f;
|
||||
float maxdist = GetMeleeRange(obj);
|
||||
|
||||
return distsq <= maxdist * maxdist;
|
||||
}
|
||||
|
||||
float Unit::GetMeleeRange(Unit const* target) const
|
||||
{
|
||||
float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f;
|
||||
return std::max(range, NOMINAL_MELEE_RANGE);
|
||||
}
|
||||
|
||||
bool Unit::IsWithinBoundaryRadius(const Unit* obj) const
|
||||
{
|
||||
if (!obj || !IsInMap(obj) || !IsInPhase(obj))
|
||||
|
||||
@@ -1386,6 +1386,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
float GetBoundaryRadius() const { return m_floatValues[UNIT_FIELD_BOUNDINGRADIUS]; }
|
||||
bool IsWithinCombatRange(const Unit* obj, float dist2compare) const;
|
||||
bool IsWithinMeleeRange(Unit const* obj) const;
|
||||
float GetMeleeRange(Unit const* target) const;
|
||||
bool IsWithinBoundaryRadius(const Unit* obj) const;
|
||||
void GetRandomContactPoint(const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const;
|
||||
uint32 m_extraAttacks;
|
||||
|
||||
@@ -5975,69 +5975,14 @@ SpellCastResult Spell::CheckRange(bool strict)
|
||||
if (!strict && m_casttime == 0)
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
Unit* target = m_targets.GetUnitTarget();
|
||||
float minRange = 0.0f;
|
||||
float maxRange = 0.0f;
|
||||
float rangeMod = 0.0f;
|
||||
if (strict && IsNextMeleeSwingSpell())
|
||||
maxRange = 100.0f;
|
||||
else if (m_spellInfo->RangeEntry)
|
||||
{
|
||||
if (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE)
|
||||
{
|
||||
rangeMod = m_caster->GetCombatReach() + 4.0f / 3.0f;
|
||||
if (target)
|
||||
rangeMod += target->GetCombatReach();
|
||||
else
|
||||
rangeMod += m_caster->GetCombatReach();
|
||||
|
||||
rangeMod = std::max(rangeMod, NOMINAL_MELEE_RANGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
float meleeRange = 0.0f;
|
||||
if (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED)
|
||||
{
|
||||
meleeRange = m_caster->GetCombatReach() + 4.0f / 3.0f;
|
||||
if (target)
|
||||
meleeRange += target->GetCombatReach();
|
||||
else
|
||||
meleeRange += m_caster->GetCombatReach();
|
||||
|
||||
meleeRange = std::max(meleeRange, NOMINAL_MELEE_RANGE);
|
||||
}
|
||||
|
||||
minRange = m_caster->GetSpellMinRangeForTarget(target, m_spellInfo) + meleeRange;
|
||||
maxRange = m_caster->GetSpellMaxRangeForTarget(target, m_spellInfo);
|
||||
|
||||
if (target || m_targets.GetCorpseTarget())
|
||||
{
|
||||
rangeMod = m_caster->GetCombatReach();
|
||||
if (target)
|
||||
rangeMod += target->GetCombatReach();
|
||||
|
||||
if (minRange > 0.0f && !(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED))
|
||||
minRange += rangeMod;
|
||||
}
|
||||
}
|
||||
|
||||
if (target && m_caster->isMoving() && target->isMoving() && !m_caster->IsWalking() && !target->IsWalking() &&
|
||||
(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE || target->GetTypeId() == TYPEID_PLAYER))
|
||||
rangeMod += 8.0f / 3.0f;
|
||||
}
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
if (Item* ranged = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK, true))
|
||||
maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f;
|
||||
|
||||
if (Player* modOwner = m_caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, this);
|
||||
|
||||
maxRange += rangeMod;
|
||||
float minRange, maxRange;
|
||||
std::tie(minRange, maxRange) = GetMinMaxRange(strict);
|
||||
|
||||
// get square values for sqr distance checks
|
||||
minRange *= minRange;
|
||||
maxRange *= maxRange;
|
||||
|
||||
Unit* target = m_targets.GetUnitTarget();
|
||||
if (target && target != m_caster)
|
||||
{
|
||||
if (m_caster->GetExactDistSq(target) > maxRange)
|
||||
@@ -6063,6 +6008,59 @@ SpellCastResult Spell::CheckRange(bool strict)
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
std::pair<float, float> Spell::GetMinMaxRange(bool strict)
|
||||
{
|
||||
float rangeMod = 0.0f;
|
||||
float minRange = 0.0f;
|
||||
float maxRange = 0.0f;
|
||||
if (strict && IsNextMeleeSwingSpell())
|
||||
{
|
||||
maxRange = 100.0f;
|
||||
return std::pair<float, float>(minRange, maxRange);
|
||||
}
|
||||
|
||||
if (m_spellInfo->RangeEntry)
|
||||
{
|
||||
Unit* target = m_targets.GetUnitTarget();
|
||||
if (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE)
|
||||
{
|
||||
rangeMod = m_caster->GetMeleeRange(target ? target : m_caster); // when the target is not a unit, take the caster's combat reach as the target's combat reach.
|
||||
}
|
||||
else
|
||||
{
|
||||
float meleeRange = 0.0f;
|
||||
if (m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED)
|
||||
meleeRange = m_caster->GetMeleeRange(target ? target : m_caster); // when the target is not a unit, take the caster's combat reach as the target's combat reach.
|
||||
|
||||
minRange = m_caster->GetSpellMinRangeForTarget(target, m_spellInfo) + meleeRange;
|
||||
maxRange = m_caster->GetSpellMaxRangeForTarget(target, m_spellInfo);
|
||||
|
||||
if (target || m_targets.GetCorpseTarget())
|
||||
{
|
||||
rangeMod = m_caster->GetCombatReach() + (target ? target->GetCombatReach() : m_caster->GetCombatReach());
|
||||
|
||||
if (minRange > 0.0f && !(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED))
|
||||
minRange += rangeMod;
|
||||
}
|
||||
}
|
||||
|
||||
if (target && m_caster->isMoving() && target->isMoving() && !m_caster->IsWalking() && !target->IsWalking() &&
|
||||
(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE || target->GetTypeId() == TYPEID_PLAYER))
|
||||
rangeMod += 8.0f / 3.0f;
|
||||
}
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR0_REQ_AMMO) && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
if (Item* ranged = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK, true))
|
||||
maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f;
|
||||
|
||||
if (Player* modOwner = m_caster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, this);
|
||||
|
||||
maxRange += rangeMod;
|
||||
|
||||
return std::pair<float, float>(minRange, maxRange);
|
||||
}
|
||||
|
||||
SpellCastResult Spell::CheckPower()
|
||||
{
|
||||
// item cast not used power
|
||||
|
||||
@@ -666,6 +666,7 @@ class TC_GAME_API Spell
|
||||
void CancelGlobalCooldown();
|
||||
|
||||
void SendLoot(ObjectGuid guid, LootType loottype);
|
||||
std::pair<float, float> GetMinMaxRange(bool strict);
|
||||
|
||||
Unit* const m_caster;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user