From 586c51b53a57217242e2a9b00a2e1c5c72895fc1 Mon Sep 17 00:00:00 2001 From: Brues <5278969+brues-code@users.noreply.github.com> Date: Sun, 26 Jul 2026 15:40:26 -0500 Subject: [PATCH] Detect bleeds authoritatively via Spell.dbc mechanics Add a GetSpellSchool bleed check (Priority 0.5) backed by DBC SpellMechanic data instead of damage-event learning / name patterns: - GetSpellMechanicByID == 15 catches spell-level bleeds (Garrote, Rupture, Rend, Rip, Pounce, Deep Wounds). - New ClassicAPI GetSpellEffectMechanics catches effect-level bleeds that the spell-level field misses -- Rake is spell-level 0 with EffectMechanic[2]=15. Wrap C_Spell.GetSpellEffectMechanics in ClassicAPI.lua (nil-guarded so older builds fall back to spell-level only). Verified against the client Spell.dbc. Also drop Hemorrhage from the bleed name-pattern fallback: the DBC gives it no bleed mechanic (physical damage), so bleed-immune mobs don't resist it -- it was a false positive. Existing learning / split-damage / patterns remain as fallback. --- ClassicAPI.lua | 13 +++++++++++++ Utility.lua | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/ClassicAPI.lua b/ClassicAPI.lua index 505ea74..b18498e 100644 --- a/ClassicAPI.lua +++ b/ClassicAPI.lua @@ -168,6 +168,19 @@ function API.GetSpellMechanicByID(spellID) return C_Spell.GetSpellMechanicByID(spellID) end +-- Per-effect SpellMechanic ids (Spell.dbc EffectMechanic[3]) as {m1, m2, m3}, +-- or nil for an invalid spell / 0 for an effect with no mechanic. Complements +-- GetSpellMechanicByID, which only reads the spell-level Mechanic field: vanilla +-- stores some mechanics on an effect instead (e.g. Rake's bleed is effect-level, +-- so GetSpellMechanicByID returns 0 but this returns {0,15,0}). Nil-guarded so an +-- older ClassicAPI build without the function degrades gracefully. +function API.GetSpellEffectMechanics(spellID) + if type(C_Spell.GetSpellEffectMechanics) == "function" then + return C_Spell.GetSpellEffectMechanics(spellID) + end + return nil +end + -------------------------------------------------------------------------------- -- State -------------------------------------------------------------------------------- diff --git a/Utility.lua b/Utility.lua index bff18f3..4f2b307 100644 --- a/Utility.lua +++ b/Utility.lua @@ -7515,6 +7515,26 @@ local spellSchoolCache = {} -- 7. Tooltip scanning (player's spellbook only) -- 8. Name pattern matching (fallback, least accurate) -- Returns nil if school cannot be determined (not cached) +-- Authoritative bleed test from Spell.dbc mechanics. A bleed carries +-- SpellMechanic 15 either at the spell level (Garrote/Rupture/Rend/Rip/Pounce/ +-- Deep Wounds) OR on an effect (Rake: spell-level 0, EffectMechanic[2]=15), so +-- both must be checked -- GetSpellMechanicByID alone misses the effect-level case. +local SPELL_MECHANIC_BLEED = 15 +local function IsBleedByMechanic(spellID) + if not spellID then return false end + local API = CleveRoids.ClassicAPI + if API.GetSpellMechanicByID(spellID) == SPELL_MECHANIC_BLEED then + return true + end + local em = API.GetSpellEffectMechanics(spellID) + if em then + for i = 1, 3 do + if em[i] == SPELL_MECHANIC_BLEED then return true end + end + end + return false +end + local function GetSpellSchool(spellName, spellID) if not spellName and not spellID then return nil end @@ -7522,7 +7542,7 @@ local function GetSpellSchool(spellName, spellID) local baseName = nil if spellName then baseName = string.gsub(spellName, "%s*%(.-%)%s*$", "") - elseif spellID and GetSpellRecField then + elseif spellID then local fullName = C_Spell.GetSpellName(spellID) if fullName then baseName = string.gsub(fullName, "%s*%(.-%)%s*$", "") @@ -7538,6 +7558,14 @@ local function GetSpellSchool(spellName, spellID) return school end + -- PRIORITY 0.5: DBC bleed mechanic (authoritative, proactive). Catches bleeds + -- before any damage event is seen, incl. effect-level ones like Rake, and + -- correctly excludes non-bleeds the name patterns would false-positive (e.g. + -- Hemorrhage). Only bleed is decided here; other schools fall through. + if spellID and IsBleedByMechanic(spellID) then + return "bleed" + end + -- PRIORITY 1: Use learned school from Nampower damage events (most accurate) if spellID and CleveRoids.spellSchoolMapping[spellID] then return CleveRoids.spellSchoolMapping[spellID] @@ -7656,7 +7684,9 @@ local function GetSpellSchool(spellName, spellID) -- Bleed effects (DoTs that ignore armor) if string.find(lower, "rip") or string.find(lower, "rake") or string.find(lower, "rupture") or string.find(lower, "garrote") or string.find(lower, "rend") or string.find(lower, "deep wound") or - string.find(lower, "hemorrhage") or string.find(lower, "pounce") then + string.find(lower, "pounce") then + -- NOTE: Hemorrhage intentionally excluded -- Spell.dbc gives it no bleed + -- mechanic (its damage is physical), so bleed-immune mobs don't resist it. school = "bleed" -- Arcane