Files
healer-man/src/game/romWarlockWarriorEnragedCoa.integration.test.ts
T
2026-10-02 10:38:12 -04:00

126 lines
5.6 KiB
TypeScript

import { beforeAll, beforeEach, describe, expect, it } from "vitest";
import { abilitiesForCharacter, learnedAbilityForBuild, preloadAbilityCatalogsForClasses } from "./abilityCatalog";
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
import { clearPartyRuntimeRegistry, registerPartyRuntimePosition, updatePartyRuntimeTargetVisibility } from "./partyRuntimeRegistry";
import { advanceDungeonPartyCombat, resetPartyRuntimeClock } from "./partyRuntime";
import { useCombatStore } from "./combatStore";
import { createConfiguredPartyMember, usePartyStore } from "./partyStore";
import { ROM_COA_WARLOCK_WARRIOR_ENRAGED } from "./romWarlockWarriorEnragedCoaMechanics";
const ABILITY_ID = "rom-warlock-rom-warrior-general-coa-499871";
const TARGET_ID = "rom-warlock-warrior-enraged-target";
function enragedAbility() {
return abilitiesForCharacter("rom-warlock", "rom-warrior").find((entry) => entry.id === ABILITY_ID)!;
}
function setPlayerPools(pools: { rage: number; focus: number; psi: number }) {
useCombatStore.setState((state) => ({
resource: pools.focus,
maxResource: 100,
resourcePools: { ...state.resourcePools, ...pools },
maxResourcePools: { ...state.maxResourcePools, rage: 100, focus: 100, psi: 6 },
}));
}
function prepareTarget() {
useCombatStore.getState().registerMob(TARGET_ID, { name: "Enraged Test Target", maxHealth: 100_000 });
setMobPosition(TARGET_ID, [5, 0, 0]);
}
describe("current CoA Warlock/Warrior Enraged runtime", () => {
beforeAll(async () => {
await preloadAbilityCatalogsForClasses(["rom-warlock"]);
});
beforeEach(() => {
clearMobRuntimeRegistry();
clearPartyRuntimeRegistry();
resetPartyRuntimeClock();
useCombatStore.setState({ playerPosition: [0, 0, 0] });
});
it("is learnable only at level 60 for Warlock/Warrior and does not replace the other Enraged row", () => {
const ability = enragedAbility();
expect(learnedAbilityForBuild(ability, 59, {})).toBeNull();
expect(learnedAbilityForBuild(ability, 60, {})).toMatchObject({ dbcSpellId: 499_871 });
expect(abilitiesForCharacter("rom-warlock", "rom-priest").some((candidate) => (
candidate.dbcSpellId === ROM_COA_WARLOCK_WARRIOR_ENRAGED.spellId
))).toBe(false);
expect(abilitiesForCharacter("rom-warrior", "rom-warlock").some((candidate) => (
candidate.dbcSpellId === ROM_COA_WARLOCK_WARRIOR_ENRAGED.spellId
))).toBe(false);
expect(abilitiesForCharacter("rom-warrior", undefined).find((candidate) => (
candidate.dbcSpellId === ROM_COA_WARLOCK_WARRIOR_ENRAGED.localWarriorGeneralSpellId
))).toBeDefined();
});
it("restores all three player resources, clamps to their caps, and honors the 40-second cooldown", () => {
useCombatStore.getState().initializeCharacter({
classId: "rom-warlock",
secondaryClassId: "rom-warrior",
raceId: "rom-dwarf",
level: 80,
});
setPlayerPools({ rage: 40, focus: 50, psi: 5 });
const ability = enragedAbility();
expect(useCombatStore.getState().castAbility(ability.id, { now: 1_000 })).toMatchObject({ ok: true });
expect(useCombatStore.getState().resourcePools).toMatchObject({ rage: 100, focus: 85, psi: 6 });
expect(useCombatStore.getState().cooldowns[ability.id]).toBe(41_000);
setPlayerPools({ rage: 50, focus: 80, psi: 5 });
expect(useCombatStore.getState().castAbility(ability.id, { now: 3_000 })).toMatchObject({
ok: false,
reason: "cooldown",
});
expect(useCombatStore.getState().castAbility(ability.id, { now: 41_000 })).toMatchObject({ ok: true });
expect(useCombatStore.getState().resourcePools).toMatchObject({ rage: 100, focus: 100, psi: 6 });
});
it("restores and caps companion Rage, Focus, and Psi through the shared resource effects", () => {
useCombatStore.getState().initializeCharacter({ classId: "rom-priest", raceId: "rom-dwarf", level: 80 });
usePartyStore.getState().initializeParty("rom-warlock-warrior-enraged-party", 80,
useCombatStore.getState().health, "damage", 2, "rom");
const member = createConfiguredPartyMember({
name: "Enraged Companion",
classId: "rom-warlock",
secondaryClassId: "rom-warrior",
raceId: "rom-dwarf",
specialization: "Warlock",
role: "damage",
}, 80, 0, "rom-warlock-warrior-enraged-party");
const ability = enragedAbility();
const pairAbilities = abilitiesForCharacter("rom-warlock", "rom-warrior");
const maximumCooldowns = Object.fromEntries(pairAbilities
.filter((candidate) => candidate.id !== ability.id)
.map((candidate) => [candidate.id, 100_000]));
usePartyStore.setState({
command: "attack",
members: [{
...member,
cooldowns: maximumCooldowns,
resourcePools: { ...member.resourcePools, focus: 20, rage: 40, psi: 5 },
resource: 20,
maxResource: 100,
}],
});
useCombatStore.getState().synchronizeActors();
registerPartyRuntimePosition(member.id, [0, 0, 0]);
prepareTarget();
useCombatStore.getState().damageMob(TARGET_ID, 100, 900);
updatePartyRuntimeTargetVisibility(member.id, TARGET_ID, true);
advanceDungeonPartyCombat(1_000);
advanceDungeonPartyCombat(3_100);
const result = usePartyStore.getState().members.find((candidate) => candidate.id === member.id);
expect(result?.cooldowns[ability.id]).toBe(41_000);
expect(result?.resourcePools.rage).toBe(100);
expect(result?.resourcePools.focus).toBeGreaterThanOrEqual(55);
expect(result?.resourcePools.focus).toBeLessThanOrEqual(100);
expect(result?.resourcePools.psi).toBe(6);
expect(useCombatStore.getState().mobs[TARGET_ID]?.health).toBe(99_900);
});
});