Update Healer Man server

This commit is contained in:
phenom committed 2026-10-02 10:38:12 -04:00
1 parent 4c768fbec6
commit b16821e92e
330 files changed
+35406 -1760

No files matched your search

+73 -3
View File
@@ -5,8 +5,18 @@ import {
} from "./talentRuntimeCatalog";
import { talentBalanceOverride } from "./balanceTuning";
import { wow335MageFlameThrowingProfile } from "./wow335MageFlameThrowingRuntime";
import {
WOW335_MAGE_IMPROVED_FIRE_BLAST_TALENT_ID,
wow335MageImprovedFireBlastCooldownReductionMs,
wow335MageImprovedFireBlastDamageBonusPercent,
} from "./wow335MageImprovedFireBlastRuntime";
import { wow335DruidTalentModifierOverrides } from "./wow335DruidTalentRuntime";
import { WOW335_DRUID_PREDATORY_INSTINCTS_TALENT_ID } from "./wow335DruidPredatoryInstinctsRuntime";
import { wow335ShamanConvectionModifiersForRank } from "./wow335ShamanTalentRuntime";
import {
WOW335_SHAMAN_ELEMENTAL_WARDING_TALENT_ID,
wow335ShamanElementalWardingModifierForRank,
} from "./wow335ShamanElementalWardingRuntime";
export type TalentModifierKind =
| "damage-percent"
@@ -67,6 +77,9 @@ const EXPLICIT_ACTIVATION_TALENTS = new Set([
// Brain Freeze mixes a conditional next Fireball/Frostfire Bolt proc with
// separate school and target riders; the proc bonus is applied at cast time.
"Brain Freeze",
// Netherwind Presence haste exists only on eligible spell-triggered stacks;
// the helper/runtime applies that temporary state instead of parsing it as passive haste.
"Netherwind Presence",
// Aura Mastery and Divine Favor carry scoped next-cast/aura effects. Their
// activation tooltips must not be parsed as persistent global modifiers.
"Aura Mastery",
@@ -81,6 +94,9 @@ const EXPLICIT_ACTIVATION_TALENTS = new Set([
// These Shaman talents activate temporary effects from combat events;
// their conditional percentages are applied by the Shaman runtime.
"Elemental Focus",
// The melee/ranged critical-strike rider only exists after an elemental
// spell critical; the Shaman runtime applies it as a timed aura.
"Elemental Devastation",
"Reverberation",
"Maelstrom Weapon",
// Tidal Waves only affects casts while its earned charge aura is active.
@@ -90,12 +106,24 @@ const EXPLICIT_ACTIVATION_TALENTS = new Set([
"Convection",
// Riptide's 25% rider only applies to the next Chain Heal on its HoT target.
"Riptide",
// Frost Warding combines an armor/resistance modifier with a Ward-only
// damage proc. Both clauses need rank/aura/event scoping in its runtime.
"Frost Warding",
// Illumination's cooldown clause is paired with a critical-heal Mana proc;
// its exact rank behavior belongs to the dedicated event helper.
"Illumination",
// Torment the Weak applies only to named damage spells and only against a
// target that is currently slowed; its conditional part is target-aware.
"Torment the Weak",
// Feral Instinct has one named damage bonus plus two cast-state clauses;
// only the named Swipe/Ravage clause is a persistent scalar modifier.
"Feral Instinct",
// Master Shapeshifter has four separate form-specific bonuses; the active
// shapeshift decides which single clause the Druid runtime can apply.
"Master Shapeshifter",
// Paladin Vengeance is keyed by talent ID below because Druid has a distinct
// same-named talent with different behavior.
"talent-1402",
]);
/**
@@ -103,8 +131,9 @@ const EXPLICIT_ACTIVATION_TALENTS = new Set([
* as always-on scalar bonuses merely because their tooltip contains phrases
* such as "reduces cast time" or "reducing mana cost".
*/
export function talentUsesExplicitActivation(talentName: string): boolean {
return EXPLICIT_ACTIVATION_TALENTS.has(talentName);
export function talentUsesExplicitActivation(talentName: string, talentId?: string): boolean {
return EXPLICIT_ACTIVATION_TALENTS.has(talentName)
|| (talentId !== undefined && EXPLICIT_ACTIVATION_TALENTS.has(talentId));
}
/**
@@ -209,10 +238,25 @@ export function talentModifiersForRanks(ranks: TalentRanks, classId?: ClassId):
// by the Druid cast runtime.
return wow335DruidTalentModifierOverrides(active.talentId, active.rank, active.description);
}
if (classId === "druid" && active.talentId === WOW335_DRUID_PREDATORY_INSTINCTS_TALENT_ID) {
// Both clauses are gated by Cat Form; the AoE rider also needs authored
// attack delivery metadata, so the generic scalar parser cannot apply them.
return [];
}
// Elemental Oath's generated rank text repeats one crit bonus for the
// owner and the party. CombatStore applies the rank once to each spell
// attack/heal source, so the broad scalar parser must not apply it again.
if (classId === "shaman" && active.talentId === "talent-2049") return [];
if (classId === "shaman" && active.talentId === WOW335_SHAMAN_ELEMENTAL_WARDING_TALENT_ID) {
const modifier = wow335ShamanElementalWardingModifierForRank(active.rank);
return modifier ? [{
...modifier,
sourceTalentId: active.talentId,
sourceTalentName: active.talentName,
rank: active.rank,
description: active.description,
}] : [];
}
if (classId === "shaman" && active.talentId === "talent-564") {
return wow335ShamanConvectionModifiersForRank(active.rank).map((modifier) => ({
...modifier,
@@ -235,6 +279,30 @@ export function talentModifiersForRanks(ranks: TalentRanks, classId?: ClassId):
description: active.description,
}] : [];
}
if (classId === "mage" && active.talentId === WOW335_MAGE_IMPROVED_FIRE_BLAST_TALENT_ID) {
const cooldownReductionMs = wow335MageImprovedFireBlastCooldownReductionMs(active.rank, "Fire Blast");
const damageBonusPercent = wow335MageImprovedFireBlastDamageBonusPercent(active.rank);
return [
...(cooldownReductionMs > 0 ? [{
kind: "cooldown-flat-ms" as const,
amount: -cooldownReductionMs,
unit: "milliseconds" as const,
scope: "cooldown of your Fire Blast spell",
}] : []),
...(damageBonusPercent > 0 ? [{
kind: "damage-percent" as const,
amount: damageBonusPercent,
unit: "percent" as const,
scope: "damage of your Fire Blast",
}] : []),
].map((modifier) => ({
...modifier,
sourceTalentId: active.talentId,
sourceTalentName: active.talentName,
rank: active.rank,
description: active.description,
}));
}
// Molten Fury is active only while the individual target is below 35%
// health. The target-health predicate is applied by the Mage damage path,
// so keep its generated rank amount out of always-on scalar modifiers.
@@ -265,7 +333,7 @@ export function talentModifiersForRanks(ranks: TalentRanks, classId?: ClassId):
description: active.description,
}];
}
if (talentUsesExplicitActivation(active.talentName)) return [];
if (talentUsesExplicitActivation(active.talentName, active.talentId)) return [];
// Its healing and damage bonuses only apply below a target-health threshold;
// the scalar parser cannot encode that condition. CombatStore applies the
// rank-aware bonus at the individual target instead.
@@ -381,6 +449,8 @@ function modifierApplies(modifier: TalentModifier, context: TalentModifierContex
const scope = modifier.scope.toLowerCase();
const tags = new Set((context.tags ?? []).map((tag) => tag.toLowerCase()));
if (scope.includes("damaging spell") && !tags.has("damage")) return false;
if (scope.includes("with a channeling or cast time")
&& !tags.has("cast-time") && !tags.has("channel")) return false;
if (scope.includes("instant") && !tags.has("instant")) return false;
const coversDirectAndPeriodic = /\bdirect and periodic\b/.test(scope);
if (scope.includes("periodic") && !coversDirectAndPeriodic && !tags.has("periodic")) return false;