aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h2
-rw-r--r--src/server/game/Spells/Spell.cpp31
-rw-r--r--src/server/game/Spells/SpellInfo.cpp35
-rw-r--r--src/server/game/Spells/SpellInfo.h3
-rw-r--r--src/server/game/Spells/SpellMgr.cpp67
-rw-r--r--src/server/game/Spells/SpellMgr.h3
6 files changed, 95 insertions, 46 deletions
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 64456094a5a..da0958df094 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -2818,7 +2818,7 @@ enum Targets
TARGET_UNIT_PASSENGER_7 = 103,
TARGET_UNIT_CONE_CASTER_TO_DEST_ENEMY = 104,
TARGET_UNIT_CASTER_AND_PASSENGERS = 105,
- TARGET_DEST_CHANNEL_CASTER = 106,
+ TARGET_DEST_NEARBY_DB = 106,
TARGET_DEST_NEARBY_ENTRY_2 = 107,
TARGET_GAMEOBJECT_CONE_CASTER_TO_DEST_ENEMY = 108,
TARGET_GAMEOBJECT_CONE_CASTER_TO_DEST_ALLY = 109,
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 733fb9f2607..ed72a1d3366 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1057,16 +1057,6 @@ void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo,
TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell destination for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
}
break;
- case TARGET_DEST_CHANNEL_CASTER:
- {
- SpellDestination dest(*channeledSpell->GetCaster());
- if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
- dest._position.SetOrientation(spellEffectInfo.PositionFacing);
-
- CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
- m_targets.SetDst(dest);
- break;
- }
default:
ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target type");
break;
@@ -1579,6 +1569,25 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffectInfo const& spellEffectIn
if (WorldObject const* summoner = casterSummon->GetSummoner())
dest = SpellDestination(*summoner);
break;
+ case TARGET_DEST_NEARBY_DB:
+ {
+ Optional<std::pair<float, float>> radiusBounds = spellEffectInfo.CalcRadiusBounds(m_caster, targetIndex, this);
+ std::vector<SpellTargetPosition const*> positionsInRange;
+ for (auto const& [_, position] : sSpellMgr->GetSpellTargetPositions(m_spellInfo->Id, spellEffectInfo.EffectIndex))
+ if (m_caster->GetMapId() == position.GetMapId() && (!radiusBounds || (!m_caster->IsInDist(position, radiusBounds->first) && m_caster->IsInDist(position, radiusBounds->second))))
+ positionsInRange.push_back(&position);
+
+ if (positionsInRange.empty())
+ {
+ TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID {}", m_spellInfo->Id);
+ SendCastResult(SPELL_FAILED_NO_VALID_TARGETS);
+ finish(SPELL_FAILED_NO_VALID_TARGETS);
+ return;
+ }
+
+ dest = Trinity::Containers::SelectRandomContainerElement(positionsInRange)->GetPosition();
+ break;
+ }
default:
{
float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex);
@@ -1599,7 +1608,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffectInfo const& spellEffectIn
case TARGET_DEST_CASTER_FRONT_RIGHT:
case TARGET_DEST_CASTER_BACK_RIGHT:
{
- constexpr float DefaultTotemDistance = 3.0f;
+ static constexpr float DefaultTotemDistance = 3.0f;
if (!spellEffectInfo.HasRadius(targetIndex))
dist = DefaultTotemDistance;
break;
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index 19d6b07d79d..12cbf68dd9f 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -347,7 +347,7 @@ std::array<SpellImplicitTargetInfo::StaticData, TOTAL_SPELL_TARGETS> SpellImplic
{TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 103 TARGET_UNIT_PASSENGER_7
{TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENEMY, TARGET_DIR_FRONT}, // 104 TARGET_UNIT_CONE_CASTER_TO_DEST_ENEMY
{TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 105 TARGET_UNIT_CASTER_AND_PASSENGERS
- {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 106 TARGET_DEST_CHANNEL_CASTER
+ {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 106 TARGET_DEST_NEARBY_DB
{TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 107 TARGET_DEST_NEARBY_ENTRY_2
{TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENEMY, TARGET_DIR_FRONT}, // 108 TARGET_GAMEOBJECT_CONE_CASTER_TO_DEST_ENEMY
{TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ALLY, TARGET_DIR_FRONT}, // 109 TARGET_GAMEOBJECT_CONE_CASTER_TO_DEST_ALLY
@@ -676,6 +676,39 @@ float SpellEffectInfo::CalcRadius(WorldObject* caster /*= nullptr*/, SpellTarget
return radius;
}
+Optional<std::pair<float, float>> SpellEffectInfo::CalcRadiusBounds(WorldObject* caster, SpellTargetIndex targetIndex, Spell* spell) const
+{
+ // TargetA -> TargetARadiusEntry
+ // TargetB -> TargetBRadiusEntry
+ // Aura effects have TargetARadiusEntry == TargetBRadiusEntry (mostly)
+ SpellRadiusEntry const* entry = TargetARadiusEntry;
+ if (targetIndex == SpellTargetIndex::TargetB && HasRadius(targetIndex))
+ entry = TargetBRadiusEntry;
+
+ Optional<std::pair<float, float>> bounds;
+ if (!entry)
+ return bounds;
+
+ bounds.emplace(entry->RadiusMin, entry->RadiusMax);
+
+ if (caster)
+ {
+ if (Player* modOwner = caster->GetSpellModOwner())
+ modOwner->ApplySpellMod(_spellInfo, SpellModOp::Radius, bounds->second, spell);
+
+ if (!_spellInfo->HasAttribute(SPELL_ATTR9_NO_MOVEMENT_RADIUS_BONUS))
+ {
+ if (Unit const* casterUnit = caster->ToUnit(); casterUnit && Spell::CanIncreaseRangeByMovement(casterUnit))
+ {
+ bounds->first = std::max(bounds->first - 2.0f, 0.0f);
+ bounds->second += 2.0f;
+ }
+ }
+ }
+
+ return bounds;
+}
+
uint32 SpellEffectInfo::GetProvidedTargetMask() const
{
return GetTargetFlagMask(TargetA.GetObjectType()) | GetTargetFlagMask(TargetB.GetObjectType());
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 35d7e8cafb1..f9f911d963d 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -267,7 +267,8 @@ public:
float CalcDamageMultiplier(WorldObject* caster, Spell* spell = nullptr) const;
bool HasRadius(SpellTargetIndex targetIndex) const;
- float CalcRadius(WorldObject* caster = nullptr, SpellTargetIndex targetIndex = SpellTargetIndex::TargetA, Spell* = nullptr) const;
+ float CalcRadius(WorldObject* caster = nullptr, SpellTargetIndex targetIndex = SpellTargetIndex::TargetA, Spell* spell = nullptr) const;
+ Optional<std::pair<float, float>> CalcRadiusBounds(WorldObject* caster, SpellTargetIndex targetIndex, Spell* spell) const;
uint32 GetProvidedTargetMask() const;
uint32 GetMissingTargetMask(bool srcSet = false, bool dstSet = false, uint32 mask = 0) const;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 779981eee1a..a3e3b4cee58 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -355,6 +355,11 @@ SpellTargetPosition const* SpellMgr::GetSpellTargetPosition(uint32 spell_id, Spe
return nullptr;
}
+Trinity::IteratorPair<SpellTargetPositionMap::const_iterator> SpellMgr::GetSpellTargetPositions(uint32 spell_id, SpellEffIndex effIndex) const
+{
+ return Trinity::Containers::MapEqualRange(mSpellTargetPositions, { spell_id, effIndex });
+}
+
SpellSpellGroupMapBounds SpellMgr::GetSpellSpellGroupMapBounds(uint32 spell_id) const
{
spell_id = GetFirstSpellInChain(spell_id);
@@ -1274,15 +1279,14 @@ void SpellMgr::LoadSpellTargetPositions()
mSpellTargetPositions.clear(); // need for reload case
- // 0 1 2 3 4 5 6
- QueryResult result = WorldDatabase.Query("SELECT ID, EffectIndex, MapID, PositionX, PositionY, PositionZ, Orientation FROM spell_target_position");
+ // 0 1 2 3 4 5 6 7
+ QueryResult result = WorldDatabase.Query("SELECT ID, EffectIndex, OrderIndex, MapID, PositionX, PositionY, PositionZ, Orientation FROM spell_target_position");
if (!result)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 spell target coordinates. DB table `spell_target_position` is empty.");
return;
}
- uint32 count = 0;
do
{
Field* fields = result->Fetch();
@@ -1290,7 +1294,7 @@ void SpellMgr::LoadSpellTargetPositions()
uint32 spellId = fields[0].GetUInt32();
SpellEffIndex effIndex = SpellEffIndex(fields[1].GetUInt8());
- SpellTargetPosition st(fields[2].GetUInt16(), fields[3].GetFloat(), fields[4].GetFloat(), fields[5].GetFloat());
+ SpellTargetPosition st(fields[3].GetUInt16(), fields[4].GetFloat(), fields[5].GetFloat(), fields[6].GetFloat());
MapEntry const* mapEntry = sMapStore.LookupEntry(st.GetMapId());
if (!mapEntry)
@@ -1318,61 +1322,62 @@ void SpellMgr::LoadSpellTargetPositions()
continue;
}
- if (!fields[6].IsNull())
- st.SetOrientation(fields[6].GetFloat());
+ SpellEffectInfo const& spellEffectInfo = spellInfo->GetEffect(effIndex);
+ if (!fields[7].IsNull())
+ st.SetOrientation(fields[7].GetFloat());
else
{
// target facing is in degrees for 6484 & 9268...
- if (spellInfo->GetEffect(effIndex).PositionFacing > 2 * float(M_PI))
- st.SetOrientation(spellInfo->GetEffect(effIndex).PositionFacing * float(M_PI) / 180);
+ if (spellEffectInfo.PositionFacing > 2 * float(M_PI))
+ st.SetOrientation(spellEffectInfo.PositionFacing * float(M_PI) / 180);
else
- st.SetOrientation(spellInfo->GetEffect(effIndex).PositionFacing);
+ st.SetOrientation(spellEffectInfo.PositionFacing);
}
auto hasTarget = [&](Targets target)
{
- SpellEffectInfo const& spellEffectInfo = spellInfo->GetEffect(effIndex);
return spellEffectInfo.TargetA.GetTarget() == target || spellEffectInfo.TargetB.GetTarget() == target;
};
- if (hasTarget(TARGET_DEST_DB) || hasTarget(TARGET_DEST_NEARBY_ENTRY_OR_DB))
- {
- std::pair<uint32, SpellEffIndex> key = std::make_pair(spellId, effIndex);
- mSpellTargetPositions[key] = st;
- ++count;
- }
- else
+ if (!hasTarget(TARGET_DEST_NEARBY_DB))
{
- TC_LOG_ERROR("sql.sql", "Spell (Id: {}, effIndex: {}) listed in `spell_target_position` does not have a target TARGET_DEST_DB (17).", spellId, uint32(effIndex));
- continue;
+ if (!hasTarget(TARGET_DEST_DB) && !hasTarget(TARGET_DEST_NEARBY_ENTRY_OR_DB))
+ {
+ TC_LOG_ERROR("sql.sql", "Spell (Id: {}, effIndex: {}) listed in `spell_target_position` does not have a target TARGET_DEST_DB ({}) or TARGET_DEST_NEARBY_DB ({}) or TARGET_DEST_NEARBY_ENTRY_OR_DB ({}).",
+ spellId, uint32(effIndex), TARGET_DEST_DB, TARGET_DEST_NEARBY_DB, TARGET_DEST_NEARBY_ENTRY_OR_DB);
+ continue;
+ }
+ if (fields[2].GetInt32() != 0)
+ {
+ TC_LOG_ERROR("sql.sql", "Spell (Id: {}, effIndex: {}) listed in `spell_target_position` does not have a target TARGET_DEST_NEARBY_DB ({}) but lists multiple points, only one is allowed.",
+ spellId, uint32(effIndex), TARGET_DEST_NEARBY_DB);
+ continue;
+ }
}
+ mSpellTargetPositions.emplace(std::make_pair(spellId, effIndex), st);
+
} while (result->NextRow());
/*
// Check all spells
- for (uint32 i = 1; i < GetSpellInfoStoreSize(); ++i)
+ for (SpellInfo const& spellInfo : mSpellInfoMap)
{
- SpellInfo const* spellInfo = GetSpellInfo(i);
- if (!spellInfo)
+ if (spellInfo.Difficulty != DIFFICULTY_NONE)
continue;
- for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
+ for (SpellEffectInfo const& effect : spellInfo.GetEffects())
{
- SpellEffectInfo const* effect = spellInfo->GetEffect(j);
- if (!effect)
- continue;
-
- if (effect->TargetA.GetTarget() != TARGET_DEST_DB && effect->TargetB.GetTarget() != TARGET_DEST_DB)
+ if (effect.TargetA.GetTarget() != TARGET_DEST_DB && effect.TargetB.GetTarget() != TARGET_DEST_DB)
continue;
- if (!GetSpellTargetPosition(i, SpellEffIndex(j)))
- TC_LOG_DEBUG("spells", "Spell (Id: {}, EffectIndex: {}) does not have record in `spell_target_position`.", i, j);
+ if (!GetSpellTargetPosition(spellInfo.Id, effect.EffectIndex))
+ TC_LOG_DEBUG("spells", "Spell (Id: {}, EffectIndex: {}) does not have record in `spell_target_position`.", spellInfo.Id, effect.EffectIndex);
}
}
*/
- TC_LOG_INFO("server.loading", ">> Loaded {} spell teleport coordinates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded {} spell teleport coordinates in {} ms", mSpellTargetPositions.size(), GetMSTimeDiffToNow(oldMSTime));
}
void SpellMgr::LoadSpellGroups()
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index c9eaf65ce06..262e11f80bf 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -408,7 +408,7 @@ typedef std::unordered_map<uint32, SpellThreatEntry> SpellThreatMap;
// coordinates for spells (accessed using SpellMgr functions)
using SpellTargetPosition = WorldLocation;
-typedef std::map<std::pair<uint32 /*spell_id*/, SpellEffIndex /*effIndex*/>, SpellTargetPosition> SpellTargetPositionMap;
+typedef std::multimap<std::pair<uint32 /*spell_id*/, SpellEffIndex /*effIndex*/>, SpellTargetPosition> SpellTargetPositionMap;
// Enum with EffectRadiusIndex and their actual radius
enum EffectRadiusIndex
@@ -727,6 +727,7 @@ class TC_GAME_API SpellMgr
// Spell target coordinates
SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const;
+ Trinity::IteratorPair<SpellTargetPositionMap::const_iterator> GetSpellTargetPositions(uint32 spell_id, SpellEffIndex effIndex) const;
// Spell Groups table
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const;