forked from mirror/azerothcore-wotlk
fix(DB/SpellCone): implement spell_cone table and radius calculation (#26024)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
--
|
||||
DROP TABLE IF EXISTS `spell_cone`;
|
||||
CREATE TABLE `spell_cone` (
|
||||
`ID` INT UNSIGNED NOT NULL COMMENT 'Spell ID',
|
||||
`ConeDegrees` SMALLINT NOT NULL DEFAULT '60' COMMENT 'Cone angle in degrees',
|
||||
PRIMARY KEY (`ID`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@@ -0,0 +1,106 @@
|
||||
--
|
||||
DELETE FROM `spell_cone` WHERE `ID` > 0;
|
||||
INSERT INTO `spell_cone` VALUES
|
||||
(5708, 90),
|
||||
(8374, 90),
|
||||
-- (9457, 90), -- Tharnariun's Heal
|
||||
(11019, 90),
|
||||
(12882, 90),
|
||||
(12887, 90),
|
||||
-- (15529, 359), -- Gout of Flame
|
||||
(15847, -120),
|
||||
(16094, 90),
|
||||
(16099, 90),
|
||||
(16169, 90),
|
||||
(16340, 90),
|
||||
(16350, 90),
|
||||
(16359, 90),
|
||||
(16390, 90),
|
||||
(16396, 120),
|
||||
(18144, 90),
|
||||
(18435, 120),
|
||||
(18500, 120),
|
||||
(19630, 120),
|
||||
(19641, 120),
|
||||
(19813, 180),
|
||||
(20667, 90),
|
||||
(20712, 120),
|
||||
(20716, 90),
|
||||
(20717, 90),
|
||||
(21071, 120),
|
||||
(21099, 120),
|
||||
(21189, 90),
|
||||
(21333, 180),
|
||||
(22479, 90),
|
||||
(22539, 120),
|
||||
(22558, 90),
|
||||
(22559, 90),
|
||||
(22560, 90),
|
||||
(22561, 90),
|
||||
-- (22600, 120), -- Force Reactive Disk
|
||||
(22642, 90),
|
||||
-- (22682, 120), -- Shadow Flame
|
||||
(22833, 120),
|
||||
(22945, 120),
|
||||
-- (22993, 120), -- Shadow Flame
|
||||
-- (23187, 120), -- Frost Burn
|
||||
-- (23189, 120), -- Frost Burn
|
||||
-- (23308, 120), -- Incinerate
|
||||
-- (23309, 120), -- Incinerate
|
||||
-- (23310, 120), -- Time Lapse
|
||||
-- (23311, 120), -- Time Lapse
|
||||
-- (23312, 120), -- Time Lapse
|
||||
-- (23313, 120), -- Corrosive Acid
|
||||
-- (23314, 120), -- Corrosive Acid
|
||||
-- (23315, 120), -- Ignite Flesh
|
||||
-- (23316, 120), -- Ignite Flesh
|
||||
(23339, 120),
|
||||
(23364, -120),
|
||||
(23461, 120),
|
||||
(23618, 90),
|
||||
(23919, 120),
|
||||
(24192, 120),
|
||||
(24682, 120),
|
||||
(24818, 120),
|
||||
(24821, 45),
|
||||
(24822, 135),
|
||||
(24823, 90),
|
||||
(24835, 180),
|
||||
(24836, 225),
|
||||
(24837, 270),
|
||||
(24838, 315),
|
||||
(24839, 120),
|
||||
(24933, 7),
|
||||
-- (25024, 45), -- Drop Mine
|
||||
-- (25026, 45), Activate MG Turret
|
||||
-- (25027, 30), -- Flamethrower
|
||||
(25029, 30), -- Flamethrower
|
||||
(25030, 90), -- Shoot Rocket
|
||||
-- (25031, 45), -- Shoot Missile
|
||||
-- (25032, 10), -- Machine Gun
|
||||
-- (25060, 90), -- Updraft
|
||||
(25145, 90),
|
||||
(25149, 90),
|
||||
(25150, 90),
|
||||
(25322, 90),
|
||||
(25653, -120),
|
||||
(25993, 120),
|
||||
(26025, 180), -- Impale used by 15233 Vekniss Guardian; Knockback AoE, Bleed Cone
|
||||
-- (26027, 180), -- Knockback
|
||||
(26029, 5), -- Dark Glare
|
||||
-- (27766, 90), -- Cannon
|
||||
(27807, 90),
|
||||
(28127, 90),
|
||||
(28157, 45),
|
||||
(28168, 120),
|
||||
(28405, 180),
|
||||
(28438, 180),
|
||||
(28459, 90),
|
||||
-- (28460, 90), -- Wail of Souls
|
||||
-- (28469, 360), -- Ghost Vision
|
||||
(28741, 120),
|
||||
(28783, 30),
|
||||
-- (29998, 180), -- Decrepit Fever
|
||||
(30043, 90),
|
||||
(30056, 180),
|
||||
(30732, 180);
|
||||
@@ -0,0 +1,7 @@
|
||||
--
|
||||
-- 25029 Flamethrower TARGET_UNIT_CONE_ENTRY
|
||||
-- 25030 Shoot Rocket TARGET_UNIT_CONE_ENTRY
|
||||
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceEntry` IN (25029, 25030)) AND (`SourceId` = 0) AND (`ElseGroup` = 0) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 0) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 15328) AND (`ConditionValue3` = 0);
|
||||
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
|
||||
(13, 5, 25029, 0, 0, 31, 0, 3, 15328, 0, 0, 0, 0, '', 'target must be \'Steam Stonk\''),
|
||||
(13, 1, 25030, 0, 0, 31, 0, 3, 15328, 0, 0, 0, 0, '', 'target must be \'Steam Stonk\'');
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include <cmath>
|
||||
#include <G3D/g3dmath.h>
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
// however, for some reasons removing it would cause a damn linking issue
|
||||
@@ -1225,9 +1226,28 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge
|
||||
SpellTargetObjectTypes objectType = targetType.GetObjectType();
|
||||
SpellTargetCheckTypes selectionType = targetType.GetCheckType();
|
||||
ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions;
|
||||
float coneAngle = M_PI / 2;
|
||||
float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod;
|
||||
float coneAngle = G3D::toRadians(60.0f);
|
||||
if (SpellCone const* sc = sSpellMgr->GetSpellCone(m_spellInfo->Id))
|
||||
coneAngle = G3D::toRadians(static_cast<float>(sc->cone_degrees));
|
||||
else
|
||||
{
|
||||
switch (targetType.GetTarget())
|
||||
{
|
||||
case TARGET_UNIT_CONE_ENEMY_24:
|
||||
coneAngle = G3D::toRadians(24.0f);
|
||||
break;
|
||||
case TARGET_UNIT_CONE_ENEMY_54:
|
||||
coneAngle = G3D::toRadians(54.0f);
|
||||
break;
|
||||
case TARGET_UNIT_CONE_ENEMY_104:
|
||||
coneAngle = G3D::toRadians(104.0f);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod;
|
||||
if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList))
|
||||
{
|
||||
Acore::WorldObjectSpellConeTargetCheck check(coneAngle, radius, m_caster, m_spellInfo, selectionType, condList);
|
||||
|
||||
@@ -5207,6 +5207,13 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].BasePoints = 1;
|
||||
});
|
||||
|
||||
// 26025 Impale
|
||||
ApplySpellFix({ 26025 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_1].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CONE_ENEMY_54);
|
||||
spellInfo->Effects[EFFECT_1].TargetB = SpellImplicitTargetInfo(0);
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -695,6 +695,16 @@ SpellTargetPosition const* SpellMgr::GetSpellTargetPosition(uint32 spell_id, Spe
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SpellCone const* SpellMgr::GetSpellCone(uint32 spell_id) const
|
||||
{
|
||||
spell_id = GetFirstSpellInChain(spell_id);
|
||||
auto itr = mSpellCones.find(spell_id);
|
||||
if (itr != mSpellCones.end())
|
||||
return &itr->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SpellSpellGroupMapBounds SpellMgr::GetSpellSpellGroupMapBounds(uint32 spell_id) const
|
||||
{
|
||||
spell_id = GetFirstSpellInChain(spell_id);
|
||||
@@ -1580,6 +1590,93 @@ void SpellMgr::LoadSpellTargetPositions()
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellCones()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
mSpellCones.clear(); // need for reload case
|
||||
|
||||
// 0 1
|
||||
QueryResult result = WorldDatabase.Query("SELECT ID, ConeDegrees FROM spell_cone");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 spell cone definitions. DB table `spell_cone` is empty.");
|
||||
LOG_INFO("server.loading", " ");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 spellId = fields[0].Get<uint32>();
|
||||
int16 coneDeg = fields[1].Get<int16>();
|
||||
|
||||
SpellInfo const* spellInfo = GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell (ID:{}) listed in `spell_cone` does not exist.", spellId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (coneDeg < -360 || coneDeg > 360)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell (Id: {}) cone degrees {} out of range (-360..360).", spellId, coneDeg);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 firstRankId = GetFirstSpellInChain(spellId);
|
||||
SpellInfo const* firstSpellInfo = GetSpellInfo(firstRankId);
|
||||
|
||||
SpellInfo const* checkInfo = firstSpellInfo ? firstSpellInfo : spellInfo;
|
||||
|
||||
bool hasCone = false;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (checkInfo->Effects[i].TargetA.GetSelectionCategory() == TARGET_SELECT_CATEGORY_CONE ||
|
||||
checkInfo->Effects[i].TargetB.GetSelectionCategory() == TARGET_SELECT_CATEGORY_CONE)
|
||||
{
|
||||
hasCone = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasCone)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell (ID:{}) listed in `spell_cone` does not have a cone implicit target.", spellId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (firstRankId != spellId)
|
||||
LOG_INFO("server.loading", "Spell (ID:{}) listed in `spell_cone` is not first rank; mapping to first rank {}.", spellId, firstRankId);
|
||||
|
||||
SpellCone sc{};
|
||||
sc.cone_degrees = coneDeg;
|
||||
|
||||
// Avoid overwriting an existing first-rank entry with conflicting values
|
||||
auto itr = mSpellCones.find(firstRankId);
|
||||
if (itr != mSpellCones.end())
|
||||
{
|
||||
if (itr->second.cone_degrees != sc.cone_degrees)
|
||||
LOG_ERROR("sql.sql",
|
||||
"Conflicting `spell_cone` entries for first-rank spell ID {}: {} vs {}. Keeping first value.",
|
||||
firstRankId,
|
||||
itr->second.cone_degrees,
|
||||
sc.cone_degrees);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSpellCones[firstRankId] = sc;
|
||||
++count;
|
||||
}
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Spell Cone definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellGroups()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
@@ -393,6 +393,13 @@ struct SpellTargetPosition
|
||||
|
||||
typedef std::map<std::pair<uint32 /*spell_id*/, SpellEffIndex /*effIndex*/>, SpellTargetPosition> SpellTargetPositionMap;
|
||||
|
||||
struct SpellCone
|
||||
{
|
||||
int16_t cone_degrees;
|
||||
};
|
||||
|
||||
typedef std::map<uint32 /*spell_id*/, SpellCone> SpellConeMap;
|
||||
|
||||
// Enum with EffectRadiusIndex and their actual radius
|
||||
enum EffectRadiusIndex
|
||||
{
|
||||
@@ -683,6 +690,7 @@ public:
|
||||
|
||||
// Spell target coordinates
|
||||
[[nodiscard]] SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const;
|
||||
[[nodiscard]] SpellCone const* GetSpellCone(uint32 spell_id) const;
|
||||
|
||||
// Spell Groups table
|
||||
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const;
|
||||
@@ -775,6 +783,7 @@ public:
|
||||
void LoadSpellRequired();
|
||||
void LoadSpellLearnSkills();
|
||||
void LoadSpellTargetPositions();
|
||||
void LoadSpellCones();
|
||||
void LoadSpellGroups();
|
||||
void LoadSpellGroupStackRules();
|
||||
void LoadSpellProcs();
|
||||
@@ -807,6 +816,7 @@ private:
|
||||
SpellRequiredMap mSpellReq;
|
||||
SpellLearnSkillMap mSpellLearnSkills;
|
||||
SpellTargetPositionMap mSpellTargetPositions;
|
||||
SpellConeMap mSpellCones;
|
||||
SpellSpellGroupMap mSpellSpellGroup;
|
||||
SpellGroupSpellMap mSpellGroupSpell;
|
||||
SpellGroupStackMap mSpellGroupStack;
|
||||
|
||||
@@ -682,6 +682,9 @@ void World::SetInitialWorldSettings()
|
||||
LOG_INFO("server.loading", "Loading Spell Target Coordinates...");
|
||||
sSpellMgr->LoadSpellTargetPositions();
|
||||
|
||||
LOG_INFO("server.loading", "Loading Spell Cone definitions...");
|
||||
sSpellMgr->LoadSpellCones();
|
||||
|
||||
LOG_INFO("server.loading", "Loading Enchant Custom Attributes...");
|
||||
sSpellMgr->LoadEnchantCustomAttr();
|
||||
|
||||
|
||||
@@ -164,6 +164,7 @@ public:
|
||||
{ "spell_proc", HandleReloadSpellProcsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PROC, Console::Yes },
|
||||
{ "spell_scripts", HandleReloadSpellScriptsCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes },
|
||||
{ "spell_target_position", HandleReloadSpellTargetPositionCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION, Console::Yes },
|
||||
{ "spell_cone", HandleReloadSpellConeCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION, Console::Yes },
|
||||
{ "spell_threats", HandleReloadSpellThreatsCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_THREATS, Console::Yes },
|
||||
{ "spell_group_stack_rules", HandleReloadSpellGroupStackRulesCommand, rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP_STACK_RULES, Console::Yes },
|
||||
{ "player_loot_template", HandleReloadLootTemplatesPlayerCommand, rbac::RBAC_PERM_COMMAND_RELOAD, Console::Yes },
|
||||
@@ -936,6 +937,14 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReloadSpellConeCommand(ChatHandler* handler)
|
||||
{
|
||||
LOG_INFO("server.loading", "Reloading Spell cone definitions...");
|
||||
sSpellMgr->LoadSpellCones();
|
||||
handler->SendGlobalGMSysMessage("DB table `spell_cone` reloaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReloadSpellThreatsCommand(ChatHandler* handler)
|
||||
{
|
||||
LOG_INFO("server.loading", "Reloading Aggro Spells Definitions...");
|
||||
|
||||
Reference in New Issue
Block a user