export interface BossBalanceOverride { readonly id: string; readonly dungeonId: string; readonly entityId: string; readonly minimumLevel?: number; readonly maximumLevel?: number; readonly healthScale?: number; readonly damageScale?: number; readonly reason: string; } export interface ResolvedBossBalanceOverride { readonly healthScale: number; readonly damageScale: number; readonly matchedOverrideIds: readonly string[]; } /** * Evidence-based exceptions to the shared boss curve. Entries may cover one * level, a bracket, or every level when both bounds are omitted. Multipliers * compose so a broad boss correction can coexist with a narrower bracket fix. */ export const BOSS_BALANCE_OVERRIDES: readonly BossBalanceOverride[] = Object.freeze([ { id: "level-80-amanitar-pressure", dungeonId: "ahnkahet-old-kingdom", entityId: "entry-30258", minimumLevel: 80, maximumLevel: 80, damageScale: 0.7, reason: "Ready-five audit: 100% wipes and 3.14x median incoming pressure." }, { id: "level-80-warp-splinter-pressure", dungeonId: "botanica", entityId: "entry-17977", minimumLevel: 80, maximumLevel: 80, damageScale: 0.56, reason: "Ready-five audit: 100% wipes and 3.90x median incoming pressure." }, { id: "level-80-maiden-of-grief-pressure", dungeonId: "halls-of-stone", entityId: "entry-27975", minimumLevel: 80, maximumLevel: 80, damageScale: 0.56, reason: "Ready-five audit: 100% wipes and 3.93x median incoming pressure." }, { id: "level-80-ick-pressure", dungeonId: "pit-of-saron", entityId: "entry-36476", minimumLevel: 80, maximumLevel: 80, damageScale: 0.54, reason: "Ready-five audit: 100% wipes and 4.11x median incoming pressure." }, { id: "level-80-murmur-pressure", dungeonId: "shadow-labyrinth", entityId: "entry-18708", minimumLevel: 80, maximumLevel: 80, damageScale: 0.68, reason: "Ready-five audit: 100% wipes and 3.22x median incoming pressure." }, { id: "level-80-keristrasza-pressure", dungeonId: "the-nexus", entityId: "entry-26723", minimumLevel: 80, maximumLevel: 80, damageScale: 0.7, reason: "Ready-five audit: 100% wipes and 3.12x median incoming pressure." }, { id: "level-80-drakos-pressure", dungeonId: "the-oculus", entityId: "entry-27654", minimumLevel: 80, maximumLevel: 80, damageScale: 0.45, reason: "Ready-five audit: 100% wipes and 4.89x median incoming pressure." }, { id: "level-80-black-knight-phase-3-pressure", dungeonId: "trial-of-the-champion", entityId: "wrath-event-black-knight-phase-3", minimumLevel: 80, maximumLevel: 80, damageScale: 0.5, reason: "Ready-five audit: 100% wipes and 4.33x median incoming pressure." }, ]); function sourceDungeonId(dungeonId: string, entityId: string): string { const prefix = "boss-testing:"; const suffix = `:${entityId}`; return dungeonId.startsWith(prefix) && dungeonId.endsWith(suffix) ? dungeonId.slice(prefix.length, -suffix.length) : dungeonId; } function safeScale(value: number | undefined): number { return Number.isFinite(value) ? Math.max(0.05, value!) : 1; } export function resolveBossBalanceOverride( dungeonId: string, entityId: string, level: number, overrides: readonly BossBalanceOverride[] = BOSS_BALANCE_OVERRIDES, ): ResolvedBossBalanceOverride { const sourceId = sourceDungeonId(dungeonId, entityId); const matching = overrides.filter((entry) => ( entry.dungeonId === sourceId && entry.entityId === entityId && level >= (entry.minimumLevel ?? Number.NEGATIVE_INFINITY) && level <= (entry.maximumLevel ?? Number.POSITIVE_INFINITY) )); return Object.freeze({ healthScale: matching.reduce((scale, entry) => scale * safeScale(entry.healthScale), 1), damageScale: matching.reduce((scale, entry) => scale * safeScale(entry.damageScale), 1), matchedOverrideIds: Object.freeze(matching.map((entry) => entry.id)), }); }