Skip to content

Difficulty modes: calibrating Normal with the balance probe (2026-10-15)

Difficulty modes: calibrating Normal with the balance probe

Section titled “Difficulty modes: calibrating Normal with the balance probe”

Task 7 of the difficulty-modes plan (docs/superpowers/specs/2026-10-15-difficulty-modes-design.md). Goal: pick the shipped defaults for the Normal knobs in sim/difficulty.gd so a new player sees the first boss, while Hard stays today’s game exactly.

Acceptance (from the plan): Normal median survival >= 150 s AND boss seen in > 50% of runs, for the median bot profile; Hard within noise of the 59.1 s baseline in docs/research/2026-10-14-balance-1.1-proposals.md.

Result: passes on two independent 40-seed blocks. Normal median 282 s with the boss seen in 33/40 runs on both blocks (66/80, 82.5%). Hard is unchanged, seed for seed.

  • Tool: tools/balance_probe/balance_probe.gd (taken from balance-1.1-proposals, plus --difficulty=normal|hard and a boss seen N/M count from sim.boss_log). Every run is a real headless SoakRun (fresh save, Cobalt, skilled autopilot under a skill profile), 6-minute cap (--ticks=21600).
  • Knob values were swept with --tun=Difficulty.NORMAL_*=..., which goes through the real Tunables.apply path, so the same values work as a remote-config patch or a console tweak.
  • 40 seeds per arm. Seed block A is --seed0=5000 (the same block the proposals doc used); block B is --seed0=5040, used to check the finalists.
  • “Boss seen” means any boss entered the field (boss_log is non-empty). In Survival the first boss cannot arrive before about 190 s: waves run for Sim.WAVE_PHASE_S (180 s), the arena then has to be cleared, then BOSS_PREP_S (10 s). So a “boss seen > 50%” target means most runs must survive past roughly 200-280 s. That bar is much higher than “median >= 150 s”.
Arm Seeds Median p25-p75 Dead < 30 s Boss seen
Pre-modes main (0784003d), original probe A 58.7 s 47.9-83.8 8/40 n/a
difficulty=hard on this branch A 58.7 s 47.9-83.8 8/40 0/40
difficulty=hard B 49.6 s 40.3-65.5 5/40 0/40
difficulty=hard, strong profile A 112.6 s 81.1-145.1 0/40 4/40

On block A the pre-modes commit and the Hard arm match on every seed (run time, death cause and level are all identical). The 0.4 s gap to the doc’s 59.1 s, and its 2/40 deaths under 30 s against 8/40 here, come from main changing between the proposals run (2026-10-14) and 0784003d. They are not caused by the difficulty code.

The knobs are listed only where they differ from the Task 1-5 starting defaults (START_FRAC 0.5, RAMP_S 120, SHOT 0.7, CHARGER_DMG 0.75, TELEGRAPH 1.33, XP 1.5 below level 8, BOSS_HP 0.75, BOSS_DMG 0.75, HIT_GRACE 1.5, MAX_HP 1.25).

Arm Knobs changed Seeds Median p25-p75 Alive at 180 s Boss seen
n1 (starting defaults) A 100.6 s 83.5-133.7 6 4/40
n2 START 0.35, RAMP 240 A 114.0 90.4-146.6 5 4/40
n3 MAX_HP 1.5, GRACE 2.0 A 105.5 83.6-136.1 5 3/40
n4 XP 2.0, XP_LEVELS 12 A 97.4 84.3-112.8 2 2/40
n5 RAMP 240, MAX_HP 1.5 A 122.5 103.0-160.8 9 8/40
n6 n5 + START 0.3, CHARGER_DMG 0.5 A 122.4 99.7-153.6 5 4/40
n7 RAMP 360, MAX_HP 2.0 A 113.6 87.1-139.7 6 6/40
n8 n5 + START 0.3, SHOT 0.5 A 119.6 91.6-155.5 6 4/40
n9 RAMP 360, START 0.25 A 139.9 101.0-184.9 13 10/40
n10 RAMP 600, START 0.15 A 173.4 110.1-278.1 18 17/40
n11 n9 + MAX_HP 1.75, GRACE 2.0 A 152.5 111.8-264.6 15 12/40
n12 n9 + XP 1.0 (boost off) A 140.1 97.7-189.1 11 9/40
n13 RAMP 600, START 0.25 A 137.4 91.8-246.9 13 11/40
n14 n10 + MAX_HP 1.75, GRACE 2.0 A 195.4 138.1-292.0 22 19/40
n15 RAMP 600, START 0.1 A 263.2 156.5-281.7 26 24/40
n16 n10 + SHOT 0.5, CHARGER_DMG 0.5 A 264.2 166.5-298.1 27 26/40
n16 same B 198.5 142.7-274.1 20 19/40 (fails)
n19 n16 with START 0.1 A 271.6 196.8-284.9 31 29/40
n19 same B 251.6 162.1-287.6 26 23/40
n20 n16 + GRACE 2.0, TELEGRAPH 2.0 A 282.0 242.1-306.3 35 33/40
n20 same B 282.0 257.6-308.2 34 33/40

After the defaults were written into sim/difficulty.gd, a rerun of block A with no --tun matched n20 on every seed.

  • Field density is the lever that matters. The biomass opening ramp (start fraction and ramp length) moved survival more than everything else combined: n9, n10 and n15 each beat any damage, HP or grace change made at the original ramp.
  • More XP does not buy survival. n4 (2x XP to level 12) levelled faster (12 at death against 9) but died slightly sooner, and n12 (boost off) matched n9. Likely cause: Sim._danger_mult() scales enemy HP with player level after DANGER_START, so a faster level-up also toughens the field. The XP knob is kept at 1.5 below level 8 because it makes the early game feel faster. It is not doing survival work.
  • Max HP and hit grace help only once density is low. n3 and n7 (more HP at the original density) barely moved the median. n14 and n20 (the same kind of change on top of the low ramp) were the biggest late gains.
  • One block of 40 seeds is not enough to call a pass. n16 passed block A at 26/40 and failed block B at 19/40. The bot’s boss-seen rate is bimodal, because a run either clears the wind-down or it doesn’t. n20 is the only arm that cleared both blocks with a margin.
  • n19 (START 0.1) also passes, but 0.1 is the registry floor for that knob, which would leave no room on the console to go gentler. n20 keeps START at 0.15.

Chosen defaults (shipped in sim/difficulty.gd)

Section titled “Chosen defaults (shipped in sim/difficulty.gd)”
Knob Was Now
NORMAL_BIOMASS_START_FRAC 0.5 0.15
NORMAL_BIOMASS_RAMP_S 120 600
NORMAL_SHOT_DMG_MULT 0.7 0.5
NORMAL_CHARGER_DMG_MULT 0.75 0.5
NORMAL_CHARGER_TELEGRAPH_MULT 1.33 2.0
NORMAL_HIT_GRACE_MULT 1.5 2.0
NORMAL_XP_MULT / NORMAL_XP_BOOST_LEVELS 1.5 / 8 unchanged
NORMAL_BOSS_HP_MULT / NORMAL_BOSS_DMG_MULT 0.75 / 0.75 unchanged
NORMAL_MAX_HP_MULT 1.25 unchanged
GOLD_MULT_NORMAL / GOLD_MULT_HARD 1.0 / 1.0 unchanged (see economy)

A ramp of 600 s means the field is at 15% of the Hard fill target at the start, about 40% at the 180 s wind-down, and only reaches full density at 10 minutes. Normal is gentler for the whole of a typical new player’s run, not only the opening. That is intended (Chris, 2026-10-15: “we have been tuning for Toby”), but it should get a human playtest.

Other profiles on the chosen defaults (no gate, recorded)

Section titled “Other profiles on the chosen defaults (no gate, recorded)”
Profile Mode Seeds Median p25-p75 Boss seen
weak Normal A 134.4 s 108.6-178.8 6/40
weak Hard (proposals doc, older main) A 41.9 s n/a n/a
strong Normal A 307.0 s 283.4-360.0 40/40
strong Hard A 112.6 s 81.1-145.1 4/40

Normal is not trivial for a skilled player. The strong bot still dies at a median of about 5 minutes, and fewer than a quarter of its runs reach the 6-minute cap. The weak bot more than triples its survival time, but it still rarely reaches a boss.

tools/economy_sim now takes --difficulty=hard|normal (career_runner.gd, EconomyCareer, and the fifth argument of scripts/economy-careers.sh). A Normal career writes reports/economy/career-normal-<profile>-<seed0>.json. Hard stays the default, so existing calibrations are unchanged. A GUT test (test_economy_career.gd) checks that a Normal career really plays Normal runs.

Three median-profile careers per mode (seed0 10000/11000/12000, the default 20-minute run cap, run until the shop is complete). Gold rates are 1.0/1.0:

Mode Gold/min Gold/run Median run Runs to 50% of shop Runs to complete shop Play time to complete shop
Hard 220 / 208 / 205 1507 / 1265 / 1279 131 / 115 / 138 s 14 / 17 / 14 16 / 20 / 17 110 / 121 / 106 min
Normal 123 / 132 / 136 1212 / 1467 / 1188 461 / 441 / 415 s 15 / 12 / 15 19 / 17 / 20 187 / 189 / 175 min

Finding (flag for Chris, rate NOT changed): at 1.0x, Normal pays about 62% of Hard’s gold per minute (about 130 against 211). Gold per run is about the same, so the number of runs needed to finish the shop is about the same (17-20 against 16-20). Because Normal runs last about 3.5 times longer, finishing the shop takes about 1.65 times as much play time (about 3.1 h against 1.9 h). That is large enough to be Chris’s call. If the aim is equal gold per hour, GOLD_MULT_NORMAL of about 1.6 would close the gap. If the aim is equal gold per run, 1.0 already does that, and Hard’s reward is its shorter runs. It is a live tunable either way.

Caveat: the career sim starts each run from the career’s shop save, so these runs are already stronger than the fresh-save probe runs above. The Hard careers’ first five runs have medians of 78-96 s, not 59 s.

  • The bot is a proxy, not a human. The skill profiles were calibrated against early human telemetry (ai/skill_profile.gd). The bot dodges and prioritises differently from a person, and the economy-sim skill notes it is weaker than humans early on. Treat the numbers as a ranking of knob settings, not as predictions of human survival times. Confirm with a human playtest on Normal.
  • A bigger hull also buffs max-HP-scaled weapons. Difficulty.apply_run_start multiplies max_hp by NORMAL_MAX_HP_MULT (1.25). Effects that scale with max HP grow with it, such as the Scar Tissue discharge (sim/weapon_scar_tissue.gd) and the Leech per-tick heal cap. This is a small confound in the Normal arms, mostly the strong one, where those builds are more common. The sweep never moved MAX_HP_MULT in the chosen arm. It stays at 1.25.
  • Boss-seen is bimodal (see n16). Any later retune should check at least two seed blocks.
  • All values stay console/remote tunables (the “Difficulty” group). Any of them can be moved live or by a remote-config patch without a rebuild. A patch still needs Chris’s authorisation.
  • 40 seeds per arm, 6-minute cap. The alive@180 and boss-seen counts are reliable to a few runs. Differences of about +-10 s in the median are within noise.