From 66d36839f092bb1016391a93b6b03733d1cd42bb Mon Sep 17 00:00:00 2001 From: Chaouki Dhib Date: Mon, 15 Aug 2016 18:17:07 +0200 Subject: [PATCH] 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 d7600f1126d2780fecdfcdfc66a598a48cee0136) # Conflicts: # src/server/game/Entities/Unit/Unit.cpp # src/server/game/Entities/Unit/Unit.h # src/server/game/Spells/Spell.cpp --- src/server/game/Entities/Unit/Unit.cpp | 8 +- src/server/game/Entities/Unit/Unit.h | 1 + src/server/game/Spells/Spell.cpp | 116 ++++++++++++------------- src/server/game/Spells/Spell.h | 1 + 4 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b0c89960fa8..abee8b5a8e1 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -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)) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 2ffb78a4fc8..0f379a7326a 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -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; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 45d681ac71a..0f5d7a13ce2 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -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 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(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(minRange, maxRange); +} + SpellCastResult Spell::CheckPower() { // item cast not used power diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 53a9de5436f..be4bed12718 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -666,6 +666,7 @@ class TC_GAME_API Spell void CancelGlobalCooldown(); void SendLoot(ObjectGuid guid, LootType loottype); + std::pair GetMinMaxRange(bool strict); Unit* const m_caster;