forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
4c768fbec6
commit
b16821e92e
330 files changed
+35406
-1760
No files matched your search
@@ -0,0 +1,192 @@
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { abilityById } from "./abilityCatalog";
|
||||
import { PLAYER_AGGRO_ID } from "./aggro";
|
||||
import { useCombatStore } from "./combatStore";
|
||||
import { clearMobRuntimeRegistry } from "./mobRuntimeRegistry";
|
||||
import { advanceDungeonPartyCombat, resetPartyRuntimeClock } from "./partyRuntime";
|
||||
import {
|
||||
clearPartyRuntimeRegistry,
|
||||
registerPartyRuntimePosition,
|
||||
} from "./partyRuntimeRegistry";
|
||||
import { createConfiguredPartyMember, usePartyStore } from "./partyStore";
|
||||
import { ROM_PRIEST_CHAMPION_BEACON_OF_REGENERATION_ID } from "./romPriestChampionBeaconRuntime";
|
||||
|
||||
const beacon = abilityById(ROM_PRIEST_CHAMPION_BEACON_OF_REGENERATION_ID)!;
|
||||
const heal = abilityById("rom-priest-primary-2")!;
|
||||
const beaconTag = "rom-priest-champion-beacon-of-regeneration";
|
||||
|
||||
function setPlayerMana(amount: number): void {
|
||||
useCombatStore.setState((state) => ({
|
||||
resource: amount,
|
||||
maxResource: amount,
|
||||
maxResourcePools: { ...state.maxResourcePools, mana: amount },
|
||||
resourcePools: { ...state.resourcePools, mana: amount },
|
||||
}));
|
||||
}
|
||||
|
||||
function activeCast(abilityId: string, targetId: string, startedAt: number, completesAt: number) {
|
||||
return {
|
||||
abilityId,
|
||||
school: "holy" as const,
|
||||
mode: "cast" as const,
|
||||
startedAt,
|
||||
completesAt,
|
||||
originalDurationMs: Math.max(0, completesAt - startedAt),
|
||||
pushbackHits: 0,
|
||||
origin: [0, 0, 0] as const,
|
||||
targetId,
|
||||
};
|
||||
}
|
||||
|
||||
describe("RoM Priest/Champion Beacon of Regeneration integration", () => {
|
||||
beforeEach(() => {
|
||||
clearMobRuntimeRegistry();
|
||||
clearPartyRuntimeRegistry();
|
||||
resetPartyRuntimeClock();
|
||||
useCombatStore.getState().initializeCharacter({
|
||||
classId: "rom-priest",
|
||||
secondaryClassId: "rom-champion",
|
||||
raceId: "rom-dwarf",
|
||||
level: 80,
|
||||
role: "healer",
|
||||
});
|
||||
usePartyStore.getState().initializeParty(
|
||||
"rom-priest-champion-beacon", 80, useCombatStore.getState().health, "healer", 2, "rom",
|
||||
);
|
||||
usePartyStore.getState().setCommand("stop");
|
||||
setPlayerMana(10_000);
|
||||
});
|
||||
|
||||
it("applies a player's Beacon with the caster's healing-done modifiers", () => {
|
||||
const seed = "rom-priest-champion-beacon-player-target";
|
||||
const marked = createConfiguredPartyMember({
|
||||
name: "Marked ally",
|
||||
classId: "rom-warrior",
|
||||
raceId: "rom-human",
|
||||
specialization: "Primary",
|
||||
role: "tank",
|
||||
}, 80, 0, seed);
|
||||
const healTarget = createConfiguredPartyMember({
|
||||
name: "Heal target",
|
||||
classId: "rom-warrior",
|
||||
raceId: "rom-human",
|
||||
specialization: "Primary",
|
||||
role: "tank",
|
||||
}, 80, 1, seed);
|
||||
usePartyStore.setState({ members: [{ ...marked, health: 1 }, { ...healTarget, health: 1 }] });
|
||||
registerPartyRuntimePosition(marked.id, [1, 0, 0]);
|
||||
registerPartyRuntimePosition(healTarget.id, [2, 0, 0]);
|
||||
useCombatStore.getState().synchronizeActors();
|
||||
|
||||
expect(useCombatStore.getState().castAbility(beacon.id, {
|
||||
targetActorId: marked.id,
|
||||
now: 1_000,
|
||||
})).toMatchObject({ ok: true });
|
||||
expect(useCombatStore.getState().auras).toEqual(expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
sourceId: PLAYER_AGGRO_ID,
|
||||
targetId: marked.id,
|
||||
expiresAt: 31_000,
|
||||
definition: expect.objectContaining({ utilityTags: [beaconTag] }),
|
||||
}),
|
||||
]));
|
||||
|
||||
expect(useCombatStore.getState().castAbility(heal.id, {
|
||||
targetActorId: healTarget.id,
|
||||
now: 3_000,
|
||||
})).toMatchObject({ ok: true });
|
||||
useCombatStore.getState().tick(3, 5_000);
|
||||
|
||||
const event = useCombatStore.getState().combatEvents.find((candidate) => (
|
||||
candidate.kind === "healing" && candidate.abilityId === beacon.id
|
||||
));
|
||||
const faith = useCombatStore.getState().auras.find((aura) => (
|
||||
aura.sourceId === PLAYER_AGGRO_ID && aura.definition.name === "Faith: healing-power-percent"
|
||||
));
|
||||
expect(faith?.definition.modifiers).toContainEqual({
|
||||
kind: "healing", direction: "done", operation: "percent", value: 0.05,
|
||||
});
|
||||
expect(event).toMatchObject({
|
||||
sourceActorId: PLAYER_AGGRO_ID,
|
||||
targetActorId: marked.id,
|
||||
rawAmount: 809,
|
||||
effectiveAmount: 809,
|
||||
overheal: 0,
|
||||
critical: false,
|
||||
});
|
||||
expect(usePartyStore.getState().members.find((member) => member.id === marked.id)?.health).toBe(810);
|
||||
});
|
||||
|
||||
it("applies a generated companion's Beacon and resolves its direct-heal trigger", () => {
|
||||
const seed = "rom-priest-champion-beacon-companion";
|
||||
const caster = createConfiguredPartyMember({
|
||||
name: "Priest/Champion",
|
||||
classId: "rom-priest",
|
||||
secondaryClassId: "rom-champion",
|
||||
raceId: "rom-dwarf",
|
||||
specialization: "Priest/Champion",
|
||||
role: "healer",
|
||||
}, 80, 0, seed);
|
||||
const marked = createConfiguredPartyMember({
|
||||
name: "Marked companion ally",
|
||||
classId: "rom-warrior",
|
||||
raceId: "rom-human",
|
||||
specialization: "Primary",
|
||||
role: "tank",
|
||||
}, 80, 1, seed);
|
||||
const healTarget = createConfiguredPartyMember({
|
||||
name: "Heal target companion",
|
||||
classId: "rom-warrior",
|
||||
raceId: "rom-human",
|
||||
specialization: "Primary",
|
||||
role: "tank",
|
||||
}, 80, 2, seed);
|
||||
usePartyStore.setState({ members: [
|
||||
{ ...caster, resource: 10_000, maxResource: 10_000, resourcePools: { ...caster.resourcePools, mana: 10_000 },
|
||||
activeCast: activeCast(beacon.id, marked.id, 1_000, 1_000), activeCastTargetId: marked.id, status: "attacking" },
|
||||
{ ...marked, health: 1 },
|
||||
{ ...healTarget, health: 1 },
|
||||
] });
|
||||
registerPartyRuntimePosition(caster.id, [0, 0, 0]);
|
||||
registerPartyRuntimePosition(marked.id, [1, 0, 0]);
|
||||
registerPartyRuntimePosition(healTarget.id, [2, 0, 0]);
|
||||
useCombatStore.getState().synchronizeActors();
|
||||
|
||||
advanceDungeonPartyCombat(1_000);
|
||||
|
||||
expect(useCombatStore.getState().auras).toEqual(expect.arrayContaining([
|
||||
expect.objectContaining({ sourceId: caster.id, targetId: marked.id, definition: expect.objectContaining({ utilityTags: [beaconTag] }) }),
|
||||
]));
|
||||
|
||||
usePartyStore.setState((state) => ({
|
||||
members: state.members.map((member) => member.id === caster.id ? {
|
||||
...member,
|
||||
activeCast: activeCast(heal.id, healTarget.id, 1_000, 3_000),
|
||||
activeCastTargetId: healTarget.id,
|
||||
status: "attacking",
|
||||
} : member),
|
||||
}));
|
||||
useCombatStore.getState().synchronizeActors();
|
||||
advanceDungeonPartyCombat(3_000);
|
||||
|
||||
const faith = useCombatStore.getState().auras.find((aura) => (
|
||||
aura.sourceId === caster.id && aura.definition.name === "Faith: healing-power-percent"
|
||||
));
|
||||
expect(faith?.definition.modifiers).toContainEqual({
|
||||
kind: "healing", direction: "done", operation: "percent", value: 0.05,
|
||||
});
|
||||
|
||||
const event = useCombatStore.getState().combatEvents.find((candidate) => (
|
||||
candidate.kind === "healing" && candidate.sourceActorId === caster.id && candidate.abilityId === beacon.id
|
||||
));
|
||||
expect(event).toMatchObject({
|
||||
targetActorId: marked.id,
|
||||
// Beacon contributes 770; the companion's ordinary Faith aura applies its +5% healing bonus.
|
||||
rawAmount: 809,
|
||||
effectiveAmount: 809,
|
||||
overheal: 0,
|
||||
critical: false,
|
||||
});
|
||||
expect(usePartyStore.getState().members.find((member) => member.id === marked.id)?.health).toBe(810);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user