aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChaouki Dhib <chaodhib@gmail.com>2016-08-15 18:17:07 +0200
committerShauren <shauren.trinity@gmail.com>2016-08-15 18:17:07 +0200
commitd7600f1126d2780fecdfcdfc66a598a48cee0136 (patch)
tree4570f34a1732aa51aa384bef0f04b28e8463fc4b
parent4a38773e3e74af329aa13e2a506ef824f2a6e4d3 (diff)
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.
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp8
-rw-r--r--src/server/game/Entities/Unit/Unit.h1
-rw-r--r--src/server/game/Spells/Spell.cpp91
-rw-r--r--src/server/game/Spells/Spell.h1
4 files changed, 54 insertions, 47 deletions
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<float>(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<float, float> 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<float, float>(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<float>(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<float, float>(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<float, float> GetMinMaxRange(bool strict);
Unit* const m_caster;