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,188 @@
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { PLAYER_AGGRO_ID } from "./aggro";
|
||||
import { useCombatStore } from "./combatStore";
|
||||
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
|
||||
import { advanceDungeonPartyCombat, resetPartyRuntimeClock } from "./partyRuntime";
|
||||
import { clearPartyRuntimeRegistry, registerPartyRuntimePosition } from "./partyRuntimeRegistry";
|
||||
import { ROM_ALL_ABILITIES } from "./romAbilityCatalog";
|
||||
import {
|
||||
ROM_DRUID_MAGE_INSPIRATION_AURA_TAG,
|
||||
romDruidMageInspirationApplySpendStack,
|
||||
romDruidMageInspirationHastePercent,
|
||||
} from "./romDruidMageInspirationRuntime";
|
||||
import { createConfiguredPartyMember, usePartyStore } from "./partyStore";
|
||||
|
||||
const EARTH_CHAIN_ID = "rom-druid-rom-mage-elite-15";
|
||||
const earthChain = ROM_ALL_ABILITIES.find((ability) => ability.id === EARTH_CHAIN_ID);
|
||||
|
||||
function inspirationAura(targetId: string) {
|
||||
return useCombatStore.getState().auras.find((aura) => aura.targetId === targetId
|
||||
&& aura.definition.utilityTags?.includes(ROM_DRUID_MAGE_INSPIRATION_AURA_TAG));
|
||||
}
|
||||
|
||||
function priest(name: string, seed: string, index: number) {
|
||||
return createConfiguredPartyMember({
|
||||
name,
|
||||
classId: "rom-priest",
|
||||
specialization: "Primary",
|
||||
role: "damage",
|
||||
}, 45, index, seed);
|
||||
}
|
||||
|
||||
describe("CoA Druid/Mage Inspiration player and companion integration", () => {
|
||||
beforeEach(() => {
|
||||
resetPartyRuntimeClock();
|
||||
clearMobRuntimeRegistry();
|
||||
clearPartyRuntimeRegistry();
|
||||
useCombatStore.getState().initializeCharacter({
|
||||
classId: "rom-priest",
|
||||
raceId: "rom-human",
|
||||
level: 45,
|
||||
role: "healer",
|
||||
});
|
||||
usePartyStore.getState().initializeParty(
|
||||
"inspiration-party-test", 45, useCombatStore.getState().health, "healer", 4, "rom",
|
||||
);
|
||||
});
|
||||
|
||||
it("awards one nearby-party stack for a player's completed Nature Power spend and applies cast haste", () => {
|
||||
if (!earthChain) throw new Error("Missing generated Druid/Mage Earth Chain row");
|
||||
useCombatStore.getState().initializeCharacter({
|
||||
classId: "rom-druid",
|
||||
secondaryClassId: "rom-mage",
|
||||
raceId: "rom-elf",
|
||||
level: 45,
|
||||
role: "damage",
|
||||
});
|
||||
useCombatStore.getState().setPlayerPosition([0, 0, 0]);
|
||||
|
||||
const seed = "inspiration-player-spend";
|
||||
const edge = priest("Range Edge", seed, 0);
|
||||
const outside = priest("Outside Range", seed, 1);
|
||||
const fallen = { ...priest("Fallen Ally", seed, 2), health: 0 };
|
||||
usePartyStore.setState({ members: [edge, outside, fallen] });
|
||||
registerPartyRuntimePosition(edge.id, [3, 4, 0]);
|
||||
registerPartyRuntimePosition(outside.id, [5.01, 0, 0]);
|
||||
registerPartyRuntimePosition(fallen.id, [1, 0, 0]);
|
||||
useCombatStore.getState().synchronizeActors();
|
||||
|
||||
useCombatStore.setState((state) => ({
|
||||
resourcePools: { ...state.resourcePools, "nature-power": 1 },
|
||||
maxResourcePools: { ...state.maxResourcePools, "nature-power": 10 },
|
||||
}));
|
||||
const targetId = "inspiration-player-target";
|
||||
useCombatStore.getState().registerMob(targetId, { name: "Target", level: 1, maxHealth: 100_000, xpReward: 0 });
|
||||
setMobPosition(targetId, [2, 0, 0]);
|
||||
useCombatStore.getState().selectMob(targetId);
|
||||
|
||||
expect(useCombatStore.getState().castAbility(EARTH_CHAIN_ID, {
|
||||
origin: [0, 0, 0], targetActorId: targetId, now: 1_000,
|
||||
}).ok).toBe(true);
|
||||
const unbuffedCastDuration = useCombatStore.getState().activeCast?.originalDurationMs ?? 0;
|
||||
expect(unbuffedCastDuration).toBeGreaterThan(0);
|
||||
useCombatStore.getState().tick(2, 3_000);
|
||||
|
||||
expect(useCombatStore.getState().resourcePools["nature-power"]).toBe(0);
|
||||
expect(inspirationAura(PLAYER_AGGRO_ID)).toMatchObject({ stacks: 1, expiresAt: 13_000 });
|
||||
expect(inspirationAura(edge.id)?.stacks).toBe(1);
|
||||
expect(inspirationAura(outside.id)).toBeUndefined();
|
||||
expect(inspirationAura(fallen.id)).toBeUndefined();
|
||||
|
||||
expect(useCombatStore.getState().castAbility(EARTH_CHAIN_ID, {
|
||||
origin: [0, 0, 0], targetActorId: targetId, now: 7_000,
|
||||
}).ok).toBe(true);
|
||||
expect(useCombatStore.getState().activeCast?.originalDurationMs).toBeLessThan(unbuffedCastDuration);
|
||||
});
|
||||
|
||||
it("awards one caster-centered stack when a generated Druid/Mage companion spends Nature Power", () => {
|
||||
if (!earthChain) throw new Error("Missing generated Druid/Mage Earth Chain row");
|
||||
const seed = "inspiration-companion-spend";
|
||||
const caster = createConfiguredPartyMember({
|
||||
name: "Druid/Mage",
|
||||
classId: "rom-druid",
|
||||
secondaryClassId: "rom-mage",
|
||||
specialization: "Primary",
|
||||
role: "damage",
|
||||
}, 45, 0, seed);
|
||||
const outside = priest("Outside Range", seed, 1);
|
||||
usePartyStore.setState({
|
||||
members: [{
|
||||
...caster,
|
||||
resourcePools: { ...caster.resourcePools, "nature-power": 1 },
|
||||
activeCast: {
|
||||
abilityId: EARTH_CHAIN_ID,
|
||||
school: "nature",
|
||||
mode: "cast",
|
||||
startedAt: 0,
|
||||
completesAt: 1_000,
|
||||
originalDurationMs: 1_000,
|
||||
pushbackHits: 0,
|
||||
origin: [0, 0, 0],
|
||||
targetId: "inspiration-companion-target",
|
||||
},
|
||||
activeCastTargetId: "inspiration-companion-target",
|
||||
status: "attacking",
|
||||
}, outside],
|
||||
command: "attack",
|
||||
activeMobId: "inspiration-companion-target",
|
||||
});
|
||||
registerPartyRuntimePosition(caster.id, [0, 0, 0]);
|
||||
registerPartyRuntimePosition(outside.id, [5.01, 0, 0]);
|
||||
useCombatStore.getState().synchronizeActors();
|
||||
useCombatStore.getState().registerMob("inspiration-companion-target", {
|
||||
name: "Target", level: 1, maxHealth: 100_000, xpReward: 0,
|
||||
});
|
||||
setMobPosition("inspiration-companion-target", [2, 0, 0]);
|
||||
useCombatStore.getState().damageMob("inspiration-companion-target", 1, 500);
|
||||
|
||||
advanceDungeonPartyCombat(1_000);
|
||||
|
||||
expect(usePartyStore.getState().members[0]?.resourcePools["nature-power"]).toBe(0);
|
||||
expect(inspirationAura(caster.id)?.stacks).toBe(1);
|
||||
expect(inspirationAura(PLAYER_AGGRO_ID)?.stacks).toBe(1);
|
||||
expect(inspirationAura(outside.id)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("applies Inspiration spell haste only once to a Mage receiving the party buff", () => {
|
||||
useCombatStore.getState().initializeCharacter({
|
||||
classId: "rom-mage",
|
||||
secondaryClassId: "rom-druid",
|
||||
raceId: "rom-elf",
|
||||
level: 45,
|
||||
role: "damage",
|
||||
});
|
||||
useCombatStore.getState().setPlayerPosition([0, 0, 0]);
|
||||
|
||||
const targetId = "inspiration-mage-target";
|
||||
useCombatStore.getState().registerMob(targetId, { name: "Target", level: 1, maxHealth: 100_000, xpReward: 0 });
|
||||
setMobPosition(targetId, [2, 0, 0]);
|
||||
useCombatStore.getState().selectMob(targetId);
|
||||
const ability = useCombatStore.getState().abilities.find((candidate) => candidate.id === "rom-mage-primary-1");
|
||||
expect(ability?.castTimeMs).toBe(3_000);
|
||||
|
||||
expect(useCombatStore.getState().castAbility("rom-mage-primary-1", {
|
||||
origin: [0, 0, 0], targetActorId: targetId, now: 1_000,
|
||||
}).ok).toBe(true);
|
||||
const unbuffedDuration = useCombatStore.getState().activeCast?.originalDurationMs ?? 0;
|
||||
expect(unbuffedDuration).toBeGreaterThan(0);
|
||||
useCombatStore.getState().tick(3, 4_000);
|
||||
useCombatStore.setState((state) => ({
|
||||
auras: [...romDruidMageInspirationApplySpendStack(
|
||||
state.auras, "druid-mage-source", [PLAYER_AGGRO_ID], 5_000,
|
||||
)],
|
||||
}));
|
||||
expect(inspirationAura(PLAYER_AGGRO_ID)?.stacks).toBe(1);
|
||||
expect(romDruidMageInspirationHastePercent(
|
||||
useCombatStore.getState().auras, PLAYER_AGGRO_ID, 5_000,
|
||||
)).toBe(2);
|
||||
|
||||
expect(useCombatStore.getState().castAbility("rom-mage-primary-1", {
|
||||
origin: [0, 0, 0], targetActorId: targetId, now: 5_000,
|
||||
}).ok).toBe(true);
|
||||
expect(useCombatStore.getState().activeCast?.startedAt).toBe(5_000);
|
||||
const buffedDuration = useCombatStore.getState().activeCast?.originalDurationMs ?? 0;
|
||||
const durationReduction = 1 - buffedDuration / unbuffedDuration;
|
||||
expect(durationReduction).toBeGreaterThan(0.01);
|
||||
expect(durationReduction).toBeLessThan(0.03);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user