Frozen Power: cross-class proc allowlist and SQL wildcards
Relax spell_proc / spell_proc_event family gates for talent -63373; gate eligible spells in spell_sha_frozen_power via chain-head IDs (Mage, Druid, Hunter, Warlock, DK, extra Shaman spells including totems and weapon imbues). World SQL: data/sql/updates/db_world/2026_05_13_01.sql and mod-paragon 2026_05_13_00_paragon_frozen_power_proc.sql. Base dumps and SpellProcTestData aligned. Docs: CLIENT-PATCHES.md (Maelstrom tooltip note, Frozen Power hook). Client sources (rebuild patch-enUS-5 / patch-enUS-6): Classless Dev/Paragon Patch UI/Interface/FrameXML/PlayerFrame.lua and Classless Dev/Paragon Advancement/.../ParagonAdvancement_TalentData.lua — not in this repo; bake MPQ before attaching Wow.exe + patches to the Gitea release. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -21,7 +21,7 @@ when a release is published here (workflow **Sync release to Fractured-Distro**)
|
||||
| Artifact | Size | Purpose |
|
||||
|---|---|---|
|
||||
| `patch-enUS-4.MPQ` | ~5 MB | DBC + GlueXML bake. Adds `CLASS_PARAGON` (id 12), the character-create slot, glue strings, game-table DBCs, and a patched `Spell.dbc`: **(1)** `RuneCostID` zeroed on every rune-cost spell so non–Death Knight clients still send DK casts (rune costs are shown via `RuneFrame.lua`); **(2)** `Reagent[]` / `ReagentCount[]` zeroed on every spell whose `SpellFamilyName` is non-zero (all class abilities), while profession crafts (`SpellFamilyName == 0`) keep their materials. Both edits mirror server load-time corrections so client preflight and server validation stay aligned. Required for character creation as Paragon to even show up. |
|
||||
| `patch-enUS-5.MPQ` | ~64 KB | FrameXML overrides. Replaces stock `PlayerFrame.lua` / `RuneFrame.lua` / `ComboFrame.lua` / `UnitFrame.lua` / `SpellBookFrame.lua` + `SpellBookFrame.xml` with Paragon-aware versions: rune simulator, combo-point simulator, server-authoritative resource sync over the `PARAA` addon channel, action-button usability + click guards, an expanded spellbook (higher `MAX_SPELLS`, 24 skill-line tabs instead of stock 8) so all-class spells render, Paragon stat tooltips on the character sheet (including filtering duplicate “attack power from strength” lines so the paper doll matches server AP), a tooltip post-processor that appends ", Paragon" to the "Classes:" line on class-restricted gear / glyphs (the server bypasses `AllowableClass` for class 12, but the engine paints the line red and omits Paragon — the Lua hook recolors it green and adds the name so the player can tell it's wearable), a **spell-tooltip post-processor** that (1) recolors and appends "(Paragon: bypassed)" to "Requires *Stance*" lines on Warrior abilities (server-side `SpellInfo::CheckShapeshift` skips stance enforcement for Paragons on `SPELLFAMILY_WARRIOR` spells, but the client still renders the requirement from the stock `Stances` DBC field which we deliberately leave unzeroed so stock Warriors keep enforcement), (2) appends a Paragon line to **Maelstrom Weapon** (53817) noting that Fireball / Frostbolt / Arcane Blast also benefit, and (3) appends a Paragon line to **Mirror Image** (55342) noting that the images cast random damage spells with a cast time from the caster's spellbook instead of Frostbolt — all three patches gate on `UnitClass("player") == "PARAGON"` so stock-class tooltips are byte-identical to vanilla, and **PetFrame** re-anchored so the **pet unit frame sits below the rune row** for Paragon (stock layout had runes overlapping the pet portrait). A **Warrior stance click bypass** wraps `UseAction` so that for Paragon characters, clicking an action slot bound to a stance-gated Warrior ability (Whirlwind, Charge, Pummel, Shield Slam, Hamstring, Overpower, Shield Bash, Shield Block, Disarm, Revenge, Spell Reflection, Recklessness, Bladestorm, Shockwave, Concussion Blow, Last Stand, Sweeping Strikes, Mocking Blow, Heroic Fury, Slam, Devastate, Intercept) routes through `CastSpellByName(name)` instead of the engine's stance-gated `UseAction` path; the engine's stance pre-check inside `UseAction` would otherwise drop the cast packet client-side and our server-side `CheckShapeshift` bypass would never get to run. Stock classes never enter the bypass branch. The paper-doll **ammo slot** follows stock visibility rules (shown for hunters / ranged weapons; hidden when `UnitHasRelicSlot` applies). |
|
||||
| `patch-enUS-5.MPQ` | ~64 KB | FrameXML overrides. Replaces stock `PlayerFrame.lua` / `RuneFrame.lua` / `ComboFrame.lua` / `UnitFrame.lua` / `SpellBookFrame.lua` + `SpellBookFrame.xml` with Paragon-aware versions: rune simulator, combo-point simulator, server-authoritative resource sync over the `PARAA` addon channel, action-button usability + click guards, an expanded spellbook (higher `MAX_SPELLS`, 24 skill-line tabs instead of stock 8) so all-class spells render, Paragon stat tooltips on the character sheet (including filtering duplicate “attack power from strength” lines so the paper doll matches server AP), a tooltip post-processor that appends ", Paragon" to the "Classes:" line on class-restricted gear / glyphs (the server bypasses `AllowableClass` for class 12, but the engine paints the line red and omits Paragon — the Lua hook recolors it green and adds the name so the player can tell it's wearable), a **spell-tooltip post-processor** that (1) recolors and appends "(Paragon: bypassed)" to "Requires *Stance*" lines on Warrior abilities (server-side `SpellInfo::CheckShapeshift` skips stance enforcement for Paragons on `SPELLFAMILY_WARRIOR` spells, but the client still renders the requirement from the stock `Stances` DBC field which we deliberately leave unzeroed so stock Warriors keep enforcement), (2) for Paragon players appends a line to **Maelstrom Weapon** (53817) noting that Fireball and Frostbolt also benefit from the buff, (3) for Paragon players appends a line to **Mirror Image** (55342) noting that the images cast random damage spells with a cast time from the caster's spellbook instead of Frostbolt, and (4) for **every** player appends a **Fractured** line to **Frozen Power** listing the spells that can proc the 15+ yard root (server `spell_sha_frozen_power` allowlist). Warrior stance lines, Maelstrom, and Mirror Image still require Paragon so other stock-class spell tooltips stay unchanged where those hooks apply, and **PetFrame** re-anchored so the **pet unit frame sits below the rune row** for Paragon (stock layout had runes overlapping the pet portrait). A **Warrior stance click bypass** wraps `UseAction` so that for Paragon characters, clicking an action slot bound to a stance-gated Warrior ability (Whirlwind, Charge, Pummel, Shield Slam, Hamstring, Overpower, Shield Bash, Shield Block, Disarm, Revenge, Spell Reflection, Recklessness, Bladestorm, Shockwave, Concussion Blow, Last Stand, Sweeping Strikes, Mocking Blow, Heroic Fury, Slam, Devastate, Intercept) routes through `CastSpellByName(name)` instead of the engine's stance-gated `UseAction` path; the engine's stance pre-check inside `UseAction` would otherwise drop the cast packet client-side and our server-side `CheckShapeshift` bypass would never get to run. Stock classes never enter the bypass branch. The paper-doll **ammo slot** follows stock visibility rules (shown for hunters / ranged weapons; hidden when `UnitHasRelicSlot` applies). |
|
||||
| `patch-enUS-6.MPQ` | ~134 KB | The `ParagonAdvancement` addon. Replaces the talent pane (`N` key) for Paragon characters with the Character Advancement panel: per-class spell tabs, talent grid, Overview/Search tabs, AE/TE currency, commit / reset / preview, login-time toast suppression, a **PETS** tab with live hunter pet talent trees (preview learn, no TE/AE cost), a dedicated **Reset Pet Talents** control (server `PARAA` `C RESET PET TALENTS` — instant, no gold, no confirmation; requires matching worldserver), bottom-row **Reset all Abilities / Reset Build / Reset all Talents** disabled while on the PETS tab so those paths cannot dismiss the pet or unlearn Tame Beast, and a **Builds** page (full-pane overlay opened from the bottom-row Builds button) for saving named, icon-tagged loadouts: New Build (+) icon picker reuses `MACRO_ICON_FILENAMES`, right-click for edit/delete, shift-left-click to favorite (favorites bubble to the top), left-click pops a Load Build confirm. Build swaps reset + refund AE/TE, re-spend on the saved recipe, and **park hunter pets** to `PET_SAVE_NOT_IN_SLOT` so their name/talents/exp are preserved across swaps. |
|
||||
| `Wow.exe` | ~7.5 MB | 3.3.5a (build 12340) client byte-patched to skip the MPQ signature check so custom `patch-enUS-N.MPQ` files load. Diff against stock is a few bytes; everything else is unchanged. |
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ INSERT INTO `spell_proc` VALUES
|
||||
(-65661,0,15,4194321,537001988,0,16,0,2,1143,0,0,0,100,0,0),
|
||||
(-64127,0,6,1,1,0,0,6,2,0,0,0,0,0,0,0),
|
||||
(-63730,0,6,2048,4,0,0,0,2,0,0,0,0,0,100,0),
|
||||
(-63373,0,11,2147483648,0,0,65536,1,2,0,0,0,0,0,0,0),
|
||||
(-63373,0,0,0,0,0,65536,1,2,0,0,0,0,0,0,0),
|
||||
(-63156,0,5,1,192,0,0,1,2,0,0,2,0,0,0,0),
|
||||
(-62764,0,9,0,268435456,0,65536,4,2,0,0,0,0,100,0,0),
|
||||
(-61846,0,0,0,0,0,64,0,2,0,0,0,0,0,0,0),
|
||||
|
||||
@@ -48,7 +48,7 @@ INSERT INTO `spell_proc_event` VALUES
|
||||
(-65661,0,15,4194321,537001988,0,16,0,0,0,100,0),
|
||||
(-64127,0,6,1,1,0,0,0,0,0,0,0),
|
||||
(-63730,0,6,2048,4,0,0,0,1,0,0,0),
|
||||
(-63373,0,11,2147483648,0,0,65536,0,0,0,0,0),
|
||||
(-63373,0,0,0,0,0,65536,0,0,0,0,0),
|
||||
(-63156,126,5,1,192,0,65536,0,0,0,0,0),
|
||||
(-62764,0,9,0,268435456,0,65536,0,0,0,100,0),
|
||||
(-61846,0,0,0,0,0,64,0,0,0,0,0),
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
-- DB update 2026_05_13_00 -> 2026_05_13_01
|
||||
-- Fractured: Frozen Power (-63373) proc family gate cleared; eligible spells are enforced in spell_sha_frozen_power (cross-class nuke/shock list).
|
||||
|
||||
UPDATE `spell_proc`
|
||||
SET `SpellFamilyName` = 0, `SpellFamilyMask0` = 0, `SpellFamilyMask1` = 0, `SpellFamilyMask2` = 0
|
||||
WHERE `SpellId` = -63373;
|
||||
|
||||
UPDATE `spell_proc_event`
|
||||
SET `SpellFamilyName` = 0, `SpellFamilyMask0` = 0, `SpellFamilyMask1` = 0, `SpellFamilyMask2` = 0
|
||||
WHERE `entry` = -63373;
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
-- mod-paragon: Frozen Power (-63373) cross-family wildcard (Fractured).
|
||||
--
|
||||
-- Stock 3.3.5 `spell_proc` for Frozen Power gates by SpellFamilyName=11
|
||||
-- (SHAMAN) plus SpellFamilyMask0=0x80000000 (Frost Shock only). The proc
|
||||
-- engine therefore never calls spell_sha_frozen_power::CheckProc when the
|
||||
-- damaging spell is not a Shaman Frost Shock family match.
|
||||
--
|
||||
-- We relax the row so:
|
||||
-- * SpellFamilyName=0 wildcard -- IsAffected short-circuits to true
|
||||
-- * SpellFamilyMask{0,1,2}=0 wildcard -- no flag-bit gating at this layer
|
||||
-- * ProcFlags / SpellTypeMask / SpellPhaseMask / HitMask unchanged from stock
|
||||
--
|
||||
-- Real filtering moves into spell_sha_frozen_power::CheckProc (first-rank
|
||||
-- spell id allowlist: Mage nukes, DK Howling Blast, Shaman LB/CL/shocks/
|
||||
-- Lava Burst, etc.) plus the existing 15 yd minimum and dummy effect chance.
|
||||
--
|
||||
-- Net effect: Fractured Frozen Power roots can proc from the curated spell
|
||||
-- list; stock proc timing (done negative magic damage, hit phase) is unchanged.
|
||||
|
||||
UPDATE `spell_proc`
|
||||
SET `SpellFamilyName` = 0, `SpellFamilyMask0` = 0, `SpellFamilyMask1` = 0, `SpellFamilyMask2` = 0
|
||||
WHERE `SpellId` = -63373;
|
||||
|
||||
UPDATE `spell_proc_event`
|
||||
SET `SpellFamilyName` = 0, `SpellFamilyMask0` = 0, `SpellFamilyMask1` = 0, `SpellFamilyMask2` = 0
|
||||
WHERE `entry` = -63373;
|
||||
@@ -1373,12 +1373,81 @@ class spell_sha_frozen_power : public AuraScript
|
||||
return ValidateSpellInfo({ SPELL_SHAMAN_FROZEN_POWER_ROOT });
|
||||
}
|
||||
|
||||
// Any rank of these spells normalizes to this chain head via GetFirstRankSpell().
|
||||
static bool IsFrozenPowerProcSpellChainHead(uint32 chainHeadSpellId)
|
||||
{
|
||||
switch (chainHeadSpellId)
|
||||
{
|
||||
case 10: // Blizzard
|
||||
case 116: // Frostbolt
|
||||
case 120: // Cone of Cold
|
||||
case 133: // Fireball
|
||||
case 348: // Immolate
|
||||
case 403: // Lightning Bolt
|
||||
case 421: // Chain Lightning
|
||||
case 1949: // Hellfire
|
||||
case 1978: // Serpent Sting
|
||||
case 2136: // Fire Blast
|
||||
case 2948: // Scorch
|
||||
case 29722: // Incinerate
|
||||
case 3606: // Searing Totem attack
|
||||
case 3674: // Black Arrow
|
||||
case 44457: // Living Bomb
|
||||
case 5176: // Wrath
|
||||
case 5570: // Insect Swarm
|
||||
case 5676: // Searing Pain
|
||||
case 5740: // Rain of Fire
|
||||
case 6353: // Soul Fire
|
||||
case 8026: // Flametongue Weapon proc
|
||||
case 8034: // Frostbrand Weapon proc
|
||||
case 8042: // Earth Shock
|
||||
case 8050: // Flame Shock
|
||||
case 8056: // Frost Shock
|
||||
case 8187: // Magma Totem proc
|
||||
case 11366: // Pyroblast
|
||||
case 13797: // Immolation Trap
|
||||
case 13813: // Explosive Trap
|
||||
case 1535: // Fire Nova
|
||||
case 16914: // Hurricane
|
||||
case 26364: // Lightning Shield proc
|
||||
case 30455: // Ice Lance
|
||||
case 31661: // Dragon's Breath
|
||||
case 44614: // Frostfire Bolt
|
||||
case 45477: // Icy Touch
|
||||
case 45524: // Chains of Ice
|
||||
case 48505: // Starfall (caster aura chain)
|
||||
case 49143: // Frost Strike
|
||||
case 49184: // Howling Blast
|
||||
case 50288: // Starfall single-target damage chain
|
||||
case 50294: // Starfall AoE damage chain
|
||||
case 50516: // Typhoon
|
||||
case 50796: // Chaos Bolt
|
||||
case 51209: // Hungering Cold
|
||||
case 51490: // Thunderstorm
|
||||
case 51505: // Lava Burst
|
||||
case 53301: // Explosive Shot
|
||||
case 71757: // Deep Freeze
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
Unit* target = eventInfo.GetActionTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
SpellInfo const* procSpell = eventInfo.GetSpellInfo();
|
||||
if (!procSpell)
|
||||
return false;
|
||||
|
||||
SpellInfo const* firstRank = procSpell->GetFirstRankSpell();
|
||||
uint32 const firstId = firstRank ? firstRank->Id : procSpell->Id;
|
||||
if (!IsFrozenPowerProcSpellChainHead(firstId))
|
||||
return false;
|
||||
|
||||
// Don't proc if target is within 15 yards
|
||||
if (GetTarget()->GetDistance(target) < 15.0f)
|
||||
return false;
|
||||
|
||||
@@ -110,7 +110,7 @@ inline std::vector<SpellProcTestEntry> GetAllSpellProcTestEntries()
|
||||
{ -65661, 0, 15, 4194321, 537001988, 0, 16, 1, 2, 0, 0, 0, 100.0f, 0.0f, 0, 0, 0, 0, 0 },
|
||||
{ -64127, 0, 6, 1, 1, 0, 0, 6, 2, 0, 0, 0, 0.0f, 0.0f, 0, 0, 0, 0, 0 },
|
||||
{ -63730, 0, 6, 2048, 4, 0, 0, 0, 2, 0, 0, 100, 0.0f, 0.0f, 0, 0, 0, 0, 0 },
|
||||
{ -63373, 0, 11, 2147483648, 0, 0, 65536, 1, 2, 0, 0, 0, 0.0f, 0.0f, 0, 0, 0, 0, 0 },
|
||||
{ -63373, 0, 0, 0, 0, 0, 65536, 1, 2, 0, 0, 0, 0.0f, 0.0f, 0, 0, 0, 0, 0 },
|
||||
{ -63156, 0, 5, 1, 192, 0, 0, 1, 2, 0, 0, 0, 0.0f, 0.0f, 0, 0, 0, 0, 0 },
|
||||
{ -62764, 0, 9, 0, 268435456, 0, 65536, 4, 2, 0, 0, 0, 100.0f, 0.0f, 0, 0, 0, 0, 0 },
|
||||
{ -61846, 0, 0, 0, 0, 0, 64, 0, 2, 0, 0, 0, 0.0f, 0.0f, 0, 0, 0, 0, 0 },
|
||||
|
||||
Reference in New Issue
Block a user