Files
dota_factory/docs/balancing/derived.md
Malte Langkabel 8d0dd6f454 name recipes after their process, not their product
Recipe display names come from the id, so a recipe that shared its id with
its output item showed the item's name back to the player. Every recipe id
now names the process that runs it: iron_mining, quartz_reduction,
steel_rolling, chip_etching, the *_framing hulls, the *_kit module prefabs,
and the drop-only shortcuts as direct_rolling/-etching/-hardening.

The three shortcut unlock groups are renamed with their recipes, since a
group's name is derived from its id the same way.

Blueprints and replays store recipe ids, so files recorded before this
rename lose their miner and assembler recipe selections.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x
2026-08-12 09:16:19 +02:00

7.8 KiB
Raw Blame History

Derived Values (current tuned state)

Everything here is derived from targets.md under the rules in rules.md, and mirrors the config files. Item threats, ship threats, ratios, and belt checks are verified by tools/threat_report.py — re-run it after any recipe or material change and update this file when values move. Combat stats were tuned empirically against the arena suite in bin/balancing/data/balancing.toml (round-by-round record in history.md).

Economy constants

  • scrap_per_threat = 0.25 — 1 scrap per 4 threat destroyed (a cruiser kill drops ~59 scrap); threat(scrap) = 4.
  • Scrap smelting: 1 scrap → 1 iron_ingot, 1 s — deliberately value-losing; reprocessing is the value-preserving path.
  • Reprocessing: 4 scrap per cycle, 4 s; full-pool weights iron_ingot 30 / copper_ingot 30 / silicon 20 / voidsteel 20 → threat(voidsteel) = (4·4 + 4)/0.2 = 100.
  • debris_despawn_seconds = 120 (a capital kill drops hundreds of scrap, collected one per salvage cycle).

Recipes and item threats

(dur in seconds; threat is per output unit)

item recipe dur out threat
iron_ore / copper_ore miner 1 1 1
quartz miner (deposit) 2 1 2
iron_ingot 1 iron_ore 1 1 2
copper_ingot 1 copper_ore 1 1 2
silicon 1 quartz 2 1 4
steel_plate 2 iron_ingot 3 1 7
copper_wire 1 copper_ingot 1 2 1.5
copper_coil 2 copper_wire 1.5 1 4.5
building_block 2 steel_plate 2 4 4
control_chip 1 silicon + 2 copper_wire 5 1 12
capacitor_bank 2 copper_coil + 1 silicon 5 1 18
hardened_steel 3 steel_plate 12 1 33
ceramic_plate 2 quartz 4 1 8
drive_unit 2 steel_plate + 2 copper_coil + 1 control_chip 8 1 43
voidsteel_plate 1 voidsteel + 1 hardened_steel 8 1 141
capital_core 2 voidsteel + 1 capacitor_bank + 1 control_chip 10 1 240

Shortcut recipes (drop-only; item threat stays defined by the base path via the max rule): direct_rolling 3 iron_ore → 1 plate (2 s, level 1), direct_etching 2 quartz → 1 chip (4 s, level 2), direct_hardening 4 iron_ingot → 1 hardened (8 s, level 2).

Ratio curve realized: t1 all 1:1 (miner:smelter); t2 clean 2:3 (ingot→plate, wire→coil); t3 strange — 2:5 (silicon→chip), 3:5 (coil→capacitor), 3:4 (plate→hardened, plate→drive); t4 inverted 3:2 (hardened→voidsteel_plate). Belt check: worst input demand 1.33 items/s, under the ~2/s single-belt cap everywhere.

Module prefabs

(contribution = item threat + module production time)

module recipe dur mod. time contribution
railgun_s 1 copper_coil 1 1 6.5
salvager 1 steel_plate + 2 copper_wire 2 1 13
repair_tool 1 steel_plate + 2 copper_wire 2 1 13
armor_plates 4 steel_plate 3 1 32
maneuvering_thrusters 1 steel_plate + 1 copper_coil 2 1 14.5
sensor_booster 2 copper_wire + 1 copper_coil 2 1 10.5
afterburner 2 copper_coil + 1 steel_plate 3 1 20
weapon_stabilizer 1 steel_plate + 1 copper_coil 2 1 14.5
weapon_primer 1 capacitor_bank + 1 copper_coil 4 2 28.5
weapon_upgrade 1 control_chip + 1 copper_coil 4 2 22.5
railgun_m 1 capacitor_bank + 2 steel_plate + 1 copper_coil 4 3 43.5
drone_bay 1 control_chip + 2 steel_plate + 1 copper_coil 4 3 37.5
railgun_l 1 capacitor_bank + 2 hardened_steel + 1 ceramic_plate 6 4 102
drone_hangar 1 voidsteel_plate + 2 control_chip + 1 drive_unit 10 6 224

Ships

(fitted = hull item + ship base time + default loadout; the default loadouts are the default_modules used by enemy waves and are geometry-validated against the hull grids)

ship hull recipe dur base default loadout fitted
drone 1 iron_ingot 1 1 railgun_s 10.5
frigate 2 steel_plate + 1 copper_wire 2 2 2× railgun_s, maneuvering_thrusters 47
destroyer 3 steel_plate + 2 copper_coil 4 3 3× railgun_s, armor_plates, sensor_booster 99
cruiser 2 hardened_steel + 2 control_chip 6 4 2× railgun_m, armor_plates, maneuvering_thrusters 233.5
battlecruiser 3 hardened_steel + 2 control_chip + 1 drive_unit 8 5 3× railgun_m, armor_plates, 2× railgun_s 354.5
battleship 3 voidsteel_plate + 1 drive_unit + 2 control_chip 10 6 railgun_l, 2× railgun_m, weapon_stabilizer, 2× railgun_s 722.5
dreadnought 5 voidsteel_plate + 1 capital_core + 2 drive_unit 12 8 3× railgun_l, 4× armor_plates, railgun_s 1491.5
carrier 5 voidsteel_plate + 1 capital_core + 2 drive_unit 12 8 drone_hangar, 2× railgun_m, 2× armor_plates, sensor_booster 1436.5

Combat stats

(arena-converged, 2026-07; see history.md rounds 15)

Weapons: railgun_s 2 dmg × 2.0 Hz (4.0 DPS), range 50 m; railgun_m 14 × 1.5 (21), range 70; railgun_l 52 × 0.8 (41.6), range 100.

Hull HP (15/threat prior + empirical trims): drone 60, frigate 300, destroyer 550, cruiser 1500, battlecruiser 2400, battleship 6300, dreadnought/carrier 24000.

Mobility ladder (speed m/s | main accel | maneuvering | angular | max rot): drone 45|60|30|12|6, frigate 35|45|22|8|4, destroyer 30|35|18|6|3, cruiser 24|25|12|4|2, battlecruiser 20|20|10|3|1.5, battleship 15|14|7|2|1, dreadnought/carrier 10|8|4|1|0.5. Sensors: 150/200/220/250/260/280/300/350 m.

Other modules: armor_plates +1200 HP; repair_tool 9 HP × 1 Hz, range 80; salvager range 60, cargo 20, 0.5 collections/s; afterburner ×1.6 speed +60 accel; maneuvering_thrusters ×1.2 speed +10 maneuvering; sensor_booster +50 m; weapon_upgrade ×1.2 damage; weapon_primer ×1.2 rate; weapon_stabilizer ×1.3 range ×0.8 rate.

Stations: HQ 5000 HP. Player station 3000 HP, 25 dmg × 1 Hz, range 120, scrap 40. Enemy station: 3000+1500x HP, 25+12x dmg, 1.0+0.1x Hz, range 120, scrap 40+30x (x = push level).

Pacing

Unlock ladder (level → unlocks; ← marks unlock_requires; starting set at 1: drone, frigate, railgun_s, salvager, block_pressing recipe):

level ships modules recipes
0 destroyer repair_tool, armor_plates
1 maneuvering_thrusters, sensor_booster direct_rolling
2 cruiser railgun_m, afterburner direct_etching, direct_hardening
3 weapon_stabilizer
4 battlecruiser ← cruiser weapon_primer, weapon_upgrade
5 drone_bay
6 battleship ← battlecruiser railgun_l ← railgun_m
8 dreadnought ← battleship
9 carrier ← battleship drone_hangar

Level 0's pool has exactly three entries (a full first dialog). Level 2 is the quartz gate: cruiser and railgun_m are the first schematics whose chains reach quartz; the shortcut outputs only become implicitly unlocked alongside them, so shortcuts cannot drop early.

Threat rate 2*x + 0.15*x*x (x = boss cycle counter), against the factory-size curve with ~half the player's output assumed military:

cycle x rate (threat/s) player military (≈ curve/2)
2 4.6 ~12
6 17.4 ~30
15 63.8 ~60
20 100 ~75
24 134

Economy: starting_building_blocks = 200; expansion cost formula 300 + 50*x + 10*x*x (x = expansions already purchased: ~1 affordable per cycle mid-game at ~1/3 of block income, stretching to 23 cycles late — quadratic so costs outrun the roughly linear block income gradually, never with a hard wall); artifact_win_count = 5 with artifact_chance_formula = 0.05*x. Building costs: belt 2, splitter 3, tunnels 5, miner 15, smelter 20, assembler 35, reprocessing plant 40, salvage bay 25, shipyard 60 — averaging ≈18 blocks per placed building (belts included), which meets the 4-minute doubling target at block threat 4.