From 46337ee2869dffc6eef6dfd2d6fd60fe4445f836 Mon Sep 17 00:00:00 2001 From: ratkosrb Date: Sun, 4 Jan 2026 08:06:53 +0200 Subject: [PATCH] Add spell cones table. --- sql/migrations/20260104051009_world.sql | 129 ++++++++++++++++++ src/game/Spells/Spell.cpp | 171 +++++++++++------------- src/game/Spells/Spell.h | 5 +- src/game/Spells/SpellMgr.cpp | 55 ++++++++ src/game/Spells/SpellMgr.h | 12 ++ src/game/World.cpp | 3 + 6 files changed, 276 insertions(+), 99 deletions(-) create mode 100644 sql/migrations/20260104051009_world.sql diff --git a/sql/migrations/20260104051009_world.sql b/sql/migrations/20260104051009_world.sql new file mode 100644 index 000000000..91d4db19b --- /dev/null +++ b/sql/migrations/20260104051009_world.sql @@ -0,0 +1,129 @@ +DROP PROCEDURE IF EXISTS add_migration; +DELIMITER ?? +CREATE PROCEDURE `add_migration`() +BEGIN +DECLARE v INT DEFAULT 1; +SET v = (SELECT COUNT(*) FROM `migrations` WHERE `id`='20260104051009'); +IF v = 0 THEN +INSERT INTO `migrations` VALUES ('20260104051009'); +-- Add your query below. + + +DROP TABLE IF EXISTS `spell_cone`; +CREATE TABLE IF NOT EXISTS `spell_cone` ( + `entry` smallint(5) unsigned NOT NULL, + `cone_degrees` smallint(6) NOT NULL COMMENT '0 to 360', + PRIMARY KEY (`entry`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +INSERT INTO `spell_cone` (`entry`, `cone_degrees`) VALUES +(5708, 90), +(8374, 90), +(9457, 90), +(11019, 90), +(12882, 90), +(12887, 90), +(15529, 359), +(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), +(22642, 90), +(22682, 120), +(22833, 120), +(22945, 120), +(22993, 120), +(23187, 120), +(23189, 120), +(23308, 120), +(23309, 120), +(23310, 120), +(23311, 120), +(23312, 120), +(23313, 120), +(23314, 120), +(23315, 120), +(23316, 120), +(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), +(25026, 45), +(25027, 30), +(25030, 90), +(25031, 45), +(25032, 10), +(25060, 90), +(25145, 90), +(25149, 90), +(25150, 90), +(25322, 90), +(25653, -120), +(25993, 120), +(26025, 180), +(26027, 180), +(26029, 5), +(27766, 90), +(27807, 90), +(28127, 90), +(28157, 45), +(28168, 120), +(28405, 180), +(28438, 180), +(28459, 90), +(28460, 90), +(28469, 360), +(28741, 120), +(28783, 30), +(29998, 180), +(30043, 90), +(30056, 180), +(30732, 180); + + +-- End of migration. +END IF; +END?? +DELIMITER ; +CALL add_migration(); +DROP PROCEDURE IF EXISTS add_migration; diff --git a/src/game/Spells/Spell.cpp b/src/game/Spells/Spell.cpp index 3565cfb1d..6e703b000 100644 --- a/src/game/Spells/Spell.cpp +++ b/src/game/Spells/Spell.cpp @@ -2779,92 +2779,79 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& break; case TARGET_ENUM_UNITS_ENEMY_IN_CONE_24: { - SpellNotifyPushType pushType = PUSH_IN_FRONT; - switch (m_spellInfo->SpellVisual) // Some spell require a different target fill - { - case 3879: - pushType = PUSH_IN_BACK; - break; - case 7441: - pushType = PUSH_IN_FRONT_15; - break; - case 7619: // anub impale - pushType = PUSH_IN_FRONT_15; - break; - } - FillAreaTargets(targetUnitMap, radius, pushType, SPELL_TARGETS_AOE_DAMAGE); + FillAreaTargets(targetUnitMap, radius, PUSH_IN_CONE, SPELL_TARGETS_AOE_DAMAGE); break; } case TARGET_ENUM_UNITS_ENEMY_IN_CONE_54: { switch (m_spellInfo->Id) { - case 24820: - case 24821: - case 24822: - case 24823: - case 24835: - case 24836: - case 24837: - case 24838: - { - UnitList tempTargetUnitMap; - FillAreaTargets(tempTargetUnitMap, radius, PUSH_SELF_CENTER, SPELL_TARGETS_AOE_DAMAGE); - - for (const auto itr : tempTargetUnitMap) + case 24820: + case 24821: + case 24822: + case 24823: + case 24835: + case 24836: + case 24837: + case 24838: { - float angle; - float arc; + UnitList tempTargetUnitMap; + FillAreaTargets(tempTargetUnitMap, radius, PUSH_SELF_CENTER, SPELL_TARGETS_AOE_DAMAGE); - switch (m_spellInfo->Id) + for (const auto itr : tempTargetUnitMap) { - case 24820: - angle = 0.0f * M_PI_F / 4.0f; - arc = 2.0f * M_PI_F / 3.0f; - break; - case 24821: - angle = 1.0f * M_PI_F / 4.0f; - arc = 2.0f * M_PI_F / 3.0f; - break; - case 24822: - angle = 2.0f * M_PI_F / 4.0f; - arc = 2.0f * M_PI_F / 3.0f; - break; - case 24823: - angle = 3.0f * M_PI_F / 4.0f; - arc = 2.0f * M_PI_F / 3.0f; - break; - case 24835: - angle = -4.0f * M_PI_F / 4.0f; - arc = 2.0f * M_PI_F / 3.0f; - break; - case 24836: - angle = -3.0f * M_PI_F / 4.0f; - arc = 2.0f * M_PI_F / 3.0f; - break; - case 24837: - angle = -2.0f * M_PI_F / 4.0f; - arc = 2.0f * M_PI_F / 3.0f; - break; - case 24838: - angle = -1.0f * M_PI_F / 4.0f; - arc = 2.0f * M_PI_F / 3.0f; - break; - default: - angle = 0.0f; - arc = M_PI_F / 2.0f; - break; + float angle; + float arc; + + switch (m_spellInfo->Id) + { + case 24820: + angle = 0.0f * M_PI_F / 4.0f; + arc = 2.0f * M_PI_F / 3.0f; + break; + case 24821: + angle = 1.0f * M_PI_F / 4.0f; + arc = 2.0f * M_PI_F / 3.0f; + break; + case 24822: + angle = 2.0f * M_PI_F / 4.0f; + arc = 2.0f * M_PI_F / 3.0f; + break; + case 24823: + angle = 3.0f * M_PI_F / 4.0f; + arc = 2.0f * M_PI_F / 3.0f; + break; + case 24835: + angle = -4.0f * M_PI_F / 4.0f; + arc = 2.0f * M_PI_F / 3.0f; + break; + case 24836: + angle = -3.0f * M_PI_F / 4.0f; + arc = 2.0f * M_PI_F / 3.0f; + break; + case 24837: + angle = -2.0f * M_PI_F / 4.0f; + arc = 2.0f * M_PI_F / 3.0f; + break; + case 24838: + angle = -1.0f * M_PI_F / 4.0f; + arc = 2.0f * M_PI_F / 3.0f; + break; + default: + angle = 0.0f; + arc = M_PI_F / 2.0f; + break; + } + + if (m_caster->HasInArc(itr, arc, angle)) + targetUnitMap.push_back(itr); } - if (m_caster->HasInArc(itr, arc, angle)) - targetUnitMap.push_back(itr); + break; } - - break; - } - default: - FillAreaTargets(targetUnitMap, radius, PUSH_IN_FRONT_90, SPELL_TARGETS_AOE_DAMAGE); - break; + default: + FillAreaTargets(targetUnitMap, radius, PUSH_IN_CONE, SPELL_TARGETS_AOE_DAMAGE); + break; } break; @@ -2881,7 +2868,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& // fill real target list if no spell script target defined FillAreaTargets(bounds.first != bounds.second ? tempTargetUnitMap : targetUnitMap, - radius, PUSH_IN_FRONT_15, bounds.first != bounds.second ? SPELL_TARGETS_ALL : targetB); + radius, PUSH_IN_CONE, bounds.first != bounds.second ? SPELL_TARGETS_ALL : targetB); for (const auto iter : tempTargetUnitMap) { @@ -8068,6 +8055,7 @@ public: Spell &i_spell; SpellNotifyPushType i_push_type; float i_radius; + float i_angle; SpellTargets i_TargetType; SpellCaster* i_originalCaster; SpellCaster* i_castingObject; @@ -8085,7 +8073,7 @@ public: SpellNotifierCreatureAndPlayer(Spell &spell, Spell::UnitList &data, float radius, SpellNotifyPushType type, SpellTargets TargetType = SPELL_TARGETS_NOT_FRIENDLY, SpellCaster* originalCaster = nullptr) - : i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_TargetType(TargetType), + : i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_angle(0.0f), i_TargetType(TargetType), i_originalCaster(originalCaster), i_castingObject(i_spell.GetCastingObject()) { if (!i_originalCaster) @@ -8093,10 +8081,9 @@ public: switch (i_push_type) { - case PUSH_IN_FRONT: - case PUSH_IN_FRONT_90: - case PUSH_IN_FRONT_15: - case PUSH_IN_BACK: + case PUSH_IN_CONE: + i_angle = sSpellMgr.GetSpellCone(i_spell.m_spellInfo->Id); + // no break case PUSH_SELF_CENTER: if (i_castingObject) { @@ -8214,21 +8201,15 @@ public: // we don't need to check InMap here, it's already done some lines above switch (i_push_type) { - case PUSH_IN_FRONT: - if (i_castingObject->IsWithinDist(unit, radius, true, SizeFactor::None) && i_castingObject->HasInArc(unit, 2 * M_PI_F / 3)) - inRange = true; - break; - case PUSH_IN_FRONT_90: - if (i_castingObject->IsWithinDist(unit, radius, true, SizeFactor::None) && i_castingObject->HasInArc(unit, M_PI_F / 2)) - inRange = true; - break; - case PUSH_IN_FRONT_15: - if (i_castingObject->IsWithinDist(unit, radius, true, SizeFactor::None) && i_castingObject->HasInArc(unit, M_PI_F / 12)) - inRange = true; - break; - case PUSH_IN_BACK: // 75 - if (i_castingObject->IsWithinDist(unit, radius, true, SizeFactor::None) && !i_castingObject->HasInArc(unit, 2 * M_PI_F - 5 * M_PI_F / 12)) - inRange = true; + case PUSH_IN_CONE: + if (i_castingObject->IsWithinDist(unit, radius, true, SizeFactor::None)) + { + // negative angle means in the back + if (i_angle > 0) + inRange = i_castingObject->HasInArc(unit, i_angle); + else if (i_angle < 0) + inRange = !i_castingObject->HasInArc(unit, (M_PI_F * 2.0f) + i_angle); + } break; case PUSH_SELF_CENTER: if (i_castingObject->IsWithinDist(unit, radius, true, SizeFactor::None)) diff --git a/src/game/Spells/Spell.h b/src/game/Spells/Spell.h index d3612a42b..5aeced88d 100644 --- a/src/game/Spells/Spell.h +++ b/src/game/Spells/Spell.h @@ -63,10 +63,7 @@ enum SpellCastFlags enum SpellNotifyPushType { - PUSH_IN_FRONT, - PUSH_IN_FRONT_90, - PUSH_IN_FRONT_15, - PUSH_IN_BACK, + PUSH_IN_CONE, PUSH_SELF_CENTER, PUSH_SRC_CENTER, PUSH_DEST_CENTER, diff --git a/src/game/Spells/SpellMgr.cpp b/src/game/Spells/SpellMgr.cpp index 7e331c296..366c7d554 100644 --- a/src/game/Spells/SpellMgr.cpp +++ b/src/game/Spells/SpellMgr.cpp @@ -2358,6 +2358,61 @@ bool SpellMgr::IsSpellValid(SpellEntry const* spellInfo, Player* pl, bool msg) return true; } +void SpellMgr::LoadSpellCones() +{ + mSpellCones.clear(); // need for reload case + + uint32 count = 0; + + // 0 1 + std::unique_ptr result(WorldDatabase.Query("SELECT `entry`, `cone_degrees` FROM `spell_cone`")); + if (!result) + { + BarGoLink bar(1); + bar.step(); + + sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, ""); + sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, ">> Loaded %u spell cones", count); + return; + } + + BarGoLink bar(result->GetRowCount()); + + do + { + Field* fields = result->Fetch(); + + bar.step(); + + uint32 entry = fields[0].GetUInt32(); + int16 degrees = fields[1].GetInt16(); + + SpellEntry const* pSpellInfo = GetSpellEntry(entry); + + if (!pSpellInfo) + { + if (!IsExistingSpellId(entry)) + sLog.Out(LOG_DBERROR, LOG_LVL_MINIMAL, "Spell %u listed in `spell_cone` does not exist", entry); + continue; + } + + if (degrees < -360 || degrees > 360) + { + sLog.Out(LOG_DBERROR, LOG_LVL_MINIMAL, "Spell %u listed in `spell_cone` has incorrect angle %u outside of valid range", entry, degrees); + continue; + } + + float angle = degrees * M_PI_F / 180.0f; + + mSpellCones[entry] = angle; + + ++count; + } while (result->NextRow()); + + sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, ""); + sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, ">> Loaded %u spell cones", count); +} + void SpellMgr::LoadSpellAreas() { mSpellAreaMap.clear(); // need for reload case diff --git a/src/game/Spells/SpellMgr.h b/src/game/Spells/SpellMgr.h index 0685b7a54..e1f1a9b64 100644 --- a/src/game/Spells/SpellMgr.h +++ b/src/game/Spells/SpellMgr.h @@ -99,6 +99,7 @@ struct SpellThreatEntry typedef std::map SpellElixirMap; typedef std::map SpellEnchantChargesMap; +typedef std::map SpellConeMap; typedef std::map SpellProcItemEnchantMap; typedef std::map SpellThreatMap; @@ -418,6 +419,15 @@ class SpellMgr return SPELL_NORMAL; } + float GetSpellCone(uint32 spellid) const + { + auto itr = mSpellCones.find(spellid); + if (itr == mSpellCones.end()) + return (60.0f * M_PI_F / 180.0f); + + return itr->second; + } + uint32 GetSpellEnchantCharges(uint32 spellid) const { auto itr = mSpellEnchantChargesMap.find(spellid); @@ -672,6 +682,7 @@ class SpellMgr void CheckUsedSpells(char const* table); // Loading data at server startup + void LoadSpellCones(); void LoadSpellChains(); void LoadSpellEnchantCharges(); void LoadSpellLearnSkills(); @@ -719,6 +730,7 @@ class SpellMgr private: SpellScriptTarget mSpellScriptTarget; + SpellConeMap mSpellCones; SpellChainMap mSpellChains; SpellChainMapNext mSpellChainsNext; SpellLearnSkillMap mSpellLearnSkills; diff --git a/src/game/World.cpp b/src/game/World.cpp index 4204cf8a7..83fbf3e48 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1607,6 +1607,9 @@ void World::SetInitialWorldSettings() sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, "Loading spell pet auras..."); sSpellMgr.LoadSpellPetAuras(); + sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, "Loading spell cones..."); + sSpellMgr.LoadSpellCones(); + sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, "Loading Player Create Info & Level Stats..."); sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, ""); sObjectMgr.LoadPlayerInfo();