Update Healer Man server

This commit is contained in:
phenom committed 2026-09-28 22:46:45 -04:00
1 parent 9d7e0e2f9e
commit 35dfdaed61
94 files changed
+17034 -418

No files matched your search

+323
View File
@@ -0,0 +1,323 @@
import { beforeEach, describe, expect, it } from "vitest";
import { abilityById } from "./abilityCatalog";
import { DEFAULT_ENEMY_ATTACK } from "./enemyAttacks";
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
import { PLAYER_AURA_ENTITY_ID, useCombatStore } from "./combatStore";
import {
ROM_KNIGHT_DIVINE_PUNISHMENT_TAG,
ROM_KNIGHT_GODS_VENGEANCE_TAG,
ROM_KNIGHT_SHIELD_OF_VALOR_TAG,
} from "./romKnightOverrides";
import { romEffectsForCast } from "./romCombatMechanics";
function stableCombatUnit(seed: string): number {
let hash = 2166136261;
for (let index = 0; index < seed.length; index += 1) {
hash ^= seed.charCodeAt(index);
hash = Math.imul(hash, 16777619);
}
return (hash >>> 0) / 0x1_0000_0000;
}
function godsVengeanceCastTime(wantProc: boolean): number {
for (let now = 11_500; now < 100_000; now += 100) {
const roll = stableCombatUnit(
`${PLAYER_AURA_ENTITY_ID}:rom-knight-general-0:gods-vengeance-target:${now}:rom-gods-vengeance`,
);
if ((roll < 0.5) === wantProc) return now;
}
throw new Error("Could not find a deterministic God's Vengeance cast-time seed.");
}
describe("RuneWaker Knight periodic skills", () => {
beforeEach(() => {
clearMobRuntimeRegistry();
useCombatStore.setState({ playerPosition: [0, 0, 0] });
});
it("keeps Holy Light Domain as a three-pulse Holy area effect", () => {
const domain = abilityById("rom-knight-rom-mage-elite-15")!;
expect(domain).toMatchObject({ dbcSpellId: 491606, target: "self", radius: 10 });
expect(domain.effects).toEqual(expect.arrayContaining([
expect.objectContaining({
kind: "dot",
school: "holy",
ticks: 3,
intervalMs: 2_000,
tag: "rom-knight-holy-light-domain",
}),
]));
expect(domain.effects.some((effect) => effect.kind === "apply-aura"
&& effect.aura.procs?.some((proc) => proc.action.kind === "custom"
&& proc.action.id === "rom-trigger-skill"))).toBe(false);
useCombatStore.getState().initializeCharacter({
classId: "rom-knight", secondaryClassId: "rom-mage", raceId: "rom-human", level: 80,
});
for (const [id, x] of [["domain-near", 5], ["domain-edge", 9], ["domain-far", 12]] as const) {
useCombatStore.getState().registerMob(id, { name: id, maxHealth: 100_000 });
setMobPosition(id, [x, 0, 0]);
}
const initialHealth = Object.fromEntries(Object.entries(useCombatStore.getState().mobs)
.map(([id, mob]) => [id, mob.health]));
expect(useCombatStore.getState().castAbility(domain.id, undefined, 1_000)).toMatchObject({ ok: true });
expect(useCombatStore.getState().effects.filter((effect) => effect.kind === "dot")
.map((effect) => effect.targetId).sort()).toEqual(["domain-edge", "domain-near"]);
expect(useCombatStore.getState().mobs["domain-near"]!.health).toBe(initialHealth["domain-near"]);
useCombatStore.getState().tick(0.1, 3_000);
const afterFirstPulse = useCombatStore.getState();
expect(afterFirstPulse.mobs["domain-near"]!.health).toBeLessThan(initialHealth["domain-near"]!);
expect(afterFirstPulse.mobs["domain-edge"]!.health).toBeLessThan(initialHealth["domain-edge"]!);
expect(afterFirstPulse.mobs["domain-far"]!.health).toBe(initialHealth["domain-far"]);
});
it("adds War Prayer Holy Seal stacks on its six three-second pulses", () => {
const prayer = abilityById("rom-knight-rom-mage-elite-50")!;
expect(prayer).toMatchObject({ dbcSpellId: 490078, target: "hostile" });
expect(prayer.effects).toEqual(expect.arrayContaining([
expect.objectContaining({ kind: "damage", school: "holy" }),
expect.objectContaining({
kind: "dot",
ticks: 6,
intervalMs: 3_000,
tag: "rom-knight-war-prayer-seal",
}),
]));
expect(prayer.effects.some((effect) => effect.kind === "apply-aura"
&& effect.aura.procs?.some((proc) => proc.action.kind === "custom"
&& proc.action.id === "rom-trigger-skill"))).toBe(false);
useCombatStore.getState().initializeCharacter({
classId: "rom-knight", secondaryClassId: "rom-mage", raceId: "rom-human", level: 80,
});
useCombatStore.getState().registerMob("war-prayer-target", { name: "War Prayer Target", maxHealth: 100_000 });
setMobPosition("war-prayer-target", [3, 0, 0]);
useCombatStore.getState().selectMob("war-prayer-target");
expect(useCombatStore.getState().castAbility(prayer.id, undefined, 1_000)).toMatchObject({ ok: true });
expect(useCombatStore.getState().comboPoints).toBe(0);
expect(useCombatStore.getState().effects).toEqual(expect.arrayContaining([
expect.objectContaining({ kind: "dot", targetId: "war-prayer-target", remainingTicks: 6 }),
]));
for (let tick = 1; tick <= 6; tick += 1) {
useCombatStore.getState().tick(0.1, 1_000 + tick * 3_000);
expect(useCombatStore.getState().comboTargetId).toBe("war-prayer-target");
expect(useCombatStore.getState().comboPoints).toBe(Math.min(tick, 4));
}
});
it("limits Divine Punishment's sourced 1% bonus to Punishment", () => {
useCombatStore.getState().initializeCharacter({
classId: "rom-knight", secondaryClassId: "rom-warrior", raceId: "rom-human", level: 80,
});
const state = useCombatStore.getState();
const passive = state.abilities.find((ability) => ability.dbcSpellId === 491608);
expect(passive?.passive).toBe(true);
const passiveAura = state.auras.find((aura) => aura.definition.utilityTags?.includes(ROM_KNIGHT_DIVINE_PUNISHMENT_TAG));
expect(passiveAura).toBeDefined();
expect(passive?.effects).toEqual([
expect.objectContaining({
kind: "apply-aura",
aura: expect.objectContaining({
utilityTags: [ROM_KNIGHT_DIVINE_PUNISHMENT_TAG],
}),
}),
]);
const passiveEffect = passive?.effects[0];
expect(passiveEffect?.kind).toBe("apply-aura");
if (passiveEffect?.kind === "apply-aura") expect(passiveEffect.aura.modifiers).toBeUndefined();
const punishment = abilityById("rom-knight-general-0")!;
const context = {
sealStacks: 4,
bleedCount: 0,
charged: false,
mainHandDagger: false,
casterMaxHealth: state.maxHealth,
targetHealthPercent: 1,
} as const;
const baseline = romEffectsForCast(punishment, context);
const boosted = romEffectsForCast(punishment, {
...context,
passiveTags: passiveAura?.definition.utilityTags ?? [],
});
const damageValues = (effects: typeof baseline) => effects
.filter((effect) => effect.kind === "damage" || effect.kind === "dot")
.map((effect) => ({
coefficient: effect.coefficient,
basePoints: "basePoints" in effect ? effect.basePoints ?? 0 : 0,
pointsPerLevel: "pointsPerLevel" in effect ? effect.pointsPerLevel ?? 0 : 0,
}));
expect(damageValues(baseline)).toHaveLength(2);
expect(damageValues(boosted)).toHaveLength(2);
for (const [index, base] of damageValues(baseline).entries()) {
expect(damageValues(boosted)[index]!.coefficient).toBeCloseTo(base.coefficient * 1.01);
expect(damageValues(boosted)[index]!.basePoints).toBeCloseTo(base.basePoints * 1.01);
expect(damageValues(boosted)[index]!.pointsPerLevel).toBeCloseTo(base.pointsPerLevel * 1.01);
}
expect(romEffectsForCast(abilityById("rom-knight-primary-1")!, {
...context,
passiveTags: passiveAura?.definition.utilityTags ?? [],
})).toEqual(romEffectsForCast(abilityById("rom-knight-primary-1")!, context));
});
it.each([true, false])("lets God's Vengeance preserve Holy Seal when the 50% roll is %s", (preservesSeal) => {
const godVengeance = abilityById("rom-knight-rom-rogue-elite-50")!;
expect(godVengeance).toMatchObject({ dbcSpellId: 499934, passive: true });
expect(godVengeance.effects).toEqual([
expect.objectContaining({
kind: "apply-aura",
recipient: "caster",
aura: expect.objectContaining({ utilityTags: [ROM_KNIGHT_GODS_VENGEANCE_TAG] }),
}),
]);
useCombatStore.getState().initializeCharacter({
classId: "rom-knight", secondaryClassId: "rom-rogue", raceId: "rom-human", level: 80,
});
useCombatStore.getState().registerMob("gods-vengeance-target", {
name: "God's Vengeance Target", maxHealth: 1_000_000,
});
setMobPosition("gods-vengeance-target", [3, 0, 0]);
useCombatStore.getState().selectMob("gods-vengeance-target");
expect(useCombatStore.getState().auras).toEqual(expect.arrayContaining([
expect.objectContaining({
targetId: PLAYER_AURA_ENTITY_ID,
definition: expect.objectContaining({ utilityTags: [ROM_KNIGHT_GODS_VENGEANCE_TAG] }),
}),
]));
expect(useCombatStore.getState().castAbility("rom-knight-primary-1", undefined, 1_000))
.toMatchObject({ ok: true });
expect(useCombatStore.getState().comboPoints).toBe(4);
const castTime = godsVengeanceCastTime(preservesSeal);
expect(useCombatStore.getState().castAbility("rom-knight-general-0", undefined, castTime))
.toMatchObject({ ok: true });
expect(useCombatStore.getState().comboPoints).toBe(preservesSeal ? 4 : 0);
expect(useCombatStore.getState().effects.some((effect) => effect.kind === "dot"
&& effect.targetId === "gods-vengeance-target" && effect.tag === "rom-holy-seal"))
.toBe(preservesSeal);
expect(useCombatStore.getState().combatEvents.some((event) => event.kind === "damage"
&& event.abilityId === "rom-knight-general-0" && event.targetActorId === "gods-vengeance-target"
&& event.effectiveAmount > 0)).toBe(true);
});
it("reduces Holy Seal cooldown by one second when Shield of Valor parries", () => {
useCombatStore.getState().initializeCharacter({
classId: "rom-knight", raceId: "rom-human", level: 80, role: "tank",
});
const holySeal = useCombatStore.getState().abilities.find((ability) => ability.dbcSpellId === 490149)!;
const shieldOfValor = abilityById("rom-knight-primary-10")!;
expect(shieldOfValor).toMatchObject({ dbcSpellId: 490468 });
useCombatStore.setState((state) => ({
gearStats: { ...state.gearStats, parryRating: 100_000 },
}));
expect(useCombatStore.getState().castAbility(shieldOfValor.id, undefined, 1_000)).toMatchObject({ ok: true });
expect(useCombatStore.getState().auras).toEqual(expect.arrayContaining([
expect.objectContaining({
targetId: PLAYER_AURA_ENTITY_ID,
definition: expect.objectContaining({ utilityTags: expect.arrayContaining([ROM_KNIGHT_SHIELD_OF_VALOR_TAG]) }),
}),
]));
useCombatStore.setState((state) => ({
cooldowns: { ...state.cooldowns, [holySeal.id]: 25_000 },
}));
useCombatStore.getState().registerMob("shield-of-valor-attacker", {
name: "Shield of Valor Attacker",
maxHealth: 100_000,
attacks: [DEFAULT_ENEMY_ATTACK],
});
setMobPosition("shield-of-valor-attacker", [2, 0, 0]);
useCombatStore.getState().damageMob("shield-of-valor-attacker", 1, 1_100);
let parryAt: number | null = null;
for (let now = 1_450; now < 16_000; now += 100) {
useCombatStore.getState().advanceMobCombat(now);
if (useCombatStore.getState().lastCombatResult?.parried) {
parryAt = now;
break;
}
}
expect(parryAt).not.toBeNull();
expect(useCombatStore.getState().cooldowns[holySeal.id]).toBe(24_000);
});
it("activates the source-backed Evil Shackles passive state", () => {
const passive = abilityById("rom-knight-rom-scout-elite-60")!;
expect(passive).toMatchObject({ dbcSpellId: 499926, passive: true });
expect(passive.effects).toEqual([
expect.objectContaining({
kind: "apply-aura",
recipient: "caster",
aura: expect.objectContaining({
durationMs: null,
utilityTags: ["rom-evil-shackles"],
}),
}),
]);
useCombatStore.getState().initializeCharacter({
classId: "rom-knight", secondaryClassId: "rom-scout", raceId: "rom-human", level: 80,
});
expect(useCombatStore.getState().auras).toEqual(expect.arrayContaining([
expect.objectContaining({
definition: expect.objectContaining({ utilityTags: ["rom-evil-shackles"] }),
}),
]));
});
it("lets Evil Shackles root non-Undead/Demon targets for half duration", () => {
const holyChains = abilityById("rom-knight-rom-scout-elite-25")!;
const rootDuration = (targetTags: readonly string[]) => {
const root = romEffectsForCast(holyChains, {
sealStacks: 0,
bleedCount: 0,
charged: false,
mainHandDagger: false,
casterMaxHealth: 2_000,
targetHealthPercent: 1,
passiveTags: ["rom-evil-shackles"],
targetTags,
}).find((effect) => effect.kind === "apply-aura" && effect.control?.kind === "root");
return root?.kind === "apply-aura" ? root.aura.durationMs : undefined;
};
expect(rootDuration(["rom-target-undead-demon"])).toBe(10_000);
expect(rootDuration(["rom-target-living"])).toBe(5_000);
expect(rootDuration([])).toBe(5_000);
useCombatStore.getState().initializeCharacter({
classId: "rom-knight", secondaryClassId: "rom-scout", raceId: "rom-human", level: 50,
});
useCombatStore.getState().registerMob("shackles-target", {
name: "Living target", maxHealth: 100_000, creatureFamily: "living",
});
setMobPosition("shackles-target", [3, 0, 0]);
useCombatStore.getState().selectMob("shackles-target");
expect(useCombatStore.getState().castAbility(holyChains.id, undefined, 1_000)).toMatchObject({
ok: false, reason: "condition-not-met",
});
useCombatStore.getState().registerMob("shackles-target", {
name: "Unknown target", maxHealth: 100_000, creatureFamily: "unknown",
});
expect(useCombatStore.getState().castAbility(holyChains.id, undefined, 2_000)).toMatchObject({
ok: false, reason: "condition-not-met",
});
useCombatStore.getState().initializeCharacter({
classId: "rom-knight", secondaryClassId: "rom-scout", raceId: "rom-human", level: 80,
});
useCombatStore.getState().registerMob("shackles-target", {
name: "Living target", maxHealth: 100_000, creatureFamily: "living",
});
setMobPosition("shackles-target", [3, 0, 0]);
useCombatStore.getState().selectMob("shackles-target");
expect(useCombatStore.getState().castAbility(holyChains.id, undefined, 3_000)).toMatchObject({ ok: true });
expect(useCombatStore.getState().mobs["shackles-target"]!.statuses).toEqual(expect.arrayContaining([
expect.objectContaining({ kind: "root", endsAt: 8_000 }),
]));
});
});