Buildings
Construction, foundations, ancient buildings and what each one does.
For players: what this is in one minute#
Buildings are the bases you and the three factions plant on the map. You start a building as a cheap foundation (it has almost no health and does nothing), then haul materials into it to finish it into a full building. A finished building gives you services — refining ore, repairing armour, copying blueprints, building items and vehicles — and you (the owner) can charge other players a fee to use it. The map also already has indestructible Ancient (neutral) buildings: giant obelisks and the three faction capital "cities" clustered around each side's spawn point. If a player building's health hits zero it can be destroyed, and most of what was stored inside is lost.
Each faction has a lore name and a colour code: RED = Jodon,
GREEN = Ephrati, BLUE = Reubo. Internal item/building codes (like
r cc) appear throughout this doc next to their display names (like the
Jodon Command Centre) so both players and developers can follow along.
There are 66 building types defined in total: 59 used in the live game (3 obelisks, 3 ancient hubs, and the per-faction set of player-buildable and city buildings) plus 7 test-only types (regtest; see §12). The full breakdown is in §0 and the catalogs in §3, §4, §7, and §13.
Authoritative reference for every building type and every building mechanic in Taurion. All rules are sourced from the Game State Processor (GSP) — the server program that computes the game's official state from on-chain moves, and the single source of truth. Human display names are the building names shown in the official client (which port the original Unreal naming); item/vehicle display names are likewise the ones shown in the official client.
Jargon used below, defined once here: HP = hit points (health); milli-HP = HP × 1000 (the GSP stores HP in thousandths for precision); L1 distance = hex grid "taxicab" distance; vCHI = the in-game currency that is burnt (destroyed) to pay base service costs; Cubits = the tradable token used on the DEX (the in-building decentralized exchange / order book); BP = blueprint; bps = basis points (1 bp = 0.01%).
Unless noted, all citations are file:line into the GSP source tree.
0. Naming, factions, and internal codes#
Internal building "type" strings are short codes such as r cc, g rf,
b vb. The first token before the space is the faction prefix, the rest is
the building-class code.
Faction prefixes#
| Prefix | Faction (game state) | Client lore name | Source |
|---|---|---|---|
r |
RED | Jodon | proto/roconfig.cpp:165-170 |
g |
GREEN | Ephrati | same |
b |
BLUE | Reubo | same |
| (none) | ANCIENT | Ancients / neutral | obelisks & ancient buildings |
The faction of a building type is inferred at runtime from the prefix, but
only for building types that contain a construction block (i.e. the
player-buildable ones). The inferred faction is written into
construction.faction (proto/roconfig.cpp:165-170 for the prefix table,
187-211 for the inference). A building's instance faction is immutable and
stored in the DB (database/building.hpp:69-70).
Complete type inventory (the count)#
Across all proto/roconfig/buildings/*.pb.text files there are 66
building_types definitions:
| Group | Count | Types |
|---|---|---|
| Obelisks | 3 | obelisk1, obelisk2, obelisk3 |
| Ancient hubs | 3 | ancient1, ancient2, ancient3 |
| RED production | 18 | r cc,r cf,r rf,r r,r rt,r vb,r ss, r c1–r c11 |
| GREEN production | 17 | g cc,g cf,g rf,g r,g rt,g vb,g ss, g c1–g c10 (no g c11) |
| BLUE production | 18 | b cc,b cf,b rf,b r,b rt,b vb,b ss, b c1–b c11 |
| Live-game subtotal | 59 | (3 + 3 + 18 + 17 + 18) |
Test-only (regtest, test.pb.text) |
7 | checkmark, itemmaker, carmaker, huesli, r test, g test, b test |
| Total | 66 |
Note GREEN has only c1–c10 (10 common buildings) while RED and BLUE each
have c1–c11 (11). The 7 test types reference two dummy construction
materials, foo and zerospace, that exist only for tests.
Building-class codes#
| Code | Class (display) | Player-buildable? | Notes |
|---|---|---|---|
cc |
Command Centre | Yes | Also the faction spawn building |
cf |
Construction Facility | Yes | |
rf |
Refinery (research/reveng) | Yes | "rf" offers blueprint copy + reverse-eng |
r |
Refinery (ore refining) | Yes | the ore-refining service building |
vb |
Vehicle Bay | Yes | |
rt |
Rocket Turret | Yes | only building with an offensive attack |
c1–c11 |
Common building | No | decorative ancient city buildings only |
ss |
City | No | type defined but never placed (legacy) |
obelisk1/2/3 |
Ancient Obelisk | No | initial neutral landmarks |
ancient1/2/3 |
Ancient Building | No | type defined but not placed in initialbuildings |
Client-only codes: the official client also lists
sf(Research Facility),ep(Energy Plant) andet(Energy Turret). These do NOT exist as GSP building types — there are no*_sf/_ep/_et.pb.textfiles. They are leftover client model mappings and have no game effect.
Display name for an instance = faction lore name + class name, e.g. r cc
shows as the Jodon Command Centre in the game UI. Worked examples across the
factions: g cf = Ephrati Construction Facility, b vb = Reubo Vehicle Bay,
r rt = Jodon Rocket Turret, g rf = Ephrati Refinery (research),
b r = Reubo Refinery (ore). The full code→model→faction mapping lives in
the official client.
1. Building data model#
1.1 Hard-coded type data (proto/config.proto:284-371, BuildingData)#
Each type entry under building_types (config map key = the type string) has:
| Field | Meaning |
|---|---|
enter_radius |
L1 (hex) radius around the centre to enter/exit |
shape_tiles[] |
footprint tiles relative to centre (untransformed) |
foundation (AllCombatData) |
combat + regen data while it's a foundation |
full_building (AllCombatData) |
combat + regen data once finished |
construction (ConstructionData) |
foundation cost, full cost, blocks, faction |
offered_services (Services) |
which of the 6 services it provides |
1.2 Per-instance state (proto/building.proto:48-120, Building)#
Stored partly in the DB row, partly in the Building proto:
| Field | Meaning |
|---|---|
DB owner |
owner account name ("" for ANCIENT) (database/building.hpp:41,66) |
DB faction |
immutable instance faction (database/building.hpp:69) |
DB centre |
hex centre coordinate |
shape_trafo.rotation_steps |
0–5 clockwise 60° rotations (building.proto:32-41) |
foundation (bool) |
true while still a foundation |
construction_inventory |
materials dropped in toward full construction |
ongoing_construction |
ongoing-op ID currently upgrading it (if any) |
combat_data |
derived from type's foundation/full data |
config.service_fee_percent |
owner-set service fee (% of base) |
config.dex_fee_bps |
owner-set DEX fee (basis points) |
age_data.founded_height / finished_height |
block heights |
1.3 Shape, rotation, footprint#
GetBuildingShape rotates each shape_tile clockwise by
rotation_steps, then offsets by the centre (buildings.cpp:35-53). A
worked example from the tests: a checkmark (tiles (0,0),(1,0),(0,1),(0,2))
placed at (-1,5) with rotation_steps = 2 yields the tiles
(-1,5),(-1,4),(0,4),(1,3) (buildings_tests.cpp:58-72).
Footprint sizes (number of tiles) vary hugely; see the catalog in §3.
2. Placement rules (founding a building)#
2.1 The fb ("found building") move#
Issued as a character sub-command. The character must be out of any building and not busy, and standing where the foundation will be placed.
[
{
"name": "domob",
"move": {"c": {"id": 1, "fb": {"t": "r cc", "rot": 3}}}
}
]
fb is an object that must have exactly two members: t (type string) and
rot (integer 0–5) (moveprocessor.cpp:1176-1184, 1140-1162). Any extra
member, missing member, non-string t, unknown type, or rot outside [0,5]
(including a float like 4.0) is rejected
(moveprocessor_tests.cpp:1751-1793).
2.2 Validation order (moveprocessor.cpp:1169-1251)#
A foundation is created only if ALL of the following hold:
fbis well-formed (above).- Character is not busy (
IsBusy()), e.g. not in an ongoing op (moveprocessor.cpp:1186-1191;_tests.cpp:1795-1806). - Character is not already inside a building
(
moveprocessor.cpp:1193-1199;_tests.cpp:1808-1819). - The type has a
constructionblock — otherwise "cannot be constructed".itemmaker-style service-only types are rejected (moveprocessor.cpp:1201-1206;_tests.cpp:1821-1830). - If the type has an inferred
construction.faction, the character's faction must match it (moveprocessor.cpp:1208-1220;_tests.cpp:1860-1883: a RED character can buildr testbut notg test). - The character's inventory holds at least the foundation cost
(
moveprocessor.cpp:1222-1235;_tests.cpp:1832-1842). CanPlaceBuildingpasses for the chosen tiles (moveprocessor.cpp:1241-1248). See §2.3.
The character itself is temporarily removed from the dynamic-obstacle map during
the placement check, since they will be inside the foundation anyway
(moveprocessor.cpp:1237-1240).
2.3 CanPlaceBuilding — terrain & collision (buildings.cpp:62-102)#
Every footprint tile must satisfy:
- Passable on the base map (
buildings.cpp:71-75;_tests.cpp:141-147). - Not in a no-combat / safe zone — you cannot build in neutral no-combat
zones or in any faction starter zone (
buildings.cpp:76-80;_tests.cpp:149-160). - Free of dynamic obstacles — no other building tile and no character
vehicle (
buildings.cpp:81-85;_tests.cpp:162-166). - All tiles in the same region — a building may not straddle two map
regions (
buildings.cpp:87-99;_tests.cpp:168-176).
2.4 What founding does (moveprocessor.cpp:1639-1669)#
- Creates a new building (
buildings.CreateNew(type, owner, faction)), owner = character's owner, faction = character's faction. - Sets
foundation = true, appliesshape_trafo, setsage_data.founded_height = current height. - Subtracts the foundation cost from the character's inventory.
- Calls
UpdateBuildingStats(foundation HP) and immediately puts the character inside the new foundation (EnterBuilding), then registers the building as a dynamic obstacle.
The character ends up inside the foundation so they can immediately drop the
remaining construction materials. Founding happens before drop/pickup
processing within the same move, so a single move can found + drop
(moveprocessor.cpp:1875-1888; _tests.cpp:1917-1940). It also happens before
exit, so xb in the same move would leave again (_tests.cpp:1942-1960).
3. Construction (foundation → full building)#
3.1 Lifecycle#
- Found a foundation (§2). HP = foundation HP (low). It has no attacks and offers no services yet (services require the full building; see §5).
- Deliver materials: a character inside the foundation
drops items into the building'sconstruction_inventory(moveprocessor.cpp:1760-1774). - When the construction inventory holds at least the full-building cost,
construction auto-starts (
MaybeStartBuildingConstruction,buildings.cpp:123-149; triggered after each drop,moveprocessor.cpp:1773). - After
construction.blocksblocks, an ongoing op finishes it (ongoings.cpp:113-143).
3.2 Auto-start of construction (buildings.cpp:123-149)#
- Requires
foundation()and aconstructionblock. - Does nothing if already constructing (
has_ongoing_construction). - Compares the full_building cost map against the current
construction_inventory; if anything is short, it waits (buildings.cpp:134-137;_tests.cpp:206-214). - When satisfied, schedules an ongoing op at
current_height + construction.blocksand stores its ID inongoing_construction(buildings.cpp:139-144;_tests.cpp:227-243).
Note the two-stage cost: the foundation cost (paid from the founder's cargo at placement) is separate from and additional to the full_building cost (dropped into the construction inventory afterward).
3.3 Completion (ongoings.cpp:113-143)#
When the ongoing op fires:
- The full_building cost is removed from
construction_inventory. - Any leftover materials in the construction inventory are credited to the
owner's account inventory inside the new building
(
ongoings.cpp:132-135). foundationis cleared,ongoing_constructioncleared,age_data.finished_height = current height.UpdateBuildingStatsapplies the full-building HP/combat.
3.4 Stats derivation (buildings.cpp:151-165)#
UpdateBuildingStats copies foundation.combat_data/regen_data while a
foundation, or full_building.* once finished, and sets current HP to max.
A foundation r rt therefore has 0 attacks and 100/100 HP; the finished
r rt has 1 attack and 1000/1000 HP (buildings_tests.cpp:76-89).
Buildings with no foundation/full_building data (ancients, obelisks,
common buildings, cities) get default/empty combat data and effectively
0 max HP — they are never targetable / indestructible in practice
(see §7, §8).
4. Catalog of player-buildable buildings#
The 6 buildable classes exist in all three factions with identical stats; only
the lore model/skin differs by faction. Costs are in raw item units (the GSP
stores quantities ×, e.g. Agarite is mat a). Service column lists
offered_services flags. HP is armour / shield. All buildable buildings
regenerate 10 HP of shield per block (regeneration_mhp.shield = 10000
milli-HP) and no armour regen unless repaired.
Display names (from the game UI): mat a = Agarite, mat b = Borolium.
4.1 Stats & services#
| Type | Class | enter_radius | tiles | Foundation HP | Full HP | Attacks | Services |
|---|---|---|---|---|---|---|---|
r r/g r/b r |
Refinery (ore) | 8 | 13/13/9 | 100k/100k | 1M/1M | none | refining |
r rt/g rt/b rt |
Rocket Turret | 6 | 19 | 100/100 | 1k/1k | 1 (see §6) | none |
r rf/g rf/b rf |
Refinery (research) | 7 | 44/46/39 | 100k/100k | 1M/1M | none | blueprint_copy, reverse_engineering |
r cf/g cf/b cf |
Construction Facility | 9/8/8 | 50/43/51 | 100k/100k | 1M/1M | none | item_construction, vehicle_construction |
r vb/g vb/b vb |
Vehicle Bay | 8/8/11 | 11/44/105 | 100k/100k | 1M/1M | none | armour_repair, vehicle_construction |
r cc/g cc/b cc |
Command Centre | 16/10/10 | 277/87/89 | 100k/100k | 1M/1M | none | ALL six services |
(enter_radius/tiles per faction file; HP/regen from *_*.pb.text; e.g.
r_r.pb.text:62-75, r_rt.pb.text:78-103, r_cc.pb.text:859-872.)
The Command Centre offers all six services and is the only buildable building offering the full set. It is also the faction's spawn building for new characters (§9).
4.2 Construction costs#
Foundation cost = paid from founder's cargo at placement; Full cost = dropped
into the construction inventory afterward. All construction takes 10 blocks
(blocks: 10).
| Type | Foundation cost | Full-building cost |
|---|---|---|
Refinery (ore) r/g/b r |
6,400,000 Agarite + 1,600,000 Borolium | 128,000,000 Agarite + 32,000,000 Borolium |
Rocket Turret r/g/b rt |
1,600,000 Agarite + 400,000 Borolium | 32,000,000 Agarite + 8,000,000 Borolium |
Refinery (research) r/g/b rf |
12,800,000 Agarite + 3,200,000 Borolium | 256,000,000 Agarite + 64,000,000 Borolium |
Construction Facility r/g/b cf |
16,000,000 Agarite + 4,000,000 Borolium | 320,000,000 Agarite + 80,000,000 Borolium |
Vehicle Bay r/g/b vb |
25,600,000 Agarite + 6,400,000 Borolium | 512,000,000 Agarite + 128,000,000 Borolium |
Command Centre r/g/b cc |
32,000,000 Agarite + 8,000,000 Borolium | 640,000,000 Agarite + 160,000,000 Borolium |
(Sources: r_r.pb.text:47-61, r_rt.pb.text:63-77, r_rf.pb.text:141-155,
r_cf.pb.text:159-173, r_vb.pb.text:42-56, r_cc.pb.text:844-857; the
g_*/b_* files carry identical costs.)
The Rocket Turret is the cheapest and the Command Centre the most expensive.
5. Services offered by buildings#
Six service types exist (config.proto:358-366, BuildingData.Services):
| Service flag | What it does | Cost mechanic |
|---|---|---|
refining |
Refine raw ores → refined materials | per-recipe RefiningData.cost (burnt vCHI) |
armour_repair |
Repair character armour HP | armour_repair_cost_millis × HP (params) |
reverse_engineering |
Reverse-engineer artefacts → blueprints | RevEngData.cost (burnt) |
blueprint_copy |
Copy a blueprint original | bp_copy_cost × complexity (params) |
item_construction |
Build fitments/items from blueprints | construction_cost × complexity |
vehicle_construction |
Build vehicles from blueprints | same as item construction |
A service can only be used inside a building whose type sets that flag; the GSP
checks Building(type).offered_services() for each operation (e.g. refining at
services.cpp:117-119, armour repair 298, reverse-eng 467, bp copy 627,
item/vehicle construction 837). The numerical service costs and block-times
themselves are documented in the services/economy doc; this doc covers which
buildings expose them and the owner-fee layer.
5.1 Where each service lives (full picture)#
| Building | refining | armour_repair | reverse_eng | bp_copy | item_construction | vehicle_construction |
|---|---|---|---|---|---|---|
cc Command Centre |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
r Refinery (ore) |
✓ | |||||
rf Refinery (research) |
✓ | ✓ | ||||
cf Construction Facility |
✓ | ✓ | ||||
vb Vehicle Bay |
✓ | ✓ | ||||
rt Rocket Turret |
(none) | |||||
Common c1–c11 |
varies* | varies* | varies* | varies* | varies* | varies* |
Ancient ancient1/2/3 & City ss |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
* The decorative common buildings DO declare offered_services (and most add
armour_repair), e.g. b c1 → armour_repair + refining; g c1 →
armour_repair + reverse_engineering + blueprint_copy. They are ancient (no
owner, no fee — see §5.2) but, being placed only inside ancient cities, are
usable service hubs. See §3.4: they have no HP data → indestructible.
(Common-building service sets, per file: e.g. b_c1.pb.text armour_repair +
refining; g_c1.pb.text armour_repair + reverse_engineering + blueprint_copy;
r_c1.pb.text armour_repair + vehicle_construction. The full per-file matrix is
in the appendix §13.)
5.2 Service fees (owner economics) (services.cpp:985-1016)#
Cost of a service = base cost (burnt) + owner fee.
- If the operation is performed by a mobile character (not inside a
building),
fee = 0(services.cpp:991-997). - If the building is ANCIENT, or the user is the owner,
fee = 0(services.cpp:999-1009). Note: an owner uses their own building free even though they would get the fee back, so they can operate on a tight budget. - Otherwise:
fee = ceil(base * config.service_fee_percent / 100)(services.cpp:1011-1015).service_fee_percentis a percentage of the base cost — e.g. 100 = a 100% surcharge.
Fee payment: the user's account is debited base + fee; base is burnt; fee
is credited to the building owner's account (services.cpp:1130-1141). The
owner can never be the same as the user when a fee is charged (asserted).
The service-cost JSON exposed to clients per operation is:
{"base": <burnt>, "fee": <owner fee>} (services.cpp:1116-1121).
5.3 Faction interaction with services#
There is no owner-faction gate on using a service inside a building. Anyone who is inside may use it. However, the outputs can be faction-gated by the user's own faction:
- Refining/reverse-engineering only yield outputs valid for the user's faction
(
services.cpp:558-567). - Item/vehicle construction: if the produced item has a faction, it must match
the user's faction (
services.cpp:854-865).
Entry to the building itself IS faction-gated — see §9.
6. Combat stats & the Rocket Turret#
Only the Rocket Turret (rt) has an offensive attack. All other buildable
buildings have empty combat_data (they can be attacked but never shoot).
Rocket Turret full-building attack (r_rt.pb.text:86-97, identical g/b):
| Property | Value |
|---|---|
| range | 6 |
| area (AoE) | 2 |
| damage | 3–9 |
| weapon_size | 40 |
A foundation rt has 0 attacks and 100/100 HP; finished it has the attack above
and 1000/1000 HP (buildings_tests.cpp:76-89).
All buildable buildings regenerate shield at 10 HP/block
(regeneration_mhp.shield = 10000). Armour does not auto-regenerate. Building
HP for finished buildings (except the turret) is 1,000,000 armour /
1,000,000 shield, making them very tanky.
Targeting/attack mechanics (who they shoot, how AoE works) are covered in the
combat doc; buildings participate via combat_data and are targetable as
TYPE_BUILDING.
7. Ancient buildings, obelisks, and common buildings#
7.1 Initial ancient buildings on the map (buildings.cpp:104-121)#
At genesis, InitialiseBuildings walks config.initial_buildings and creates
each as ANCIENT, owner = "", with founded_height = finished_height = 0,
then UpdateBuildingStats. Because these types lack
foundation/full_building data, they get default (effectively 0 max-HP /
no-combat) combat data — they are never killed.
The placed initial buildings (proto/roconfig/initialbuildings.pb.text):
| Type | Centre (x, y) | Notes |
|---|---|---|
obelisk1 |
(-125, 810) | neutral landmark, no-combat r=30 |
obelisk2 |
(-1301, 902) | neutral landmark |
obelisk3 |
(-637, -291) | neutral landmark |
g cc |
(-3489, 1823) | GREEN spawn (building id 4) |
b cc |
(636, 2446) | BLUE spawn (building id 5) |
r cc |
(1919, -2605) | RED spawn (building id 6) |
g c1–g c10, r c1–r c11, b c1–b c11 |
many | decorative city clusters |
The three command centres are placed as ANCIENT at genesis (so the spawn targets exist) — they are not owned by any player even though
ccis a player-buildable type. Players can additionally build their owncc.Building IDs are assigned in file order: obelisk1=1, obelisk2=2, obelisk3=3,
g cc=4,b cc=5,r cc=6 — matchingparams.spawn_areas(params.pb.text:33-47).
The bulk of the file (lines 31–666) is dense clusters of c1–c11 common
buildings forming the three ancient "cities" near each faction's command
centre, each tile-rotated to fit together
(initialbuildings.pb.text:131-665).
7.2 Obelisks (obelisk1/2/3.pb.text)#
Huge neutral landmarks. enter_radius 31–35, footprints ~970–1075 tiles. No
construction, no combat, no services. Surrounded by 30-tile no-combat zones
(safezones.pb.text:26-28).
7.3 ancient1/2/3 and ss cities — defined but unused#
ancient1/2/3.pb.text define large all-service ancient hubs (enter_radius
54/56/58, ~352–378 tiles, all six services, no HP/combat/construction), and
r/g/b ss.pb.text define enormous "City" types (enter_radius 150, all six
services). Neither appears in initialbuildings.pb.text nor anywhere in the
GSP source, so they are not placed in the live game. Treat them as legacy /
client-compat definitions.
7.4 Common buildings c1–c11#
Decorative ancient city buildings. They declare enter_radius,
offered_services, and shape_tiles, but have no construction,
foundation, or full_building data — so they cannot be built by players and
are indestructible. They DO offer services (mostly armour_repair plus one
other), making the ancient cities functioning service hubs with zero owner
fee (ANCIENT → fee 0). Full per-file service matrix in §13.
8. Destruction — what happens & what drops#
When a building's HP reaches 0 it is killed via KillProcessor::ProcessBuilding
(combat.cpp:1164-1277). Only player-built buildings can ever reach this state
(ancients have no combat data).
8.1 Items collected before drop#
A "combined inventory" totalInv is assembled from everything inside
(combat.cpp:1177-1241):
- All account inventories stored in the building
(
combat.cpp:1179-1183). - Every character inside the building is destroyed; their cargo, their
vehicle item, and all their fitments are added to
totalInv(combat.cpp:1185-1200). (Characters inside a destroyed building die.) - Ongoing operations inside: a blueprint-copy returns its original BP type;
an item-construction returns its original BP (if any) — both added to
totalInv(combat.cpp:1202-1224). - DEX open bids: reserved Cubits are refunded to the bidders' accounts
(
combat.cpp:1226-1234). DEX asks: reserved item quantities are added tototalInv(combat.cpp:1235-1236). - If it was still a foundation, its
construction_inventoryis added (combat.cpp:1240-1241).
8.2 The drop roll (combat.cpp:1245-1271)#
The building is removed as a dynamic obstacle. Then, for each item position in
totalInv (iterated in sorted order for determinism), the GSP rolls:
- 30% chance (
BUILDING_INVENTORY_DROP_PERCENT = 30,combat.cpp:43-47) the entire stack of that item drops as ground loot at the building's centre; otherwise the whole stack is destroyed.
So on average ~70% of everything inside a destroyed building is lost forever.
8.3 Cleanup (combat.cpp:1273-1276)#
Building inventories, ongoing ops, and DEX orders for the building are deleted, then the building row itself is deleted.
Contrast with character death: a killed character's cargo always drops, but equipped fitments only drop at a 20% chance (
EQUIPPED_FITMENT_DROP_PERCENT = 20,combat.cpp:49-53) and the vehicle is always destroyed.
9. Entering & leaving buildings#
9.1 Entering (eb move)#
[
{"name": "domob", "move": {"c": {"id": 1, "eb": 100}}}
]
eb sets the character's "intent" to enter building ID 100; eb: null cancels
intent (moveprocessor.cpp:662-727, 1502-1508; _tests.cpp:2040-2078).
Validation at parse time (moveprocessor.cpp:662-727):
- Rejected if already in a building (
670-677). - Building must exist (
700-707). - Faction gate: anyone may enter ANCIENT buildings, but otherwise a
character may only enter a building of its own faction
(
moveprocessor.cpp:709-720).
The intent is realized later by ProcessEnterBuildings (buildings.cpp:178-233):
- A character actually enters only if its position is within the building's
enter_radius(L1 distance) of the centre (buildings.cpp:215-221;_tests.cpp:327-339"TooFar"). E.g. for acheckmark(radius 5) a character at distance 5 enters but distance 6 does not (_tests.cpp:388-412). - A busy character cannot enter (
buildings.cpp:192-197;_tests.cpp:298-311). - If the building was destroyed in the meantime, the intent is cleared
(
buildings.cpp:204-213;_tests.cpp:313-325).
Entering effects (EnterBuilding, buildings.cpp:167-176): the vehicle is
removed from the dynamic-obstacle map, building_id is set, the enter-intent is
cleared, combat target is cleared, and movement and mining are stopped
(_tests.cpp:341-386).
9.2 Leaving (xb move)#
[
{"name": "domob", "move": {"c": {"id": 1, "xb": {}}}}
]
xb must be an empty object (moveprocessor.cpp:729-744). A busy character
cannot exit (746-751). LeaveBuilding (buildings.cpp:235-252) places the
character at a random passable, unobstructed tile within enter_radius of the
centre, via ChooseSpawnLocation. If the whole radius is blocked it falls
outside the radius rather than failing (_tests.cpp:480-491), and many
simultaneous exits each get distinct tiles (_tests.cpp:493-517).
10. Owner configuration, transfer, and the update delay#
All owner operations are issued under the top-level b move command (NOT under
a character c). b may be a single object or an array of operations
(moveprocessor.cpp:343-405).
10.1 Config update (sf service fee, xf DEX fee)#
[
{
"name": "andy",
"move": {"b": [
{"id": 101, "sf": 50},
{"id": 102, "xf": 250}
]}
}
]
sf=service_fee_percent. Must be an unsigned integer0 ≤ sf ≤ MAX_SERVICE_FEE_PERCENT = 1000(moveprocessor.cpp:48,258-273). Above 1000, negative, float, or string values are rejected (_tests.cpp:3359-3414).xf=dex_fee_bps(basis points). Must be an unsigned integer0 ≤ xf ≤ MAX_DEX_FEE_BPS = 3000(moveprocessor.cpp:54,279-294;_tests.cpp:3416-3471). 3000 bps = 30% cap.- Only the owner may update; ancient buildings can never be updated
(
moveprocessor.cpp:386-401;_tests.cpp:3295-3317).
Updates are not applied immediately. They are scheduled as an ongoing op at
current_height + params.building_update_delay
(moveprocessor.cpp:1907-1921). Default delay = 120 blocks
(params.pb.text:18). When the op fires, the new config is merged into the
existing config so unset fields are preserved (ongoings.cpp:206-217). In the
JSON state this pending op shows as {"operation": "config", "newconfig": {...}}
(gamestatejson.cpp:558-560).
Multiple config updates to the same building in one move each create their own delayed op (
_tests.cpp:3319-3357).
10.2 Transfer (send)#
[
{"name": "andy", "move": {"b": {"id": 101, "send": "domob"}}}
]
send transfers ownership (moveprocessor.cpp:298-324, 1922-1930):
- Target account must exist and be initialised
(
moveprocessor.cpp:307-314;_tests.cpp:3473-3496rejects uninit/nonexistent). - Target must be the same faction as the building
(
moveprocessor.cpp:315-321; transfer to a BLUE account of a RED building is rejected). - Effect is immediate (no delay):
b.SetOwner(newOwner)(moveprocessor.cpp:1929). - Only the owner may issue it (the surrounding
TryBuildingUpdatesowner check applies). Asendand ansf/xfcan be combined in onebentry; the config update schedules first, then the transfer applies — so the schedule is attributed to the old owner and the building ends up with the new owner (moveprocessor.cpp:327-341;_tests.cpp:3498-3515).
11. Game-state JSON (what the client reads)#
GameStateJson::Convert<Building> (gamestatejson.cpp:407-468) emits per
building:
{
"id": 1234,
"type": "r cc",
"foundation": true, // present only while a foundation
"faction": "r", // "r"|"g"|"b"|"a" (ancient)
"owner": "domob", // omitted for ancient
"centre": {"x": 1919, "y": -2605},
"rotationsteps": 0,
"config": {"servicefee": 50, "dexfee": 2.5}, // dexfee = bps/100 (a percent)
"tiles": [{"x":..,"y":..}, ...], // transformed footprint
"combat": { /* HP, attacks, regen — see combat doc */ },
// foundation only:
"construction": {"ongoing": 9001, "inventory": {"mat a": 1000}},
// full building only:
"inventories": {"domob": {"mat a": 5}}, // per-account stored items
"reserved": {"mat a": 3}, // items reserved by DEX asks
"orderbook": { /* DEX bids/asks in this building */ },
// always:
"age": {"founded": 0, "finished": 12345} // "finished" omitted while foundation
}
config.servicefee is the raw percent; config.dexfee is reported as a
percent (dex_fee_bps / 100.0) (gamestatejson.cpp:330-336).
The full building list is exposed under the top-level buildings array of game
state (gamestatejson.cpp:746-794).
12. Starter cities & spawning (geography)#
Each faction has a command centre at genesis (ANCIENT), a 300-tile starter safe zone around it, and a surrounding decorative ancient "city" of common buildings.
| Faction | Command Centre centre | Spawn building id | Starter zone centre / radius |
|---|---|---|---|
| RED (Jodon) | (1919, -2605) | 6 | (1960, -2601), r=300 (safezones.pb.text:3-8) |
| GREEN (Ephrati) | (-3489, 1823) | 4 | (-3472, 1824), r=300 (safezones.pb.text:10-15) |
| BLUE (Reubo) | (636, 2446) | 5 | (547, 2497), r=300 (safezones.pb.text:17-22) |
New characters spawn inside their faction's command centre
(spawn.cpp:117-152): they are created with a starter vehicle —
rv st = Raider (RED), gv st = Scarab (GREEN), bv st =
Barracuda (BLUE) — one lf gun = Light Rail Gun fitment, and
building_id set to the faction's spawn building (params.spawn_areas,
params.pb.text:33-47). Display names are the ones shown in the game UI.
Within a starter safe zone (a faction zone), no combat occurs and no new
buildings may be founded (safe-zone rule, buildings.cpp:76-80;
_tests.cpp:149-160 confirms StarterFor((-2042,100)) == RED).
Mainnet vs testnet/regtest. Building type definitions, services, HP, costs, and the
building_update_delay/fee caps are shared. The mainnet safe zones, spawn areas, prizes, and params live inproto/roconfig/{safezones,params,...}.pb.text. The regtest config (config.proto:646-660,testnet_merge/regtest_merge) merges in alternativetest_safezones.pb.text/test_params.pb.textand thebuildings/test.pb.texttypes (checkmark,huesli,itemmaker,carmaker,r/g/b test) used only by tests. Notably, regtest replaces (not concatenates) the safe-zones and prizes lists.god_modeistruein the bundled params (params.pb.text:31) — it enables admin teleport/mint commands and is intended to be disabled on mainnet.
13. Appendix — full service matrix of common (ancient) buildings#
All offer armour_repair plus the listed extra(s). enter_radius / footprint
tiles also shown. Sources: {r,g,b}_c*.pb.text.
| Type | enter_radius | tiles | Extra services (besides armour_repair) |
|---|---|---|---|
r c1 |
12 | 164 | vehicle_construction |
r c2 |
13 | 174 | refining |
r c3 |
10 | 104 | item_construction |
r c4 |
8 | 62 | reverse_engineering, blueprint_copy |
r c5 |
9 | 64 | vehicle_construction |
r c6 |
8 | 43 | refining |
r c7 |
10 | 107 | item_construction |
r c8 |
9 | 72 | reverse_engineering, blueprint_copy |
r c9 |
8 | 50 | vehicle_construction |
r c10 |
7 | 29 | refining |
r c11 |
8 | 49 | item_construction |
g c1 |
14 | 255 | reverse_engineering, blueprint_copy |
g c2 |
12 | 140 | item_construction |
g c3 |
12 | 134 | vehicle_construction |
g c4 |
7 | 35 | refining |
g c5 |
8 | 49 | reverse_engineering, blueprint_copy |
g c6 |
8 | 43 | item_construction |
g c7 |
11 | 99 | vehicle_construction |
g c8 |
9 | 71 | refining |
g c9 |
10 | 81 | reverse_engineering, blueprint_copy |
g c10 |
10 | 84 | item_construction |
b c1 |
10 | 111 | refining |
b c2 |
12 | 126 | reverse_engineering, blueprint_copy |
b c3 |
10 | 77 | item_construction |
b c4 |
10 | 90 | vehicle_construction |
b c5 |
12 | 139 | refining |
b c6 |
11 | 120 | reverse_engineering, blueprint_copy |
b c7 |
8 | 53 | item_construction |
b c8 |
11 | 121 | vehicle_construction |
b c9 |
9 | 64 | refining |
b c10 |
9 | 62 | reverse_engineering, blueprint_copy |
b c11 |
8 | 49 | item_construction |
(Green has only c1–c10; Red and Blue have c1–c11.)
Open questions#
ancient1/2/3andss(City) types are defined but never instantiated. They have full all-service configs and large footprints but appear in neitherinitialbuildings.pb.textnor any GSP source path. It is unclear whether they are dead config kept for historical reasons, intended for a future admin/god-mode placement, or were placed via a mechanism not present in the read sources. (The official client even notes that cities are "manually recreated from individual buildings".)- Genesis command centres are ANCIENT but
ccis a player-buildable type. The three spawn CCs are created with faction ANCIENT / no owner, so they are indestructible (no combat data) and free of fees. A player-builtccwould instead have the full-building 1M/1M HP and owner fees. The exact intended long-term behavior if a faction's spawn CC were ever absent (it can't be, as ancient) is not exercised in the read code. sf/ep/etclient model codes map to client model assets but have no GSP type. They render nothing in the live game; presumably future/cut content.