Files
healer-man/src/game/coaRangerFocusRuntime.test.ts
2026-10-04 13:13:35 -04:00

97 lines
4.4 KiB
TypeScript

import { beforeEach, describe, expect, it } from "vitest";
import { companionActorFromMember } from "./combatActorAuthority";
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
import { commitPartyAbilityUse, partyAbilityCosts } from "./partyAbilityAi";
import { advanceDungeonPartyCombat, resetPartyRuntimeClock } from "./partyRuntime";
import { clearPartyRuntimeRegistry } from "./partyRuntimeRegistry";
import { createConfiguredPartyMember, usePartyStore } from "./partyStore";
import { abilitiesForClass, resourceProfileForClass } from "./abilityCatalog";
import { useCombatStore } from "./combatStore";
describe("Ranger Focus resource runtime", () => {
beforeEach(() => {
clearMobRuntimeRegistry();
clearPartyRuntimeRegistry();
resetPartyRuntimeClock();
});
it("spends and restores the player's displayed primary Focus pool", () => {
const profile = resourceProfileForClass("ranger");
expect(profile).toMatchObject({ type: "focus", name: "Focus", maximum: 100, initial: 100, regenerationPerSecond: 10 });
useCombatStore.getState().initializeCharacter({ classId: "ranger", raceId: "human", level: 20 });
const initial = useCombatStore.getState();
expect(initial.resourceName).toBe("Focus");
expect(initial.resource).toBe(initial.resourcePools.focus);
expect(initial.maxResource).toBe(initial.maxResourcePools.focus);
const powerShot = abilitiesForClass("ranger").find((ability) => ability.dbcSpellId === 501698)!;
expect(powerShot.name).toBe("Power Shot");
expect(powerShot.cost.resource).toBe("focus");
useCombatStore.getState().registerMob("ranger-focus-target", {
name: "Ranger Focus Target",
level: 20,
maxHealth: 50_000,
});
setMobPosition("ranger-focus-target", [8, 0, 0]);
useCombatStore.getState().selectMob("ranger-focus-target");
expect(useCombatStore.getState().castAbility(powerShot.id, undefined, 1_000)).toMatchObject({ ok: true });
const afterCast = useCombatStore.getState();
expect(afterCast.resource).toBeLessThan(initial.resource);
expect(afterCast.resourcePools.focus).toBe(afterCast.resource);
useCombatStore.getState().tick(1, 2_000);
const afterRecovery = useCombatStore.getState();
expect(afterRecovery.resource).toBeGreaterThan(afterCast.resource);
expect(afterRecovery.resourcePools.focus).toBe(afterRecovery.resource);
});
it("keeps an Archery companion's primary Focus pool aligned through party spending and recovery", () => {
useCombatStore.getState().initializeCharacter({ classId: "warrior", raceId: "human", level: 80 });
usePartyStore.getState().initializeParty(
"ranger-focus-party",
80,
useCombatStore.getState().health,
"damage",
1,
);
const ranger = createConfiguredPartyMember({
name: "Archery Ranger",
classId: "ranger",
specialization: "Archery",
specializationId: "ranger:archery",
talentTreeId: "coa-ranger-54",
talentRanks: {},
role: "damage",
}, 80, 0, "ranger-focus-party");
expect(ranger.resourceType).toBe("focus");
expect(ranger.resource).toBe(ranger.resourcePools.focus);
expect(ranger.maxResource).toBe(ranger.resourceMaximums?.focus);
const serratedShot = abilitiesForClass("ranger").find((ability) => ability.dbcSpellId === 500073)!;
expect(serratedShot.name).toBe("Serrated Shot");
expect(partyAbilityCosts(ranger, serratedShot, 1_000)).toContainEqual({ resource: "focus", amount: 25 });
const spent = commitPartyAbilityUse(ranger, serratedShot, 1_000);
expect(spent).not.toBeNull();
expect(spent!.resource).toBeLessThan(ranger.resource);
expect(spent!.resourcePools.focus).toBe(spent!.resource);
const actor = companionActorFromMember(spent!);
expect(actor.resources.focus).toMatchObject({
current: spent!.resource,
maximum: spent!.maxResource,
regenerationPerSecond: resourceProfileForClass("ranger").regenerationPerSecond,
});
usePartyStore.setState({ members: [spent!], command: "stop", activeMobId: null });
useCombatStore.getState().commitCompanionActors(usePartyStore.getState().members);
advanceDungeonPartyCombat(1_000);
advanceDungeonPartyCombat(2_000);
const recovered = usePartyStore.getState().members[0]!;
expect(recovered.resourcePools.focus).toBeGreaterThan(spent!.resourcePools.focus ?? 0);
expect(recovered.resource).toBe(recovered.resourcePools.focus);
});
});