aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Spells
diff options
context:
space:
mode:
authorChaouki Dhib <chaodhib@gmail.com>2017-03-23 00:43:04 +0100
committerfunjoker <funjoker109@gmail.com>2020-04-24 17:18:49 +0200
commit5d076cfe291980bc5be9d44ffbae887e3dd5ad59 (patch)
treeac91fc74a4643ce7c1a525c2739af2dcfa3f05ed /src/server/game/Spells
parentb8b6fd9ca0defda540f122bedf5f187d45bc11c7 (diff)
Core/Spells: fix wrong distance calculations in AoE spells [Needs testing] (#16290)
Core/Spells: Fix wrong distance calculations in AoE spells. Pull request #16290 by chaodhib. God bless, finally. (cherry picked from commit a1f2f30c145f6ad9c4baeffeff32618e71ff537c)
Diffstat (limited to 'src/server/game/Spells')
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp10
-rw-r--r--src/server/game/Spells/Spell.cpp37
-rw-r--r--src/server/game/Spells/SpellEffects.cpp20
-rw-r--r--src/server/game/Spells/SpellInfo.cpp29
-rw-r--r--src/server/game/Spells/SpellInfo.h1
5 files changed, 72 insertions, 25 deletions
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 074da315ad3..175959a15d4 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -2312,7 +2312,7 @@ void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* c
case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
{
units.push_back(GetUnitOwner());
- Trinity::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, effect->Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS));
+ Trinity::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, effect->Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS), false, true);
Trinity::UnitListSearcher<Trinity::AnyGroupedUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
break;
@@ -2320,14 +2320,14 @@ void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit* c
case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
{
units.push_back(GetUnitOwner());
- Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS));
+ Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS), false, true);
Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
{
- Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo); // No GetCharmer in searcher
+ Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo, false, true); // No GetCharmer in searcher
Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), units, u_check);
Cell::VisitAllObjects(GetUnitOwner(), searcher, radius);
break;
@@ -2396,13 +2396,13 @@ void DynObjAura::FillTargetMap(std::unordered_map<Unit*, uint32>& targets, Unit*
if (effect->TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY
|| effect->TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY)
{
- Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS));
+ Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS), false, true);
Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check);
Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius);
}
else
{
- Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
+ Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, nullptr, false, true);
Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetDynobjOwner(), units, u_check);
Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius);
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 8ef877e6881..779b0d0495c 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1245,6 +1245,11 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge
if (!effect)
return;
float radius = effect->CalcRadius(m_caster) * m_spellValue->RadiusMod;
+
+ // if this is a proximity based aoe (Frost Nova, Psychic Scream, ...), include the caster's own combat reach
+ if (targetType.IsProximityBasedAoe())
+ radius += GetCaster()->GetCombatReach();
+
SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), effect->ImplicitTargetConditions);
CallScriptObjectAreaTargetSelectHandlers(targets, effIndex, targetType);
@@ -1300,7 +1305,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
float dist = frand(minDist, maxDist);
float x, y, z;
float angle = float(rand_norm()) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
- m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dist, angle);
+ m_caster->GetClosePoint(x, y, z, DEFAULT_PLAYER_BOUNDING_RADIUS, dist, angle);
float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseShift(), x, y, z, true, 50.0f);
float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
@@ -1333,7 +1338,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
{
float dist = effect->CalcRadius(m_caster);
float angle = targetType.CalcDirectionAngle();
- float objSize = m_caster->GetObjectSize();
+ float objSize = m_caster->GetCombatReach();
switch (targetType.GetTarget())
{
@@ -1391,7 +1396,7 @@ void Spell::SelectImplicitTargetDestTargets(SpellEffIndex effIndex, SpellImplici
if (SpellEffectInfo const* effect = GetEffect(effIndex))
{
float angle = targetType.CalcDirectionAngle();
- float objSize = target->GetObjectSize();
+ float objSize = target->GetCombatReach();
float dist = effect->CalcRadius(m_caster);
if (dist < objSize)
dist = objSize;
@@ -1615,7 +1620,7 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge
}
}
- const float size = std::max((*itr)->GetObjectSize(), 1.0f);
+ const float size = std::max((*itr)->GetCombatReach(), 1.0f);
const float objDist2d = srcPos.GetExactDist2d(*itr);
const float dz = (*itr)->GetPositionZ() - srcPos.m_positionZ;
@@ -5300,13 +5305,13 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (!target->IsWithinLOSInMap(m_caster)) //Do full LoS/Path check. Don't exclude m2
return SPELL_FAILED_LINE_OF_SIGHT;
- float objSize = target->GetObjectSize();
+ float objSize = target->GetCombatReach();
float range = m_spellInfo->GetMaxRange(true, m_caster, this) * 1.5f + objSize; // can't be overly strict
m_preGeneratedPath = Trinity::make_unique<PathGenerator>(m_caster);
m_preGeneratedPath->SetPathLengthLimit(range);
// first try with raycast, if it fails fall back to normal path
- float targetObjectSize = std::min(target->GetObjectSize(), 4.0f);
+ float targetObjectSize = std::min(target->GetCombatReach(), 4.0f);
bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + targetObjectSize, false, true);
if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT)
return SPELL_FAILED_OUT_OF_RANGE;
@@ -7895,8 +7900,20 @@ WorldObjectSpellAreaTargetCheck::WorldObjectSpellAreaTargetCheck(float range, Po
bool WorldObjectSpellAreaTargetCheck::operator()(WorldObject* target)
{
- if (!target->IsWithinDist3d(_position, _range) && !(target->ToGameObject() && target->ToGameObject()->IsInRange(_position->GetPositionX(), _position->GetPositionY(), _position->GetPositionZ(), _range)))
- return false;
+ if (target->ToGameObject())
+ {
+ // isInRange including the dimension of the GO
+ bool isInRange = target->ToGameObject()->IsInRange(_position->GetPositionX(), _position->GetPositionY(), _position->GetPositionZ(), _range);
+ if (!isInRange)
+ return false;
+ }
+ else
+ {
+ bool isInsideCylinder = target->IsWithinDist2d(_position, _range) && std::abs(target->GetPositionZ() - _position->GetPositionZ()) <= _range;
+ if (!isInsideCylinder)
+ return false;
+ }
+
return WorldObjectSpellTargetCheck::operator ()(target);
}
@@ -7913,7 +7930,7 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target)
}
else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE))
{
- if (!_caster->HasInLine(target, target->GetObjectSize(), _caster->GetObjectSize()))
+ if (!_caster->HasInLine(target, target->GetCombatReach(), _caster->GetCombatReach()))
return false;
}
else
@@ -7933,7 +7950,7 @@ WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Po
bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target)
{
// return all targets on missile trajectory (0 - size of a missile)
- if (!_caster->HasInLine(target, target->GetObjectSize(), TRAJECTORY_MISSILE_SIZE))
+ if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE))
return false;
if (target->GetExactDist2d(_position) > _range)
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 74148998c51..e370f558d4b 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -2306,7 +2306,7 @@ void Spell::EffectTeleUnitsFaceCaster(SpellEffIndex /*effIndex*/)
float dis = effectInfo->CalcRadius(m_caster);
float fx, fy, fz;
- m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetObjectSize(), dis);
+ m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetCombatReach(), dis);
unitTarget->NearTeleportTo(fx, fy, fz, -m_caster->GetOrientation(), unitTarget == m_caster);
}
@@ -2659,7 +2659,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex)
//OldSummon->GetMap()->Remove(OldSummon->ToCreature(), false);
float px, py, pz;
- owner->GetClosePoint(px, py, pz, OldSummon->GetObjectSize());
+ owner->GetClosePoint(px, py, pz, OldSummon->GetCombatReach());
OldSummon->NearTeleportTo(px, py, pz, OldSummon->GetOrientation());
//OldSummon->Relocate(px, py, pz, OldSummon->GetOrientation());
@@ -2679,7 +2679,7 @@ void Spell::EffectSummonPet(SpellEffIndex effIndex)
}
float x, y, z;
- owner->GetClosePoint(x, y, z, owner->GetObjectSize());
+ owner->GetClosePoint(x, y, z, owner->GetCombatReach());
Pet* pet = owner->SummonPet(petentry, x, y, z, owner->GetOrientation(), SUMMON_PET, 0);
if (!pet)
return;
@@ -3041,7 +3041,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex)
if (m_targets.HasDst())
destTarget->GetPosition(x, y, z);
else
- m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
+ m_caster->GetClosePoint(x, y, z, DEFAULT_PLAYER_BOUNDING_RADIUS);
Map* map = target->GetMap();
Position pos = Position(x, y, z, target->GetOrientation());
@@ -3922,7 +3922,7 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex)
destTarget->GetPosition(x, y, z);
// Summon in random point all other units if location present
else
- m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE);
+ m_caster->GetClosePoint(x, y, z, DEFAULT_PLAYER_BOUNDING_RADIUS);
Map* map = m_caster->GetMap();
Position pos = Position(x, y, z, m_caster->GetOrientation());
@@ -4219,7 +4219,7 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
if (m_preGeneratedPath->GetPathType() == PATHFIND_BLANK)
{
//unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
- Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster));
+ Position pos = unitTarget->GetFirstCollisionPosition(unitTarget->GetCombatReach(), unitTarget->GetRelativeAngle(m_caster));
if (G3D::fuzzyGt(m_spellInfo->Speed, 0.0f) && m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION))
speed = pos.GetExactDist(m_caster) / speed;
@@ -4493,7 +4493,7 @@ void Spell::EffectResurrectPet(SpellEffIndex /*effIndex*/)
// Reposition the pet's corpse before reviving so as not to grab aggro
// We can use a different, more accurate version of GetClosePoint() since we have a pet
float x, y, z; // Will be used later to reposition the pet if we have one
- player->GetClosePoint(x, y, z, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle());
+ player->GetClosePoint(x, y, z, pet->GetCombatReach(), PET_FOLLOW_DIST, pet->GetFollowAngle());
pet->NearTeleportTo(x, y, z, player->GetOrientation());
pet->Relocate(x, y, z, player->GetOrientation()); // This is needed so SaveStayPosition() will get the proper coords.
}
@@ -4656,7 +4656,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex)
else if (effectInfo->HasRadius() && m_spellInfo->Speed == 0)
{
float dis = effectInfo->CalcRadius(m_originalCaster);
- m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis);
+ m_caster->GetClosePoint(fx, fy, fz, DEFAULT_PLAYER_BOUNDING_RADIUS, dis);
}
else
{
@@ -4665,7 +4665,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex)
float max_dis = m_spellInfo->GetMaxRange(true);
float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis;
- m_caster->GetClosePoint(fx, fy, fz, DEFAULT_WORLD_OBJECT_SIZE, dis);
+ m_caster->GetClosePoint(fx, fy, fz, DEFAULT_PLAYER_BOUNDING_RADIUS, dis);
}
Map* cMap = m_caster->GetMap();
@@ -5076,7 +5076,7 @@ void Spell::EffectCreateTamedPet(SpellEffIndex /*effIndex*/)
// relocate
float px, py, pz;
- unitTarget->GetClosePoint(px, py, pz, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle());
+ unitTarget->GetClosePoint(px, py, pz, pet->GetCombatReach(), PET_FOLLOW_DIST, pet->GetFollowAngle());
pet->Relocate(px, py, pz, unitTarget->GetOrientation());
// add to world
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 3266343d8b3..12eb37b6861 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -75,6 +75,35 @@ bool SpellImplicitTargetInfo::IsArea() const
return GetSelectionCategory() == TARGET_SELECT_CATEGORY_AREA || GetSelectionCategory() == TARGET_SELECT_CATEGORY_CONE;
}
+bool SpellImplicitTargetInfo::IsProximityBasedAoe() const
+{
+ switch (_target)
+ {
+ case TARGET_UNIT_SRC_AREA_ENTRY:
+ case TARGET_UNIT_SRC_AREA_ENEMY:
+ case TARGET_UNIT_CASTER_AREA_PARTY:
+ case TARGET_UNIT_SRC_AREA_ALLY:
+ case TARGET_UNIT_SRC_AREA_PARTY:
+ case TARGET_UNIT_LASTTARGET_AREA_PARTY:
+ case TARGET_GAMEOBJECT_SRC_AREA:
+ case TARGET_UNIT_CASTER_AREA_RAID:
+ case TARGET_CORPSE_SRC_AREA_ENEMY:
+ return true;
+
+ case TARGET_UNIT_DEST_AREA_ENTRY:
+ case TARGET_UNIT_DEST_AREA_ENEMY:
+ case TARGET_UNIT_DEST_AREA_ALLY:
+ case TARGET_UNIT_DEST_AREA_PARTY:
+ case TARGET_GAMEOBJECT_DEST_AREA:
+ case TARGET_UNIT_TARGET_AREA_RAID_CLASS:
+ return false;
+
+ default:
+ TC_LOG_WARN("spells", "SpellImplicitTargetInfo::IsProximityBasedAoe called a non-aoe spell");
+ return false;
+ }
+}
+
SpellTargetSelectionCategories SpellImplicitTargetInfo::GetSelectionCategory() const
{
return _data[_target].SelectionCategory;
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index d663c2359f0..e4b8709308b 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -286,6 +286,7 @@ public:
SpellImplicitTargetInfo(uint32 target);
bool IsArea() const;
+ bool IsProximityBasedAoe() const;
SpellTargetSelectionCategories GetSelectionCategory() const;
SpellTargetReferenceTypes GetReferenceType() const;
SpellTargetObjectTypes GetObjectType() const;