Update Healer Man server

This commit is contained in:
phenom committed 2026-09-30 09:57:13 -04:00
1 parent 35dfdaed61
commit 4fb7a0b9c8
161 files changed
+24618 -529

No files matched your search

+248 -2
View File
@@ -1,9 +1,15 @@
import { beforeEach, describe, expect, it } from "vitest";
import { ROM_ALL_ABILITIES } from "./romAbilityCatalog";
import { clearMobRuntimeRegistry, getMobPosition, setMobPosition } from "./mobRuntimeRegistry";
import { useCombatStore } from "./combatStore";
import { PLAYER_AURA_ENTITY_ID, useCombatStore } from "./combatStore";
import { romEffectsForCast, type RomCastMechanics } from "./romCombatMechanics";
import { romChampionCastEffects } from "./romChampionOverrides";
import {
ROM_CHAMPION_SOUL_FORGE_PROC_ACTION_ID,
ROM_CHAMPION_SOUL_FORGE_PROFILE,
ROM_CHAMPION_WAY_OF_FRENZY_PROC_ACTION_ID,
ROM_CHAMPION_WAY_OF_FRENZY_PROFILE,
romChampionCastEffects,
} from "./romChampionOverrides";
const empty: RomCastMechanics = {
sealStacks: 0,
@@ -133,6 +139,234 @@ describe("RoM Champion source-specific behavior", () => {
expect(useCombatStore.getState().resourcePools.rage).toBeGreaterThanOrEqual(10);
});
it("restores Rune Pulse's source-defined Rage only when its damage lands", () => {
const runePulse = sourceAbility(498529);
expect(runePulse.description).toContain("When it hits, it will restore");
const effects = castEffects(498529);
const hit = effects.find((effect) => effect.kind === "damage");
expect(hit?.kind).toBe("damage");
if (hit?.kind === "damage") expect(hit.onDamageResource).toEqual({ resource: "rage", amount: 5 });
expect(effects.some((effect) => effect.kind === "apply-aura" && effect.aura.id.includes("-622327-")))
.toBe(false);
});
it("routes Rune Siphon's positive source component to the caster as healing", () => {
const runeSiphon = sourceAbility(498595);
expect(runeSiphon.secondaryClassId).toBe("rom-warlock");
expect(runeSiphon.description).toContain("restores (DMG8) HP to the caster");
const effects = castEffects(498595);
expect(effects.filter((effect) => effect.kind === "damage")).toHaveLength(2);
expect(effects.filter((effect) => effect.kind === "heal")).toEqual([
expect.objectContaining({ kind: "heal", recipient: "caster", basePoints: 24, pointsPerLevel: 4 }),
]);
useCombatStore.getState().initializeCharacter({
classId: "rom-champion", secondaryClassId: "rom-warlock", raceId: "rom-dwarf", level: 70,
});
useCombatStore.getState().registerMob("champion-rune-siphon-target", {
name: "Rune Siphon Target",
maxHealth: 100_000,
});
setMobPosition("champion-rune-siphon-target", [3, 0, 0]);
useCombatStore.getState().selectMob("champion-rune-siphon-target");
useCombatStore.getState().damagePlayer(Math.floor(useCombatStore.getState().maxHealth / 2));
useCombatStore.setState((state) => ({
resource: 100,
resourcePools: { ...state.resourcePools, rage: 100, focus: 100 },
}));
const healthBeforeCast = useCombatStore.getState().health;
expect(useCombatStore.getState().castAbility("rom-champion-rom-warlock-elite-20", undefined, 1_000))
.toMatchObject({ ok: true });
expect(useCombatStore.getState().health).toBeGreaterThan(healthBeforeCast);
});
it("arms Soul Forge Mystery's source-backed dark-magic bonus on critical attacks", () => {
const soulForge = sourceAbility(498652);
expect(soulForge.secondaryClassId).toBe("rom-warlock");
expect(soulForge.description).toContain("If critical attack occurs while in effect");
const localCritAuras = soulForge.effects.filter((effect) => effect.kind === "apply-aura"
&& effect.aura.id.includes(`-${ROM_CHAMPION_SOUL_FORGE_PROFILE.criticalAuraComponentId}-`));
const localDarkAura = soulForge.effects.find((effect) => effect.kind === "apply-aura"
&& effect.aura.id.includes(`-${ROM_CHAMPION_SOUL_FORGE_PROFILE.darkPowerComponentId}-`));
expect(localCritAuras.length).toBeGreaterThan(0);
expect(localCritAuras.every((effect) => effect.kind === "apply-aura"
&& effect.aura.durationMs === 300_000)).toBe(true);
expect(localDarkAura).toMatchObject({
kind: "apply-aura",
aura: {
durationMs: 10_000,
modifiers: [expect.objectContaining({ kind: "damage", direction: "dealt", school: "shadow", value: 0.1 })],
},
});
const effects = castEffects(498652);
const criticalAura = effects.find((effect) => effect.kind === "apply-aura"
&& effect.aura.id.includes(`-${ROM_CHAMPION_SOUL_FORGE_PROFILE.criticalAuraComponentId}-`));
expect(criticalAura?.kind).toBe("apply-aura");
if (criticalAura?.kind === "apply-aura") {
expect(criticalAura.aura.procs).toEqual(expect.arrayContaining([
expect.objectContaining({
triggers: "crit",
chance: 1,
action: expect.objectContaining({
kind: "custom",
id: ROM_CHAMPION_SOUL_FORGE_PROC_ACTION_ID,
data: expect.objectContaining({
sourceSpellId: 498652,
sourceComponentId: 621341,
durationMs: 10_000,
disposition: "buff",
maxStacks: 1,
stackBehavior: "refresh",
target: "aura-source",
modifierSchool: "shadow",
modifierValue: 0.1,
}),
}),
}),
]));
}
expect(effects.some((effect) => effect.kind === "apply-aura"
&& effect.aura.id.includes(`-${ROM_CHAMPION_SOUL_FORGE_PROFILE.darkPowerComponentId}-`))).toBe(false);
});
it("grants Soul Forge Mystery's shadow bonus after a critical hit", () => {
useCombatStore.getState().initializeCharacter({
classId: "rom-champion",
secondaryClassId: "rom-warlock",
raceId: "rom-dwarf",
level: 80,
xp: 0,
});
const soulForge = useCombatStore.getState().abilities.find((ability) => ability.dbcSpellId === 498652)!;
expect(useCombatStore.getState().castAbility(soulForge.id, undefined, 1_000).ok).toBe(true);
expect(useCombatStore.getState().auras.some((aura) => aura.definition.id === "rom-champion-soul-forge-dark-magic"))
.toBe(false);
useCombatStore.getState().registerMob("soul-forge-crit-target", { name: "Target", maxHealth: 100_000, xpReward: 0 });
useCombatStore.getState().damageMob(
"soul-forge-crit-target",
100,
2_000,
undefined,
"shadow",
{
attackKind: "spell",
seed: "soul-forge-guaranteed-critical",
abilityId: soulForge.id,
criticalChanceBonusPercent: 100,
rules: { canMiss: false, canCrit: true, canDodge: false, canParry: false, canBlock: false },
},
);
expect(useCombatStore.getState().auras).toEqual(expect.arrayContaining([
expect.objectContaining({
sourceId: PLAYER_AURA_ENTITY_ID,
targetId: PLAYER_AURA_ENTITY_ID,
definition: expect.objectContaining({
id: "rom-champion-soul-forge-dark-magic",
durationMs: ROM_CHAMPION_SOUL_FORGE_PROFILE.darkMagicAuraDurationMs,
modifiers: [expect.objectContaining({
kind: "damage",
direction: "dealt",
school: "shadow",
operation: "percent",
value: ROM_CHAMPION_SOUL_FORGE_PROFILE.darkMagicBonusPercent,
})],
}),
}),
]));
});
it("arms Way of Frenzy only on Divine Vengeance and caps its local 2% Stamina stacks at five", () => {
const wayOfFrenzy = sourceAbility(ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.sourceSpellId);
const divineVengeance = sourceAbility(ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.triggerSpellId);
expect(wayOfFrenzy).toMatchObject({ classId: "rom-champion", secondaryClassId: "rom-priest", passive: true });
expect(divineVengeance.id).toBe(ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.triggerAbilityId);
expect(wayOfFrenzy.effects).toEqual(expect.arrayContaining([
expect.objectContaining({
kind: "apply-aura",
recipient: "caster",
aura: expect.objectContaining({
id: "rom-champion-way-of-frenzy-passive",
durationMs: null,
procs: [expect.objectContaining({
triggers: ["hit", "crit"],
abilityIds: [divineVengeance.id],
chance: 1,
action: expect.objectContaining({
kind: "custom",
id: ROM_CHAMPION_WAY_OF_FRENZY_PROC_ACTION_ID,
data: expect.objectContaining({
sourceSpellId: ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.sourceSpellId,
sourceComponentId: ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.sourceComponentId,
triggerSpellId: ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.triggerSpellId,
durationMs: 60_000,
maxStacks: ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.maxStacks,
staminaPercentPerStack: ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.staminaPercentPerStack,
}),
}),
})],
}),
}),
]));
expect(wayOfFrenzy.effects.some((effect) => effect.kind === "apply-aura"
&& effect.aura.modifiers?.some((modifier) => modifier.kind === "stat" && modifier.stat === "stamina")))
.toBe(false);
useCombatStore.getState().initializeCharacter({
classId: "rom-champion",
secondaryClassId: "rom-priest",
raceId: "rom-dwarf",
level: 70,
});
useCombatStore.getState().registerMob("way-of-frenzy-target", { name: "Target", maxHealth: 100_000, xpReward: 0 });
const stackAuraId = "rom-champion-way-of-frenzy-stacks";
const stackAura = () => useCombatStore.getState().auras.find((aura) => aura.definition.id === stackAuraId);
expect(useCombatStore.getState().auras.some((aura) => aura.definition.id === "rom-champion-way-of-frenzy-passive"))
.toBe(true);
expect(stackAura()).toBeUndefined();
const unrelatedAbility = sourceAbility(498528);
useCombatStore.getState().damageMob("way-of-frenzy-target", 100, 2_000, undefined, "physical", {
attackKind: "melee",
seed: "way-of-frenzy-unrelated-hit",
abilityId: unrelatedAbility.id,
rules: { canMiss: false, canCrit: false, canDodge: false, canParry: false, canBlock: false },
});
expect(stackAura()).toBeUndefined();
for (let hit = 0; hit < 6; hit += 1) {
useCombatStore.getState().damageMob("way-of-frenzy-target", 100, 3_000 + hit * 1_000, undefined, "physical", {
attackKind: "melee",
seed: `way-of-frenzy-divine-vengeance-${hit}`,
abilityId: divineVengeance.id,
rules: { canMiss: false, canCrit: false, canDodge: false, canParry: false, canBlock: false },
});
}
expect(stackAura()).toMatchObject({
stacks: ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.maxStacks,
expiresAt: 68_000,
definition: {
durationMs: 60_000,
maxStacks: 5,
stackBehavior: "add",
modifiers: [{
kind: "stat",
stat: "stamina",
operation: "percent",
value: ROM_CHAMPION_WAY_OF_FRENZY_PROFILE.staminaPercentPerStack,
perStack: true,
}],
},
});
});
it("scales Determination Rune's source max-health shield and leaves unrelated casts unchanged", () => {
const determinationRune = sourceAbility(498584);
const sourceShield = determinationRune.effects.find((effect) => effect.kind === "apply-aura"
@@ -191,4 +425,16 @@ describe("RoM Champion source-specific behavior", () => {
expect(castEffects(498599).some((effect) => effect.kind === "cooldown-reset")).toBe(false);
expect(castEffects(498535).some((effect) => effect.kind === "cooldown-reset")).toBe(false);
});
it("cleanses every modeled harmful aura on the party with Righteous Explosion", () => {
const cleanse = castEffects(499836).find((effect) => effect.kind === "dispel");
expect(cleanse).toMatchObject({
kind: "dispel",
mode: "cleanse",
relationship: "friendly",
scope: "party",
maxCount: 99,
});
});
});