Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tuning constants

Audience       Anyone rebalancing the game — changing how much a
               wand hurts, how cursed the loot is, how fast the
               Dungeon Lord evicts you.
Prerequisites  None.
Status         Describes `models/src/constants.rs` as it is in the
               source. If this page and the source disagree, the
               source is right and this page is a bug.

The dry facts: where each knob lives and what it does. Why the numbers are what they are is ../explanation/combat-and-balance.md.

Every balance number in the model is defined in one file:

models/src/constants.rs

It is organised into pub mod blocks by domain, and every constant carries a doc comment explaining what it does and — where it matters — what else you have to touch if you change it. The file itself is the reference; this page is the map to it.

The module that uses a constant re-exports it (often under its old name), so existing call sites and doc links keep working. You change the value in constants.rs and nowhere else, unless a doc comment there tells you otherwise.

The modules

constants::HoldsRead when you want to change
combatExcellent-hit odds and dice, the chip-damage floor, the odds a corpse keeps each piece of gear, a shattered cursed suit’s splintershow swingy a fight is
playerStarting HP / armour / power / magic, sight radiusthe hero’s opening position (new games only)
lurkStarting HP / magic (-b lurk), GROWTH_CHANCE and GROWTH_STEP for feeding off a killhow the lurk starts and how fast it grows
progressionFINAL_DEPTH, DUNGEON_LORD_PATIENCE, the staircase heal divisor, DIFFICULTY_TIER_LAST_DEPTH (the depth bands the crowding budgets step at)how long a run is and how hard attrition bites
mapWIDTH, HEIGHT, dark-room chancethe playfield (see the determinism caveat below)
populationMonster / trap / item budgets per floor, the placement retry budget (PLACEMENT_TRIES), how they scale with the difficulty tier, how many runs of the budgets a battlefield, vault or bee world gets, corridor lurkers, hidden items, the cutoffs the level feeling reads (FEELING_MONSTERS, FEELING_ITEMS)how crowded and dangerous a floor is, and how often a level feeling speaks
potionsWhat a dose is worth: the max-HP a healing / extra healing potion adds, the power gain strength adds and poison takes (with its floor), the share of turns paralysis eatshow much a potion swings a run
scrollsWhat one enchantment is worth (and that a minus is mended whole), how long sleep and hold last, how often sleep backfires on the readerhow strong the room-clearing scrolls are
decksDECK_SIZE, REVERSED_MIN / REVERSED_MAX, CARD_CHAIN_CAP, BALA_POWER, BOLE_ARMOR, WORLD_TURNS, CARD_CASTER_CASTS, GOLDEN_WIND_SUMMONS, CARD_POINTS (what each card in a thrown hand pays)how wild a deck of cards runs
runesPROTECTION_TURNS, RECHARGE_STEP, RECHARGE_CAPhow long a rune of protection holds and how much one of recharging gives
trapsArrow / dart damage dice, TRAP_DAMAGE_TIER_LAST_DEPTH and the per-tier bonus / strength drain, the bear-trap thrash, the trick-shot burst (TRICK_SHOT_RADIUS, PICKUP_TRICK_SHOT_RADIUS and the shared dice), TRAP_BREAK_CHANCEhow much a trap hurts and how fast it scales
wandsWAND_CHARGES, zap damage dice, both blast radii, per-charge dice a thrown wand spends, DIG_RANGE (how deep a wand of digging bores)how good a wand is
lootEnchantment odds (normal / exceptional / cursed), the bonus ranges, ammo bundle size, the improvised-throw diehow the drop table feels
itemsTHROW_RANGE, LIGHT_THROW_RANGE, LAUNCHER_RANGE, STACK_LIMIT, PACK_CAPACITYreach and pack density
ringsSTEALTH_RANGE (how close a stealthy player is noticed at), TELEPORT_MAGIC_COST, and the numeric rings’ quality: PLAIN_BONUS, EXCEPTIONAL_BONUS, CURSED_BONUS_MIN, CURSED_BONUS_MAX, MEGACURSED_BONUS_MIN, MEGACURSED_BONUS_MAXthe two rings with a number that isn’t on their row, and what a numeric ring rolls
scoreKILL_PER_MAX_HP, COMBO_BONUS_PER_KILL, COMBO_PRIDE_CHANCE, STAIR_PER_TIER, SCORE_FLASH_TURNSwhat the run is scored on, and how loudly
monstersDEFAULT_SPAWN_WEIGHTthe baseline rarity a bestiary row gets
spiritsALIGNMENT_POLE (how far alignment drifts before spirits turn hostile for good), SPAWN_WEIGHT, PINK_DEMON_ODDS_PER_PIECE (each piece of gear the pink demon destroys adds this to the odds they join you), the red demon’s RED_DEMON_GEAR_PRICE (Max HP) and the gnome’s GNOME_SCROLL_PRICE / GNOME_POTION_PRICE / GNOME_WAND_PRICE (Max Ma), the barterer’s BARTER_STOCK_MIN / BARTER_STOCK_MAX, the ALIGNMENT_STEP a poof moves alignment by, the HELPER_GAINED_ALIGNMENT / HELPER_BLOWN_UP_ALIGNMENT a Helper gained or blown up moves it by, and the angel’s test of faith (TEST_OF_FAITH_HP_DIVISOR, TEST_OF_FAITH_GEAR_BONUS, TEST_OF_FAITH_DUD_BONUS)how common spirits are and how fast they turn on you
helpersACCEPT_CHANCE, SHAPESHIFT_CHANCEhow often a thrown treat wins a Helper, how often a dog’s or mirror hound’s kill changes its shape, once
spellsSPELLSET_CAP, the dice behind the spells that roll their own (Thunderbolt, Force Lance, Circle of Death, Frost Nova), the stand-in batteries (LUX_CHARGES, METEOR_STRIKE_CHARGES), and a staff’s TURBO_MAGIC_COST_MULT / TURBO_MAGIC_POWER_MULThow much a spell costs and how hard it lands
travelStep caps on autoexplore / fast-move, the HP divisor below which auto-fight refusesonly if a walk loops, or auto-fight is too brave or too timid
hudMessage-log rows shown at once, the two wrap widths (normal and --MORE--), and how much scrollback LOG_HISTORY_CAP keepsthe log’s footprint on screen
abilitiesThe per-turn odds of the passive abilities (aggravate monster, regeneration, teleportitis, polymorphitis) and MOMENTUM_PER_HIThow often a ring does its thing on its own
conditionsCONFUSION_STUMBLE_CHANCE, the share of a confused player’s steps that go astrayhow much confusion costs (paralysis’s dial is in potions)
speedSLOW_RATE, NORMAL_RATE, QUICK_RATE, FAST_RATE and the ACTION_COST they are read againsthow often each tempo acts
layoutThe grid ordinary floors are laid out on: SECTIONS, GUTTER, PADDING, the smallest room, EMPTY_SECTION_CHOICESthe shape of a floor (moves every layout on every seed)
special_levelsThe carving dials of the labyrinth, vault, bee world, castle and islandthe shape of one special level (moves its layout on every seed)
iceA kicked ice cube’s cold dice and flight range, and how much bone and vapor it shatters intohow hard the cube hits, how showy it ends
shakeHow long each kind of screen shake lasts and how far it throws the maphow hard a blow feels

Two caveats worth repeating

map::WIDTH / map::HEIGHT pin every seed. models/tests/it/determinism.rs asserts that a given seed produces the same walls it always has. Changing either dimension moves every wall on every seed and that test will fail — correctly. Only change them as a deliberate “all old seeds are void” decision.

Enchantment odds are read as ranges against a 0..100 roll. loot::NORMAL_QUALITY_PCT and loot::EXCEPTIONAL_QUALITY_PCT must sum to 100 or less; the remainder is the cursed share. The prose odds tables in this directory’s content-tables.md and in catalog::Quality::roll do not update themselves.

What is deliberately not in constants.rs

  • Content-table numbers — a monster’s HP, a weapon’s die, a potion’s colour. Those are data, one row per thing, in catalog.rs / monsters.rs / traps.rs. See content-tables.md.
  • Animation timing — the millisecond figures in particles.rs (bolt speed, blast ripple) and the wave counts in magicmap.rs. Presentation feel, wound tightly around the code that reads them. The shake table is the exception, in constants::shake.
  • RNG salts and the neighbour-offset tables. Structural, not balance.

See also

constants.rs                         the file itself, fully commented
../../engine/src/constants.rs        screen size and frame/pause timing in the binary
../../particle-core/src/constants.rs ripple and shake clocks, the shake pattern
../explanation/combat-and-balance.md  why the numbers are what they are
content-tables.md                     the per-row content numbers