diff options
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 170 |
1 files changed, 60 insertions, 110 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 4ea9982ae35..29940ca1b06 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -512,7 +512,7 @@ SpellValue::SpellValue(SpellInfo const* proto) Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID, bool skipCheck) : m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)), m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster) -, m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster)) +, m_spellValue(new SpellValue(m_spellInfo)), _spellEvent(nullptr), m_preGeneratedPath(PathGenerator(m_caster)) { m_customError = SPELL_CUSTOM_ERROR_NONE; m_skipCheck = skipCheck; @@ -801,21 +801,35 @@ void Spell::SelectSpellTargets() } } + if (uint64 dstDelay = CalculateDelayMomentForDst()) + m_delayMoment = dstDelay; +} + +uint64 Spell::CalculateDelayMomentForDst() const +{ if (m_targets.HasDst()) { if (m_targets.HasTraj()) { float speed = m_targets.GetSpeedXY(); if (speed > 0.0f) - m_delayMoment = (uint64)floor(m_targets.GetDist2d() / speed * 1000.0f); + return (uint64)floor(m_targets.GetDist2d() / speed * 1000.0f); } else if (m_spellInfo->Speed > 0.0f) { // We should not subtract caster size from dist calculation (fixes execution time desync with animation on client, eg. Malleable Goo cast by PP) float dist = m_caster->GetExactDist(*m_targets.GetDstPos()); - m_delayMoment = (uint64) std::floor(dist / m_spellInfo->Speed * 1000.0f); + return (uint64)std::floor(dist / m_spellInfo->Speed * 1000.0f); } } + + return 0; +} + +void Spell::RecalculateDelayMomentForDst() +{ + m_delayMoment = CalculateDelayMomentForDst(); + m_caster->m_Events.ModifyEventTime(_spellEvent, GetDelayStart() + m_delayMoment); } void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, uint32& processedEffectMask) @@ -868,6 +882,12 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar case TARGET_SELECT_CATEGORY_AREA: SelectImplicitAreaTargets(effIndex, targetType, effectMask); break; + case TARGET_SELECT_CATEGORY_TRAJ: + // just in case there is no dest, explanation in SelectImplicitDestDestTargets + CheckDst(); + + SelectImplicitTrajTargets(effIndex, targetType); + break; case TARGET_SELECT_CATEGORY_DEFAULT: switch (targetType.GetObjectType()) { @@ -1378,9 +1398,6 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT case TARGET_DEST_DYNOBJ_NONE: case TARGET_DEST_DEST: return; - case TARGET_DEST_TRAJ: - SelectImplicitTrajTargets(effIndex); - return; default: { float angle = targetType.CalcDirectionAngle(); @@ -1506,9 +1523,7 @@ float tangent(float x) return 0.0f; } -#define DEBUG_TRAJ(a) //a - -void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex) +void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType) { if (!m_targets.HasTraj()) return; @@ -1517,12 +1532,14 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex) if (!dist2d) return; - float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - m_targets.GetSrcPos()->m_positionZ; + Position srcPos = *m_targets.GetSrcPos(); + srcPos.SetOrientation(m_caster->GetOrientation()); + float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - srcPos.m_positionZ; std::list<WorldObject*> targets; - Trinity::WorldObjectSpellTrajTargetCheck check(dist2d, m_targets.GetSrcPos(), m_caster, m_spellInfo); + Trinity::WorldObjectSpellTrajTargetCheck check(dist2d, &srcPos, m_caster, m_spellInfo, targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions); Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> searcher(m_caster, targets, check, GRID_MAP_TYPE_MASK_ALL); - SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, m_targets.GetSrcPos(), dist2d); + SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, &srcPos, dist2d); if (targets.empty()) return; @@ -1532,16 +1549,16 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex) float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d); if (a > -0.0001f) a = 0; - DEBUG_TRAJ(TC_LOG_ERROR("spells", "Spell::SelectTrajTargets: a %f b %f", a, b);) + // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range) + // limit max range to 300 yards, sometimes triggered spells can have 50000yds float bestDist = m_spellInfo->GetMaxRange(false); + if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[effIndex].TriggerSpell)) + bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f)); std::list<WorldObject*>::const_iterator itr = targets.begin(); for (; itr != targets.end(); ++itr) { - if (!m_caster->HasInLine(*itr, 5.0f)) - continue; - if (m_spellInfo->CheckTarget(m_caster, *itr, true) != SPELL_CAST_OK) continue; @@ -1557,104 +1574,33 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex) } } - const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3) - /// @todo all calculation should be based on src instead of m_caster - const float objDist2d = m_targets.GetSrcPos()->GetExactDist2d(*itr) * std::cos(m_targets.GetSrcPos()->GetRelativeAngle(*itr)); - const float dz = (*itr)->GetPositionZ() - m_targets.GetSrcPos()->m_positionZ; - - DEBUG_TRAJ(TC_LOG_ERROR("spells", "Spell::SelectTrajTargets: check %u, dist between %f %f, height between %f %f.", (*itr)->GetEntry(), objDist2d - size, objDist2d + size, dz - size, dz + size);) - - float dist = objDist2d - size; - float height = dist * (a * dist + b); - DEBUG_TRAJ(TC_LOG_ERROR("spells", "Spell::SelectTrajTargets: dist %f, height %f.", dist, height);) - if (dist < bestDist && height < dz + size && height > dz - size) - { - bestDist = dist > 0 ? dist : 0; - break; - } - -#define CHECK_DIST {\ - DEBUG_TRAJ(TC_LOG_ERROR("spells", "Spell::SelectTrajTargets: dist %f, height %f.", dist, height);)\ - if (dist > bestDist)\ - continue;\ - if (dist < objDist2d + size && dist > objDist2d - size)\ - {\ - bestDist = dist;\ - break;\ - }\ - } - - if (!a) - { - height = dz - size; - dist = height / b; - CHECK_DIST; + const float size = std::max((*itr)->GetObjectSize(), 1.0f); + const float objDist2d = srcPos.GetExactDist2d(*itr); + const float dz = (*itr)->GetPositionZ() - srcPos.m_positionZ; - height = dz + size; - dist = height / b; - CHECK_DIST; + const float horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr))); + const float sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f)); + const float distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f); + const float height = distToHitPoint * (a * distToHitPoint + b); + if (fabs(dz - height) > size + b / 2.0f + TRAJECTORY_MISSILE_SIZE) continue; - } - - height = dz - size; - float sqrt1 = b * b + 4 * a * height; - if (sqrt1 > 0) - { - sqrt1 = std::sqrt(sqrt1); - dist = (sqrt1 - b) / (2 * a); - CHECK_DIST; - } - height = dz + size; - float sqrt2 = b * b + 4 * a * height; - if (sqrt2 > 0) + if (distToHitPoint < bestDist) { - sqrt2 = std::sqrt(sqrt2); - dist = (sqrt2 - b) / (2 * a); - CHECK_DIST; - - dist = (-sqrt2 - b) / (2 * a); - CHECK_DIST; - } - - if (sqrt1 > 0) - { - dist = (-sqrt1 - b) / (2 * a); - CHECK_DIST; + bestDist = distToHitPoint; + break; } } - if (m_targets.GetSrcPos()->GetExactDist2d(m_targets.GetDstPos()) > bestDist) + if (dist2d > bestDist) { float x = m_targets.GetSrcPos()->m_positionX + std::cos(m_caster->GetOrientation()) * bestDist; float y = m_targets.GetSrcPos()->m_positionY + std::sin(m_caster->GetOrientation()) * bestDist; float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b); - if (itr != targets.end()) - { - float distSq = (*itr)->GetExactDistSq(x, y, z); - float sizeSq = (*itr)->GetObjectSize(); - sizeSq *= sizeSq; - DEBUG_TRAJ(TC_LOG_ERROR("spells", "Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);) - if (distSq > sizeSq) - { - float factor = 1 - std::sqrt(sizeSq / distSq); - x += factor * ((*itr)->GetPositionX() - x); - y += factor * ((*itr)->GetPositionY() - y); - z += factor * ((*itr)->GetPositionZ() - z); - - distSq = (*itr)->GetExactDistSq(x, y, z); - DEBUG_TRAJ(TC_LOG_ERROR("spells", "Initial %f %f %f %f %f", x, y, z, distSq, sizeSq);) - } - } - - Position trajDst; - trajDst.Relocate(x, y, z, m_caster->GetOrientation()); - SpellDestination dest(*m_targets.GetDst()); - dest.Relocate(trajDst); - - CallScriptDestinationTargetSelectHandlers(dest, effIndex, SpellImplicitTargetInfo(TARGET_DEST_TRAJ)); + SpellDestination dest(x, y, z, m_caster->GetOrientation()); + CallScriptDestinationTargetSelectHandlers(dest, effIndex, targetType); m_targets.ModDst(dest); } } @@ -2916,8 +2862,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered m_triggeredByAuraSpell = triggeredByAura->GetSpellInfo(); // create and add update event for this spell - SpellEvent* Event = new SpellEvent(this); - m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1)); + _spellEvent = new SpellEvent(this); + m_caster->m_Events.AddEvent(_spellEvent, m_caster->m_Events.CalculateTime(1)); //Prevent casting at cast another spell (ServerSide check) if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS) && m_caster->IsNonMeleeSpellCast(false, true, true) && m_cast_count) @@ -7685,9 +7631,9 @@ WorldObjectSpellTargetCheck::WorldObjectSpellTargetCheck(Unit* caster, Unit* ref _targetSelectionType(selectionType), _condList(condList) { if (condList) - _condSrcInfo = new ConditionSourceInfo(NULL, caster); + _condSrcInfo = new ConditionSourceInfo(nullptr, caster); else - _condSrcInfo = NULL; + _condSrcInfo = nullptr; } WorldObjectSpellTargetCheck::~WorldObjectSpellTargetCheck() @@ -7793,7 +7739,7 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target) } else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE)) { - if (!_caster->HasInLine(target, _caster->GetObjectSize() + target->GetObjectSize())) + if (!_caster->HasInLine(target, target->GetObjectSize(), _caster->GetObjectSize())) return false; } else @@ -7804,15 +7750,19 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target) return WorldObjectSpellAreaTargetCheck::operator ()(target); } -WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, SpellInfo const* spellInfo) - : WorldObjectSpellAreaTargetCheck(range, position, caster, caster, spellInfo, TARGET_CHECK_DEFAULT, NULL) { } +WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList) + : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _range(range), _position(position) { } bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target) { // return all targets on missile trajectory (0 - size of a missile) - if (!_caster->HasInLine(target, target->GetObjectSize())) + if (!_caster->HasInLine(target, target->GetObjectSize(), TRAJECTORY_MISSILE_SIZE)) return false; - return WorldObjectSpellAreaTargetCheck::operator ()(target); + + if (target->GetExactDist2d(_position) > _range) + return false; + + return WorldObjectSpellTargetCheck::operator ()(target); } } //namespace Trinity |