5. Balance definitions & constants
Kind-specific server balance lives in server/crates/rules/src/defs.rs; faction availability,
buildables, trainables, upgrade ids, and ability carriers live in
server/crates/rules/src/faction.rs; terrain movement/cover/concealment hooks live in
server/crates/rules/src/terrain.rs. Grass, bare road, and all four marked road tiles share open-ground
passability, cover, concealment, and line-of-sight behavior; road applies a 1.5x movement-speed
multiplier.
server/crates/rules/src/balance.rs is the stable public re-export surface for timings, tile size,
starting resources, supply caps, mining amounts, support-weapon constants, body dimensions, upgrade
and ability scalars, and stat helpers. Its internal server/crates/rules/src/balance/*.rs modules
group those Rust-owned values by domain, and its unit_stats(kind) and building_stats(kind)
helpers read the defs table.
Default attack range, damage, cooldown, weapon class, and weapon-policy metadata are exposed through
server/crates/rules/src/combat.rs weapon profiles; current profile values mirror the defs records
so legacy attack_profile(kind) and weapon_class(kind) callers remain behavior-compatible.
Direct-fire damage, miss policy, tank-facing modifiers, and over-penetration policy consume the
selected weapon profile instead of inferring those behaviors only from the firing entity kind.
The Panzerfausts Training Centre upgrade unlocks a separate Barracks-trained Panzerfaust unit. It
inherits Rifleman combat and movement but carries one disposable anti-armor shot that deals 100
base damage with 50% armor penetration and no tank-facing modifier. The shot is detached at launch;
the same Panzerfaust immediately returns to normal movement and rifle combat while the projectile
travels, preserving its kind, orders, HP, control-group identity, and trench.
Tanks also have a live secondary tank_coax profile owned by combat rules: 6-tile range, 4 small-arms
damage, 6-tick cooldown, no Tank armor-facing multiplier, and direct-fire overpenetration.
client/src/config.js is the stable public facade for the subset the UI/render/fog needs (costs,
supply, sight, sizes, colors, and command-card descriptors). Its internal
client/src/config/timing.js, client/src/config/rules_mirror.js, and
client/src/config/factions.js modules hold Rust-owned mirror data and helpers; its
client/src/config/presentation.js module holds client-owned presentation data. Keep both sides in
sync; run
node scripts/check-faction-catalog-parity.mjs to mechanically compare the Rust-authoritative
default faction catalog to the client descriptors.
The server wiki’s /wiki/stats page is generated from the same Rust definitions and faction
catalogs. Its unit/building damage, range, cooldown, and weapon columns intentionally show
primary/default weapon stats only; secondary weapons such as the Tank coax are documented here until
generated secondary-weapon rows exist. For changes that affect visible stats, faction availability,
upgrades, or ability metadata, run node scripts/check-wiki.mjs; it includes the wiki route/table
checks and the client catalog parity check.
server/src/config.rs and server/crates/sim/src/config.rs are compatibility shims for
Rust-owned balance exports while call sites are migrated. They should not accumulate server-shell
or sim-only implementation constants. Those values belong beside the module that owns the behavior.
Final source-of-truth map and guardrails
Use server/crates/rules/src/defs.rs for unit/building stat records, costs, supply, sight, ranges,
footprints, body dimensions, and build/train timing. Use server/crates/rules/src/faction.rs for
faction catalogs: buildables, trainables, research rows, ability carriers, command-card descriptors,
and ability/upgrade metadata exported by Rust. Use server/crates/rules/src/balance.rs as the
stable public balance surface; the internal balance/timing.rs, balance/map.rs,
balance/economy.rs, balance/supply.rs, balance/bodies.rs, balance/support_weapons.rs,
balance/upgrades.rs, balance/abilities.rs, and balance/stats.rs files group shared scalar
constants and helper definitions without changing ownership or exported names. Sim-only behavior
constants belong beside the sim module that owns the behavior rather than in the compatibility
config shims.
Phase 4 left the movement/arrival recovery constants (STUCK_EPS_PX,
STUCK_ARRIVAL_TICKS, TOLERANT_ARRIVAL_RADIUS_PX, SIDESTEP_*,
STATIC_BLOCKED_REPATH_TICKS, ARRIVE_RADIUS_INTERMEDIATE_PX,
VEHICLE_WAYPOINT_ACCEPTANCE_RADIUS_PX, SCOUT_CAR_FINAL_GOAL_TOLERANCE_PX,
SCOUT_CAR_STUCK_RECOVERY_TRIGGER_TICKS, SCOUT_CAR_REVERSE_RECOVERY_DISTANCE_PX, and
SCOUT_CAR_RECOVERY_COOLDOWN_TICKS) on the rts_rules::balance::* surface as explicit
compatibility exports. They are sim-movement policy, not client-mirrored balance values; moving
them beside rts-sim movement should be a later API/design migration rather than a silent Phase 4
source shuffle.
client/src/config.js mirrors only the subset needed by UI, rendering, fog previews, and command
cards while preserving the historical public import path. Rust-owned mirrored values live behind
client/src/config/timing.js, client/src/config/rules_mirror.js, and
client/src/config/factions.js; they include gameplay-visible costs, supply, sight, footprints,
body dimensions, client-visible timing/range/duration constants, faction legality, upgrade
metadata, ability descriptors exported by the Rust faction catalog, ability effect fields exported
in the rules dump—including Smoke Plus cloud radius and duration—and resource starting amounts. Client-owned values live in
client/src/config/presentation.js and include render colors, camera defaults, fog overlay alpha,
command-card layout hints, local presentation labels/icons that are not exported by Rust, and
resource render labels/sizes.
Run node scripts/check-faction-catalog-parity.mjs after changing Rust-owned values that are
mirrored into client/src/config.js. The check runs the Rust rts-rules faction catalog dump,
including the clientConfig parity payload, and compares the client mirror for catalogs, stat
fields, body dimensions, resource amounts, upgrade metadata, ability compact/order-stage codes, and
Rust-owned ability descriptors/effect fields. Run node scripts/check-wiki.mjs as well when a
change affects visible stats, faction availability, upgrades, or ability metadata that appears on
the generated /wiki/stats page.
| Constant | Before cleanup | After cleanup | Mirror impact |
|---|---|---|---|
MORTAR_FIRE_TOLERANCE_RAD | Sim-only mortar aim tolerance exported from server/crates/sim/src/config.rs beside mirrored balance constants | Sim-local server/crates/sim/src/game/mortar.rs FIRE_TOLERANCE_RAD, owned by mortar firing behavior | None; it is not mirrored into client/src/config.js and does not change wire shape or balance values |
Client mirror boundary inventory
Phase 1 records the current source-of-truth map before later phases add broader mechanical checks.
The faction parity check guards the current structured clientConfig payload shape for constants,
unit/building stat fields, vehicle bodies, resource amounts, upgrades, ability effect fields,
catalog ids, fixture-only catalog presence, and playable faction exposure. This is an inventory
only; it does not change balance, gameplay, or client rendering. The remaining split-blocking
structured parity gap was command budget, which remains sim command-service policy mirrored by the
client outside the Rust rules dump. Phase 2 keeps client/src/config.js hand-authored and guarded
by validation-only checks rather than generating client config from Rust; generation would blur the
current Rust-owned mirror/client-owned presentation boundary and make future config splits harder to
review.
| Value/path | Rust owner | JS mirror path | Category | Current checker | Proposed future checker | Client-only exclusion reason | Compact version impact |
|---|---|---|---|---|---|---|---|
TICK_HZ, TICK_MS, TILE_SIZE, simulation timing scalars | server/crates/rules/src/balance.rs, re-exported by server/src/config.rs and server/crates/sim/src/config.rs | client/src/config.js TICK_HZ, SNAPSHOT_MS, interpolation delay constants | balance scalar | scripts/check-faction-catalog-parity.mjs checks TICK_HZ and client-visible duration constants against the Rust rules dump | Extend the structured dump if another timing scalar becomes client-visible | Interpolation delay is client-only smoothing; TICK_HZ is mirrored | No compact impact unless snapshot cadence or compact fields change |
| Unit and building costs, supply, sight, footprint/radius, train/build times, and command-card stat rows | server/crates/rules/src/defs.rs and server/crates/rules/src/balance.rs; faction legality in server/crates/rules/src/faction.rs | client/src/config.js STATS, WORKER_BUILDABLE, FACTION_CATALOGS | balance scalar / faction catalog fact | scripts/check-faction-catalog-parity.mjs checks catalog legality, costs, supply, sight, ranges, build ticks, building footprints, requirements, train lists, research lists, and non-body unit render radius; node scripts/check-wiki.mjs covers generated wiki stats when run | Future work can move client-only labels/icons into Rust catalogs if they should become authoritative | Client-only labels/icons in STATS are presentation unless the Rust catalog exports them; STATS.size for body-driven vehicles is presentation because the Rust-owned body dimensions are checked separately | No compact impact |
| Vehicle/body dimensions | server/crates/rules/src/balance.rs *_BODY_* constants | client/src/config.js TANK_BODY, ANTI_TANK_GUN_BODY, ARTILLERY_BODY, SCOUT_CAR_BODY, SCOUT_PLANE_BODY, COMMAND_CAR_BODY | balance scalar | scripts/check-faction-catalog-parity.mjs checks every client body length, width, and clearance against the Rust rules dump | Keep adding new body records to the dump/check when body-driven units are added | None; client uses these for art, selection, and advisory placement previews, including Tank Trap preview rejection for vehicle-body units, while Rust collision is authoritative; Scout Plane body dimensions are render/selection metadata only and do not create a ground collision body | No compact impact |
| Ability descriptors, carrier lists, target mode, range, cooldown, cost, queueability, autocast, command-card label/icon/hotkey/title | server/crates/rules/src/faction.rs plus scalar constants in server/crates/rules/src/balance.rs | client/src/config.js ABILITIES and imported ABILITY ids | faction catalog fact / balance scalar | scripts/check-faction-catalog-parity.mjs checks exported command-card descriptors, carriers, target mode, range, cooldown, cost, queueability, autocast, compact codes, and Rust-owned effect fields present on descriptors such as radius, delay, duration, pull multipliers, speed, and damage; protocol parity checks ability compact codes | Future effect fields should be added to the Rust dump and descriptor assertion when they become client-visible | Not UI-only when the field is exported by Rust faction catalogs or balance constants; purely local affordance copy belongs in the documented exclusion list | Code changes may affect compact ability/order-stage codes; descriptor-only changes do not |
| Upgrade descriptors, research building, prerequisites, cost, and research time | server/crates/rules/src/faction.rs plus server/crates/rules/src/balance.rs upgrade constants | client/src/config.js UPGRADES and imported UPGRADE ids | faction catalog fact / balance scalar | scripts/check-faction-catalog-parity.mjs checks research building, list membership, upgrade costs, research ticks, and prerequisite upgrade ids | Labels/icons/descriptions can be moved into Rust catalogs later if they should become authoritative | Labels/icons/descriptions are client-only today unless moved into the Rust catalog | No compact impact unless upgrade ids/codes change |
| Entrenchment dig-in/combat/trench-footprint constants | server/crates/rules/src/balance/entrenchment.rs | client/src/config.js ENTRENCHMENT_* exports | balance scalar | scripts/check-faction-catalog-parity.mjs checks dig-in ticks, range bonus, direct-damage reduction, area-damage reduction, and trench radius against the Rust rules dump | Keep future client-visible entrenchment scalars in the structured dump | Not client-only because these constants describe authoritative trench timing/combat/footprint rules, even before all phases consume them | No compact impact unless the trench snapshot shape changes |
| Resource node starting amounts and economy resource names | server/crates/rules/src/balance.rs STEEL_PATCH_AMOUNT, OIL_GEYSER_AMOUNT; fixed Steel/Oil economy fields in sim/protocol | client/src/config.js RESOURCE_AMOUNTS, KIND.STEEL, KIND.OIL, HUD/resource render helpers | balance scalar / wire DTO | scripts/check-faction-catalog-parity.mjs checks node starting amounts; protocol parity checks resource kind codes | Add future client-visible resource amounts to the rules dump/check | Resource render labels and sizes are client presentation; amounts affect minimap/tooltips/render assumptions | Resource kind/code changes affect protocol/compact; amount changes do not |
Human command budget values BASE_COMMAND_SUPPLY_CAP, COMMAND_CAR_SUPPLY_CAP_BONUS | server/crates/sim/src/command_budget.rs, applied by server/crates/sim/src/game/services/commands.rs as command admission policy | client/src/config.js exports consumed by client/src/command_budget.js, selection, control groups, and HUD budget display | sim command-service policy mirrored by client | scripts/check-faction-catalog-parity.mjs compares the sim-owned command-budget dump with the client exports; server command-budget tests and client contract tests exercise each side; node tests/client_contracts.mjs snapshots public client/src/config.js export names for split safety | Keep command budget in the sim-owned dump/check unless a future design intentionally moves ownership into rts-rules::balance; keep public config export snapshots current when adding or removing exports | Not client-only because the client mirror previews the server’s command acceptance cap; not Rust rules-owned unless a later design explicitly moves ownership | No compact impact |
PLAYER_PALETTE | server/src/lobby/mod.rs | client/src/config.js PLAYER_PALETTE | server-owned presentation data mirrored by client | tests/protocol_parity.mjs source-scrapes the lobby palette | Structured lobby/config dump | Not client-only because server assigns lobby/start colors and sends them on the wire | No compact impact |
| Terrain, health, selection, placement, and drag colors | None in Rust; rendering-only choices | client/src/config.js COLORS except resource identity colors that should stay consistent with Steel/Oil presentation | UI-only presentation data | None | Exclusion list in future config parity check | Client owns visual palette; it does not affect simulation, wire DTO shape, or authoritative fog | No compact impact |
| Fog overlay alpha | Authoritative fog visibility is in sim snapshots; alpha is not a Rust value | client/src/config.js FOG_EXPLORED_ALPHA, FOG_UNEXPLORED_ALPHA | UI-only presentation data | None | Exclusion list in future config parity check | Client owns opacity; Rust owns which tiles/entities are visible | No compact impact |
| Camera defaults | None in Rust | client/src/config.js CAMERA | UI-only presentation data | None | Exclusion list in future config parity check | Client-only input/render affordance | No compact impact |
| Anti-tank gun field-of-fire preview | server/crates/rules/src/balance.rs ANTI_TANK_GUN_FIELD_OF_FIRE_RAD is authoritative at 35 degrees total | client/src/config.js ANTI_TANK_GUN_FIELD_OF_FIRE_RAD | balance scalar / advisory UI mirror | scripts/check-faction-catalog-parity.mjs checks the client preview against the Rust field-of-fire constant | Keep the preview Rust-owned because it represents the authoritative deployed firing arc | Not client-only: the client preview represents an authoritative firing arc | No compact impact |
Parity exclusions after the split
The structured rules dump intentionally excludes client-owned presentation values that do not have
Rust catalog or balance ownership: global terrain and selection colors, fog overlay alpha, camera
defaults, command-card layout hints, and resource render labels/sizes. STATS labels and icons
remain client-owned until they are exported by a Rust catalog. STATS.size for units with a
Rust-owned body record is also presentation-only; the parity check enforces those units through
their *_BODY_* length, width, and clearance values instead.
5.0 Faction economy contract
The faction rollout keeps Steel, Oil, and Supply as the global economy contract. Faction catalogs
decide which global units, buildings, upgrades, and abilities are legal for a player and define
starting Steel/Oil values plus starting entity loadouts, but they still use fixed steel, oil,
supplyUsed, and supplyCap fields. Unknown non-empty faction ids do not fall back to the
Kriegsia catalog in lower-level economy queries: catalog-gated build/train/research/gather,
production-anchor, and supply checks return empty or false. Start-map resource nodes remain Steel
and Oil nodes. Score values, replay analysis values, command-card costs, affordability checks,
refunds, and supply reservation are intentionally Steel/Oil/Supply-shaped.
Catalog existence is not lifecycle admission. server/crates/rules/src/faction.rs may contain
playable catalogs, explicit fixture catalogs, and future catalog data, but
server/src/lobby/faction_validation.rs decides which ids can enter normal lobby, AI, replay,
branch, self-play, dev, match-history, and post-match paths. Fixture-only and
reserved/future ids must not inherit Kriegsia economy behavior or appear in product selectors just
because their catalog rows are dumpable.
Approved direct Steel/Oil/Supply modules for this plan are:
server/crates/rules/src/defs.rs,server/crates/rules/src/economy.rs, andserver/crates/rules/src/balance.rsfor authoritative costs, node amounts, and supply values.server/crates/sim/src/game/player_state.rs,services/commands.rs,services/construction.rs,services/economy.rs,services/supply.rs,scoring.rs,analysis.rs,snapshot.rs,replay.rs, andsetup.rsfor fixed-field simulation, score/replay analysis, and start/loadout compatibility shims. New lifecycle/replay starts should prefer per-playerPlayerStartingLoadoutrecords over global starting Steel/Oil overrides.server/crates/protocol/src/lib.rs,server/src/protocol.rs,server/crates/sim/src/protocol.rs, andclient/src/protocol.jsfor the mirrored wire and compact transport fields.client/src/config.js,client/src/hud.js,client/src/hud_command_card.js,client/src/observer_analysis_overlay.js,client/src/scoreboard.js, and resource rendering helpers for current HUD, command-card, replay-analysis, score, and map-resource display.
Generic resources are deferred. If a future faction needs a non-Steel/Oil resource, that work must be a separate migration across player state, snapshots, compact transport, replay artifacts, observer analysis, scoring, HUD rows, command-card costs, protocol parity, and prediction/WASM compatibility.
5.1 Target theme and MVP combat loop
The target gameplay direction is a simplified World War II-inspired battlefield with fictional, faction-agnostic sides. This is not a historical simulation. The theme should support readable gameplay, clear unit roles, and strong terrain identity without national or regime-specific iconography.
MVP scope:
- No combat air forces.
scout_planeis non-combat reconnaissance launched by the Command Car Scout Plane ability. Each sortie has a 30-second total lifetime from launch, flies to a targeted orbit, provides vision throughout transit and any remaining orbit time, and then disappears. - Late-game Artillery is implemented as the Superior Firepower capstone; Mortar Teams remain the early delayed-area fire tool.
- No mines, morale, logistics, suppression-depth model, or detailed tank armor model yet. Tanks do have a simple hull-facing armor rule for anti-tank damage.
Core unit roles:
- Rifleman is the baseline combat unit: cheap, flexible, useful for capturing and holding ground, and the primary answer to enemy infantry in forests.
- Machine gun is the defensive escalation unit: it takes one second
(
MACHINE_GUNNER_SETUP_TICKS) to set up after stopping, then fires at a very high rate. Once deployed it must spend the same one-second interval tearing down before it can move. Machine-gun nests are the main base-defense tool and should dominate open-ground infantry combat in the second stage of the game. - Scout Car is the Mobile Warfare path-entry unit from Vehicle Works: fast, unarmored, high-vision, and useful for raiding, scouting, and smoke-enabled attacks before heavier armor arrives.
- Tank is the machine-gun breaker and open-ground power unit: immune to rifle and machine-gun small-arms fire, strong against static defenses and exposed infantry, but vulnerable to other tanks and anti-tank infantry.
- Panzerfaust is a Barracks-trained Rifleman variant unlocked by Panzerfausts research. It carries one disposable 5-tile, 50%-armor-penetrating shot while ordinary Riflemen remain unchanged and oil-free. Automatic use is limited to visible Scout Cars, Tanks, and Command Cars already in range; Mortar Teams, Artillery, infantry, buildings, and obstacles are not launcher targets. Explicit Attack orders remain stationary, so the vehicle must already be within launcher range. There is no salvo coordination or overkill suppression.
- Anti-tank gun team is the ambush counter to tanks: it can fight while packed at short range with reduced damage, or manually set up into a longer-ranged fixed field of fire. Deployed guns are dangerous from the side or rear, but weak or inefficient against regular infantry and cannot fire outside their emplacement arc.
- Mortar Team is the Superior Firepower path-entry pressure unit from Gun Works: its setup time is provisionally set to zero ticks for balance improvement, it cannot shoot while moving, and it lands delayed area shells that punish static positions and clumped units.
- Artillery is the Superior Firepower late capstone from Gun Works: it uses a tank-sized gameplay footprint but renders at 75% of its prior authored size as an exposed field piece, must deploy into a narrow firing arc, cannot shoot inside its minimum range, and spends steel on each long-range Fire shell.
Terrain rules:
- Open ground favors machine guns and tanks.
- Forests are passable by infantry and impassable to tanks.
- Infantry in forests gets defensive and concealment bonuses.
- Forests are intentionally “infantry country”: the main way to clear infantry from a forest is to send in your own infantry.
- Tanks and machine guns can contain forests by covering exits, clearings, and forest edges, but they should not reliably clear forest infantry from outside.
Intended progression:
- Early game: riflemen fight for map control.
- Midgame: machine guns lock down open lanes and bases.
- Armor phase: tanks break machine-gun-heavy defensive lines in open terrain.
- Counter-armor phase: anti-tank infantry, forest ambushes, and other tanks punish unsupported tanks.
- Forest fights remain infantry-led so tanks and machine guns never become universal answers.
5.2 Current implementation constants
The current implementation uses the themed unit/building names below. Combat is handled by the
shared attack model plus the support-weapon setup/teardown state, tank turret aim gates, and
tank hull-facing damage modifiers for anti-tank hits against tank victims. Tanks keep their active
movement path while firing on either Move or AttackMove orders and keep their base 5-tile
weapon range while moving. After a tank has spent three seconds (90 ticks) without path-driven
translation or hull rotation, its range has linearly expanded to 14 tiles; any later path-driven
movement or hull rotation resets it to the base range. A stationary Tank that survives enemy direct
AP damage autonomously turns its hull toward the damage source without changing its order, target,
path, turret aim, or stationary range. The first Tank cannon, Anti-Tank Gun, or Panzerfaust hit locks
its source for three seconds. Hits during that window neither redirect the hull nor extend the lock;
after it expires, the next qualifying hit may establish a new lock. Active movement paths and zero
oil prevent this response, while Hold Position explicitly allows it. Riflemen upgraded with
Methamphetamines gain
permanent moving fire, keep advancing while firing with normal accuracy, and move at tank speed.
Panzerfausts upgraded with Methamphetamines receive the normal Rifleman moving fire, tank-speed
movement, and 25% faster rifle attacks plus the Panzerfaust windup boost. Machine Gunners upgraded with
Methamphetamines move at unupgraded Rifleman speed and use half-length setup/teardown timers; other
mobile combat units still hold position once a target is in weapon range. Scout cars also fire while
moving using an independent rear machine-gun facing. They are unarmored light vehicles and do not
receive armored damage reduction, but anti-tank guns do not roll their infantry miss chance against them.
Plain Move tanks, scout cars, and Methamphetamines-upgraded Riflemen and Panzerfausts only fire at enemies already in
weapon range. Their active AttackMove orders use the same moving-fire policy while they are still
following the player-issued path: auto-acquisition can aim and fire only at targets that are
currently inside weapon range and pass hostile, visibility, smoke, line-of-sight, and blocker
checks, but it cannot replace the commanded destination with an enemy-directed path. Non-moving-fire
AttackMove units pause for fireable in-range targets and then resume the original destination.
Direct Attack orders and post-arrival behavior remain stationary. Tank auto-targeting first checks
in-range Anti-Tank Guns, Tanks, and Mortar Teams, in that order, before generic
acquisition. This priority applies when the tank acquires after firing or when its committed target
stops being fireable; a still-fireable target prepared during reload is not reranked on the ready
tick. Priority never considers out-of-range targets or overrides explicit player attack orders.
Forest-specific rules are future work.
The unit, building, and resource-node tables below are the human-readable form of the authoritative
rules::defs records.
Default auto-acquisition groups already-legal targets before applying weapon fit or distance:
unit attackers prefer non-economy combat units, then economy workers (Worker and Golem),
then buildings and other non-unit cleanup targets. Small-arms default weapons prefer soft targets
(ArmorClass::Small) over armored targets within the same target group, but they
still fire at armor or buildings when no better legal target exists. Completed Tank Traps are
excluded from automatic acquisition for every unit and weapon, including ground Attack Move and
route obstruction; only a direct Attack on a Tank Trap may target it. That explicit command captures
the visible completed Tank Trap cluster within 4 tiles, while vehicle pathfinding continues routing
around the obstacles. Anti-armor default weapons
prefer anti-armor threats and armored units over ordinary soft units. Anti-Tank Guns cannot
auto-acquire or accept direct Attack orders against infantry-sized targets: Workers, Golems,
Riflemen, Panzerfausts, and Machine Gunners. Crewed support weapons and other non-infantry targets
remain legal. Tanks keep a narrower
immediate-threat override for targets already in relevant range: Anti-Tank Guns are first, then
other anti-armor threats, armored obstacles, support weapons, and only then ordinary soft targets.
The rules-owned TargetFacts surface records the current target-policy facts for every
EntityKind, including the Tank coax infantry-priority group. The live coax policy ranks Riflemen
and Machine Gunners first, economy workers (Worker and Golem) second, and fallback legal
targets such as vehicles, buildings, support weapons, and field obstacles last; resource nodes are
not legal coax targets.
Default weapons perform a full acquisition pass when ready and targetless, immediately after each
shot to prepare the next engagement during reload, or when the prepared target is no longer
fireable on the ready tick. Reload, setup, and aiming ticks revalidate only that committed target;
they do not rerank nearby enemies. A targetless travelling Attack Move may scan during reload so a
non-Mortar unit stops at the first in-range engagement, then follows the same committed-target
rule. A still-fireable prepared target therefore receives the next
shot even if a higher-priority threat appeared during reload. The post-shot pass may then select
that higher-priority threat for the following cycle. Tank coax fire has no independent retained
target slot, so its acquisition pass runs only when the coax cooldown is ready. This cadence is
limited to default attacks; future grenades, satchels, or demolition attacks need separate attack
profiles and explicit activation/autocast policy instead of being folded into default targeting.
TICK_HZ = 30,SNAPSHOT_EVERY_N_TICKS = 1.ROAD_MOVEMENT_SPEED_MULTIPLIER = 1.5. Bare road plus horizontal, vertical, NW-SE diagonal, and NE-SW diagonal marked road tiles share this rule. A moving unit samples the terrain under its center at the start of each authoritative movement tick; roads otherwise behave like grass, including passability, construction, cover, concealment, and line of sight.MACHINE_GUNNER_SETUP_TICKS = 30(~1s setup or teardown for support weapons), halved toMETHAMPHETAMINES_MACHINE_GUNNER_SETUP_TICKS = 15after Methamphetamines research.- Anti-Tank Guns use
ANTI_TANK_GUN_SETUP_TICKS = 75(~2.5s) andANTI_TANK_GUN_TEARDOWN_TICKS = 45(~1.5s). - Mortar Teams use
MORTAR_TEAM_SETUP_TICKS = 45(~1.5s),MORTAR_TEAM_TEARDOWN_TICKS = 15(~0.5s),MORTAR_MIN_RANGE_TILES = 5,MORTAR_RANGE_TILES = 17, andMORTAR_FIELD_OF_FIRE_RAD = 360 degrees total,MORTAR_SHELL_DELAY_TICKS = 68(~2.27s travel),MORTAR_OUTER_RADIUS_TILES = 1.5,MORTAR_INNER_RADIUS_TILES = 0.5,MORTAR_OUTER_DAMAGE = 40,MORTAR_INNER_DAMAGE = 100,MORTAR_VISIBLE_MEDIAN_SCATTER_TILES = 1.0, andMORTAR_BLIND_MEDIAN_SCATTER_TILES = 4.0. Mortar facing uses sim-localmortar::TURN_RATE_RAD_PER_TICK = PI / 6, so a 180-degree turn takes 6 ticks (~200ms at 30 Hz) instead of snapping instantly. Neither radius has armor penetration: armored targets take the standard non-piercing reduction, resulting in 25 inner damage or 10 outer damage before other modifiers. Manual Fire uses hotkeyXand remains a player-directed override that does not require setup, but it must land in the 5-to-17-tile range band. Autocast uses normal idle/attack-move acquisition after Mortar Autocast research completes and fires only while fully deployed, at targets inside the same range band and its full 360-degree field of fire. Autocast aims at a target’s current position and does not lead movement. Manual and autocast shots scatter from the intended impact point: if the point is visible to the firing team, the deterministic radial scatter has a one-tile median miss radius; otherwise it has a four-tile median miss radius. Autocast prefers targets whose deterministic scattered impact avoids same-team units/buildings when alternatives are available. Mortar impacts apply the same damage to friendly and enemy units/buildings; autocast skips deterministic scattered impact points that would hit any same-team unit or building at its current position, while manual fire remains unrestricted. - anti-tank guns fire only while deployed, with
ANTI_TANK_GUN_DEPLOYED_RANGE_TILES = 20andANTI_TANK_GUN_FIELD_OF_FIRE_RAD = 35 degrees total; packed, setting-up, and tearing-down guns cannot fire. A deployed gun’s setup cone remains fixed while its body and barrel turn together atANTI_TANK_GUN_TURN_RATE_RAD_PER_TICK = 0.035to track targets inside that cone; targets outside the cone are ignored until teardown and redeployment. While packed and mobile, an Anti-Tank Gun moves at 1.52 px/tick and turns its body atANTI_TANK_GUN_BODY_TURN_RATE_DEGREES_PER_SECOND = 50; sharp heading changes still reduce throttle until the gun pivots in place. - Panzerfaust units carry a one-shot 5-tile loaded weapon that targets only visible
Scout Cars, Tanks, and Command Cars with
PANZERFAUST_DAMAGE = 100,PANZERFAUST_ARMOR_PENETRATION = 0.5,PANZERFAUST_WINDUP_TICKS = 15, andPANZERFAUST_TRAVEL_TICKS = 15. The Panzerfaust becomes spent immediately at launch and can move and use its rifle while the detached projectile travels. Against Armored Tanks, the 50% penetration lands as 63 effective damage; unarmored Scout Cars take the full 100 damage. Methamphetamines reduces the windup constant to 12 ticks; travel stays 15 ticks. The dedicated runtime owns only the one-shot launcher, exact vehicle whitelist, and disposable state; the entity remains a Panzerfaust throughout. - Tank hull-facing damage modifiers for tank and anti-tank gun hits are 1.0x front, 1.5x side, and 1.7x rear.
- Artillery uses
ARTILLERY_MIN_RANGE_TILES = 10,ARTILLERY_MAX_RANGE_TILES = 35,ARTILLERY_FIELD_OF_FIRE_RAD = 30 degrees total,ARTILLERY_RELOAD_TICKS = 90(~3s),ARTILLERY_SETUP_TICKS = 180(~6s setup or teardown),ARTILLERY_SHELL_DELAY_TICKS = 150(~5s), andARTILLERY_AMMO_COST_STEEL = 10. It moves at 1.6 px/tick, slightly faster than the Anti-Tank Gun’s 1.52 px/tick speed. Unified Fire uses a player-selected radius clamped betweenARTILLERY_MIN_FIRE_RADIUS_TILES = 6andARTILLERY_BLANKET_RADIUS_TILES = 15around the stored locked center. Every shell lands at a point sampled uniformly by area inside that circle. There is no separate range-based error, accuracy sequence, or repeated-shot tightening. Artillery Fire Control costs 100 steel and 150 oil, takes 20 seconds, requires Artillery, and reduces the minimum selected radius toARTILLERY_FIRE_CONTROL_MIN_FIRE_RADIUS_TILES = 3. Its body length, width, clearance, and selection radius are scaled to 75% of the Tank, matching its rendered rig and shrinking both its visual and authoritative gameplay footprint. It costs 150 steel / 50 oil to train. Impacts deal 75 armor-piercing damage within 2/3 tile and non-armor-piercing falloff down to 20 damage at 2 tiles, including friendly fire. TANK_OIL_COST_PER_PX = 20 / (96 * TILE_SIZE): tank movement still uses the original 96-tile calibration, so driving the wider 126-tile map costs proportionally more oil than before.SCOUT_CAR_OIL_COST_PER_PX = 5 / (96 * TILE_SIZE): scout cars burn oil for movement at half the previous tank movement rate. Command Cars use this same movement-oil cost. Tanks, scout cars, and command cars cannot advance while their owner has zero oil.- Scout Plane constants for the Command Car Scout Plane ability:
SCOUT_PLANE_COST_STEEL = 50,SCOUT_PLANE_COST_OIL = 75,SCOUT_PLANE_HP = 40,SCOUT_PLANE_SIGHT_TILES = 19,SCOUT_PLANE_SPEED_PX_PER_TICK = 2.6,SCOUT_PLANE_SUPPLY = 0,SCOUT_PLANE_ORBIT_RADIUS_TILES = 2,SCOUT_PLANE_LIFETIME_TICKS = 900, andSCOUT_PLANE_ABILITY_COOLDOWN_TICKS = 900. It has no default weapon and a zero-radius authoritative movement/collision body, so it neither reserves nor blocks ground pathing. The client mirror uses a 48x34 px body and 17 px render size. Command Cars keep Breakthrough and add Scout Plane on theCgrid slot; the ability launches instantly from the selected Command Car without a City Centre requirement. Each Command Car tracks its own 30-second cooldown; active sorties are otherwise independent and every plane contributes aerial sight. - Tank stationary range ramps from the base 5-tile weapon range to 14 tiles over
TICK_HZ * 3ticks. Movement-path translation or hull rotation resets the ramp; autonomous armor reaction, turret aiming, collision shoves, and external pulls do not. - Human selection and command bandwidth is supply-based:
BASE_COMMAND_SUPPLY_CAP = 24command supply plusCOMMAND_CAR_SUPPLY_CAP_BONUS = 20and the Command Car’s own command weight for each selected/commanded Command Car. Units use their mirrored supply as command weight, so current Tanks consume 8 command supply and three Tanks fill the base budget; Command Cars still appear as weighted selections but their own weight is offset before their bonus is added. - Methamphetamines (Training Centre research): costs 100 steel / 100 oil and takes 600 ticks (~20s). Once complete, all current and future Riflemen for that player gain permanent moving rifle fire, 1.25x movement speed (matching tank speed at 2.0 px/tick), no extra movement miss chance, and 25% faster attacks (16 tick cooldown becomes 12). It also increases that player’s Machine Gunners from 1.28 px/tick to unupgraded Rifleman speed (1.6 px/tick) and halves their setup and teardown timers from 30 ticks to 15. Panzerfausts also use the reduced 12-tick Panzerfaust windup.
- Panzerfausts (Training Centre research, protocol id
panzerfausts): costs 100 steel / 100 oil and takes 600 ticks (~20s). Completion unlocks Panzerfaust training at the Barracks. Riflemen are never automatically armed or rearmed. - Entrenchment (Training Centre research, protocol id
entrenchment): costs 100 steel / 0 oil and takes 600 ticks (~20s). The rules surface defines Riflemen, Panzerfausts, and Machine Gunners as eligible entrenchment infantry; Engineers/Workers, Mortar Teams, Ekat, Golems, Ekat-faction units, vehicles, buildings, support weapons other than Machine Gunners, and non-infantry entities are excluded. Eligible infantry owned by a player with completed Entrenchment create neutral trenches after holding ground on untrenched terrain for 90 ticks (~3s), and any eligible infantry can occupy an existing empty trench while stopped in its footprint. A trench can actively hold only one infantry unit, so nearby eligible infantry dig their own adjacent trenches instead of sharing one. Active occupation grants +1 tile weapon range, reduces incoming direct damage by 50% after normal weapon/armor/facing calculations, reduces incoming area damage by 25% after existing falloff/armor rules, and suppresses over-penetration through or into the entrenched unit. Entrenchment does not add a direct-shot miss chance. Tank cannon direct shots have no intrinsic infantry dodge chance. Anti-Tank Guns cannot choose infantry-sized units as primary targets; their existing 90% infantry miss roll still applies to incidental overpenetration candidates. Each Anti-Tank Gun roll happens before the entrenched direct-damage reduction, and every overpenetration candidate rolls separately. The trench radius is 0.375 tile. The client renders neutral trench terrain as brown ground and marks occupied eligible infantry with a small brown rim. The selected-unit panel reports existing-trench reuse, researched dig-in availability, and occupied benefits as a player-facing status only; the server remains authoritative for actual occupation and combat modifiers. - AT Guns (R&D Complex research, protocol id
anti_tank_gun_unlock): costs 100 steel / 50 oil and takes 300 ticks (~10s). Once complete, that player can train Anti-Tank Guns from Gun Works. AT Guns keeps its own R&D command-card slot while incomplete. - Artillery (R&D Complex research, protocol id
artillery_unlock): costs 200 steel / 100 oil and takes 750 ticks (~25s). It has its own permanent R&D slot and requires AT Guns either completed or earlier in that R&D Complex’s queue when ordered. Research begins only after the earlier AT Guns item completes. Once complete, that player can train Artillery from Gun Works. - Tank Production (R&D Complex research, protocol id
tank_unlock): costs 150 steel / 100 oil and takes 600 ticks (~20s). Once complete, that player can train Tanks from Vehicle Works. Scout Cars remain immediately trainable from Vehicle Works; Command Cars require only a completed R&D Complex and do not require Tank Production. - Mortar Autocast (R&D Complex research, protocol id
mortar_autocast): costs 150 steel / 150 oil and takes 600 ticks (~20s). Mortar Team autocast is unavailable before completion. Once complete, all current and future Mortar Teams for that player start with autocast enabled; players can still turn autocast off per selected Mortar Team. - Smoke Plus (R&D Complex research, protocol id
smoke_plus): costs 150 steel / 150 oil and takes 600 ticks (~20s). Once complete, future Scout Car Smoke casts by that player use a 4-tile cloud radius and last 10 seconds instead of the base 2-tile radius and 5-second duration. - Ability metadata is Rust-authoritative in
server/crates/rules/src/faction.rs. The faction catalog records carriers, target mode, ranges, cooldowns, charges, Steel/Oil cost, queueability, autocast support, and command-card affordances;client/src/config.jsis mechanically checked against that registry for client-visible ability descriptors. Server execution maps those registry rows to a small set of sim-local effect hooks: legacy no-op, owned area status, delayed world effect, dash return, line projectile, Magic Anchor placement, Golem consumption, and the artillery fire path. The visiblepointFirecatalog row supplies the unified Fire button, while the hiddenblanketFirerow backs the radius-bearing server order. Both retain the same range band, ammunition cost, and reload cadence. The legacychargeability id remains registry-backed only for old command/replay decoding and has no carriers, cooldown, command-card entry, or runtime status. - Ekat is the first playable one-hero faction unit. The
ekatcatalog starts with one Ekat and one Zamok, no workers, no buildable menu, no research, and no other controllable combat units besides Golems produced from Zamok. Ekat has 150 HP, no passive regeneration, 1.6 px/tick speed, 12-tile sight, no default attack, and no Steel/Oil/Supply cost. Her Dash ability targets up to 5 tiles, has no resource cost, has an 8s cooldown, requires a statically standable landing point, and leaves a four-second return marker that can be recast after one tick if the marker destination remains standable. Her Line Shot ability targets up to 6 tiles, has no resource cost, has a 10s cooldown, and launches an 8 px/tick out-and-back projectile that deals 40 damage to enemy targetable entities intersecting each 0.6-tile-wide swept leg once per leg; if her Magic Anchor is active, the same activation also launches a second projectile from the anchor toward the cursor. Her Magic Anchor ability targets up to 5 tiles, has no resource cost, places one replacement-style non-blocking, non-attackable 10-second pull field with a 3-tile radius, slows units moving away from the anchor to as low as 0.45x speed near the center, boosts units moving toward the anchor up to 1.35x speed near the center, and drags idle units toward the anchor with less displacement for braced or heavy units. Her Consume ability is self-targeted, has no resource cost or cooldown, consumes the nearest owned living Golem within 2 tiles, and heals Ekat to full HP. Existing prototype combat abilities remain directly available until the Ekat tech-unlock building slice replaces them. - Scout Car Smoke (hotkey
D): Scout cars have a targeted smoke-grenade ability once their player completes an R&D Complex; no completed Gun Works is required. Each scout car holds up to 2 Smoke charges and has unlimited lifetime uses. Smoke has no steel or oil cost and no activation cooldown, so both stored charges can be cast back-to-back. Spending the first charge starts a sequential recharge queue: one missing charge returns after 15 seconds, and a second missing charge returns after another 15 seconds. Target range: 14 tiles from the caster. Launch delay: up to 100 ms at max range, scaling down for closer targets. Cloud radius: 2 tiles. Cloud duration: 5 seconds. After Smoke Plus research, future casts by that player use a 4-tile radius and 10-second duration. Expected role: an offensive tool for closing on long-range defenses; push a scout car forward, place smoke between the advance and the anti-tank gun / machine-gun nest, then move mobile units through the resulting dead zone. Active smoke is neutral world state: it blocks authoritative fog and combat LOS, prevents units inside smoke from contributing vision, hides enemies inside smoke, and does not participate in pathing, collision, scoring, supply, or targeting as an entity. Units inside a cloud still receive that cloud in their own snapshot so the obscuring effect remains visible to the player occupying it. The command card shows the selected Scout Car’s remaining charges as2,1, or0. While a missing charge regenerates, the ability’s existing clock animation shows progress toward the next charge; recharge does not disable a stored charge that is still available. - Command Car aura and Breakthrough! (hotkey
E): Each completed Command Car continuously gives owned units within 9 tiles a 1.4x speed multiplier. This passive aura has no smoke interaction, and overlapping Command Cars do not stack. Breakthrough is the self-targeted instant active version: it applies the full 1.8x speed status to owned units currently within that same radius for 180 ticks (~6s), with a 750-tick (~25s) per-caster cooldown, no resource cost, queueability, and movement during casting. The active status uses the 2.2x multiplier while the affected unit is inside smoke or during the 60-tick (~2s) recent-smoke grace window after leaving it; it overrides the passive aura. Multiple active Breakthrough effects do not stack; a shorter refresh cannot reduce an active buff. Enemies see the active status only when the affected unit is otherwise visible through authoritative fog. The client draws the permanent radius faintly for each visible Command Car and brightens it while the active aura is running. Fake Army and allied-unit support are deferred. - Map:
TILE_SIZE = 32px. New normal lobbies default to the imported 126×126 two-player map atserver/assets/maps/1v1.json(ten permanent resource base locations), served for tooling at/maps/1v1.json. The 1v1 terrain includes authored roads connecting the starts and central approaches. The four-startDefaultmap remains the hardcoded asset atserver/assets/maps/default-handcrafted.jsonfor generic simulation setup, Labs, and replay compatibility; it is the original 96×96 handcrafted map padded with 15 passable grass tiles on every edge. Both map JSON assets use terrain row strings, flatstartLocations, and flatbaseSites. - Start:
STARTING_STEEL = 75,STARTING_OIL = 0,STARTING_WORKERS = 6, one City Centre at the player’s start tile, 12 steel patches with 625 steel each split into two six-wide fields four tiles out on opposite sides of the base + 3 oil patches with 962 oil each nearby. Each base therefore holds 7,500 steel and 2,886 oil, a 2.599:1 Steel/Oil ratio (the nearest whole-unit node capacity to the 2.6:1 target). - Supply: every active player has an intrinsic
300supply allowance, which is also the hard cap. Buildings do not provide supply: City Centres, Zamoks, and legacy fixture/replay Depots all grant+0. Supply remains an army-size limit without forcing expansion or supply-building chores. - Attached steel mining: gatherers walk to a steel patch, latch onto it, and mine in place.
Every
HARVEST_TICKS = 40the base load (STEEL_LOAD = 2) is deposited directly into the player’s economy only if the resource node is withinMINING_CC_RANGE_TILES = 11.0tiles of a completed home-base mining anchor owned by that player: City Centre for Kriegsia, or Zamok for Ekat. Workers deposit the base load; Golems deposit four times the base load. Starting resources are placed withinCC_RESOURCE_MAX_DIST_TILES = 7.0, giving City Centres a four-tile mining buffer around the authored/base resource cluster. If no completed mining anchor is close enough, gatherers ignore new gather orders for that steel patch and active miners scatter roughly one tile away from the patch. When a patch empties the gatherer goes idle (no automatic retarget). - Oil extraction: workers do not directly mine oil. The worker build card exposes Pump Jack in its
top-middle
Wslot with the normal cost and build-time tooltip. Arming it snaps the placement preview to the nearest live oil patch within one map tile of the cursor. A worker right-click on a live oil patch continues to issue the same Pump Jack build directly. Completed Pump Jacks mineOIL_LOAD = 2everyHARVEST_TICKS = 40, matching one worker’s former oil rate, and deplete the underlying oil node. When that final load empties the patch, its Pump Jack disappears with it. Pump Jack placement requires overlap with a live oil node, but has no tech or mining-anchor requirement. AI resource planning treats oil patches within the 11-tile mining-anchor range as immediately available Pump Jack sites. Friendly units standing over the patch do not intercept the contextual right-click; when the builder arrives, owned and allied units overlapping the footprint are moved to the nearest clear positions before the Pump Jack scaffold is placed. Enemy units remain blockers. - One gatherer per direct-mined patch: each direct-mined node has a single harvest slot
(
Entity::miner). A patch is occupied only after the gatherer reachesGatherPhase::Harvesting; right-clicking a patch does not reserve it. Extra gatherers that arrive while the slot is taken go idle. The slot is advisory and self-heals — it’s only honored while the recorded gatherer is alive and actively harvesting that node, so death / re-order / retarget free it automatically. - Starting and expansion resources: every authored base site gets 12 steel patches and 3 oil
patches. Map schema v3 stores flat
startLocationsandbaseSites: the number of start locations limits player count, while every base site remains present in every match. A player receives a City Centre, workers, and the normal resource cluster at an assigned start; unclaimed starts and all other base sites keep their resource clusters as neutral expansion locations. The seed only determines player-to-start assignment, never which base sites exist. This lets a map have any safe bounded number of base locations without assigning natural sites to players or maintaining multiple player-count layouts.
Unit stats (hp, dmg, range[tiles], cooldown[ticks], speed[px/tick], sight[tiles], cost, supply, buildTicks):
| kind | hp | dmg | range | cd | speed | sight | steel | oil | sup | buildTicks |
|---|---|---|---|---|---|---|---|---|---|---|
| worker | 40 | 4 | 1 | 24 | 2.0 | 10 | 50 | 0 | 1 | 396 (~13.2s) |
| golem | 160 | 16 | 1 | 24 | 2.0 | 10 | 0 | 0 | 4 | 396 (~13.2s); provisional free Ekat worker-like economy body trained at Zamok; mines at 4x worker load; can be consumed by Ekat for full heal |
| rifleman | 45 | 5 | 5 | 16 | 1.6 | 11 | 25 | 0 | 1 | 300 (~10s) |
| panzerfaust | 45 | 5 rifle / 100 launcher | 5 | 16 rifle / one lifetime launcher | 1.6 | 11 | 55 | 5 | 1 | 300 (~10s); requires completed Panzerfausts research |
| machine_gunner | 55 | 4 | 6 | 6 | 1.28 | 11 | 75 | 10 | 2 | 400 (~13s) |
| mortar_team | 75 | 40 outer / 100 inner AOE | 5-17 | 60 | 1.6 | 10 | 100 | 40 | 3 | 460 (~15s); trained at Gun Works (steelworks kind) |
| anti_tank_gun | 45 | 100 deployed / 75 packed | 20 deployed / 5 packed | 72 | 1.52 | 9 | 150 | 40 | 3 | 440 (~15s); requires Gun Works (steelworks kind) and AT Guns (anti_tank_gun_unlock) researched in R&D Complex |
| artillery | 200 | 75 AP inner / 75-20 outer AOE | 10-35 artillery fire | 90 | 1.6 | 7 | 150 | 50 | 4 | 600 (~20s); requires Gun Works (steelworks kind) and Artillery (artillery_unlock) researched in R&D Complex; rendered at 75% of its prior size with a matching 75%-of-Tank gameplay footprint; 2/3-tile inner and 2-tile outer blast radii; soft target with no armor damage reduction |
| scout_car | 100 | 6 | 7 | 6 | 2.35 | 15 | 125 | 50 | 3 | 480 (~16s) |
| scout_plane | 40 | 0 | 0 | 0 | 2.6 | 19 | 50 | 75 | 0 | 0; launched instantly from a selected ready Command Car without a City Centre requirement; unlimited independent active sorties; non-combat recon with 2-tile orbit radius and a 30-second total lifetime from launch, including transit, followed by despawn; 30-second caster-local cooldown, no ground collision reservation, and 48x34 px client render body |
| tank | 292 | 60 cannon; 4 coax | 5 moving / 14 fully stationary cannon; 6 coax | 72 cannon; 6 coax | 2.0 | 9 | 425 | 150 | 8 | 750 (~25s); requires Vehicle Works (factory kind) and Tank Production (tank_unlock) researched in R&D Complex; coax is a secondary small-arms weapon that fires through the current turret arc |
| command_car | 150 | 0 | 0 | 0 | 2.35 | 8 | 150 | 75 | 4 | 450 (~15s); trained at Vehicle Works (factory kind) and requires a completed R&D Complex, but no Tank Production research; no weapon; Scout Car-style movement with a smaller jeep-sized body |
| ekat | 150 | 0 | 0 | 0 | 1.6 | 12 | 0 | 0 | 0 | 0; Ekat faction hero; no default attack; no passive regeneration; consumes nearby Golems for recovery |
Building stats (hp, sight, cost, footprint tiles wxh, buildTicks, extra). Building sight is measured outward from the footprint edge, not from only the building center, so sight 1 reveals the full footprint plus a one-tile perimeter around it. Sight 0 buildings do not reveal fog tiles:
| kind | player-facing name | hp | sight | cost | foot | buildTicks | notes |
|---|---|---|---|---|---|---|---|
| city_centre | City Centre | 300 | 1 | 450 steel + 150 oil | 3x3 | 750 | trains workers; no supply; players start with one free |
| zamok | Zamok | 600 | 1 | 0 | 3x3 | 0 | Ekat start building; no supply; trains Golem; no research in first playable slice |
| depot | Supply Depot | 110 | 1 | 100 | 2x2 | 300 | disabled in the current experiment (not buildable and no command-card button); retained for replay and fixture compatibility; no supply |
| barracks | Barracks | 165 | 1 | 150 | 3x2 | 200 | trains rifleman, machine_gunner, and panzerfaust; Machine Gunner requires a completed Training Centre and Panzerfaust requires completed Panzerfausts research; requires a City Centre |
| training_centre | Training Centre | 200 | 1 | 100 steel + 50 oil | 3x2 | 560 | shared prerequisite before either advanced path; unlocks machine_gunner training at barracks and researches Methamphetamines, Panzerfausts, and Entrenchment; requires a City Centre and Barracks |
| research_complex | R&D Complex | 165 | 1 | 100 steel + 100 oil | 3x3 | 450 | research-only building for AT Guns, Artillery, Tank Production, Mortar Autocast, and Smoke Plus; requires a City Centre and Training Centre |
| factory | Vehicle Works | 200 | 1 | 125 steel + 125 oil | 3x3 | 749 | Mobile Warfare path building; trains scout_car immediately, then tank and command_car after Tank Production research; requires a City Centre and Training Centre |
| steelworks | Gun Works | 200 | 1 | 150 steel + 100 oil | 3x3 | 599 | Superior Firepower path building; trains mortar_team immediately, Anti-Tank Guns after AT Guns, and Artillery after Artillery research; requires a City Centre and Training Centre |
| tank_trap | Tank Trap | 120 | 0 | 30 steel + 0 oil | 1x1 | 300 | engineer-built vehicle obstacle available from the worker build card after a completed Training Centre; A-clicking a completed trap captures every currently visible completed trap within 4 tiles as one cluster-clear order; workers deconstruct completed traps in 150 ticks and refund the cost to the deconstructing player; sparse orthogonal pairs close the single tile between them for vehicle movement only; armored, no trains, no supply, no weapon, no fog reveal, not an elimination building |
| pump_jack | Pump Jack | 50 | 1 | 50 steel + 0 oil | 1x1 | 600 | contextual oil extractor built by workers on live oil patches; may be built at any distance, but mines 2 oil per 40 ticks only while its patch is within the 11-tile mining range of an owned or allied completed City Centre/Zamok; ejects friendly footprint occupants when its builder arrives; unarmored, immobile, no trains, no supply, no weapon, and does not block shots or line of sight; no tech requirement |
Win: a player is eliminated when they own zero elimination-counting buildings; units and
Tank Traps alone do not keep them alive. Last player standing wins; a 1-player match never ends
(sandbox/exploration mode). In a
3-4 player match, a connected human who is eliminated receives a one-time gameOver score
snapshot immediately while the remaining players keep playing; final match resolution sends
gameOver only to players who have not already received one.