forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
69809f7228
commit
ff20ab8779
101 files changed
+16713
-945
No files matched your search
@@ -0,0 +1,86 @@
|
||||
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
||||
import { preloadAbilityCatalogsForClasses } from "./abilityCatalog";
|
||||
import { PLAYER_AGGRO_ID } from "./aggro";
|
||||
import { applyAura } from "./combatAuras";
|
||||
import { useCombatStore } from "./combatStore";
|
||||
import { registerCombatSpatialProvider, resetCombatSpatialProvider } from "./combatSpatial";
|
||||
import { clearMobRuntimeRegistry, registerMobRuntime } from "./mobRuntimeRegistry";
|
||||
import { clearPartyRuntimeRegistry } from "./partyRuntimeRegistry";
|
||||
import { usePartyStore } from "./partyStore";
|
||||
import { ROM_SCOUT_AUTO_SHOT_ABILITY_ID } from "./romScoutAutoShot";
|
||||
|
||||
const TARGET = "pacify-weapon-swing-fixture";
|
||||
const ORIGIN = [0, 0, 0] as const;
|
||||
const FRONT = [0, 0, -2] as const;
|
||||
|
||||
function prepare(pacified: boolean, targetId = PLAYER_AGGRO_ID) {
|
||||
useCombatStore.getState().initializeCharacter({ classId: "warrior", level: 30 });
|
||||
usePartyStore.setState({ members: [] });
|
||||
useCombatStore.getState().setPlayerPosition(ORIGIN);
|
||||
useCombatStore.getState().registerMob(TARGET, { name: "Synthetic autoattack target",
|
||||
level: 1, maxHealth: 1_000_000, xpReward: 0 });
|
||||
registerMobRuntime(TARGET, FRONT, 0);
|
||||
registerCombatSpatialProvider({ actor: (id) => id === TARGET
|
||||
? { id, position: FRONT, yaw: 0 } : { id, position: ORIGIN, yaw: Math.PI },
|
||||
hasLineOfSight: () => true, projectGroundPoint: (position) => position });
|
||||
useCombatStore.setState((state) => ({ autoAttackTargetId: TARGET,
|
||||
nextAutoAttackAt: 1_000, nextOffhandAutoAttackAt: 1_000,
|
||||
auras: pacified ? [...applyAura(state.auras, { definition: {
|
||||
id: "synthetic-source-pacify", name: "Accepted pacify aura fixture",
|
||||
disposition: "buff", durationMs: 2_000, utilityTags: ["pacified"],
|
||||
}, sourceId: targetId, targetId, now: 1_000 }).auras] : state.auras,
|
||||
}));
|
||||
}
|
||||
function playerSwings() {
|
||||
return useCombatStore.getState().combatEvents.filter((event) => event.sourceActorId === PLAYER_AGGRO_ID
|
||||
&& event.targetActorId === TARGET && event.attackHand === "mainhand");
|
||||
}
|
||||
|
||||
describe("accepted pacify aura suppresses player weapon autos", () => {
|
||||
beforeAll(async () => { await preloadAbilityCatalogsForClasses(["warrior", "rom-scout", "rom-rogue"]); });
|
||||
afterEach(() => { clearMobRuntimeRegistry(); clearPartyRuntimeRegistry(); resetCombatSpatialProvider(); });
|
||||
|
||||
it("holds due swings through the whole aura window and resumes once at expiry", () => {
|
||||
prepare(true);
|
||||
for (const now of [1_000, 1_500, 2_999]) useCombatStore.getState().tick(0.05, now);
|
||||
expect(playerSwings()).toHaveLength(0);
|
||||
expect(useCombatStore.getState().mobs[TARGET]!.health).toBe(1_000_000);
|
||||
expect(useCombatStore.getState().autoAttackTargetId).toBe(TARGET);
|
||||
useCombatStore.getState().tick(0.05, 3_000);
|
||||
expect(playerSwings()).toHaveLength(1);
|
||||
expect(useCombatStore.getState().nextAutoAttackAt).toBeGreaterThan(3_000);
|
||||
useCombatStore.getState().tick(0.05, 3_001);
|
||||
expect(playerSwings()).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("does not borrow another actor's pacify aura", () => {
|
||||
prepare(true, "another-actor");
|
||||
useCombatStore.getState().tick(0.05, 1_000);
|
||||
expect(playerSwings()).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("also holds the owned Scout ranged-auto scheduler until pacify expires", () => {
|
||||
prepare(false);
|
||||
useCombatStore.getState().initializeCharacter({ classId: "rom-scout", secondaryClassId: "rom-rogue",
|
||||
raceId: "rom-human", statRuleset: "rom", level: 30, inventory: [], equipment: {} });
|
||||
useCombatStore.getState().registerMob(TARGET, { name: "Synthetic ranged auto target",
|
||||
level: 1, maxHealth: 1_000_000, xpReward: 0 });
|
||||
useCombatStore.getState().setPlayerPosition(ORIGIN);
|
||||
// Synthetic already-selected ranged mode; the real native scheduler and
|
||||
// automatic Training Gear profile resolve subsequent weapon results.
|
||||
useCombatStore.setState((state) => ({ autoShotTargetId: TARGET, nextAutoShotAt: 1_000,
|
||||
auras: [...applyAura(state.auras, { definition: {
|
||||
id: "synthetic-ranged-pacify", name: "Accepted ranged pacify fixture",
|
||||
disposition: "buff", durationMs: 2_000, utilityTags: ["pacified"],
|
||||
}, sourceId: PLAYER_AGGRO_ID, targetId: PLAYER_AGGRO_ID, now: 1_000 }).auras],
|
||||
}));
|
||||
const rangedEvents = () => useCombatStore.getState().combatEvents.filter((event) => event.sourceActorId === PLAYER_AGGRO_ID
|
||||
&& event.abilityId === ROM_SCOUT_AUTO_SHOT_ABILITY_ID && event.attackHand === "ranged");
|
||||
for (const now of [1_000, 1_500, 2_999]) useCombatStore.getState().tick(0.05, now);
|
||||
expect(rangedEvents()).toHaveLength(0);
|
||||
useCombatStore.getState().tick(0.05, 3_000);
|
||||
expect(rangedEvents()).toHaveLength(1);
|
||||
useCombatStore.getState().tick(0.05, 3_001);
|
||||
expect(rangedEvents()).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user