import { WOW335_TALENT_NODES } from "./wow335Talents.generated"; export const WOW335_DEATH_KNIGHT_BLOOD_GORGED_TALENT_ID = "talent-2034"; const BLOOD_GORGED_DAMAGE_CHILD_IDS = [50096, 50108, 50109, 50110, 50111] as const; const BLOOD_GORGED_ARMOR_CHILD_IDS = [61274, 61275, 61276, 61277, 61278] as const; /** Local Spell.dbc uses Death Knight family 15 and this three-word aura mask. */ export const WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_NAME = 15; export const WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_MASK = [0x01400001, 0, 0] as const; const BLOOD_GORGED_NODE = WOW335_TALENT_NODES.find( (node) => node.id === WOW335_DEATH_KNIGHT_BLOOD_GORGED_TALENT_ID, ); export interface Wow335DeathKnightBloodGorgedProfile { readonly rank: number; readonly damageBonusPercent: number; readonly armorPenetrationPercent: number; readonly damageChildSpellId: number; readonly armorChildSpellId: number; readonly damageAuraType: 79; readonly damageSchoolMask: 127; readonly armorAuraType: 280; readonly spellFamilyName: 15; readonly spellFamilyMask: readonly [number, number, number]; } /** * Read the rank values and child-spell links from the generated local talent * rows. Aura types and the family mask are verified against the local 3.3.5 * Spell.dbc and recorded in docs/WOW_DEATH_KNIGHT_BLOOD_GORGED.md. */ export function wow335DeathKnightBloodGorgedProfile( rank: number, ): Wow335DeathKnightBloodGorgedProfile | null { const normalizedRank = Math.trunc(rank); const rankEffect = BLOOD_GORGED_NODE?.rankEffects[normalizedRank - 1]; const rankDescription = BLOOD_GORGED_NODE?.rankDescriptions[normalizedRank - 1]; if (normalizedRank < 1 || !rankEffect || !rankDescription) return null; const descriptionValues = rankDescription.match( /^When you are above 75% health, you deal (\d+)% more damage\. In addition, your attacks ignore up to (\d+)% of your opponent's armor at all times\.$/, ); const damageBonusPercent = Number(descriptionValues?.[1]); const armorPenetrationPercent = Number(descriptionValues?.[2]); const damageChild = rankEffect.effects.find( (effect) => effect.triggerSpellId === BLOOD_GORGED_DAMAGE_CHILD_IDS[normalizedRank - 1], ); const armorChild = rankEffect.effects.find( (effect) => effect.triggerSpellId === BLOOD_GORGED_ARMOR_CHILD_IDS[normalizedRank - 1], ); if (!descriptionValues || !damageChild || !armorChild || damageChild.basePoints !== damageBonusPercent || armorChild.basePoints !== armorPenetrationPercent || damageBonusPercent <= 0 || armorPenetrationPercent <= 0) return null; return { rank: normalizedRank, damageBonusPercent, armorPenetrationPercent, damageChildSpellId: damageChild.triggerSpellId, armorChildSpellId: armorChild.triggerSpellId, damageAuraType: 79, damageSchoolMask: 127, armorAuraType: 280, spellFamilyName: WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_NAME, spellFamilyMask: WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_MASK, }; } /** The local DBC aura applies only to matching Death Knight family-15 spells. */ export function wow335DeathKnightBloodGorgedAffectsSpell( spellFamilyName: number, spellFamilyFlags: readonly [number, number, number], ): boolean { if (spellFamilyName !== WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_NAME) return false; if (spellFamilyFlags.some((flags) => !Number.isSafeInteger(flags) || flags < 0 || flags > 0xFFFFFFFF)) return false; return WOW335_DEATH_KNIGHT_BLOOD_GORGED_FAMILY_MASK.some((mask, index) => ( (spellFamilyFlags[index] & mask) !== 0 )); } /** Above 75% is strict; exactly 75% does not receive the damage bonus. */ export function wow335DeathKnightBloodGorgedDamageBonusPercent( rank: number, currentHealth: number, maximumHealth: number, spellFamilyName: number, spellFamilyFlags: readonly [number, number, number], ): number { const profile = wow335DeathKnightBloodGorgedProfile(rank); if (!profile || !wow335DeathKnightBloodGorgedAffectsSpell(spellFamilyName, spellFamilyFlags) || !Number.isFinite(currentHealth) || currentHealth < 0 || !Number.isFinite(maximumHealth) || maximumHealth <= 0 || currentHealth <= maximumHealth * 0.75) return 0; return profile.damageBonusPercent; } /** Armor penetration is unconditional on health, but remains family-mask gated. */ export function wow335DeathKnightBloodGorgedArmorPenetrationPercent( rank: number, spellFamilyName: number, spellFamilyFlags: readonly [number, number, number], ): number { const profile = wow335DeathKnightBloodGorgedProfile(rank); if (!profile || !wow335DeathKnightBloodGorgedAffectsSpell(spellFamilyName, spellFamilyFlags)) return 0; return profile.armorPenetrationPercent; }