Release Healer Man 0.1.14

This commit is contained in:
phenom committed 2026-09-05 11:40:50 -04:00
1 parent 67d7a8ebe7
commit 7b41b102fa
147 files changed
+169892 -1342

No files matched your search

+114
View File
@@ -0,0 +1,114 @@
import { beforeEach, describe, expect, it } from "vitest";
import { encounterTimeline } from "./encounterTimeline";
import { useCombatStore } from "./combatStore";
describe("encounter mechanic timeline", () => {
beforeEach(() => {
useCombatStore.getState().initializeCharacter({ classId: "priest", level: 40 });
useCombatStore.getState().registerMob("boss", {
name: "Timeline Boss",
boss: true,
maxHealth: 1_000,
attacks: [{
id: "timed-quake",
name: "Timed Quake",
delivery: "area",
target: "nearby-party",
school: "nature",
animation: "cast",
range: 20,
radius: 10,
cooldownMs: 15_000,
repeatCooldownMs: [12_000, 18_000],
damageMultiplier: 1,
}, {
id: "health-adds",
name: "Awaken Adds",
delivery: "area",
target: "self",
school: "physical",
animation: "cast",
range: 0,
cooldownMs: 1_000,
maximumCasts: 1,
damageMultiplier: 0,
effect: { kind: "summon", creatureEntry: 1, count: 2 },
condition: { kind: "self-health-percent", minimum: 0, maximum: 70 },
}],
});
useCombatStore.setState((state) => ({
mobs: {
...state.mobs,
boss: {
...state.mobs.boss,
engaged: true,
abilityReadyAt: { "timed-quake": 16_000, "health-adds": 1_000 },
},
},
}));
});
it("shows both timer countdowns and pending health thresholds", () => {
const model = encounterTimeline(useCombatStore.getState().mobs, 10_000);
expect(model?.bossName).toBe("Timeline Boss");
expect(model?.rows.map((row) => [row.name, row.kind, row.value])).toEqual([
["Timed Quake", "timer", "6.0s"],
["Awaken Adds", "health", "70% HP"],
]);
});
it("promotes an active cast and hides a completed one-shot threshold", () => {
useCombatStore.setState((state) => ({
mobs: {
...state.mobs,
boss: {
...state.mobs.boss,
abilityCastCounts: { "health-adds": 1 },
activeCast: {
attackId: "timed-quake",
name: "Timed Quake",
school: "nature",
interruptible: true,
targetActorId: "__player__",
sourcePosition: [0, 0, 0],
targetPosition: [0, 0, 5],
sourceYaw: 0,
startedAt: 10_000,
completesAt: 12_000,
},
},
},
}));
expect(encounterTimeline(useCombatStore.getState().mobs, 11_250)?.rows).toMatchObject([{
name: "Timed Quake",
kind: "casting",
value: "0.8s",
}]);
});
it("keeps every pending health threshold visible beyond the countdown row limit", () => {
const boss = useCombatStore.getState().mobs.boss;
const extraTimers = Array.from({ length: 5 }, (_, index) => ({
...boss.attacks[0],
id: `extra-timer-${index}`,
name: `Extra Timer ${index}`,
}));
useCombatStore.setState((state) => ({
mobs: {
...state.mobs,
boss: {
...state.mobs.boss,
attacks: [...state.mobs.boss.attacks, ...extraTimers],
abilityReadyAt: {
...state.mobs.boss.abilityReadyAt,
...Object.fromEntries(extraTimers.map((attack, index) => [attack.id, 11_000 + index * 1_000])),
},
},
},
}));
const rows = encounterTimeline(useCombatStore.getState().mobs, 10_000, 4)?.rows ?? [];
expect(rows.filter((row) => row.kind === "timer")).toHaveLength(4);
expect(rows.filter((row) => row.kind === "health").map((row) => row.value)).toEqual(["70% HP"]);
});
});