diff options
author | xinef1 <w.szyszko2@gmail.com> | 2017-02-06 01:10:15 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2019-06-15 18:41:09 +0200 |
commit | 3f7fe6f8a51f61083b4940eaadddc3b390f8e238 (patch) | |
tree | ca293817d626010fc8c92692863a549fb5bcf429 /src | |
parent | c53df2adb0d22acbaeaa02638edb5fafea5ba61e (diff) |
Core/Spells: Remade trajectory target selection (#19048)
* Remade trajectory target selection
* Added possibility to apply conditions to trajectory spells
* Properly recalculate delay time if CMSG_UPDATE_PROJECTILE_POSITION is received
(cherrypicked from c6060dd0c511ddad3cb1f0423aa9ccf2de7aedec)
Diffstat (limited to 'src')
-rw-r--r-- | src/common/Utilities/EventProcessor.cpp | 14 | ||||
-rw-r--r-- | src/common/Utilities/EventProcessor.h | 1 | ||||
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Position.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Position.h | 2 | ||||
-rw-r--r-- | src/server/game/Handlers/SpellHandler.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 173 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 14 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 3 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 15 |
11 files changed, 114 insertions, 118 deletions
diff --git a/src/common/Utilities/EventProcessor.cpp b/src/common/Utilities/EventProcessor.cpp index 41fcc1fe8f7..9df76f96438 100644 --- a/src/common/Utilities/EventProcessor.cpp +++ b/src/common/Utilities/EventProcessor.cpp @@ -119,6 +119,20 @@ void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime m_events.insert(std::pair<uint64, BasicEvent*>(e_time, Event)); } +void EventProcessor::ModifyEventTime(BasicEvent* Event, uint64 newTime) +{ + for (auto itr = m_events.begin(); itr != m_events.end(); ++itr) + { + if (itr->second != Event) + continue; + + Event->m_execTime = newTime; + m_events.erase(itr); + m_events.insert(std::pair<uint64, BasicEvent*>(newTime, Event)); + break; + } +} + uint64 EventProcessor::CalculateTime(uint64 t_offset) const { return(m_time + t_offset); diff --git a/src/common/Utilities/EventProcessor.h b/src/common/Utilities/EventProcessor.h index cb98e6079ed..799623b1ed7 100644 --- a/src/common/Utilities/EventProcessor.h +++ b/src/common/Utilities/EventProcessor.h @@ -77,6 +77,7 @@ class TC_COMMON_API EventProcessor void Update(uint32 p_time); void KillAllEvents(bool force); void AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime = true); + void ModifyEventTime(BasicEvent* Event, uint64 newTime); uint64 CalculateTime(uint64 t_offset) const; protected: diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index adcd5f0543a..c3496ae356e 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -1736,6 +1736,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const case TARGET_SELECT_CATEGORY_NEARBY: case TARGET_SELECT_CATEGORY_CONE: case TARGET_SELECT_CATEGORY_AREA: + case TARGET_SELECT_CATEGORY_TRAJ: continue; default: break; @@ -1746,6 +1747,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const case TARGET_SELECT_CATEGORY_NEARBY: case TARGET_SELECT_CATEGORY_CONE: case TARGET_SELECT_CATEGORY_AREA: + case TARGET_SELECT_CATEGORY_TRAJ: continue; default: break; diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp index dd79adc9792..d23c2a7af65 100644 --- a/src/server/game/Entities/Object/Position.cpp +++ b/src/server/game/Entities/Object/Position.cpp @@ -170,11 +170,12 @@ bool Position::HasInArc(float arc, const Position* obj, float border) const return ((angle >= lborder) && (angle <= rborder)); } -bool Position::HasInLine(Position const* pos, float width) const +bool Position::HasInLine(Position const* pos, float objSize, float width) const { if (!HasInArc(float(M_PI), pos)) return false; + width += objSize; float angle = GetRelativeAngle(pos); return std::fabs(std::sin(angle)) * GetExactDist2d(pos->GetPositionX(), pos->GetPositionY()) < width; } diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h index b2f8e312766..5f9f40276c2 100644 --- a/src/server/game/Entities/Object/Position.h +++ b/src/server/game/Entities/Object/Position.h @@ -219,7 +219,7 @@ public: bool IsWithinBox(const Position& center, float xradius, float yradius, float zradius) const; bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const; - bool HasInLine(Position const* pos, float width) const; + bool HasInLine(Position const* pos, float objSize, float width) const; std::string ToString() const; // modulos a radian orientation to the range of 0..2PI diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 4ce38852b0e..c91231df279 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -582,6 +582,9 @@ void WorldSession::HandleMissileTrajectoryCollision(WorldPackets::Spells::Missil pos.Relocate(packet.CollisionPos); spell->m_targets.ModDst(pos); + // we changed dest, recalculate flight time + spell->RecalculateDelayMomentForDst(); + WorldPackets::Spells::NotifyMissileTrajectoryCollision notify; notify.Caster = packet.Target; notify.CastID = packet.CastID; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 43c2f1c29a5..847b14765e2 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -522,7 +522,7 @@ protected: Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID, bool skipCheck) : m_spellInfo(info), m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster), -m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo, caster)) +m_spellValue(new SpellValue(caster->GetMap()->GetDifficultyID(), m_spellInfo, caster)), _spellEvent(nullptr) { _effects = info->GetEffectsForDifficulty(caster->GetMap()->GetDifficultyID()); @@ -793,24 +793,38 @@ 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(std::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()); if (!m_spellInfo->HasAttribute(SPELL_ATTR9_SPECIAL_DELAY_CALCULATION)) - m_delayMoment = uint64(std::floor(dist / m_spellInfo->Speed * 1000.0f)); + return (uint64)std::floor(dist / m_spellInfo->Speed * 1000.0f); else - m_delayMoment = uint64(m_spellInfo->Speed * 1000.0f); + return (uint64)std::floor(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()) { @@ -1405,9 +1425,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: { if (SpellEffectInfo const* effect = GetEffect(effIndex)) @@ -1543,9 +1560,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; @@ -1554,12 +1569,15 @@ 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; + SpellEffectInfo const* effect = m_spellInfo->GetEffect(effIndex); 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(), effect->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; @@ -1569,16 +1587,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(effect->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; @@ -1594,104 +1612,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); } @@ -2912,8 +2859,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered } // 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_castId.IsEmpty()) @@ -7747,9 +7694,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() @@ -7855,7 +7802,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 @@ -7869,15 +7816,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 diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 259af5c2885..4f8ca3b3caa 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -47,6 +47,7 @@ class Object; class PathGenerator; class Player; class SpellEffectInfo; +class SpellEvent; class SpellImplicitTargetInfo; class SpellInfo; class SpellScript; @@ -66,6 +67,7 @@ enum WeaponAttackType : uint8; #define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS) #define MAX_SPELL_RANGE_TOLERANCE 3.0f +#define TRAJECTORY_MISSILE_SIZE 3.0f enum SpellCastFlags { @@ -503,7 +505,7 @@ class TC_GAME_API Spell void SelectImplicitCasterObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); void SelectImplicitTargetObjectTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); void SelectImplicitChainTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask); - void SelectImplicitTrajTargets(SpellEffIndex effIndex); + void SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); void SelectEffectTypeImplicitTargets(uint32 effIndex); @@ -663,6 +665,8 @@ class TC_GAME_API Spell uint64 GetDelayStart() const { return m_delayStart; } void SetDelayStart(uint64 m_time) { m_delayStart = m_time; } uint64 GetDelayMoment() const { return m_delayMoment; } + uint64 CalculateDelayMomentForDst() const; + void RecalculateDelayMomentForDst(); bool IsNeedSendToClient() const; @@ -877,6 +881,7 @@ class TC_GAME_API Spell uint32 m_spellState; int32 m_timer; + SpellEvent* _spellEvent; TriggerCastFlags _triggeredCastFlags; // if need this can be replaced by Aura copy @@ -943,9 +948,12 @@ namespace Trinity bool operator()(WorldObject* target); }; - struct TC_GAME_API WorldObjectSpellTrajTargetCheck : public WorldObjectSpellAreaTargetCheck + struct TC_GAME_API WorldObjectSpellTrajTargetCheck : public WorldObjectSpellTargetCheck { - WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, SpellInfo const* spellInfo); + float _range; + Position const* _position; + WorldObjectSpellTrajTargetCheck(float range, Position const* position, Unit* caster, + SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer* condList); bool operator()(WorldObject* target); }; } diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 90ca90f9740..54ae71ef0ea 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -307,7 +307,7 @@ SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 86 TARGET_DEST_DEST_RANDOM {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 87 TARGET_DEST_DEST {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 88 TARGET_DEST_DYNOBJ_NONE - {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 89 TARGET_DEST_TRAJ + {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_TRAJ, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 89 TARGET_DEST_TRAJ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 90 TARGET_UNIT_TARGET_MINIPET {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 91 TARGET_DEST_DEST_RADIUS {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 92 TARGET_UNIT_SUMMONER diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index ff053e0550b..1194c303b50 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -84,7 +84,8 @@ enum SpellTargetSelectionCategories TARGET_SELECT_CATEGORY_CHANNEL, TARGET_SELECT_CATEGORY_NEARBY, TARGET_SELECT_CATEGORY_CONE, - TARGET_SELECT_CATEGORY_AREA + TARGET_SELECT_CATEGORY_AREA, + TARGET_SELECT_CATEGORY_TRAJ }; enum SpellTargetReferenceTypes diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index fca727cf98b..4a42fa64b62 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3420,6 +3420,21 @@ void SpellMgr::LoadSpellInfoCorrections() { if (!effect) continue; + + if (effect->IsEffect() && (effect->TargetA.GetTarget() == TARGET_DEST_TRAJ || effect->TargetB.GetTarget() == TARGET_DEST_TRAJ)) + { + // Get triggered spell if any + if (SpellInfo* spellInfoTrigger = const_cast<SpellInfo*>(GetSpellInfo(effect->TriggerSpell))) + { + float maxRangeMain = spellInfo->GetMaxRange(); + float maxRangeTrigger = spellInfoTrigger->GetMaxRange(); + + // check if triggered spell has enough max range to cover trajectory + if (maxRangeTrigger < maxRangeMain) + spellInfoTrigger->RangeEntry = spellInfo->RangeEntry; + } + } + switch (effect->Effect) { case SPELL_EFFECT_CHARGE: |