Release Healer Man 0.1.44

This commit is contained in:
phenom committed 2026-09-14 22:12:49 -04:00
1 parent ccc01396cd
commit 756ee4f64a
24 files changed
+575 -46

No files matched your search

+39 -7
View File
@@ -4,11 +4,41 @@ import { dungeonEnemyHealthBaseline, scaledDungeonEnemyLevel } from "./dungeonLe
import { finalDungeonBoss } from "./dungeonRunStore";
import type { DungeonDefinition } from "./dungeonTypes";
import type { PopulationEntityDefinition } from "./mobPopulation";
import type { ContentCategoryId } from "../app/contentCategories";
/** Shared by rendering and deterministic combat benchmarks; preserves authored stats above the floor. */
const WOW_BOSS_HEALTH_FLOOR: readonly (readonly [level: number, health: number])[] = [
[2, 900],
[4, 1_300],
[9, 7_000],
[21, 11_000],
[41, 23_000],
[80, 180_000],
];
function interpolatedFloor(level: number, anchors: readonly (readonly [number, number])[]): number {
const upperIndex = anchors.findIndex(([anchorLevel]) => level <= anchorLevel);
if (upperIndex <= 0) return anchors[0][1];
if (upperIndex < 0) return anchors[anchors.length - 1][1];
const [lowerLevel, lowerHealth] = anchors[upperIndex - 1];
const [upperLevel, upperHealth] = anchors[upperIndex];
const progress = (level - lowerLevel) / (upperLevel - lowerLevel);
return lowerHealth + (upperHealth - lowerHealth) * progress;
}
function partyBossHealthFloor(level: number, characterSource: ContentCategoryId): number {
if (characterSource === "wow") return interpolatedFloor(level, WOW_BOSS_HEALTH_FLOOR);
const baseline = 1_000 + level * 1_200 + level * level * 22;
// Each catalog is calibrated independently against its strongest canonical
// class-role cohort so every fight retains the 25/45-second mechanic window.
return baseline * (characterSource === "rom" ? 1.15 : 1.75);
}
/** Campaign fights retain a durability floor; testing rooms use level-scaled authored stats. */
export function dungeonEnemyScaling(dungeon: DungeonDefinition, entity: PopulationEntityDefinition,
instanceId: string, characterLevel: number, difficultyId: string, bossDifficulty: number) {
instanceId: string, characterLevel: number, difficultyId: string, bossDifficulty: number,
characterSource: ContentCategoryId = "wow") {
const boss = entity.kind === "boss";
const testing = dungeon.id.startsWith("boss-testing:");
const level = scaledDungeonEnemyLevel(characterLevel, boss);
const authoredHealth = entity.combat?.healthMultiplier ?? 1;
const authoredDamage = entity.combat?.damageMultiplier ?? 1;
@@ -16,10 +46,12 @@ export function dungeonEnemyScaling(dungeon: DungeonDefinition, entity: Populati
const native = entity.combat?.serverEntry ? creatureRuntimeBaseStats(entity.combat.serverEntry, level) : null;
const originalHealth = (baseline ?? native?.health ?? (boss ? 260 + level * 65 : 72 + level * 22)) * authoredHealth;
const multipliers = boss ? bossDifficultyMultipliers(bossDifficulty) : { health: 1, damage: 1 };
const finalBoss = boss && finalDungeonBoss(dungeon, difficultyId)?.id === instanceId;
// Calibrated against active RoM, WoW and CoA class-role rotations with heirlooms.
// Every class faces the same floor; the margin covers stronger CoA burst builds.
const bossFloor = (1_000 + level * 1_200 + level * level * 22) * 1.75 * (finalBoss ? 1.8 : 1);
return { level, maxHealth: (boss ? Math.max(originalHealth, bossFloor) : originalHealth) * multipliers.health,
const finalBoss = boss && !testing && finalDungeonBoss(dungeon, difficultyId)?.id === instanceId;
// Match durability to the character's game, including when crossing dungeon catalogs.
const partyHealthFloor = partyBossHealthFloor(level, characterSource);
const bossFloor = partyHealthFloor * (finalBoss ? 1.8 : 1);
// A test room's sole objective must not promote every boss to a campaign finale
// or replace low-level native health with the campaign's full-party minimum.
return { level, maxHealth: (boss && !testing ? Math.max(originalHealth, bossFloor) : originalHealth) * multipliers.health,
healthMultiplier: authoredHealth * multipliers.health, damageMultiplier: authoredDamage * multipliers.damage };
}