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

+300
View File
@@ -0,0 +1,300 @@
import { beforeEach, describe, expect, it } from "vitest";
import { ROM_ALL_ABILITIES, romTriggeredAbilityBySpellId } from "./romAbilityCatalog";
import { applyAura, absorbDamage } from "./combatAuras";
import { PLAYER_AURA_ENTITY_ID, useCombatStore } from "./combatStore";
import { clearPartyRuntimeRegistry, registerPartyRuntimePosition } from "./partyRuntimeRegistry";
import { clearMobRuntimeRegistry, setMobPosition } from "./mobRuntimeRegistry";
import { DEFAULT_ENEMY_ATTACK } from "./enemyAttacks";
import { usePartyStore } from "./partyStore";
import { romEffectsForCast, type RomCastMechanics } from "./romCombatMechanics";
import {
ROM_WARDEN_DAMAGE_TRANSFER_FRACTION,
ROM_WARDEN_DAMAGE_TRANSFER_TAG,
ROM_WARDEN_WILL_ATTACK_TAG,
} from "./romWardenOverrides";
const emptyContext: RomCastMechanics = {
sealStacks: 0,
bleedCount: 0,
charged: false,
mainHandDagger: false,
casterMaxHealth: 2_000,
targetHealthPercent: 1,
};
function effectsFor(spellId: number, context: Partial<RomCastMechanics> = {}) {
const ability = ROM_ALL_ABILITIES.find((entry) => entry.dbcSpellId === spellId)!;
expect(ability).toBeDefined();
return romEffectsForCast(ability, { ...emptyContext, ...context });
}
function initializeRomCharacter(
classId: "rom-warden" | "rom-warrior" | "rom-druid",
secondaryClassId?: "rom-warden" | "rom-warrior",
) {
useCombatStore.getState().initializeCharacter({
classId,
...(secondaryClassId ? { secondaryClassId } : {}),
raceId: classId === "rom-warrior" ? "rom-human" : "rom-elf",
level: 80,
});
useCombatStore.setState((state) => ({
resource: 1_000,
maxResource: 1_000,
resourcePools: { ...state.resourcePools, mana: 1_000, rage: 1_000, "nature-power": 0 },
maxResourcePools: { ...state.maxResourcePools, mana: 1_000, rage: 1_000, "nature-power": 100 },
}));
}
describe("RoM Warden and Warden-linked source behaviors", () => {
beforeEach(() => {
clearPartyRuntimeRegistry();
clearMobRuntimeRegistry();
useCombatStore.setState({ playerPosition: [0, 0, 0] });
});
it("gates Will Attack's 10% damage reduction on the passive and places it on Frantic Briar's target", () => {
const passive = effectsFor(494610).find((effect) => effect.kind === "apply-aura");
expect(passive?.kind).toBe("apply-aura");
if (passive?.kind === "apply-aura") {
expect(passive.aura.utilityTags).toContain(ROM_WARDEN_WILL_ATTACK_TAG);
expect(passive.aura.modifiers ?? []).toHaveLength(0);
}
const withoutPassive = effectsFor(493391);
expect(withoutPassive.some((effect) => effect.kind === "apply-aura" && effect.sourceAuraType === 173)).toBe(false);
expect(withoutPassive.some((effect) => effect.kind === "apply-aura" && effect.sourceAuraType === 24)).toBe(true);
expect(withoutPassive.filter((effect) => effect.kind === "damage")).toHaveLength(2);
const withPassive = effectsFor(493391, { passiveTags: [ROM_WARDEN_WILL_ATTACK_TAG] });
expect(withPassive.filter((effect) => effect.kind === "damage")).toHaveLength(2);
expect(withPassive.filter((effect) => effect.kind === "apply-aura" && effect.sourceAuraType === 173)).toHaveLength(1);
expect(withPassive.find((effect) => effect.kind === "apply-aura" && effect.aura.id === "rom-warden-will-attack"))
.toMatchObject({
kind: "apply-aura",
recipient: "ability-target",
aura: {
name: "Will Attack",
disposition: "debuff",
durationMs: 10_000,
modifiers: [{ kind: "damage", direction: "dealt", attackKind: "melee", operation: "percent", value: -0.1 }],
},
});
});
it("reduces a Frantic Briar target's melee hit only while Will Attack is learned", () => {
const incomingDamage = (withWillAttack: boolean) => {
clearMobRuntimeRegistry();
initializeRomCharacter("rom-warden", "rom-warrior");
if (!withWillAttack) {
useCombatStore.setState((state) => ({
auras: state.auras.filter((aura) => !aura.definition.utilityTags?.includes(ROM_WARDEN_WILL_ATTACK_TAG)),
}));
}
const mobId = "will-attack-target";
useCombatStore.getState().registerMob(mobId, {
name: "Will Attack target",
maxHealth: 100_000,
attacks: [{ ...DEFAULT_ENEMY_ATTACK, id: "will-attack-swing", initialCooldownMs: [0, 0] }],
});
setMobPosition(mobId, [2, 0, 0]);
useCombatStore.getState().selectMob(mobId);
const hasPassive = useCombatStore.getState().auras.some((aura) => (
aura.targetId === PLAYER_AURA_ENTITY_ID
&& aura.definition.utilityTags?.includes(ROM_WARDEN_WILL_ATTACK_TAG)
));
expect(hasPassive).toBe(withWillAttack);
expect(useCombatStore.getState().castAbility("rom-warden-primary-11", undefined, 1_000))
.toMatchObject({ ok: true });
const targetDebuff = useCombatStore.getState().auras.some((aura) => (
aura.targetId === mobId && aura.definition.id === "rom-warden-will-attack"
));
expect(targetDebuff).toBe(withWillAttack);
useCombatStore.getState().damageMob(mobId, 1, 1_000);
return useCombatStore.getState().advanceMobCombat(1_450, [0, 0, 0]);
};
const normalDamage = incomingDamage(false);
const reducedDamage = incomingDamage(true);
expect(normalDamage).toBeGreaterThan(0);
expect(reducedDamage).toBeCloseTo(normalDamage * 0.9, 0);
});
it("keeps Nature Crystal active and makes its owner immune while blocking attack skills", () => {
initializeRomCharacter("rom-warden");
const now = Date.now();
expect(useCombatStore.getState().castAbility("rom-warden-primary-6", undefined, now)).toMatchObject({ ok: true });
useCombatStore.getState().tick(4, now + 4_000);
const crystal = useCombatStore.getState().summons.find((summon) => summon.creatureId === 102325)!;
expect(crystal.expiresAt).toBeGreaterThan(now + 60_000);
const health = useCombatStore.getState().health;
expect(useCombatStore.getState().damagePlayer(100, "fire")).toBe(0);
expect(useCombatStore.getState().health).toBe(health);
useCombatStore.getState().registerMob("warden-crystal-target", { name: "Target", maxHealth: 10_000 });
useCombatStore.getState().selectMob("warden-crystal-target");
expect(useCombatStore.getState().castAbility("rom-warden-primary-0", undefined, now + 6_000))
.toMatchObject({ ok: false, reason: "condition-not-met" });
});
it("scales Crystalline Protection to 10% of each recipient's own maximum health", () => {
initializeRomCharacter("rom-warden");
usePartyStore.getState().initializeParty("warden-crystalline-protection", 80, useCombatStore.getState().health, "healer", 3, "rom");
const [first, second] = usePartyStore.getState().members;
expect(first).toBeDefined();
expect(second).toBeDefined();
const members = usePartyStore.getState().members.map((member, index) => ({
...member,
maxHealth: index === 0 ? 2_000 : 5_000,
health: index === 0 ? 1_000 : 2_500,
}));
usePartyStore.setState({ members });
members.forEach((member, index) => registerPartyRuntimePosition(member.id, [2 + index, 0, 0]));
const playerMaxHealthBeforeCast = useCombatStore.getState().maxHealth;
expect(useCombatStore.getState().castAbility("rom-warden-primary-23", undefined, Date.now())).toMatchObject({ ok: true });
const auras = useCombatStore.getState().auras;
const absorbFor = (targetId: string) => auras.find((aura) => aura.targetId === targetId
&& aura.definition.name === "Crystalline Protection")?.absorbs[0]?.remaining;
expect(absorbFor(PLAYER_AURA_ENTITY_ID)).toBe(Math.round(playerMaxHealthBeforeCast * 0.1));
expect(absorbFor(members[0]!.id)).toBe(200);
expect(absorbFor(members[1]!.id)).toBe(500);
});
it("absorbs exactly two Heart of the Oak attack packets and leaves ordinary point shields unchanged", () => {
initializeRomCharacter("rom-warden");
expect(useCombatStore.getState().castAbility("rom-warden-primary-10", undefined, Date.now())).toMatchObject({ ok: true });
expect(useCombatStore.getState().damagePlayer(100, "physical")).toBe(0);
expect(useCombatStore.getState().damagePlayer(100, "fire")).toBe(0);
expect(useCombatStore.getState().damagePlayer(100, "physical")).toBeGreaterThan(0);
const flatShield = applyAura([], {
definition: {
id: "test:flat-absorb",
name: "Flat absorb",
disposition: "buff",
durationMs: 10_000,
absorbs: [{ id: "pool", amount: 5 }],
},
sourceId: "test-source",
targetId: "target",
now: 1,
}).auras;
const result = absorbDamage(flatShield, {
targetId: "target",
amount: 10,
school: "physical",
now: 2,
countsAsAttack: true,
});
expect(result).toMatchObject({ absorbed: 5, remainingDamage: 5 });
});
it("transfers 30% of incoming damage to a nearby Warden pet and disables the reduction without one", () => {
const incomingHealthLoss = (withPet: boolean, petDistance = 0) => {
initializeRomCharacter("rom-warden");
const now = Date.now();
if (withPet) {
const summonAbility = ROM_ALL_ABILITIES.find((ability) => ability.dbcSpellId === 493333)!;
expect(useCombatStore.getState().castAbility(summonAbility.id, undefined, now)).toMatchObject({ ok: true });
const summonCast = useCombatStore.getState().activeCast;
if (summonCast) useCombatStore.getState().tick(0.1, summonCast.completesAt);
useCombatStore.setState((state) => ({
summons: state.summons.map((summon) => summon.creatureId === 102297
? { ...summon, expiresAt: now + 20_000 }
: summon),
}));
}
const petBefore = useCombatStore.getState().summons.find((summon) => summon.creatureId === 102297);
if (petBefore && petDistance > 0) {
useCombatStore.setState((state) => ({
summons: state.summons.map((summon) => summon.id === petBefore.id
? { ...summon, position: [petDistance, 0, 0] }
: summon),
}));
}
const transferAbility = ROM_ALL_ABILITIES.find((ability) => ability.dbcSpellId === 493399)!;
expect(useCombatStore.getState().castAbility(transferAbility.id, undefined, now + 6_000)).toMatchObject({ ok: true });
const playerHealthBefore = useCombatStore.getState().health;
const petHealthBefore = useCombatStore.getState().summons.find((summon) => summon.creatureId === 102297)?.health ?? 0;
useCombatStore.getState().damagePlayer(500, "physical", 80, now + 7_000);
const state = useCombatStore.getState();
const petHealthAfter = state.summons.find((summon) => summon.creatureId === 102297)?.health ?? 0;
return {
playerDamage: playerHealthBefore - state.health,
petDamage: petHealthBefore - petHealthAfter,
};
};
const unshared = incomingHealthLoss(false);
const unsharedDamage = unshared.playerDamage;
const outOfRange = incomingHealthLoss(true, 301);
expect(unshared.petDamage).toBe(0);
expect(outOfRange.playerDamage).toBe(unsharedDamage);
expect(outOfRange.petDamage).toBe(0);
const shared = incomingHealthLoss(true);
expect(shared.petDamage).toBeGreaterThan(0);
expect(shared.playerDamage + shared.petDamage).toBeCloseTo(unsharedDamage, -1);
expect(shared.petDamage / (shared.playerDamage + shared.petDamage))
.toBeCloseTo(ROM_WARDEN_DAMAGE_TRANSFER_FRACTION, 1);
});
it("removes the unquantified Weak Point Strike bonus and models Awakening immunity and next critical", () => {
const weakPoint = effectsFor(494043);
expect(weakPoint.filter((effect) => effect.kind === "damage")).toHaveLength(1);
const awakening = effectsFor(499495);
const auras = awakening.filter((effect) => effect.kind === "apply-aura");
expect(auras).toHaveLength(2);
expect(auras).toEqual(expect.arrayContaining([
expect.objectContaining({
recipient: "caster",
aura: expect.objectContaining({ durationMs: 10_000, controlImmunities: ["root", "slow"] }),
}),
expect.objectContaining({
recipient: "caster",
aura: expect.objectContaining({
durationMs: null,
utilityTags: expect.arrayContaining(["next-offensive-critical"]),
}),
}),
]));
expect(auras.some((effect) => effect.kind === "apply-aura" && effect.control)).toBe(false);
});
it("spends one Nature Power for Healing Ripple's additional heal", () => {
const baseline = effectsFor(494323, { naturePower: 0 });
const empowered = effectsFor(494323, { naturePower: 1 });
expect(baseline.filter((effect) => effect.kind === "heal")).toHaveLength(1);
expect(baseline.some((effect) => effect.kind === "resource-drain")).toBe(false);
expect(empowered.filter((effect) => effect.kind === "heal")).toHaveLength(2);
expect(empowered).toContainEqual({ kind: "resource-drain", amount: 1, burn: false, resource: "nature-power" });
});
it("scales Gift Pulse by spent Nature Power and targets nearby party members", () => {
expect(effectsFor(499936, { naturePower: 0 })).toEqual([]);
const empowered = effectsFor(499936, { naturePower: 3 });
const empoweredHeal = empowered.find((effect) => effect.kind === "heal");
expect(empoweredHeal?.kind).toBe("heal");
if (empoweredHeal?.kind === "heal") expect(empoweredHeal.percentMaxHealth).toBeCloseTo(0.3);
expect(empowered.find((effect) => effect.kind === "resource-drain"))
.toEqual({ kind: "resource-drain", amount: 3, burn: false, resource: "nature-power" });
expect(effectsFor(499936, { naturePower: 20 }).find((effect) => effect.kind === "heal"))
.toMatchObject({ percentMaxHealth: 1 });
expect(ROM_ALL_ABILITIES.find((ability) => ability.dbcSpellId === 499936))
.toMatchObject({ targeting: { shape: "circle", radius: 10 } });
});
it("puts Mysterious Grace modifier auras on the party, and leaves Revival's absent state unresolved", () => {
const grace = effectsFor(494372);
const modifierAuras = grace.filter((effect) => effect.kind === "apply-aura" && effect.aura.modifiers?.length);
expect(modifierAuras.length).toBeGreaterThan(0);
expect(modifierAuras.every((effect) => effect.kind === "apply-aura" && effect.scope === "party")).toBe(true);
expect(grace.filter((effect) => effect.kind === "apply-aura" && !effect.aura.modifiers?.length)
.every((effect) => effect.kind === "apply-aura" && effect.scope === undefined)).toBe(true);
expect(romTriggeredAbilityBySpellId(499544)).toBeNull();
});
});