diff options
| author | Chaouki Dhib <chaodhib@gmail.com> | 2017-03-23 00:43:04 +0100 |
|---|---|---|
| committer | funjoker <funjoker109@gmail.com> | 2020-04-24 17:18:49 +0200 |
| commit | 5d076cfe291980bc5be9d44ffbae887e3dd5ad59 (patch) | |
| tree | ac91fc74a4643ce7c1a525c2739af2dcfa3f05ed /src/server/game/Spells | |
| parent | b8b6fd9ca0defda540f122bedf5f187d45bc11c7 (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.cpp | 10 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 37 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 20 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 29 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellInfo.h | 1 |
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; |
