diff options
author | xinef1 <w.szyszko2@gmail.com> | 2017-02-06 01:10:15 +0100 |
---|---|---|
committer | ariel- <ariel-@users.noreply.github.com> | 2017-02-05 21:10:15 -0300 |
commit | c6060dd0c511ddad3cb1f0423aa9ccf2de7aedec (patch) | |
tree | f418ab2a2b7f12bf5384e8653eeb3481370108b6 | |
parent | d06391d0628ffbf43da471c83653853b0926b4ab (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
-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 | 170 | ||||
-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 | 18 |
11 files changed, 115 insertions, 117 deletions
diff --git a/src/common/Utilities/EventProcessor.cpp b/src/common/Utilities/EventProcessor.cpp index 07fce187ad3..039ca37b9d7 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 3b924dbb3e5..2f65957581c 100644 --- a/src/common/Utilities/EventProcessor.h +++ b/src/common/Utilities/EventProcessor.h @@ -79,6 +79,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 dee3933bcde..e389f45ceb0 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -1627,6 +1627,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; @@ -1637,6 +1638,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 c9e6ea6eee8..0fdbaf8e008 100644 --- a/src/server/game/Entities/Object/Position.cpp +++ b/src/server/game/Entities/Object/Position.cpp @@ -159,11 +159,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 46c8d4874ec..db694a51bfd 100644 --- a/src/server/game/Entities/Object/Position.h +++ b/src/server/game/Entities/Object/Position.h @@ -230,7 +230,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 32ace07d9ec..955bb114ec4 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -701,6 +701,9 @@ void WorldSession::HandleUpdateProjectilePosition(WorldPacket& recvPacket) pos.Relocate(x, y, z); spell->m_targets.ModDst(pos); + // we changed dest, recalculate flight time + spell->RecalculateDelayMomentForDst(); + WorldPacket data(SMSG_SET_PROJECTILE_POSITION, 21); data << uint64(casterGuid); data << uint8(castCount); 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 diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index e2508da33e0..ed57e3aac6b 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -33,9 +33,11 @@ class WorldObject; class Aura; class SpellScript; class ByteBuffer; +class SpellEvent; #define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS) #define MAX_SPELL_RANGE_TOLERANCE 3.0f +#define TRAJECTORY_MISSILE_SIZE 3.0f enum SpellCastFlags { @@ -373,7 +375,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(uint8 effIndex); @@ -497,6 +499,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; @@ -694,6 +698,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 @@ -754,9 +759,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 ad58119547c..b436bc0749f 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -298,7 +298,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 736caf7d4c6..4739f888da4 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -82,7 +82,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 382490dd5e4..b7405cbc906 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2744,6 +2744,24 @@ void SpellMgr::LoadSpellInfoCorrections() if (!spellInfo) continue; + // Fix range for trajectory triggered spell + for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) + { + if (spellInfo->Effects[j].IsEffect() && (spellInfo->Effects[j].TargetA.GetTarget() == TARGET_DEST_TRAJ || spellInfo->Effects[j].TargetB.GetTarget() == TARGET_DEST_TRAJ)) + { + // Get triggered spell if any + if (SpellInfo* spellInfoTrigger = const_cast<SpellInfo*>(GetSpellInfo(spellInfo->Effects[j].TriggerSpell))) + { + float maxRangeMain = spellInfo->RangeEntry ? spellInfo->RangeEntry->maxRangeHostile : 0.0f; + float maxRangeTrigger = spellInfoTrigger->RangeEntry ? spellInfoTrigger->RangeEntry->maxRangeHostile : 0.0f; + + // check if triggered spell has enough max range to cover trajectory + if (maxRangeTrigger < maxRangeMain) + spellInfoTrigger->RangeEntry = spellInfo->RangeEntry; + } + } + } + for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) { switch (spellInfo->Effects[j].Effect) |