import type { ActiveAura } from "./combatAuras"; import type { EnemyAuraSourceProfile, EnemySourceAuraContract } from "./enemySourceAuras"; const BLOODLUST_EFFECT = Object.freeze({ effectType: 6, auraType: 138, basePoints: 30, mechanic: 0, implicitTargetA: 21, implicitTargetB: 0, radius: 0, miscValue: 0, periodMs: 0, }); const bloodlustContract = (profile: EnemyAuraSourceProfile): EnemySourceAuraContract => Object.freeze({ spellId: 6742, name: "Bloodlust", profile, signature: Object.freeze({ rangeIndex: 4, schoolMask: 8, damageClass: 1, durationMs: 30_000, effects: Object.freeze([BLOODLUST_EFFECT]), }), durationMs: 30_000, targetGeometry: Object.freeze({ kind: "explicit-friendly", rangeYards: 30 }), disposition: "buff", dispelCategory: "magic", stackAmount: 0, childTriggerSpellIds: Object.freeze([]), modifiers: Object.freeze([ Object.freeze({ kind: "stat", stat: "melee-haste", operation: "flat", value: 30, multiplicative: true }), ]), unsupportedEffects: Object.freeze([]), }); const CONTRACTS: Readonly> = Object.freeze({ ascension: bloodlustContract("ascension"), epoch: bloodlustContract("epoch"), }); /** Return the profile-specific audited Spell.dbc contract for NPC Bloodlust 6742. */ export function enemyBloodlustContract(profile: EnemyAuraSourceProfile): EnemySourceAuraContract { return CONTRACTS[profile]; } /** * Return the remaining main-hand/off-hand swing interval multiplier for one * enemy's already-filtered active auras. Marked source Aura 138 modifiers use * AzerothCore's separate percent speed factors; unmarked modifiers retain the * runtime's existing additive haste calculation as a compatibility fallback. */ export function enemyMeleeHasteIntervalMultiplier(auras: readonly ActiveAura[]): number { let sourceIntervalMultiplier = 1; let additiveHastePercent = 0; for (const aura of auras) { for (const modifier of aura.definition.modifiers ?? []) { if (modifier.kind !== "stat" || modifier.stat !== "melee-haste" || modifier.operation !== "flat") continue; const hastePercent = modifier.value * (modifier.perStack === false ? 1 : aura.stacks); if (!modifier.multiplicative) { additiveHastePercent += hastePercent; continue; } sourceIntervalMultiplier *= hastePercent >= 0 ? 1 / Math.max(0.01, 1 + hastePercent / 100) : 1 + Math.abs(hastePercent) / 100; } } return sourceIntervalMultiplier / Math.max(0.01, 1 + additiveHastePercent / 100); }