Release Healer Man 0.1.9

This commit is contained in:
phenom committed 2026-08-30 14:16:56 -04:00
1 parent c245a199b6
commit d060296ade
74 files changed
+5901 -334

No files matched your search

+68
View File
@@ -22,6 +22,7 @@ import { abilitiesForClass, defaultActionBarForClass } from "./abilityCatalog";
import { defaultActionBindings } from "./actionBindings";
import { deriveCharacterStats } from "./wotlkStats";
import { subscribeCombatPresentation, type CombatPresentationEvent } from "./combatPresentation";
import { loadCanonicalBenchmarkBuilds } from "./benchmark/benchmarkBuilds";
function allocateTalentRanks(name: string, ranks: number): void {
const talent = TALENT_NODES.find((node) => node.name === name);
@@ -843,6 +844,7 @@ describe("combat store", () => {
it("allocates the first WotLK talent point at level 10 and clamps settings", () => {
useCombatStore.getState().initializeCharacter({ classId: "priest", level: 10 });
expect(useCombatStore.getState().settings.masterVolume).toBe(0);
const holy = talentNodesForTree("priest-holy")[0];
const shadow = talentNodesForTree("priest-shadow")[0];
expect(useCombatStore.getState().allocateTalent(holy.id)).toBe(true);
@@ -869,12 +871,44 @@ describe("combat store", () => {
showMobAggroRanges: true,
threatMeterPosition: { x: 0, y: 1 },
});
useCombatStore.getState().updateSettings({
gameplayFrameRate: 30,
previewFrameRate: 15,
});
expect(useCombatStore.getState().settings).toMatchObject({
gameplayFrameRate: 30,
previewFrameRate: 15,
});
useCombatStore.getState().initializeCharacter({ classId: "priest" });
expect(useCombatStore.getState().settings.showThreatMeter).toBe(false);
useCombatStore.getState().initializeCharacter({
classId: "priest",
settings: { masterVolume: 0.6 },
});
expect(useCombatStore.getState().settings.masterVolume).toBe(0.6);
useCombatStore.getState().resetSettings();
expect(useCombatStore.getState().settings).toEqual(DEFAULT_GAMEPLAY_SETTINGS);
});
it("does not notify subscribers for unchanged positions or settings", () => {
let notifications = 0;
const unsubscribe = useCombatStore.subscribe(() => {
notifications += 1;
});
useCombatStore.getState().setPlayerPosition([0, 0, 0]);
useCombatStore.getState().updateSettings({
masterVolume: DEFAULT_GAMEPLAY_SETTINGS.masterVolume,
gameplayFrameRate: DEFAULT_GAMEPLAY_SETTINGS.gameplayFrameRate,
});
useCombatStore.getState().resetSettings();
expect(notifications).toBe(0);
useCombatStore.getState().updateSettings({ gameplayFrameRate: 30 });
expect(notifications).toBe(1);
unsubscribe();
});
it("keeps a CoA tree ability uncastable until its exact node is purchased", () => {
useCombatStore.getState().initializeCharacter({ classId: "stormbringer", level: 60 });
const ability = abilitiesForClass("stormbringer").find((candidate) => (
@@ -897,6 +931,40 @@ describe("combat store", () => {
expect(useCombatStore.getState().castAbility(ability.id, [0, 0, 0], 3_000).reason).not.toBe("not-learned");
});
it("breaks recursive hit-proc spell cycles in the canonical Felsworn tank build", async () => {
const build = (await loadCanonicalBenchmarkBuilds(60, ["felsworn"]))
.find((candidate) => candidate.role === "tank")!;
useCombatStore.getState().initializeCharacter({
classId: build.classId,
level: build.level,
talentRanks: build.talentRanks,
});
registerTarget("felsworn-proc-dummy", [10, 0, 0], 1_000_000, 0);
expect(useCombatStore.getState().auras).toContainEqual(expect.objectContaining({
definition: expect.objectContaining({ name: "Doomstride (Aura 42)" }),
}));
const result = useCombatStore.getState().castAbility(
"felsworn-sargeron-smite",
[0, 0, 0],
1,
);
const state = useCombatStore.getState();
const damage = 1_000_000 - state.mobs["felsworn-proc-dummy"].health;
const damageAbilityIds = state.combatEvents
.filter((event) => event.kind === "damage")
.map((event) => event.abilityId);
expect(result.ok).toBe(true);
expect(damage).toBeGreaterThan(0);
expect(damage).toBeLessThan(100_000);
expect(damageAbilityIds.filter((abilityId) => abilityId === "coa-triggered-807962"))
.toHaveLength(1);
expect(state.auras).toContainEqual(expect.objectContaining({
definition: expect.objectContaining({ name: "Felwracked (Aura 4)" }),
}));
});
it("resets encounter health without erasing earned progression", () => {
registerTarget("mob", [2, 0, 0], 1, 100);
useCombatStore.getState().damageMob("mob", 5, 1000);