106 lines
4.4 KiB
TypeScript
106 lines
4.4 KiB
TypeScript
import { WOW335_TALENT_NODES } from "./wow335Talents.generated";
|
|
|
|
export const WOW335_WARRIOR_BLOOD_CRAZE_TALENT_ID = "talent-661";
|
|
export const WOW335_WARRIOR_BLOOD_CRAZE_COOLDOWN_KEY = "wow335-warrior-blood-craze";
|
|
export const WOW335_WARRIOR_BLOOD_CRAZE_DURATION_MS = 6_000;
|
|
export const WOW335_WARRIOR_BLOOD_CRAZE_INTERNAL_COOLDOWN_MS = 12_000;
|
|
|
|
export const WOW335_WARRIOR_SECOND_WIND_TALENT_ID = "talent-1663";
|
|
export const WOW335_WARRIOR_SECOND_WIND_COOLDOWN_KEY = "wow335-warrior-second-wind";
|
|
export const WOW335_WARRIOR_SECOND_WIND_INTERVAL_MS = 2_000;
|
|
|
|
const WOW335_WARRIOR_SECOND_WIND_SOURCE = WOW335_TALENT_NODES.find((node) => (
|
|
node.id === WOW335_WARRIOR_SECOND_WIND_TALENT_ID
|
|
));
|
|
|
|
export interface Wow335WarriorSecondWindProfile {
|
|
readonly rank: 1 | 2 | 3;
|
|
readonly healthThresholdPercent: number;
|
|
readonly procChancePercent: number;
|
|
readonly durationMs: number;
|
|
readonly cooldownMs: number;
|
|
readonly ticks: number;
|
|
readonly intervalMs: number;
|
|
readonly totalHealing: number;
|
|
readonly healingPerTick: number;
|
|
readonly tickAmounts: readonly number[];
|
|
}
|
|
|
|
/**
|
|
* Uses the populated generated rank tooltip for threshold, duration, heal,
|
|
* cooldown, and the generated rank procChance. WotLKDB spells 29841/29842
|
|
* both show a 2-second periodic interval; the generated custom rank-3 child
|
|
* (829839) has no WotLKDB row, so the same confirmed cadence is carried forward.
|
|
*/
|
|
export function wow335WarriorSecondWindProfile(
|
|
baseHealth: number,
|
|
rank: number,
|
|
): Wow335WarriorSecondWindProfile | null {
|
|
const safeRank = Math.min(3, Math.max(0, Math.trunc(Number.isFinite(rank) ? rank : 0)));
|
|
const rankDescription = WOW335_WARRIOR_SECOND_WIND_SOURCE?.rankDescriptions[safeRank - 1];
|
|
const rankEffect = WOW335_WARRIOR_SECOND_WIND_SOURCE?.rankEffects[safeRank - 1];
|
|
if (safeRank === 0 || !rankDescription || !rankEffect || !Number.isFinite(baseHealth) || baseHealth <= 0) {
|
|
return null;
|
|
}
|
|
|
|
const healthThresholdPercent = Number(rankDescription.match(/below (\d+)% health/i)?.[1]);
|
|
const healPercent = Number(rankDescription.match(/(\d+)% of your base health over (\d+) seconds/i)?.[1]);
|
|
const durationSeconds = Number(rankDescription.match(/base health over (\d+) seconds/i)?.[1]);
|
|
const cooldownSeconds = Number(rankDescription.match(/once every (\d+) seconds/i)?.[1]);
|
|
const durationMs = durationSeconds * 1_000;
|
|
if (!Number.isFinite(healthThresholdPercent) || !Number.isFinite(healPercent)
|
|
|| !Number.isFinite(durationMs) || durationMs <= 0 || durationMs % WOW335_WARRIOR_SECOND_WIND_INTERVAL_MS !== 0
|
|
|| !Number.isFinite(cooldownSeconds) || cooldownSeconds <= 0) return null;
|
|
|
|
const ticks = durationMs / WOW335_WARRIOR_SECOND_WIND_INTERVAL_MS;
|
|
const totalHealing = Math.round(baseHealth * healPercent / 100);
|
|
const baseTickHealing = Math.floor(totalHealing / ticks);
|
|
const bonusTicks = totalHealing - baseTickHealing * ticks;
|
|
const tickAmounts = Array.from({ length: ticks }, (_, index) => baseTickHealing + Number(index < bonusTicks));
|
|
return {
|
|
rank: safeRank as 1 | 2 | 3,
|
|
healthThresholdPercent,
|
|
procChancePercent: Math.max(0, Math.min(100, rankEffect.procChance)),
|
|
durationMs,
|
|
cooldownMs: cooldownSeconds * 1_000,
|
|
ticks,
|
|
intervalMs: WOW335_WARRIOR_SECOND_WIND_INTERVAL_MS,
|
|
totalHealing,
|
|
healingPerTick: totalHealing / ticks,
|
|
tickAmounts,
|
|
};
|
|
}
|
|
|
|
export interface Wow335WarriorBloodCrazeProfile {
|
|
readonly rank: 1 | 2 | 3;
|
|
readonly ticks: number;
|
|
readonly intervalMs: number;
|
|
readonly totalHealing: number;
|
|
readonly healingPerTick: number;
|
|
}
|
|
|
|
/**
|
|
* Builds the tooltip-defined total heal and uses each rank's hidden child aura
|
|
* interval only to distribute it through the six-second duration. Rank 3's
|
|
* one-second interval is also exposed by WotLKDB spell 16491.
|
|
*/
|
|
export function wow335WarriorBloodCrazeProfile(
|
|
baseHealth: number,
|
|
rank: number,
|
|
enraged: boolean,
|
|
): Wow335WarriorBloodCrazeProfile | null {
|
|
const safeRank = Math.min(3, Math.max(0, Math.trunc(Number.isFinite(rank) ? rank : 0)));
|
|
if (safeRank === 0 || !Number.isFinite(baseHealth) || baseHealth <= 0) return null;
|
|
|
|
const intervalMs = [0, 3_000, 1_500, 1_000][safeRank];
|
|
const ticks = WOW335_WARRIOR_BLOOD_CRAZE_DURATION_MS / intervalMs;
|
|
const totalHealing = Math.round(baseHealth * safeRank / 100 * (enraged ? 3 : 1));
|
|
return {
|
|
rank: safeRank as 1 | 2 | 3,
|
|
ticks,
|
|
intervalMs,
|
|
totalHealing,
|
|
healingPerTick: totalHealing / ticks,
|
|
};
|
|
}
|