Paragon: AE/TE currency, Character Advancement commit/reset, panel SQL

- mod-paragon: Paragon_Essence addon channel (PARAA), commit queue, resets,
  spell chain learn with passive child tracking, silence-window hints for
  cascade learns, trainer exemptions for pet/portal trainers
- SQL: character_paragon_panel_* tables, paragon_spell_ae_cost world data
- Core: Player Paragon class talent learn hook; Trainer skip for Paragon
  where appropriate
- Ignore local build-worldserver.log

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Docker Build
2026-05-08 21:42:39 -04:00
parent e2bed00b5c
commit 203356aca8
7 changed files with 1500 additions and 17 deletions
@@ -23,9 +23,17 @@ Paragon.Currency.GrantLevelMin = 10
Paragon.Currency.AE.PerLevel = 1
Paragon.Currency.TE.PerLevel = 1
# Flat TE cost per successful talent rank learn (hook runs once per LearnTalent).
# Applies to passive / aura-only talents (addToSpellBook == 0).
Paragon.Currency.TE.TalentLearnCost = 1
# AE cost per rank for addToSpellBook talents (Starfall, Bladestorm, …).
# Those talents also charge TE.TalentLearnCost per rank — each rank costs
# both essences at the configured amounts.
Paragon.Currency.AE.TalentLearnCost = 1
# Default AE cost when spell is not listed in world.paragon_spell_ae_cost.
Paragon.Currency.AE.DefaultSpellCost = 2
# (Phase 3a: every learnable spell baked into the Character Advancement panel
# has an explicit row of value 1 in that table, so this default only kicks in
# for spells learned via .paragon learn that aren't in the panel's bake.)
Paragon.Currency.AE.DefaultSpellCost = 1
# Diagnostics ----------------------------------------------------------------
# When enabled, dumps every Paragon's rune cooldown state to the server log
@@ -0,0 +1,34 @@
-- Spells and talents learned only through Character Advancement (Lock In / .paragon learn).
-- Apply to the character database (same as `characters`, `character_spell`, etc.).
CREATE TABLE IF NOT EXISTS `character_paragon_panel_spells` (
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
`spell_id` INT UNSIGNED NOT NULL,
PRIMARY KEY (`guid`, `spell_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='mod-paragon: spells purchased via Character Advancement';
CREATE TABLE IF NOT EXISTS `character_paragon_panel_talents` (
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
`talent_id` SMALLINT UNSIGNED NOT NULL,
`rank` TINYINT UNSIGNED NOT NULL,
PRIMARY KEY (`guid`, `talent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='mod-paragon: talent ranks purchased via Character Advancement';
-- Passive "dependent" spells that AzerothCore's `addSpell` machinery
-- (via spell_learn_spell + SPELL_EFFECT_LEARN_SPELL) auto-grants when a
-- panel-purchased spell is learned. We keep them learned (some are
-- required for the parent ability to function -- e.g. Frost Fever for
-- Icy Touch, Blood Plague for Plague Strike) but record them here so
-- Reset Abilities / Reset Everything can unlearn them alongside the
-- parent. Only passive auto-learns are tracked here; active dependents
-- (Death Coil, Death Grip, ...) are revoked at learn time and never
-- reach this table.
CREATE TABLE IF NOT EXISTS `character_paragon_panel_spell_children` (
`guid` INT UNSIGNED NOT NULL COMMENT 'characters.guid',
`parent_spell_id` INT UNSIGNED NOT NULL COMMENT 'character_paragon_panel_spells.spell_id',
`child_spell_id` INT UNSIGNED NOT NULL COMMENT 'auto-learned passive spell id',
PRIMARY KEY (`guid`, `parent_spell_id`, `child_spell_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='mod-paragon: passive auto-learn dependents to unlearn on reset';
@@ -1,11 +1,446 @@
-- Optional per-spell AE costs for Paragon spell purchases (.paragon learn).
-- Apply to the *world* database.
-- Per-spell AE costs for Paragon spell purchases (.paragon learn / panel Lock In).
-- Auto-generated by tools/_gen_paragon_spell_ae_cost_sql.py.
-- Apply to the *world* database (AzerothCore's SQL updater handles this on worldserver start).
-- The flat 1-AE cost is a Phase 3 placeholder; tune individual rows here as the
-- economy gets balanced (e.g., 5 AE for top-rank baseline like Cyclone).
CREATE TABLE IF NOT EXISTS `paragon_spell_ae_cost` (
`spell_id` INT UNSIGNED NOT NULL,
`ae_cost` SMALLINT UNSIGNED NOT NULL DEFAULT '2',
`ae_cost` SMALLINT UNSIGNED NOT NULL DEFAULT '1',
PRIMARY KEY (`spell_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='mod-paragon: AE cost per spell';
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
COMMENT='mod-paragon: AE cost per spell';
-- Bulk-load: replace the entire table with the current bake. Manual edits
-- to specific rows will be lost when this script regenerates the file --
-- track per-spell tuning in a separate INSERT ... ON DUPLICATE KEY UPDATE
-- file (e.g. paragon_spell_ae_cost_overrides.sql) if needed.
DELETE FROM `paragon_spell_ae_cost`;
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
(10, 1),
(17, 1),
(53, 1),
(72, 1),
(75, 1),
(78, 1),
(99, 1),
(100, 1),
(116, 1),
(118, 1),
(120, 1),
(122, 1),
(130, 1),
(131, 1),
(132, 1),
(133, 1),
(136, 1),
(139, 1),
(168, 1),
(172, 1),
(324, 1),
(331, 1),
(339, 1),
(348, 1),
(370, 1),
(403, 1),
(408, 1),
(421, 1),
(453, 1),
(465, 1),
(467, 1),
(469, 1),
(475, 1),
(498, 1),
(527, 1),
(528, 1),
(543, 1),
(546, 1),
(552, 1),
(556, 1),
(585, 1),
(586, 1),
(587, 1),
(588, 1),
(589, 1),
(596, 1),
(603, 1),
(604, 1),
(605, 1),
(633, 1),
(635, 1),
(642, 1),
(676, 1),
(686, 1),
(687, 1),
(689, 1),
(693, 1),
(694, 1),
(698, 1),
(702, 1),
(703, 1),
(706, 1),
(710, 1),
(740, 1),
(755, 1),
(759, 1),
(770, 1),
(772, 1),
(774, 1),
(779, 1),
(781, 1),
(845, 1),
(853, 1),
(871, 1),
(879, 1),
(883, 1),
(921, 1),
(976, 1),
(980, 1),
(982, 1),
(1002, 1),
(1008, 1),
(1022, 1),
(1038, 1),
(1044, 1),
(1064, 1),
(1079, 1),
(1082, 1),
(1098, 1),
(1120, 1),
(1126, 1),
(1130, 1),
(1152, 1),
(1160, 1),
(1161, 1),
(1243, 1),
(1449, 1),
(1454, 1),
(1459, 1),
(1462, 1),
(1463, 1),
(1464, 1),
(1490, 1),
(1494, 1),
(1495, 1),
(1499, 1),
(1510, 1),
(1513, 1),
(1515, 1),
(1535, 1),
(1543, 1),
(1680, 1),
(1706, 1),
(1714, 1),
(1715, 1),
(1719, 1),
(1725, 1),
(1752, 1),
(1766, 1),
(1776, 1),
(1784, 1),
(1822, 1),
(1833, 1),
(1842, 1),
(1850, 1),
(1856, 1),
(1943, 1),
(1949, 1),
(1953, 1),
(1966, 1),
(1978, 1),
(2006, 1),
(2008, 1),
(2050, 1),
(2054, 1),
(2060, 1),
(2061, 1),
(2062, 1),
(2094, 1),
(2096, 1),
(2098, 1),
(2120, 1),
(2136, 1),
(2139, 1),
(2362, 1),
(2457, 1),
(2458, 1),
(2484, 1),
(2565, 1),
(2637, 1),
(2641, 1),
(2643, 1),
(2645, 1),
(2687, 1),
(2782, 1),
(2812, 1),
(2825, 1),
(2893, 1),
(2908, 1),
(2912, 1),
(2944, 1),
(2948, 1),
(2973, 1),
(2974, 1),
(2983, 1),
(3034, 1),
(3043, 1),
(3044, 1),
(3045, 1),
(3411, 1),
(3561, 1),
(3562, 1),
(3563, 1),
(3565, 1),
(3566, 1),
(3567, 1),
(3738, 1),
(4987, 1),
(5116, 1),
(5118, 1),
(5138, 1),
(5143, 1),
(5171, 1),
(5176, 1),
(5185, 1),
(5209, 1),
(5211, 1),
(5215, 1),
(5217, 1),
(5221, 1),
(5225, 1),
(5229, 1),
(5246, 1),
(5277, 1),
(5308, 1),
(5384, 1),
(5484, 1),
(5500, 1),
(5502, 1),
(5504, 1);
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
(5675, 1),
(5676, 1),
(5697, 1),
(5730, 1),
(5740, 1),
(5782, 1),
(5938, 1),
(6117, 1),
(6143, 1),
(6196, 1),
(6197, 1),
(6201, 1),
(6229, 1),
(6343, 1),
(6346, 1),
(6353, 1),
(6366, 1),
(6495, 1),
(6552, 1),
(6572, 1),
(6673, 1),
(6770, 1),
(6785, 1),
(6789, 1),
(6940, 1),
(7294, 1),
(7302, 1),
(7384, 1),
(8004, 1),
(8017, 1),
(8024, 1),
(8033, 1),
(8042, 1),
(8050, 1),
(8056, 1),
(8075, 1),
(8092, 1),
(8122, 1),
(8129, 1),
(8143, 1),
(8170, 1),
(8177, 1),
(8181, 1),
(8184, 1),
(8190, 1),
(8227, 1),
(8232, 1),
(8512, 1),
(8647, 1),
(8676, 1),
(8921, 1),
(8936, 1),
(8998, 1),
(9005, 1),
(9484, 1),
(10059, 1),
(10326, 1),
(10595, 1),
(11416, 1),
(11417, 1),
(11418, 1),
(11419, 1),
(11420, 1),
(13159, 1),
(13161, 1),
(13163, 1),
(13165, 1),
(13795, 1),
(13809, 1),
(13813, 1),
(14752, 1),
(14914, 1),
(15237, 1),
(16689, 1),
(16857, 1),
(16914, 1),
(18499, 1),
(19740, 1),
(19742, 1),
(19746, 1),
(19750, 1),
(19752, 1),
(19801, 1),
(19876, 1),
(19878, 1),
(19879, 1),
(19880, 1),
(19882, 1),
(19883, 1),
(19884, 1),
(19885, 1),
(19888, 1),
(19891, 1),
(20043, 1),
(20154, 1),
(20164, 1),
(20165, 1),
(20166, 1),
(20217, 1),
(20230, 1),
(20252, 1),
(20484, 1),
(20736, 1),
(21084, 1),
(21562, 1),
(21849, 1),
(22568, 1),
(22570, 1),
(22812, 1),
(22842, 1),
(23028, 1),
(23920, 1),
(23922, 1),
(24275, 1),
(25780, 1),
(25782, 1),
(25894, 1),
(25898, 1),
(25899, 1),
(26573, 1),
(26679, 1),
(27243, 1),
(27681, 1),
(27683, 1),
(28176, 1),
(29166, 1),
(29722, 1),
(29858, 1),
(29893, 1),
(30451, 1),
(30455, 1),
(30482, 1),
(31224, 1),
(31789, 1),
(31801, 1),
(31884, 1),
(32182, 1),
(32223, 1),
(32266, 1),
(32267, 1),
(32271, 1),
(32272, 1),
(32375, 1),
(32379, 1),
(32546, 1),
(32645, 1),
(33076, 1),
(33690, 1),
(33691, 1),
(33745, 1),
(33763, 1),
(33786, 1),
(34026, 1),
(34074, 1),
(34428, 1),
(34433, 1),
(34477, 1),
(34600, 1),
(35715, 1),
(35717, 1),
(36936, 1),
(42650, 1),
(42955, 1),
(43265, 1),
(43987, 1),
(44614, 1),
(45438, 1),
(45462, 1),
(45477, 1),
(45524, 1),
(45529, 1),
(45902, 1),
(46584, 1),
(47476, 1),
(47528, 1),
(47541, 1),
(47568, 1),
(47897, 1),
(48018, 1),
(48020, 1),
(48045, 1),
(48263, 1),
(48265, 1),
(48266, 1),
(48707, 1),
(48721, 1),
(48743, 1),
(48792, 1),
(49020, 1),
(49358, 1),
(49359, 1),
(49360, 1),
(49361, 1),
(49576, 1),
(49998, 1),
(50464, 1),
(50842, 1),
(51722, 1),
(51723, 1),
(52610, 1);
INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES
(53140, 1),
(53142, 1),
(53407, 1),
(53408, 1),
(53600, 1),
(53601, 1),
(53736, 1),
(54428, 1),
(55342, 1),
(55694, 1),
(56641, 1),
(57755, 1),
(57934, 1),
(57994, 1),
(60192, 1),
(61846, 1),
(62078, 1),
(62124, 1),
(62757, 1),
(64382, 1),
(64843, 1);
-- Example (uncomment to use):
-- INSERT INTO `paragon_spell_ae_cost` (`spell_id`, `ae_cost`) VALUES (55050, 2);
File diff suppressed because it is too large Load Diff