Update Healer Man server
This commit is contained in:
1 parent
39458d5de6
commit
6cc1b9217f
203 files changed
+133929
-31271
No files matched your search
@@ -7,12 +7,35 @@ import type { PopulationEntityDefinition } from "./mobPopulation";
|
||||
import type { ContentCategoryId } from "../app/contentCategories";
|
||||
import { isBiteSizedDungeonId } from "./dungeonContentSource";
|
||||
import { resolveBossBalanceOverride } from "./bossBalanceOverrides";
|
||||
import type { CharacterStatRuleset } from "./characterStatRuleset";
|
||||
import { clampPlayerLevel } from "./progression";
|
||||
|
||||
// Simulator health budgets measured with the five native training builds and
|
||||
// active player rotations. Keep the legacy RoM/WoW-stat curve independent.
|
||||
const ROM_NATIVE_HEALTH_BANDS: readonly (readonly [number, number, number])[] = [
|
||||
// character level, trash scale, boss scale
|
||||
[1, 0.4, 0.2], [10, 1.0, 0.6], [30, 1.1, 0.85], [60, 1.5, 1.5],
|
||||
[65, 1.8, 1.9], [66, 2.6, 2.8], [79, 4.5, 4.8], [80, 4.5, 4.8],
|
||||
];
|
||||
|
||||
// Normal training-party point-damage budgets. Native HP/DEF grows faster than
|
||||
// the shared creature budget; exact source formulas bypass this adjustment.
|
||||
const ROM_NATIVE_DAMAGE_BANDS: readonly (readonly [number, number])[] = [
|
||||
[1, 1], [10, 1], [30, 3], [60, 10], [65, 12], [66, 20], [79, 40], [80, 40],
|
||||
];
|
||||
|
||||
// Legacy RoM-character parties still use their compatibility-stat output
|
||||
// while generated RoM NPCs use native snapshots. Retune only the boss-health
|
||||
// floor for that mixed mode; explicit native RoM health bands stay independent.
|
||||
const ROM_LEGACY_BOSS_HEALTH_SCALE: readonly (readonly [level: number, scale: number])[] = [
|
||||
[1, 1], [7, 1], [8, 1.12], [70, 1.12], [80, 2.3],
|
||||
];
|
||||
|
||||
const WOW_BOSS_HEALTH_FLOOR: readonly (readonly [level: number, health: number])[] = [
|
||||
// The starter anchors include enough room for authentic presence, imbue,
|
||||
// disease, and shock rotations to retain the 25/45-second mechanic window.
|
||||
[2, 1_050],
|
||||
[4, 1_500],
|
||||
// Calibrate the starter floors to the tested Ready five-member party while
|
||||
// retaining the existing 25/45-second mechanic windows.
|
||||
[2, 1_800],
|
||||
[4, 2_600],
|
||||
[9, 7_000],
|
||||
[21, 11_000],
|
||||
[41, 23_000],
|
||||
@@ -74,7 +97,7 @@ function partyBossHealthFloor(level: number, characterSource: ContentCategoryId,
|
||||
/** Campaign fights retain their full durability floor; testing rooms use a reduced floor. */
|
||||
export function dungeonEnemyScaling(dungeon: DungeonDefinition, entity: PopulationEntityDefinition,
|
||||
instanceId: string, characterLevel: number, difficultyId: string, bossDifficulty: number,
|
||||
characterSource: ContentCategoryId = "wow") {
|
||||
characterSource: ContentCategoryId = "wow", statRuleset: CharacterStatRuleset = "wow") {
|
||||
const boss = entity.kind === "boss";
|
||||
const testing = dungeon.id.startsWith("boss-testing:");
|
||||
const level = scaledDungeonEnemyLevel(characterLevel, boss);
|
||||
@@ -90,7 +113,10 @@ export function dungeonEnemyScaling(dungeon: DungeonDefinition, entity: Populati
|
||||
const multipliers = boss ? bossDifficultyMultipliers(bossDifficulty) : { health: 1, damage: 1 };
|
||||
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, testing);
|
||||
const legacyRomCompatibilityBossScale = boss && characterSource === "rom" && statRuleset === "wow"
|
||||
? interpolatedFloor(clampPlayerLevel(characterLevel), ROM_LEGACY_BOSS_HEALTH_SCALE)
|
||||
: 1;
|
||||
const partyHealthFloor = partyBossHealthFloor(level, characterSource, testing) * legacyRomCompatibilityBossScale;
|
||||
const biteSizedBoss = boss && !testing && isBiteSizedDungeonId(dungeon.id);
|
||||
const biteSizedFloorScale = biteSizedBoss
|
||||
? interpolatedFloor(characterLevel, BITE_SIZED_BOSS_HEALTH_BANDS.map(([levelAnchor, floor]) => [levelAnchor, floor]))
|
||||
@@ -121,7 +147,14 @@ export function dungeonEnemyScaling(dungeon: DungeonDefinition, entity: Populati
|
||||
const bossOverride = boss
|
||||
? resolveBossBalanceOverride(dungeon.id, entity.id, level)
|
||||
: { healthScale: 1, damageScale: 1 };
|
||||
return { level, maxHealth: scaledHealth * multipliers.health * bossOverride.healthScale,
|
||||
healthMultiplier: authoredHealth * multipliers.health * bossOverride.healthScale,
|
||||
damageMultiplier: authoredDamage * multipliers.damage * testingDamageScale * bossOverride.damageScale };
|
||||
const nativeHealthScale = characterSource === "rom" && statRuleset === "rom"
|
||||
? interpolatedFloor(clampPlayerLevel(characterLevel), ROM_NATIVE_HEALTH_BANDS.map(
|
||||
([anchor, trashScale, bossScale]) => [anchor, boss ? bossScale : trashScale]))
|
||||
: 1;
|
||||
const nativeDamageBudgetScale = characterSource === "rom" && statRuleset === "rom"
|
||||
? interpolatedFloor(clampPlayerLevel(characterLevel), ROM_NATIVE_DAMAGE_BANDS) : 1;
|
||||
return { level, maxHealth: scaledHealth * multipliers.health * bossOverride.healthScale * nativeHealthScale,
|
||||
healthMultiplier: authoredHealth * multipliers.health * bossOverride.healthScale * nativeHealthScale,
|
||||
damageMultiplier: authoredDamage * multipliers.damage * testingDamageScale * bossOverride.damageScale,
|
||||
nativeDamageBudgetScale };
|
||||
}
|
||||
Reference in new issue
Block a user