forked from phenom/healer-man
154 lines
5.8 KiB
TypeScript
154 lines
5.8 KiB
TypeScript
import type { AuraDefinition } from "./combatAuras";
|
|
import { WOW335_TALENT_NODES } from "./wow335Talents.generated";
|
|
|
|
export const WOW335_MAGE_WINTERS_CHILL_TALENT_ID = "talent-68";
|
|
export const WOW335_MAGE_WINTERS_CHILL_TAG = "wow335-mage-winters-chill";
|
|
|
|
const WINTERS_CHILL_TALENT = WOW335_TALENT_NODES.find((talent) => (
|
|
talent.id === WOW335_MAGE_WINTERS_CHILL_TALENT_ID
|
|
));
|
|
|
|
function tooltipNumber(description: string, pattern: RegExp): number {
|
|
const parsed = Number(description.match(pattern)?.[1]);
|
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
}
|
|
|
|
const WINTERS_CHILL_EFFECT_DESCRIPTION = WINTERS_CHILL_TALENT?.rankDescriptions[0] ?? "";
|
|
const WINTERS_CHILL_TARGET_CRITICAL_CHANCE_PER_STACK_PERCENT = tooltipNumber(
|
|
WINTERS_CHILL_EFFECT_DESCRIPTION,
|
|
/increasing the chance spells will critically strike the target by\s+(\d+(?:\.\d+)?)%/i,
|
|
);
|
|
const WINTERS_CHILL_TARGET_HEALING_REDUCTION_PER_STACK_PERCENT = tooltipNumber(
|
|
WINTERS_CHILL_EFFECT_DESCRIPTION,
|
|
/reducing healing received by\s+(\d+(?:\.\d+)?)%/i,
|
|
);
|
|
const WINTERS_CHILL_DURATION_MS = tooltipNumber(
|
|
WINTERS_CHILL_EFFECT_DESCRIPTION,
|
|
/for\s+(\d+(?:\.\d+)?)\s+seconds/i,
|
|
) * 1_000;
|
|
const WINTERS_CHILL_MAXIMUM_STACKS = tooltipNumber(
|
|
WINTERS_CHILL_EFFECT_DESCRIPTION,
|
|
/stacks up to\s+(\d+)\s+times/i,
|
|
);
|
|
|
|
function normalizedRank(rank: number): number {
|
|
return Number.isFinite(rank)
|
|
? Math.max(0, Math.min(WINTERS_CHILL_TALENT?.rankEffects.length ?? 0, Math.trunc(rank)))
|
|
: 0;
|
|
}
|
|
|
|
function generatedRankValue(rank: number, pattern: RegExp): number {
|
|
const description = WINTERS_CHILL_TALENT?.rankDescriptions[normalizedRank(rank) - 1] ?? "";
|
|
return tooltipNumber(description, pattern);
|
|
}
|
|
|
|
export const WOW335_MAGE_WINTERS_CHILL_AURA: AuraDefinition = {
|
|
id: "wow335:mage:winters-chill",
|
|
name: "Winter's Chill",
|
|
description: `Each stack increases incoming spell critical chance by ${WINTERS_CHILL_TARGET_CRITICAL_CHANCE_PER_STACK_PERCENT}% and reduces healing received by ${WINTERS_CHILL_TARGET_HEALING_REDUCTION_PER_STACK_PERCENT}% for ${WINTERS_CHILL_DURATION_MS / 1_000} seconds.`,
|
|
disposition: "debuff",
|
|
durationMs: WINTERS_CHILL_DURATION_MS,
|
|
maxStacks: WINTERS_CHILL_MAXIMUM_STACKS,
|
|
stackBehavior: "add",
|
|
uniqueBySource: false,
|
|
// Local child data is absent; WotLKDB 3.3.5a spell 12579 identifies it as Magic-dispellable.
|
|
dispelCategory: "magic",
|
|
modifiers: [{
|
|
kind: "healing",
|
|
direction: "taken",
|
|
operation: "percent",
|
|
value: -WINTERS_CHILL_TARGET_HEALING_REDUCTION_PER_STACK_PERCENT / 100,
|
|
}],
|
|
utilityTags: [WOW335_MAGE_WINTERS_CHILL_TAG],
|
|
};
|
|
|
|
export interface Wow335MageWintersChillEvent {
|
|
readonly abilityName: string;
|
|
readonly attackKind: string;
|
|
readonly school: string;
|
|
readonly periodic: boolean;
|
|
readonly landedDamage: number;
|
|
}
|
|
|
|
export interface Wow335MageWintersChillProfile {
|
|
readonly casterCriticalChanceBonusPercent: number;
|
|
readonly procChancePercent: number;
|
|
readonly targetCriticalChanceBonusPercentPerStack: number;
|
|
readonly targetHealingReceivedReductionPercentPerStack: number;
|
|
readonly durationMs: number;
|
|
readonly maximumStacks: number;
|
|
}
|
|
|
|
/**
|
|
* Local generated Mage talent node 68, ranks 11180/28592/28593. Its rank
|
|
* descriptions give the passive crit bonus, proc chance, and custom 8-second
|
|
* child effect values; the stock 3.3.5a child row is not this custom payload.
|
|
*/
|
|
export function wow335MageWintersChillProfileForRank(rank: number): Wow335MageWintersChillProfile {
|
|
const normalized = normalizedRank(rank);
|
|
const rankEffect = WINTERS_CHILL_TALENT?.rankEffects[normalized - 1];
|
|
return {
|
|
casterCriticalChanceBonusPercent: generatedRankValue(
|
|
normalized,
|
|
/critical strike chance with all spells and abilities by\s+(\d+(?:\.\d+)?)%/i,
|
|
),
|
|
procChancePercent: Math.max(0, Math.min(100, rankEffect?.procChance ?? 0)),
|
|
targetCriticalChanceBonusPercentPerStack: WINTERS_CHILL_TARGET_CRITICAL_CHANCE_PER_STACK_PERCENT,
|
|
targetHealingReceivedReductionPercentPerStack: WINTERS_CHILL_TARGET_HEALING_REDUCTION_PER_STACK_PERCENT,
|
|
durationMs: WINTERS_CHILL_DURATION_MS,
|
|
maximumStacks: WINTERS_CHILL_MAXIMUM_STACKS,
|
|
};
|
|
}
|
|
|
|
export function wow335MageWintersChillProcChancePercent(
|
|
rank: number,
|
|
event: Wow335MageWintersChillEvent,
|
|
): number {
|
|
const profile = wow335MageWintersChillProfileForRank(rank);
|
|
const eligible = profile.procChancePercent > 0
|
|
&& event.attackKind === "spell"
|
|
&& event.school === "frost"
|
|
&& !event.periodic
|
|
&& Number.isFinite(event.landedDamage)
|
|
&& event.landedDamage > 0
|
|
&& event.abilityName.toLowerCase() !== "frozen orb";
|
|
return eligible ? profile.procChancePercent : 0;
|
|
}
|
|
|
|
export function wow335MageWintersChillShouldProc(
|
|
rank: number,
|
|
event: Wow335MageWintersChillEvent,
|
|
roll: number,
|
|
): boolean {
|
|
if (!Number.isFinite(roll) || roll < 0 || roll >= 1) return false;
|
|
return roll < wow335MageWintersChillProcChancePercent(rank, event) / 100;
|
|
}
|
|
|
|
export function wow335MageWintersChillStacksAfterEvent(
|
|
currentStacks: number,
|
|
rank: number,
|
|
event: Wow335MageWintersChillEvent,
|
|
roll: number,
|
|
): number {
|
|
const profile = wow335MageWintersChillProfileForRank(rank);
|
|
const stacks = Number.isFinite(currentStacks)
|
|
? Math.max(0, Math.min(profile.maximumStacks, Math.trunc(currentStacks)))
|
|
: 0;
|
|
return wow335MageWintersChillShouldProc(rank, event, roll)
|
|
? Math.min(profile.maximumStacks, stacks + 1)
|
|
: stacks;
|
|
}
|
|
|
|
export function wow335MageWintersChillTargetModifiers(stacks: number): {
|
|
readonly criticalChanceBonusPercent: number;
|
|
readonly healingReceivedReductionPercent: number;
|
|
} {
|
|
const normalized = Number.isFinite(stacks)
|
|
? Math.max(0, Math.min(WINTERS_CHILL_MAXIMUM_STACKS, Math.trunc(stacks)))
|
|
: 0;
|
|
return {
|
|
criticalChanceBonusPercent: normalized * WINTERS_CHILL_TARGET_CRITICAL_CHANCE_PER_STACK_PERCENT,
|
|
healingReceivedReductionPercent: normalized * WINTERS_CHILL_TARGET_HEALING_REDUCTION_PER_STACK_PERCENT,
|
|
};
|
|
}
|