Skip to content

Commit 2a51a64

Browse files
committed
Core/Spells: Reimplemented target type 106 as random point from points predefined in database
Closes TrinityCore#30116
1 parent 476b895 commit 2a51a64

File tree

7 files changed

+98
-46
lines changed

7 files changed

+98
-46
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ALTER TABLE `spell_target_position` DROP PRIMARY KEY;
2+
ALTER TABLE `spell_target_position` ADD `OrderIndex` int NOT NULL DEFAULT '0' AFTER `EffectIndex`;
3+
ALTER TABLE `spell_target_position` ADD PRIMARY KEY(`ID`,`EffectIndex`,`OrderIndex`);

src/server/game/Miscellaneous/SharedDefines.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2874,7 +2874,7 @@ enum Targets
28742874
TARGET_UNIT_PASSENGER_7 = 103,
28752875
TARGET_UNIT_CONE_CASTER_TO_DEST_ENEMY = 104,
28762876
TARGET_UNIT_CASTER_AND_PASSENGERS = 105,
2877-
TARGET_DEST_CHANNEL_CASTER = 106,
2877+
TARGET_DEST_NEARBY_DB = 106,
28782878
TARGET_DEST_NEARBY_ENTRY_2 = 107,
28792879
TARGET_GAMEOBJECT_CONE_CASTER_TO_DEST_ENEMY = 108,
28802880
TARGET_GAMEOBJECT_CONE_CASTER_TO_DEST_ALLY = 109,

src/server/game/Spells/Spell.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,16 +1057,6 @@ void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo,
10571057
TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell destination for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
10581058
}
10591059
break;
1060-
case TARGET_DEST_CHANNEL_CASTER:
1061-
{
1062-
SpellDestination dest(*channeledSpell->GetCaster());
1063-
if (m_spellInfo->HasAttribute(SPELL_ATTR4_USE_FACING_FROM_SPELL))
1064-
dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1065-
1066-
CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1067-
m_targets.SetDst(dest);
1068-
break;
1069-
}
10701060
default:
10711061
ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target type");
10721062
break;
@@ -1579,6 +1569,25 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffectInfo const& spellEffectIn
15791569
if (WorldObject const* summoner = casterSummon->GetSummoner())
15801570
dest = SpellDestination(*summoner);
15811571
break;
1572+
case TARGET_DEST_NEARBY_DB:
1573+
{
1574+
Optional<std::pair<float, float>> radiusBounds = spellEffectInfo.CalcRadiusBounds(m_caster, targetIndex, this);
1575+
std::vector<SpellTargetPosition const*> positionsInRange;
1576+
for (auto const& [_, position] : sSpellMgr->GetSpellTargetPositions(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1577+
if (m_caster->GetMapId() == position.GetMapId() && (!radiusBounds || (!m_caster->IsInDist(position, radiusBounds->first) && m_caster->IsInDist(position, radiusBounds->second))))
1578+
positionsInRange.push_back(&position);
1579+
1580+
if (positionsInRange.empty())
1581+
{
1582+
TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID {}", m_spellInfo->Id);
1583+
SendCastResult(SPELL_FAILED_NO_VALID_TARGETS);
1584+
finish(SPELL_FAILED_NO_VALID_TARGETS);
1585+
return;
1586+
}
1587+
1588+
dest = Trinity::Containers::SelectRandomContainerElement(positionsInRange)->GetPosition();
1589+
break;
1590+
}
15821591
default:
15831592
{
15841593
float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex);
@@ -1599,7 +1608,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffectInfo const& spellEffectIn
15991608
case TARGET_DEST_CASTER_FRONT_RIGHT:
16001609
case TARGET_DEST_CASTER_BACK_RIGHT:
16011610
{
1602-
constexpr float DefaultTotemDistance = 3.0f;
1611+
static constexpr float DefaultTotemDistance = 3.0f;
16031612
if (!spellEffectInfo.HasRadius(targetIndex))
16041613
dist = DefaultTotemDistance;
16051614
break;

src/server/game/Spells/SpellInfo.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ std::array<SpellImplicitTargetInfo::StaticData, TOTAL_SPELL_TARGETS> SpellImplic
347347
{TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 103 TARGET_UNIT_PASSENGER_7
348348
{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
349349
{TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 105 TARGET_UNIT_CASTER_AND_PASSENGERS
350-
{TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CHANNEL, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 106 TARGET_DEST_CHANNEL_CASTER
350+
{TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 106 TARGET_DEST_NEARBY_DB
351351
{TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_ENTRY, TARGET_DIR_NONE}, // 107 TARGET_DEST_NEARBY_ENTRY_2
352352
{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
353353
{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
@@ -715,6 +715,39 @@ float SpellEffectInfo::CalcRadius(WorldObject* caster /*= nullptr*/, SpellTarget
715715
return radius;
716716
}
717717

718+
Optional<std::pair<float, float>> SpellEffectInfo::CalcRadiusBounds(WorldObject* caster, SpellTargetIndex targetIndex, Spell* spell) const
719+
{
720+
// TargetA -> TargetARadiusEntry
721+
// TargetB -> TargetBRadiusEntry
722+
// Aura effects have TargetARadiusEntry == TargetBRadiusEntry (mostly)
723+
SpellRadiusEntry const* entry = TargetARadiusEntry;
724+
if (targetIndex == SpellTargetIndex::TargetB && HasRadius(targetIndex))
725+
entry = TargetBRadiusEntry;
726+
727+
Optional<std::pair<float, float>> bounds;
728+
if (!entry)
729+
return bounds;
730+
731+
bounds.emplace(entry->RadiusMin, entry->RadiusMax);
732+
733+
if (caster)
734+
{
735+
if (Player* modOwner = caster->GetSpellModOwner())
736+
modOwner->ApplySpellMod(_spellInfo, SpellModOp::Radius, bounds->second, spell);
737+
738+
if (!_spellInfo->HasAttribute(SPELL_ATTR9_NO_MOVEMENT_RADIUS_BONUS))
739+
{
740+
if (Unit const* casterUnit = caster->ToUnit(); casterUnit && Spell::CanIncreaseRangeByMovement(casterUnit))
741+
{
742+
bounds->first = std::max(bounds->first - 2.0f, 0.0f);
743+
bounds->second += 2.0f;
744+
}
745+
}
746+
}
747+
748+
return bounds;
749+
}
750+
718751
uint32 SpellEffectInfo::GetProvidedTargetMask() const
719752
{
720753
return GetTargetFlagMask(TargetA.GetObjectType()) | GetTargetFlagMask(TargetB.GetObjectType());

src/server/game/Spells/SpellInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ class TC_GAME_API SpellEffectInfo
266266
float CalcDamageMultiplier(WorldObject* caster, Spell* spell = nullptr) const;
267267

268268
bool HasRadius(SpellTargetIndex targetIndex) const;
269-
float CalcRadius(WorldObject* caster = nullptr, SpellTargetIndex targetIndex = SpellTargetIndex::TargetA, Spell* = nullptr) const;
269+
float CalcRadius(WorldObject* caster = nullptr, SpellTargetIndex targetIndex = SpellTargetIndex::TargetA, Spell* spell = nullptr) const;
270+
Optional<std::pair<float, float>> CalcRadiusBounds(WorldObject* caster, SpellTargetIndex targetIndex, Spell* spell) const;
270271

271272
uint32 GetProvidedTargetMask() const;
272273
uint32 GetMissingTargetMask(bool srcSet = false, bool dstSet = false, uint32 mask = 0) const;

src/server/game/Spells/SpellMgr.cpp

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,11 @@ SpellTargetPosition const* SpellMgr::GetSpellTargetPosition(uint32 spell_id, Spe
355355
return nullptr;
356356
}
357357

358+
Trinity::IteratorPair<SpellTargetPositionMap::const_iterator> SpellMgr::GetSpellTargetPositions(uint32 spell_id, SpellEffIndex effIndex) const
359+
{
360+
return Trinity::Containers::MapEqualRange(mSpellTargetPositions, { spell_id, effIndex });
361+
}
362+
358363
SpellSpellGroupMapBounds SpellMgr::GetSpellSpellGroupMapBounds(uint32 spell_id) const
359364
{
360365
spell_id = GetFirstSpellInChain(spell_id);
@@ -1156,23 +1161,22 @@ void SpellMgr::LoadSpellTargetPositions()
11561161

11571162
mSpellTargetPositions.clear(); // need for reload case
11581163

1159-
// 0 1 2 3 4 5 6
1160-
QueryResult result = WorldDatabase.Query("SELECT ID, EffectIndex, MapID, PositionX, PositionY, PositionZ, Orientation FROM spell_target_position");
1164+
// 0 1 2 3 4 5 6 7
1165+
QueryResult result = WorldDatabase.Query("SELECT ID, EffectIndex, OrderIndex, MapID, PositionX, PositionY, PositionZ, Orientation FROM spell_target_position");
11611166
if (!result)
11621167
{
11631168
TC_LOG_INFO("server.loading", ">> Loaded 0 spell target coordinates. DB table `spell_target_position` is empty.");
11641169
return;
11651170
}
11661171

1167-
uint32 count = 0;
11681172
do
11691173
{
11701174
Field* fields = result->Fetch();
11711175

11721176
uint32 spellId = fields[0].GetUInt32();
11731177
SpellEffIndex effIndex = SpellEffIndex(fields[1].GetUInt8());
11741178

1175-
SpellTargetPosition st(fields[2].GetUInt16(), fields[3].GetFloat(), fields[4].GetFloat(), fields[5].GetFloat());
1179+
SpellTargetPosition st(fields[3].GetUInt16(), fields[4].GetFloat(), fields[5].GetFloat(), fields[6].GetFloat());
11761180

11771181
MapEntry const* mapEntry = sMapStore.LookupEntry(st.GetMapId());
11781182
if (!mapEntry)
@@ -1200,61 +1204,62 @@ void SpellMgr::LoadSpellTargetPositions()
12001204
continue;
12011205
}
12021206

1203-
if (!fields[6].IsNull())
1204-
st.SetOrientation(fields[6].GetFloat());
1207+
SpellEffectInfo const& spellEffectInfo = spellInfo->GetEffect(effIndex);
1208+
if (!fields[7].IsNull())
1209+
st.SetOrientation(fields[7].GetFloat());
12051210
else
12061211
{
12071212
// target facing is in degrees for 6484 & 9268...
1208-
if (spellInfo->GetEffect(effIndex).PositionFacing > 2 * float(M_PI))
1209-
st.SetOrientation(spellInfo->GetEffect(effIndex).PositionFacing * float(M_PI) / 180);
1213+
if (spellEffectInfo.PositionFacing > 2 * float(M_PI))
1214+
st.SetOrientation(spellEffectInfo.PositionFacing * float(M_PI) / 180);
12101215
else
1211-
st.SetOrientation(spellInfo->GetEffect(effIndex).PositionFacing);
1216+
st.SetOrientation(spellEffectInfo.PositionFacing);
12121217
}
12131218

12141219
auto hasTarget = [&](Targets target)
12151220
{
1216-
SpellEffectInfo const& spellEffectInfo = spellInfo->GetEffect(effIndex);
12171221
return spellEffectInfo.TargetA.GetTarget() == target || spellEffectInfo.TargetB.GetTarget() == target;
12181222
};
12191223

1220-
if (hasTarget(TARGET_DEST_DB) || hasTarget(TARGET_DEST_NEARBY_ENTRY_OR_DB))
1221-
{
1222-
std::pair<uint32, SpellEffIndex> key = std::make_pair(spellId, effIndex);
1223-
mSpellTargetPositions[key] = st;
1224-
++count;
1225-
}
1226-
else
1224+
if (!hasTarget(TARGET_DEST_NEARBY_DB))
12271225
{
1228-
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));
1229-
continue;
1226+
if (!hasTarget(TARGET_DEST_DB) && !hasTarget(TARGET_DEST_NEARBY_ENTRY_OR_DB))
1227+
{
1228+
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 ({}).",
1229+
spellId, uint32(effIndex), TARGET_DEST_DB, TARGET_DEST_NEARBY_DB, TARGET_DEST_NEARBY_ENTRY_OR_DB);
1230+
continue;
1231+
}
1232+
if (fields[2].GetInt32() != 0)
1233+
{
1234+
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.",
1235+
spellId, uint32(effIndex), TARGET_DEST_NEARBY_DB);
1236+
continue;
1237+
}
12301238
}
12311239

1240+
mSpellTargetPositions.emplace(std::make_pair(spellId, effIndex), st);
1241+
12321242
} while (result->NextRow());
12331243

12341244
/*
12351245
// Check all spells
1236-
for (uint32 i = 1; i < GetSpellInfoStoreSize(); ++i)
1246+
for (SpellInfo const& spellInfo : mSpellInfoMap)
12371247
{
1238-
SpellInfo const* spellInfo = GetSpellInfo(i);
1239-
if (!spellInfo)
1248+
if (spellInfo.Difficulty != DIFFICULTY_NONE)
12401249
continue;
12411250
1242-
for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
1251+
for (SpellEffectInfo const& effect : spellInfo.GetEffects())
12431252
{
1244-
SpellEffectInfo const* effect = spellInfo->GetEffect(j);
1245-
if (!effect)
1246-
continue;
1247-
1248-
if (effect->TargetA.GetTarget() != TARGET_DEST_DB && effect->TargetB.GetTarget() != TARGET_DEST_DB)
1253+
if (effect.TargetA.GetTarget() != TARGET_DEST_DB && effect.TargetB.GetTarget() != TARGET_DEST_DB)
12491254
continue;
12501255
1251-
if (!GetSpellTargetPosition(i, SpellEffIndex(j)))
1252-
TC_LOG_DEBUG("spells", "Spell (Id: {}, EffectIndex: {}) does not have record in `spell_target_position`.", i, j);
1256+
if (!GetSpellTargetPosition(spellInfo.Id, effect.EffectIndex))
1257+
TC_LOG_DEBUG("spells", "Spell (Id: {}, EffectIndex: {}) does not have record in `spell_target_position`.", spellInfo.Id, effect.EffectIndex);
12531258
}
12541259
}
12551260
*/
12561261

1257-
TC_LOG_INFO("server.loading", ">> Loaded {} spell teleport coordinates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1262+
TC_LOG_INFO("server.loading", ">> Loaded {} spell teleport coordinates in {} ms", mSpellTargetPositions.size(), GetMSTimeDiffToNow(oldMSTime));
12581263
}
12591264

12601265
void SpellMgr::LoadSpellGroups()

src/server/game/Spells/SpellMgr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ typedef std::unordered_map<uint32, SpellThreatEntry> SpellThreatMap;
409409
// coordinates for spells (accessed using SpellMgr functions)
410410
using SpellTargetPosition = WorldLocation;
411411

412-
typedef std::map<std::pair<uint32 /*spell_id*/, SpellEffIndex /*effIndex*/>, SpellTargetPosition> SpellTargetPositionMap;
412+
typedef std::multimap<std::pair<uint32 /*spell_id*/, SpellEffIndex /*effIndex*/>, SpellTargetPosition> SpellTargetPositionMap;
413413

414414
// Enum with EffectRadiusIndex and their actual radius
415415
enum EffectRadiusIndex
@@ -729,6 +729,7 @@ class TC_GAME_API SpellMgr
729729

730730
// Spell target coordinates
731731
SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const;
732+
Trinity::IteratorPair<SpellTargetPositionMap::const_iterator> GetSpellTargetPositions(uint32 spell_id, SpellEffIndex effIndex) const;
732733

733734
// Spell Groups table
734735
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const;

0 commit comments

Comments
 (0)