Paragon: cascade guard for class skill lines + panel catalog backfill
The skill-line cascade in Player::learnSkillRewardedSpells re-fires from _LoadSkills (every login), UpdateSkillsForLevel (every level-up), UpdateSkillPro (every weapon-skill tick on a training dummy), and SetSkill (first time a class skill is granted). Each pass re-grants every SkillLineAbility-tagged class ability on the matching skill line, which leaks Blood Presence / Death Coil / Death Grip / etc. back into the spellbook within seconds even after the player intentionally refunded them via the Character Advancement panel. Path B fix: a 5-line guard at the top of learnSkillRewardedSpells skips the cascade for class-category skill lines on CLASS_PARAGON characters. mod-paragon already calls Player::learnSpell directly for the abilities the player actually purchased (and their attached passives), so the panel becomes the sole authority over class abilities. Profession, weapon, language, and racial cascades stay enabled so recipe auto-learn, weapon proficiencies, and racial perks still work. Side effect: passives that previously rode along on the cascade (Forceful Deflection on Blood Strike, Runic Focus on Icy Touch) must be force-attached the same way Blood Plague / Frost Fever already are. Extend kAttached and kFixup in Paragon_Essence.cpp to do that; existing characters self-heal on next login. Backfill paragon_spell_ae_cost for 42 spells newly exposed by the panel after the ClassMask=0 filter was removed from the client catalog generator (Lava Burst, Hex, Evocation, Kill Shot, Path of Frost, Horn of Winter, Rune Strike, Raise Ally, Dark Command, etc.). Migration is INSERT IGNORE so any per-spell tuning on existing rows is preserved. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -21,6 +21,7 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(10, 1),
|
||||
(17, 1),
|
||||
(53, 1),
|
||||
(66, 1),
|
||||
(72, 1),
|
||||
(75, 1),
|
||||
(78, 1),
|
||||
@@ -30,6 +31,7 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(118, 1),
|
||||
(120, 1),
|
||||
(122, 1),
|
||||
(126, 1),
|
||||
(130, 1),
|
||||
(131, 1),
|
||||
(132, 1),
|
||||
@@ -52,6 +54,7 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(469, 1),
|
||||
(475, 1),
|
||||
(498, 1),
|
||||
(526, 1),
|
||||
(527, 1),
|
||||
(528, 1),
|
||||
(543, 1),
|
||||
@@ -73,22 +76,28 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(676, 1),
|
||||
(686, 1),
|
||||
(687, 1),
|
||||
(688, 1),
|
||||
(689, 1),
|
||||
(691, 1),
|
||||
(693, 1),
|
||||
(694, 1),
|
||||
(697, 1),
|
||||
(698, 1),
|
||||
(702, 1),
|
||||
(703, 1),
|
||||
(706, 1),
|
||||
(710, 1),
|
||||
(712, 1),
|
||||
(740, 1),
|
||||
(755, 1),
|
||||
(759, 1),
|
||||
(768, 1),
|
||||
(770, 1),
|
||||
(772, 1),
|
||||
(774, 1),
|
||||
(779, 1),
|
||||
(781, 1),
|
||||
(783, 1),
|
||||
(845, 1),
|
||||
(853, 1),
|
||||
(871, 1),
|
||||
@@ -104,6 +113,7 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(1038, 1),
|
||||
(1044, 1),
|
||||
(1064, 1),
|
||||
(1066, 1),
|
||||
(1079, 1),
|
||||
(1082, 1),
|
||||
(1098, 1),
|
||||
@@ -176,6 +186,7 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(2812, 1),
|
||||
(2825, 1),
|
||||
(2893, 1),
|
||||
(2894, 1),
|
||||
(2908, 1),
|
||||
(2912, 1),
|
||||
(2944, 1),
|
||||
@@ -194,6 +205,7 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(3565, 1),
|
||||
(3566, 1),
|
||||
(3567, 1),
|
||||
(3714, 1),
|
||||
(3738, 1),
|
||||
(4987, 1),
|
||||
(5116, 1),
|
||||
@@ -205,7 +217,9 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(5185, 1),
|
||||
(5209, 1),
|
||||
(5211, 1),
|
||||
(5215, 1),
|
||||
(5215, 1);
|
||||
|
||||
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(5217, 1),
|
||||
(5221, 1),
|
||||
(5225, 1),
|
||||
@@ -215,11 +229,10 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(5308, 1),
|
||||
(5384, 1),
|
||||
(5484, 1),
|
||||
(5487, 1),
|
||||
(5500, 1),
|
||||
(5502, 1),
|
||||
(5504, 1);
|
||||
|
||||
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(5504, 1),
|
||||
(5675, 1),
|
||||
(5676, 1),
|
||||
(5697, 1),
|
||||
@@ -244,6 +257,8 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(6770, 1),
|
||||
(6785, 1),
|
||||
(6789, 1),
|
||||
(6795, 1),
|
||||
(6807, 1),
|
||||
(6940, 1),
|
||||
(7294, 1),
|
||||
(7302, 1),
|
||||
@@ -283,6 +298,7 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(11418, 1),
|
||||
(11419, 1),
|
||||
(11420, 1),
|
||||
(12051, 1),
|
||||
(13159, 1),
|
||||
(13161, 1),
|
||||
(13163, 1),
|
||||
@@ -297,6 +313,7 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(16857, 1),
|
||||
(16914, 1),
|
||||
(18499, 1),
|
||||
(19263, 1),
|
||||
(19740, 1),
|
||||
(19742, 1),
|
||||
(19746, 1),
|
||||
@@ -323,7 +340,6 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(20252, 1),
|
||||
(20484, 1),
|
||||
(20736, 1),
|
||||
(21084, 1),
|
||||
(21562, 1),
|
||||
(21849, 1),
|
||||
(22568, 1),
|
||||
@@ -331,6 +347,8 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(22812, 1),
|
||||
(22842, 1),
|
||||
(23028, 1),
|
||||
(23161, 1),
|
||||
(23214, 1),
|
||||
(23920, 1),
|
||||
(23922, 1),
|
||||
(24275, 1),
|
||||
@@ -349,6 +367,7 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(29722, 1),
|
||||
(29858, 1),
|
||||
(29893, 1),
|
||||
(30449, 1),
|
||||
(30451, 1),
|
||||
(30455, 1),
|
||||
(30482, 1),
|
||||
@@ -372,12 +391,14 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(33745, 1),
|
||||
(33763, 1),
|
||||
(33786, 1),
|
||||
(33943, 1),
|
||||
(34026, 1),
|
||||
(34074, 1),
|
||||
(34428, 1),
|
||||
(34433, 1),
|
||||
(34477, 1),
|
||||
(34600, 1),
|
||||
(34767, 1),
|
||||
(35715, 1),
|
||||
(35717, 1),
|
||||
(36936, 1),
|
||||
@@ -398,7 +419,9 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(47541, 1),
|
||||
(47568, 1),
|
||||
(47897, 1),
|
||||
(48018, 1),
|
||||
(48018, 1);
|
||||
|
||||
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(48020, 1),
|
||||
(48045, 1),
|
||||
(48263, 1),
|
||||
@@ -416,14 +439,19 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(49576, 1),
|
||||
(49998, 1),
|
||||
(50464, 1),
|
||||
(50769, 1),
|
||||
(50842, 1),
|
||||
(51505, 1),
|
||||
(51514, 1),
|
||||
(51722, 1),
|
||||
(51723, 1),
|
||||
(52610, 1);
|
||||
|
||||
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(51730, 1),
|
||||
(52127, 1),
|
||||
(52610, 1),
|
||||
(53140, 1),
|
||||
(53142, 1),
|
||||
(53271, 1),
|
||||
(53351, 1),
|
||||
(53407, 1),
|
||||
(53408, 1),
|
||||
(53600, 1),
|
||||
@@ -432,15 +460,23 @@ INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(54428, 1),
|
||||
(55342, 1),
|
||||
(55694, 1),
|
||||
(56222, 1),
|
||||
(56641, 1),
|
||||
(56815, 1),
|
||||
(57330, 1),
|
||||
(57755, 1),
|
||||
(57934, 1),
|
||||
(57994, 1),
|
||||
(60192, 1),
|
||||
(61846, 1),
|
||||
(61999, 1),
|
||||
(62078, 1),
|
||||
(62124, 1),
|
||||
(62757, 1),
|
||||
(64382, 1),
|
||||
(64843, 1);
|
||||
(64843, 1),
|
||||
(64901, 1),
|
||||
(66842, 1),
|
||||
(66843, 1),
|
||||
(66844, 1);
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
-- mod-paragon: backfill paragon_spell_ae_cost rows for spells newly exposed
|
||||
-- by the Character Advancement panel after removing the over-aggressive
|
||||
-- ClassMask=0 filter from tools/_gen_paragon_advancement_spells_lua.py.
|
||||
--
|
||||
-- The base file (data/sql/db-world/base/paragon_spell_ae_cost.sql) was
|
||||
-- regenerated alongside this migration so fresh deployments already have
|
||||
-- these rows. Existing servers do not re-run base files on content change,
|
||||
-- so this update inserts the new (spell_id, ae_cost) pairs idempotently.
|
||||
-- INSERT IGNORE keeps any per-row tuning a server operator may have already
|
||||
-- applied to spell_ids that happen to overlap.
|
||||
--
|
||||
-- New ids include: 51505 Lava Burst (Shaman), 12051 Evocation / 1066 Aqueous
|
||||
-- Form / Hex / Mage Ward / Spellsteal (Mage), 53351 Kill Shot / 19263
|
||||
-- Deterrence / 53271 Master's Call (Hunter), 3714 Path of Frost / 57330
|
||||
-- Horn of Winter / 56815 Rune Strike / 61999 Raise Ally / 56222 Dark Command
|
||||
-- (DK), and 39 other trainer-taught class abilities whose stock
|
||||
-- SkillLineAbility.dbc rows have ClassMask=0 (the skill line itself pins the
|
||||
-- class for these rows; ClassMask is redundant on class-spec lines).
|
||||
|
||||
INSERT IGNORE INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
|
||||
(66, 1), -- Invisibility (Mage)
|
||||
(126, 1), -- Eye of Kilrogg (Warlock)
|
||||
(526, 1), -- Cure Toxins (Shaman)
|
||||
(688, 1), -- Summon Imp (Warlock)
|
||||
(691, 1), -- Summon Felhunter (Warlock)
|
||||
(697, 1), -- Summon Voidwalker (Warlock)
|
||||
(712, 1), -- Summon Succubus (Warlock)
|
||||
(768, 1), -- Cat Form (Druid)
|
||||
(783, 1), -- Travel Form (Druid)
|
||||
(1066, 1), -- Aqueous Form (Mage)
|
||||
(2894, 1), -- Fire Resistance Totem (Shaman)
|
||||
(3714, 1), -- Path of Frost (DK)
|
||||
(5215, 1), -- Prowl (Druid)
|
||||
(5487, 1), -- Bear Form (Druid)
|
||||
(5504, 1), -- Conjure Refreshment (Mage)
|
||||
(6795, 1), -- Growl (Druid)
|
||||
(6807, 1), -- Maul (Druid)
|
||||
(12051, 1), -- Evocation (Mage)
|
||||
(19263, 1), -- Deterrence (Hunter)
|
||||
(23161, 1), -- Summon Dreadsteed (Warlock)
|
||||
(23214, 1), -- Summon Charger (Paladin)
|
||||
(30449, 1), -- Spellsteal (Mage)
|
||||
(33943, 1), -- Flight Form (Druid)
|
||||
(34767, 1), -- Summon Felguard (Warlock)
|
||||
(48018, 1), -- Demonic Circle: Summon (Warlock)
|
||||
(50769, 1), -- Revive (Druid)
|
||||
(51505, 1), -- Lava Burst (Shaman)
|
||||
(51514, 1), -- Hex (Shaman)
|
||||
(51730, 1), -- Earthliving Weapon (Shaman)
|
||||
(52127, 1), -- Water Shield (Shaman)
|
||||
(52610, 1), -- Savage Roar (Druid)
|
||||
(53271, 1), -- Master's Call (Hunter)
|
||||
(53351, 1), -- Kill Shot (Hunter)
|
||||
(56222, 1), -- Dark Command (DK)
|
||||
(56815, 1), -- Rune Strike (DK)
|
||||
(57330, 1), -- Horn of Winter (DK)
|
||||
(61999, 1), -- Raise Ally (DK)
|
||||
(64843, 1), -- Divine Hymn (Priest)
|
||||
(64901, 1), -- Hymn of Hope (Priest)
|
||||
(66842, 1), -- Call of the Elements (Shaman totem set)
|
||||
(66843, 1), -- Call of the Ancestors (Shaman totem set)
|
||||
(66844, 1); -- Call of the Spirits (Shaman totem set)
|
||||
@@ -1203,10 +1203,21 @@ void PanelLearnSpellChain(Player* pl, uint32 baseSpellId)
|
||||
// spellbook icons. The correct *passive* spellbook entries the
|
||||
// player is supposed to see are 59879 / 59921 (the descriptive
|
||||
// "Passive disease" rows; SPELL_ATTR0_PASSIVE bit set).
|
||||
// After the Paragon class-skill cascade guard landed in
|
||||
// Player::learnSkillRewardedSpells, NONE of the DK skill-line
|
||||
// cascade rewards are auto-granted any more — so passives that
|
||||
// used to ride along on a class skill cascade (Forceful
|
||||
// Deflection on Blood Strike, Runic Focus on Icy Touch) must be
|
||||
// explicitly attached here, the same way Blood Plague / Frost
|
||||
// Fever are. Add new entries when a panel-purchased active is
|
||||
// expected to come with a passive spellbook entry that no
|
||||
// SPELL_EFFECT_LEARN_SPELL on the parent provides.
|
||||
struct AttachedPassive { uint32 parentHead; uint32 attachedSpell; };
|
||||
static AttachedPassive const kAttached[] = {
|
||||
{ 45462, 59879 }, // Plague Strike -> Blood Plague (passive entry)
|
||||
{ 45477, 59921 }, // Icy Touch -> Frost Fever (passive entry)
|
||||
{ 45477, 59921 }, // Icy Touch -> Frost Fever (passive entry)
|
||||
{ 45477, 61455 }, // Icy Touch -> Runic Focus (parry from spell power)
|
||||
{ 45902, 49410 }, // Blood Strike -> Forceful Deflection (parry from strength)
|
||||
};
|
||||
|
||||
// Self-heal: a previous build of mod-paragon (briefly shipped)
|
||||
@@ -3889,16 +3900,25 @@ public:
|
||||
lb.child, lb.parent, player->GetName());
|
||||
}
|
||||
}
|
||||
// 2b) Re-attach the correct passive spellbook entry (59879 /
|
||||
// 59921) for any panel-purchased Plague Strike / Icy Touch
|
||||
// that's missing it. `learnSpell` here can re-fire the DK
|
||||
// skill-line cascade and re-grant Blood Presence / Death
|
||||
// Coil / Death Grip / Forceful Deflection — Step 3's
|
||||
// scoped sweep is what cleans those up.
|
||||
// 2b) Re-attach the correct passive spellbook entries for any
|
||||
// panel-purchased parent that is missing them. After the
|
||||
// class-skill cascade guard in
|
||||
// Player::learnSkillRewardedSpells, the cascade no longer
|
||||
// fires for Paragons, so these attachments are the ONLY
|
||||
// source for the disease passive icons (Blood Plague /
|
||||
// Frost Fever) and the small DK weapon passives (Forceful
|
||||
// Deflection from Blood Strike, Runic Focus from Icy
|
||||
// Touch). Existing characters predating the guard may
|
||||
// have FD/RF in their spellbook from the cascade but no
|
||||
// panel_spell_children row tying them to the parent;
|
||||
// re-running learnSpell when they already have the spell
|
||||
// just records the child row and is a no-op otherwise.
|
||||
struct LegacyFix { uint32 parent; uint32 correctChild; };
|
||||
static LegacyFix const kFixup[] = {
|
||||
{ 45462, 59879 },
|
||||
{ 45477, 59921 },
|
||||
{ 45462, 59879 }, // Plague Strike -> Blood Plague (passive)
|
||||
{ 45477, 59921 }, // Icy Touch -> Frost Fever (passive)
|
||||
{ 45477, 61455 }, // Icy Touch -> Runic Focus
|
||||
{ 45902, 49410 }, // Blood Strike -> Forceful Deflection
|
||||
};
|
||||
for (auto const& lf : kFixup)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user