Update Healer Man server

This commit is contained in:
phenom committed 2026-09-28 22:46:45 -04:00
1 parent 9d7e0e2f9e
commit 35dfdaed61
94 files changed
+17034 -418

No files matched your search

+45 -12
View File
@@ -149,7 +149,9 @@ export interface AbilityHealingRecipients {
readonly center?: "caster" | "ability-target";
readonly radius?: number;
readonly maximumTargets?: number;
readonly selection?: "random";
readonly falloffPerJump?: number;
readonly selection?: "random" | "lowest-max-health";
readonly excludeCaster?: boolean;
}
export interface AbilityDamageResource {
@@ -166,12 +168,21 @@ export type AbilityEffect =
/** Optional stack-based payload used by poison-consuming finishers. */
readonly poison?: import("./roguePoison").RoguePoisonFinisherScaling;
}
| ({ readonly kind: "heal"; readonly coefficient: number; readonly percentMaxHealth?: number } & AbilityAmountScaling & AbilityHealingRecipients)
| ({ readonly kind: "heal"; readonly coefficient: number; readonly percentMaxHealth?: number; readonly percentOfDamage?: number } & AbilityAmountScaling & AbilityHealingRecipients)
| ({ readonly kind: "shield"; readonly coefficient: number; readonly durationMs: number } & AbilityAmountScaling & AbilityHealingRecipients)
| ({ readonly kind: "dot"; readonly coefficient: number; readonly school?: DamageSchool; readonly ticks: number; readonly intervalMs: number; readonly startsImmediately?: boolean; readonly tag?: string } & AbilityAmountScaling & AbilityDamageResource)
| ({ readonly kind: "hot"; readonly coefficient: number; readonly ticks: number; readonly intervalMs: number } & AbilityAmountScaling & AbilityHealingRecipients)
| { readonly kind: "resurrection"; readonly percentMaxHealth: number }
| { readonly kind: "summon"; readonly creatureId: number; readonly coefficient: number; readonly durationMs: number }
| ({ readonly kind: "hot"; readonly coefficient: number; readonly ticks: number; readonly intervalMs: number; readonly percentMaxHealth?: number } & AbilityAmountScaling & AbilityHealingRecipients)
| { readonly kind: "resurrection"; readonly percentMaxHealth: number; readonly flatHealth?: number }
| {
readonly kind: "summon";
readonly creatureId: number;
readonly coefficient: number;
readonly durationMs: number;
/** Source-defined pulse for stationary healing totems. */
readonly healingPulse?: { readonly amount: number; readonly intervalMs: number; readonly radius: number };
/** Source-defined party absorb area carried by a stationary Death Knight zone. */
readonly antiMagicZone?: { readonly radius: number; readonly capacityBase: number; readonly capacityPerAttackPower: number; readonly absorbFraction: number; readonly intervalMs: number };
}
| { readonly kind: "resource"; readonly amount: number; readonly resource?: ResourceType; readonly percentage?: boolean }
| { readonly kind: "combo"; readonly amount: number }
| { readonly kind: "taunt"; readonly durationMs: number; readonly maxTargets?: number }
@@ -180,7 +191,7 @@ export type AbilityEffect =
readonly kind: "apply-aura";
readonly aura: AuraDefinition;
/** Some hostile spells apply their beneficial rider to the caster. */
readonly recipient?: "ability-target" | "caster";
readonly recipient?: "ability-target" | "caster" | "pet";
/** Party/raid area auras are applied to the player and every active party member. */
readonly scope?: "target" | "party";
/** Some party effects benefit allies but exclude the caster. */
@@ -218,11 +229,18 @@ export type AbilityEffect =
| { readonly kind: "dispel-mechanic"; readonly mechanic: number; readonly maxCount: number }
| { readonly kind: "pet"; readonly action: "summon" | "call" | "recall" | "dismiss" | "resurrect" | "feed" | "tame"; readonly creatureId?: number }
| { readonly kind: "totem"; readonly action: "destroy-all" }
| { readonly kind: "rune"; readonly action: "activate"; readonly count: number }
| {
readonly kind: "rune";
readonly action: "activate";
readonly count: number;
readonly runeType?: "blood" | "frost" | "unholy";
readonly convertToDeathMs?: number;
}
| {
readonly kind: "cooldown-reset";
readonly mode: "reset" | "reduce";
readonly abilityName?: string;
readonly excludeAbilityNames?: readonly string[];
readonly amountMs?: number;
/** Fraction of the target ability's remaining cooldown removed at execution time. */
readonly amountPercent?: number;
@@ -907,7 +925,7 @@ const abilityCatalog: Record<string, AbilityDefinition> = {};
let romEliteAbilities: readonly AbilityDefinition[] = [];
let romTriggeredAbilityResolver: ((spellId: number) => AbilityDefinition | null) | null = null;
const coaTriggeredAbilities = new Map<number, AbilityDefinition>();
const classicChannelTriggeredAbilities = new Map<number, AbilityDefinition>();
const classicTriggeredAbilities = new Map<number, AbilityDefinition>();
let classicLoad: Promise<void> | null = null;
let romLoad: Promise<void> | null = null;
const coaLoads = new Map<CoaClassId, Promise<void>>();
@@ -950,7 +968,7 @@ async function preloadClassicAbilityCatalog(): Promise<void> {
if (classicLoad) return classicLoad;
classicLoad = import("./wow335AbilityCatalog").then(({
WOW335_ABILITIES_BY_CLASS,
WOW335_CHANNEL_TRIGGERED_ABILITIES_BY_SPELL_ID,
WOW335_TRIGGERED_ABILITIES_BY_SPELL_ID,
}) => {
for (const classId of BASE_CLASS_IDS) {
registerClassAbilities(
@@ -958,8 +976,8 @@ async function preloadClassicAbilityCatalog(): Promise<void> {
mergeWow335ClassicAbilities(CLASSIC_CORE_ABILITIES[classId], WOW335_ABILITIES_BY_CLASS[classId]),
);
}
for (const [spellId, ability] of Object.entries(WOW335_CHANNEL_TRIGGERED_ABILITIES_BY_SPELL_ID)) {
classicChannelTriggeredAbilities.set(Number(spellId), ability);
for (const [spellId, ability] of Object.entries(WOW335_TRIGGERED_ABILITIES_BY_SPELL_ID)) {
classicTriggeredAbilities.set(Number(spellId), ability);
}
}).catch((error: unknown) => {
classicLoad = null;
@@ -1026,7 +1044,7 @@ export function triggeredAbilityBySpellId(
includeCoa = true,
): AbilityDefinition | null {
return romTriggeredAbilityResolver?.(spellId)
?? classicChannelTriggeredAbilities.get(spellId)
?? classicTriggeredAbilities.get(spellId)
?? (includeCoa ? coaTriggeredAbilities.get(spellId) : undefined)
?? null;
}
@@ -1048,6 +1066,21 @@ export function abilitiesForCharacter(
return [...primary, ...secondaryGeneral, ...elites];
}
/** Return the RuneWaker Nature Power cap granted by the learned Brilliance passive. */
export function naturePowerMaximumForCharacter(
classId: ClassId,
secondaryClassId: ClassId | null | undefined,
level: number,
): number {
const hasBrillianceOfNature = abilitiesForCharacter(classId, secondaryClassId).some((ability) => (
ability.source === "runewaker"
&& ability.dbcSpellId === 494931
&& ability.passive
&& level >= ability.unlockLevel
));
return hasBrillianceOfNature ? 15 : 10;
}
export function abilityRankForLevel(
ability: AbilityDefinition,
playerLevel: number,