From d7600f1126d2780fecdfcdfc66a598a48cee0136 Mon Sep 17 00:00:00 2001 From: Chaouki Dhib Date: Mon, 15 Aug 2016 18:17:07 +0200 Subject: 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. --- src/server/game/Entities/Unit/Unit.cpp | 8 ++- src/server/game/Entities/Unit/Unit.h | 1 + src/server/game/Spells/Spell.cpp | 91 +++++++++++++++++----------------- src/server/game/Spells/Spell.h | 1 + 4 files changed, 54 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index a3e20b7c07d..80f2531e223 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -485,11 +485,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); +} + void Unit::GetRandomContactPoint(const Unit* obj, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const { float combat_reach = GetCombatReach(); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 4589ec9a180..5162d2398c3 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1291,6 +1291,7 @@ class TC_GAME_API Unit : public WorldObject float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; } bool IsWithinCombatRange(const Unit* obj, float dist2compare) const; bool IsWithinMeleeRange(Unit const* obj) const; + float GetMeleeRange(Unit const* target) const; void GetRandomContactPoint(const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const; uint32 m_extraAttacks; bool m_canDualWield; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 5e58a602a43..8fc8282b549 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5831,46 +5831,69 @@ SpellCastResult Spell::CheckRange(bool strict) if (!strict && m_casttime == 0) return SPELL_CAST_OK; + 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) + return SPELL_FAILED_OUT_OF_RANGE; + + if (minRange > 0.0f && m_caster->GetExactDistSq(target) < minRange) + return SPELL_FAILED_OUT_OF_RANGE; + + if (m_caster->GetTypeId() == TYPEID_PLAYER && + (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast(M_PI), target)) + return SPELL_FAILED_UNIT_NOT_INFRONT; + } + + if (m_targets.HasDst() && !m_targets.HasTraj()) + { + if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange) + return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; + if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange) + return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; + } + + return SPELL_CAST_OK; +} + +std::pair Spell::GetMinMaxRange(bool strict) +{ + float rangeMod = 0.0f; float minRange = 0.0f; float maxRange = 0.0f; - float rangeMod = 0.0f; if (strict && IsNextMeleeSwingSpell()) + { maxRange = 100.0f; - else if (m_spellInfo->RangeEntry) + return std::pair(minRange, maxRange); + } + + if (m_spellInfo->RangeEntry) { + Unit* target = m_targets.GetUnitTarget(); if (m_spellInfo->RangeEntry->type & 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); + 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->type & 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); - } + 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(); - if (target) - rangeMod += target->GetCombatReach(); + rangeMod = m_caster->GetCombatReach() + (target ? target->GetCombatReach() : m_caster->GetCombatReach()); + if (minRange > 0.0f && !(m_spellInfo->RangeEntry->type & SPELL_RANGE_RANGED)) minRange += rangeMod; @@ -5891,31 +5914,7 @@ SpellCastResult Spell::CheckRange(bool strict) maxRange += rangeMod; - minRange *= minRange; - maxRange *= maxRange; - - if (target && target != m_caster) - { - if (m_caster->GetExactDistSq(target) > maxRange) - return SPELL_FAILED_OUT_OF_RANGE; - - if (minRange > 0.0f && m_caster->GetExactDistSq(target) < minRange) - return SPELL_FAILED_OUT_OF_RANGE; - - if (m_caster->GetTypeId() == TYPEID_PLAYER && - (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast(M_PI), target)) - return SPELL_FAILED_UNIT_NOT_INFRONT; - } - - if (m_targets.HasDst() && !m_targets.HasTraj()) - { - if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange) - return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; - if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange) - return !(_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_OUT_OF_RANGE : SPELL_FAILED_DONT_REPORT; - } - - return SPELL_CAST_OK; + return std::pair(minRange, maxRange); } SpellCastResult Spell::CheckPower() diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 46384fc54ec..c834d187720 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -507,6 +507,7 @@ class TC_GAME_API Spell void CancelGlobalCooldown(); void SendLoot(ObjectGuid guid, LootType loottype); + std::pair GetMinMaxRange(bool strict); Unit* const m_caster; -- cgit v1.2.3