Files
healer-man/src/game/romNativeDungeonPacing.test.ts
T
2026-10-04 13:13:35 -04:00

90 lines
5.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { dungeonEnemyScaling } from "./dungeonBossScaling";
import { bossDifficultyMultipliers } from "./dungeonDifficulty";
import { requireDungeonDefinition } from "./dungeonRegistry";
import { finalDungeonBoss } from "./dungeonRunStore";
import { useCombatStore } from "./combatStore";
const dungeon = requireDungeonDefinition("barren-caves");
const boss = finalDungeonBoss(dungeon)!;
const bossSpawn = dungeon.staticSpawns.find((spawn) => spawn.id === boss.id)!;
const trashSpawn = dungeon.staticSpawns.find((spawn) => dungeon.entities[spawn.entityId].kind === "mob")!;
describe("native RoM dungeon health budgets", () => {
it("calibrates the level-one native Anglo boss without changing trash health", () => {
const nativeBoss = dungeonEnemyScaling(dungeon, dungeon.entities[bossSpawn.entityId], boss.id,
1, "normal", 1, "rom", "rom");
const legacyBoss = dungeonEnemyScaling(dungeon, dungeon.entities[bossSpawn.entityId], boss.id,
1, "normal", 1, "rom", "wow");
const nativeTrash = dungeonEnemyScaling(dungeon, dungeon.entities[trashSpawn.entityId], trashSpawn.id,
1, "normal", 1, "rom", "rom");
const legacyTrash = dungeonEnemyScaling(dungeon, dungeon.entities[trashSpawn.entityId], trashSpawn.id,
1, "normal", 1, "rom", "wow");
expect(nativeBoss.maxHealth).toBe(1_848);
expect(nativeBoss.maxHealth).toBeCloseTo(legacyBoss.maxHealth * 0.2);
expect(nativeTrash.maxHealth).toBeCloseTo(legacyTrash.maxHealth * 0.4);
expect(nativeTrash.nativeDamageBudgetScale).toBe(1);
});
it("keeps native training budgets independent of legacy stats and authored difficulty", () => {
for (const level of [1, 30, 66, 79, 80]) for (const spawn of [trashSpawn, bossSpawn]) {
const entity = dungeon.entities[spawn.entityId];
const legacy = dungeonEnemyScaling(dungeon, entity, spawn.id, level, "normal", 1, "rom");
expect(dungeonEnemyScaling(dungeon, entity, spawn.id, level, "normal", 1, "rom", "wow")).toEqual(legacy);
const native = dungeonEnemyScaling(dungeon, entity, spawn.id, level, "normal", 1, "rom", "rom");
expect(native.maxHealth).not.toBe(legacy.maxHealth);
expect(native.damageMultiplier).toBe(legacy.damageMultiplier);
expect(legacy.nativeDamageBudgetScale).toBe(1);
expect(native.nativeDamageBudgetScale).toBeGreaterThanOrEqual(1);
expect(native.level).toBe(legacy.level);
for (const source of ["wow", "coa"] as const) {
expect(dungeonEnemyScaling(dungeon, entity, spawn.id, level, "normal", 1, source, "rom"))
.toEqual(dungeonEnemyScaling(dungeon, entity, spawn.id, level, "normal", 1, source));
}
}
});
it("retains the level-80 cap and 79-to-80 native boss health plateau", () => {
const entity = dungeon.entities[bossSpawn.entityId];
const at = (level: number) => dungeonEnemyScaling(dungeon, entity, boss.id, level, "normal", 1, "rom", "rom");
expect(at(79)).toEqual(at(80));
expect(at(120)).toEqual(at(80));
expect(at(80).level).toBe(80);
});
it("does not compound damage during live registration or retain native pressure after a mode switch", () => {
const entity = dungeon.entities[bossSpawn.entityId];
const native = dungeonEnemyScaling(dungeon, entity, boss.id, 80, "normal", 1, "rom", "rom");
const legacy = dungeonEnemyScaling(dungeon, entity, boss.id, 80, "normal", 1, "rom", "wow");
const combat = useCombatStore.getState();
combat.initializeCharacter({ classId: "rom-priest", raceId: "rom-human", level: 80, statRuleset: "rom" });
combat.registerMob("legacy-reference", { name: "Anglo", boss: true, ...legacy, xpReward: 0 });
combat.registerMob("live-registration", { name: "Anglo", boss: true, ...native, xpReward: 0 });
const first = useCombatStore.getState().mobs["live-registration"];
combat.registerMob("live-registration", { name: "Anglo", boss: true, ...native, xpReward: 0 });
expect(useCombatStore.getState().mobs["live-registration"].attackDamage).toBe(first.attackDamage);
expect(useCombatStore.getState().mobs["live-registration"].attackPowerDamageContribution).toBe(first.attackPowerDamageContribution);
combat.registerMob("live-registration", { name: "Anglo", boss: true, ...legacy, xpReward: 0 });
const switched = useCombatStore.getState().mobs["live-registration"];
const reference = useCombatStore.getState().mobs["legacy-reference"];
expect(switched.attackDamage).toBe(reference.attackDamage);
expect(switched.attackPowerDamageContribution).toBe(reference.attackPowerDamageContribution);
expect(switched.nativeDamageBudgetScale).toBe(1);
});
it("keeps each difficulty multiplier and leaves trash independent of the boss slider", () => {
const entity = dungeon.entities[bossSpawn.entityId];
const easy = dungeonEnemyScaling(dungeon, entity, boss.id, 30, "normal", 1, "rom", "rom");
for (let difficulty = 2; difficulty <= 10; difficulty += 1) {
const scaled = dungeonEnemyScaling(dungeon, entity, boss.id, 30, "normal", difficulty, "rom", "rom");
expect(scaled.maxHealth).toBeCloseTo(easy.maxHealth * bossDifficultyMultipliers(difficulty).health);
expect(scaled.damageMultiplier).toBeCloseTo(easy.damageMultiplier * bossDifficultyMultipliers(difficulty).damage);
expect(dungeonEnemyScaling(dungeon, dungeon.entities[trashSpawn.entityId], trashSpawn.id,
30, "normal", difficulty, "rom", "rom"))
.toEqual(dungeonEnemyScaling(dungeon, dungeon.entities[trashSpawn.entityId], trashSpawn.id,
30, "normal", 1, "rom", "rom"));
}
});
});