import type { AbilityDefinition, AbilityEffect } from "./abilityCatalog"; export const ROM_KNIGHT_SCOUT_BLOOD_PUNISHMENT_TAG = "rom-blood-punishment"; export const ROM_SCOUT_BLOOD_ARROW_AURA_TAG = "rom-self-health-drain"; const BLOOD_PUNISHMENT_MODIFIERS = [ { kind: "healing", direction: "taken", operation: "percent", value: 0.15 }, { kind: "damage", direction: "dealt", school: "holy", operation: "percent", value: 0.05 }, ] as const satisfies NonNullable["aura"]["modifiers"]>; function hasPassive(tags: readonly string[] | ReadonlySet): boolean { return Array.isArray(tags) ? tags.includes(ROM_KNIGHT_SCOUT_BLOOD_PUNISHMENT_TAG) : (tags as ReadonlySet).has(ROM_KNIGHT_SCOUT_BLOOD_PUNISHMENT_TAG); } /** * Current CoA Blood Punishment modifies the active Blood Arrow aura itself. * Keeping both modifiers on the source aura makes them actor-local and gives * them the same removal/expiry lifecycle as Blood Arrow, without inventing a * second timer for the passive. */ export function romKnightScoutBloodPunishmentActivationEffects( ability: AbilityDefinition, effects: readonly AbilityEffect[], passiveTags: readonly string[] | ReadonlySet, ): readonly AbilityEffect[] { if (ability.source !== "runewaker" || ability.classId !== "rom-scout" || ability.secondaryClassId !== undefined || ability.dbcSpellId !== 490434 || !hasPassive(passiveTags)) return effects; let attachedToActiveArrow = false; const updated = effects.map((effect) => { if (effect.kind !== "apply-aura" || effect.recipient !== "caster" || !effect.aura.utilityTags?.includes(ROM_SCOUT_BLOOD_ARROW_AURA_TAG)) return effect; attachedToActiveArrow = true; const current = effect.aura.modifiers ?? []; const modifiers = BLOOD_PUNISHMENT_MODIFIERS.filter((addition) => !current.some((modifier) => { if (addition.kind === "healing") return modifier.kind === "healing" && modifier.direction === addition.direction && modifier.operation === addition.operation && modifier.value === addition.value; return modifier.kind === "damage" && modifier.direction === addition.direction && modifier.school === addition.school && modifier.operation === addition.operation && modifier.value === addition.value; })); return modifiers.length === 0 ? effect : { ...effect, aura: { ...effect.aura, modifiers: [...current, ...modifiers] }, }; }); return attachedToActiveArrow ? updated : effects; }