52 lines
2.5 KiB
TypeScript
52 lines
2.5 KiB
TypeScript
import { triggeredAbilityBySpellId, type AbilityDefinition, type AbilityEffect } from "./abilityCatalog";
|
|
|
|
type ChannelAmountEffect = Extract<AbilityEffect, { kind: "damage" | "dot" | "heal" | "hot" }>;
|
|
|
|
export function channelPulseCount(ability: AbilityDefinition): number {
|
|
if (ability.channelPulses && ability.channelPulses > 0) return Math.max(1, Math.round(ability.channelPulses));
|
|
if (ability.channelTickMs && ability.channelTickMs > 0) {
|
|
return Math.max(1, Math.round(ability.castTimeMs / ability.channelTickMs)
|
|
+ (ability.channelStartsWithPulse ? 1 : 0));
|
|
}
|
|
return ability.dbcSpellId === 491164 ? 4 : 5;
|
|
}
|
|
|
|
export function channelPulseAt(ability: AbilityDefinition, startedAt: number, durationMs: number, pulseIndex: number): number {
|
|
const intervals = Math.max(1, channelPulseCount(ability) - (ability.channelStartsWithPulse ? 1 : 0));
|
|
return startedAt + (pulseIndex + (ability.channelStartsWithPulse ? 0 : 1)) * durationMs / intervals;
|
|
}
|
|
|
|
/** Direct channel amounts span the cast; periodic trigger payloads fire each pulse. */
|
|
export function channelAmountEffects(ability: AbilityDefinition, totalTicks: number): readonly {
|
|
effect: ChannelAmountEffect;
|
|
multiplier: number;
|
|
}[] {
|
|
const ticks = Math.max(1, totalTicks);
|
|
const amounts: { effect: ChannelAmountEffect; multiplier: number }[] = [];
|
|
for (const effect of ability.effects) {
|
|
if (effect.kind === "damage" || effect.kind === "heal" || effect.kind === "dot" || effect.kind === "hot") {
|
|
amounts.push({ effect, multiplier: ability.name === "Penance"
|
|
? 1
|
|
: ability.dbcSpellId === 491164 && effect.kind === "damage"
|
|
? 1
|
|
: (effect.kind === "dot" || effect.kind === "hot" ? effect.ticks : 1) / ticks });
|
|
} else if (effect.kind === "apply-aura") {
|
|
for (const proc of effect.aura.procs ?? []) {
|
|
const triggers = Array.isArray(proc.triggers) ? proc.triggers : [proc.triggers];
|
|
const action = proc.action;
|
|
if (!triggers.includes("periodic") || proc.chance !== 1 || proc.internalCooldownMs || proc.charges !== undefined
|
|
|| action.kind !== "custom"
|
|
|| !["wow335-trigger-spell", "rom-trigger-skill"].includes(action.id)
|
|
|| typeof action.data?.spellId !== "number") continue;
|
|
const payload = triggeredAbilityBySpellId(action.data.spellId);
|
|
for (const payloadEffect of payload?.effects ?? []) {
|
|
if (payloadEffect.kind === "damage" || payloadEffect.kind === "heal") {
|
|
amounts.push({ effect: payloadEffect, multiplier: 1 });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return amounts;
|
|
}
|