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

+105
View File
@@ -0,0 +1,105 @@
import { beforeEach, describe, expect, it } from "vitest";
import { PLAYER_AGGRO_ID } from "./aggro";
import { abilityTalentNodeId, type AbilityDefinition } from "./abilityCatalog";
import { clearMobRuntimeRegistry } from "./mobRuntimeRegistry";
import { clearPartyRuntimeRegistry } from "./partyRuntimeRegistry";
import { useCombatStore, type TimedCombatEffect } from "./combatStore";
function prepareSwiftmend(): AbilityDefinition {
useCombatStore.getState().initializeCharacter({ classId: "druid", level: 80, xp: 0 });
useCombatStore.setState((state) => ({ health: 1_000, resource: state.maxResource }));
const ability = useCombatStore.getState().abilities.find((candidate) => candidate.name === "Swiftmend");
if (!ability) throw new Error("Druid Swiftmend is missing from the learned ability catalog.");
const talentId = abilityTalentNodeId(ability);
if (!talentId) throw new Error("Druid Swiftmend has no active talent node.");
useCombatStore.setState((state) => ({ talentRanks: { ...state.talentRanks, [talentId]: 1 } }));
return ability;
}
function hot(
sourceName: "Rejuvenation" | "Regrowth",
sourceActorId: string,
tickHealing: number,
remainingTicks: number,
nextTickAt: number,
id: string,
fixedAmount?: number,
): TimedCombatEffect {
const sourceAbility = useCombatStore.getState().abilities.find((ability) => ability.name === sourceName);
if (!sourceAbility) throw new Error(`Druid ${sourceName} is missing from the learned ability catalog.`);
return {
id,
kind: "hot",
sourceAbilityId: sourceAbility.id,
sourceActorId,
targetId: null,
coefficient: 0,
basePoints: tickHealing,
dieSides: 1,
pointsPerLevel: 0,
sourceLevel: 80,
...(fixedAmount === undefined ? {} : { fixedAmount }),
remainingTicks,
intervalMs: 3_000,
nextTickAt,
};
}
function castSwiftmend(ability: AbilityDefinition, now = 1_000) {
const result = useCombatStore.getState().castAbility(ability.id, { targetActorId: null, now });
expect(result.ok).toBe(true);
const event = useCombatStore.getState().combatEvents.filter((candidate) => (
candidate.kind === "healing" && candidate.abilityId === ability.id
)).at(-1);
if (!event || event.kind !== "healing") throw new Error("Swiftmend did not record its healing event.");
return event;
}
function expectCriticalAdjustedRawHealing(rawAmount: number, critical: boolean, baseAmount: number): void {
expect(rawAmount).toBe(baseAmount * (critical ? 1.5 : 1));
}
describe("WoW Druid active talent runtime", () => {
beforeEach(() => {
clearMobRuntimeRegistry();
clearPartyRuntimeRegistry();
});
it.each([
["Rejuvenation", 100, 5, 400],
["Regrowth", 150, 7, 900],
] as const)("Swiftmend uses its source 12/18-second amount for %s", (sourceName, tickHealing, remainingTicks, expected) => {
const swiftmend = prepareSwiftmend();
const sourceHot = hot(sourceName, PLAYER_AGGRO_ID, tickHealing, remainingTicks, 4_000, "swiftmend-source-hot");
useCombatStore.setState({ effects: [sourceHot] });
const event = castSwiftmend(swiftmend);
expectCriticalAdjustedRawHealing(event.rawAmount, event.critical, expected);
expect(useCombatStore.getState().effects).toEqual([]);
});
it("prefers its own Hot over a shorter foreign Hot", () => {
const swiftmend = prepareSwiftmend();
const foreignShort = hot("Rejuvenation", "party-druid-short", 25, 1, 1_500, "swiftmend-foreign-short", 25);
const casterHot = hot("Regrowth", PLAYER_AGGRO_ID, 100, 7, 16_000, "swiftmend-caster-long");
useCombatStore.setState({ effects: [foreignShort, casterHot] });
const event = castSwiftmend(swiftmend);
expectCriticalAdjustedRawHealing(event.rawAmount, event.critical, 600);
expect(useCombatStore.getState().effects.map((effect) => effect.id)).toEqual([foreignShort.id]);
});
it("uses the shortest foreign Rejuvenation or Regrowth when no caster Hot exists", () => {
const swiftmend = prepareSwiftmend();
const longerRegrowth = hot("Regrowth", "party-druid-long", 50, 7, 4_000, "swiftmend-foreign-long", 50);
const shorterRejuvenation = hot("Rejuvenation", "party-druid-short", 100, 5, 4_000, "swiftmend-foreign-short", 100);
useCombatStore.setState({ effects: [longerRegrowth, shorterRejuvenation] });
const event = castSwiftmend(swiftmend);
expectCriticalAdjustedRawHealing(event.rawAmount, event.critical, 400);
expect(useCombatStore.getState().effects.map((effect) => effect.id)).toEqual([longerRegrowth.id]);
});
});