aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/Utilities/EventProcessor.cpp14
-rw-r--r--src/common/Utilities/EventProcessor.h1
-rw-r--r--src/server/game/Conditions/ConditionMgr.cpp2
-rw-r--r--src/server/game/Entities/Object/Position.cpp3
-rw-r--r--src/server/game/Entities/Object/Position.h2
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp3
-rw-r--r--src/server/game/Spells/Spell.cpp173
-rw-r--r--src/server/game/Spells/Spell.h14
-rw-r--r--src/server/game/Spells/SpellInfo.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.h3
-rw-r--r--src/server/game/Spells/SpellMgr.cpp15
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: