Workers, Residences & Factory Automation
5.1 Worker entity
Workers are npc_instances (19) with employer_id — same stats, inventory, and death rules as other NPCs; plus job state (13).
worker:
id: worker_ana
name: Ana
employer_character_id:...
residence_id: residence_b
lodging_bed_id: bed_2
wage_account: employer_bank # deducted per tick
state: working | traveling | resting | idle | dismissed
attributes: # same families as players (`11`)
STR, DEX, STA, VIT,...
skills:
logging: 12
hauling: 8
carpentry: 5
trading: 3
pools:
stamina: { current, max }
hunger: { current, max }
inventory: WorkerCarrier # limited slots — mass/volume (`08`)
equipment: # job outfit
hands: iron_axe
body: work_tunic
pack: small_backpack
active_job_id: job_lumber_loop
5.2 Hire & dismiss
| Action | Cost |
|---|---|
| Hire | Up-front fee + a daily wage (employer sets; minimum floor per ruleset). First paycheck is the next game day |
| Dismiss | Worker leaves only after backpay is settled. Firing does not erase debt or keep their level |
Hire from labor broker NPCs in towns or recruit after quests. Worker cap per residence from building tier + CHA (optional).
5.3 Training
Employer pays training fee (coins from bank or residence treasury):
training_session(worker, skill, fee) → skill_xp += f(fee, worker.VIT, teacher_quality)
Training can be passive on-job (slow XP while doing related tasks) or active (paid courses at guild hall — faster). Skilled workers: faster harvest, shorter craft ticks, better yields, fewer failures.
5.4 Wages, effort & silver sink (implemented)
Workers are a deliberate coin sink: harder routes cost more payroll, and skilled workers charge more while doing more labor per day.
Payroll formula (once per game day)
Wages bill when the world-clock day rolls, on the same day the ledger uses. A worker hired today is first billed at the next rollover. wage_interval_ticks is unused.
due_cp = round(
(base_cp + finished_step_cp + travel_cp) * level_wage_mult * army_wage_mult
).max(1)
| Component | Source |
|---|---|
base_cp |
Employer-set wage.copper_per_interval (hire min from NPC def). Defenders use base × defender_wage_mult plus equipped gear value, even on a quiet day |
finished_step_cp |
Effort for steps finished today × wage_copper_per_effort. A harvest route pays harvest_route per node completed, once per node per day. A second pass of the same step does not add again. Idle and companion with nothing finished pay the idle rate only — a suspended route is not billed. A job loop that finished nothing pays no loop effort |
travel_cp |
Meters walked this interval × travel_copper_per_m |
level_wage_mult |
1 + (level − 1) × wage_per_level (default 0.03) |
army_wage_mult |
1 + (hired − 1) × army_wage_scale_per_extra |
Fight and ability fees are added for defenders only when those actions happened. Strike days add 0; frozen backpay is unchanged.
Step costing rules (the content files → workers.step_costs):
| Step kind | Default effort | Notes |
|---|---|---|
harvest_route |
2.2 per node | 20-node route ≈ 44 effort units |
harvest |
2.0 | Single-resource stop |
craft |
1.8 | Per craft stop in the compiled loop |
travel |
0.7 | Flat complexity; meters paid separately |
broker_sell |
0.8 | |
deposit / withdraw / pickup |
~0.45–0.55 | |
rest / wait / idle |
0.15–0.3 | Cheap parking |
A companion or idle worker with no finished steps pays the idle rate. The rates above are what a finished step of that kind adds.
Pay sources (treasury order)
- Employer bank ledger (automatic paycheck withdraw; works while offline while the region still tracks the character)
- Assigned lodging container contents
- Other employer-owned placed chests within 12 m of lodging (or employer if no lodging)
- Employer carried coins (root + worn bags)
Other player expenses (taxes, shipping fees, shop buys, hire/train fees, property upkeep) use the same bank-then-purse rule via try_spend_copper.
If the full amount cannot be paid, that day's wage is added to backpay and the worker enters Strike (job loop halted). They do not work, and they cannot be dismissed, until the entire backpay is paid. A short payroll does not fire them. While striking, collection retries about every 5 s so restocking lodging, chests, or the bank clears the debt without waiting for the next day. Further days on strike do not add another paycheck: pay stops when work stops, so time away cannot grow a debt the idle worker cannot earn down. The next worked day bills normally again after the frozen backpay is settled.
Hunger / thirst
Per-tick drain is multiplied by the current step’s effort rate (hunger_effort_scale / thirst_effort_scale). On lodging rest_if_needed, workers eat/drink one pantry consumable from the assigned bed container only when hunger or thirst is below 65% — stock the bed itself with soup/water (nearby chests are not scanned for meals; that path is wages-only).
Level bonuses (skilled workers)
| Bonus | Formula (capped) | Effect |
|---|---|---|
| Wage | 1 + (L−1)×wage_per_level (default 0.03) |
Higher daily payroll |
| Labor | labor_per_day + (L−1)×labor_per_level (40 + 2 per level) |
More harvests and crafts that day |
| Harvest speed | duration ÷ 1+(L−1)×0.03 (cap 1.75×) |
Shorter channels |
| Craft speed | same shape | Shorter craft ticks |
| Move speed | × 1+(L−1)×0.02 (cap 1.4×) |
Faster travel |
Level is worth keeping. A level-20 laborer costs about ×1.57 wages and gets 78 labor instead of 40 (about ×1.95 output), plus faster channels and walking so the larger pool still fits in the workday. Dismissing them to hire a fresh level-1 worker throws away that output and still requires the backpay to be paid first.
Worker XP pacing
Cumulative XP → level via xp_base × growth^(L−1) ceilings. Defaults: xp_base: 2000, growth: 1.65, awards 0.35 per harvest/craft/sell, 1.0 per route wrap, soft-capped at xp_max_per_route_loop: 8 so craft-until-exhausted cannot dump a level in one loop. Expect ~80+ gatherer loops to L2 and hundreds to mid levels.
Client UI
Workers dock shows today's accrued pay and, when the authored route would cost more, that quote (due→quote cp). The i ledger Labor section lists each worker's accrued daily pay, route sales estimate, net, and any backpay.
If the employer cannot pay → worker strikes until the full backpay is settled. Dismiss is refused while backpay remains.
7.1 Job definition
A job is a repeating cycle of steps. One active_job per worker.
job_id: job_chop_to_storage_a
worker_id: worker_ana
enabled: true
checkpoint: true # resume mid-cycle after rest
steps:
- step: travel
target: { poi: forest_patch_7 } # harvest node / landmark / coords
- step: harvest
resource: oak_log
tool: iron_axe # must be equipped
until: { inventory_full: true } | { qty: 20 }
- step: travel
target: { storage: storage_house_a }
- step: deposit
storage: storage_house_a
filter: { items: [oak_log] }
deposit_all: true
- step: travel
target: { lodging: lodging_b } # optional: only if stamina low (condition)
- step: rest_if_needed # implicit between cycles
job_id: job_mill_planks
worker_id: worker_ben
steps:
- step: travel
target: { storage: storage_house_a }
- step: withdraw
storage: storage_house_a
items: [{ template: oak_log, qty: 10 }]
- step: travel
target: { device: wood_mill_1 }
- step: craft
device: wood_mill_1
recipe: lumber_to_plank
qty: 10 # or until inputs exhausted
- step: travel
target: { storage: storage_house_b }
- step: deposit
storage: storage_house_b
filter: { items: [hardwood_plank] }
job_id: job_sell_planks
worker_id: worker_cara
steps:
- step: travel
target: { storage: storage_house_b }
- step: withdraw
storage: storage_house_b
items: [{ template: hardwood_plank, qty: 50 }]
- step: travel
target: { broker: market_c_broker }
- step: broker_sell
broker: market_c_broker
items: [{ template: hardwood_plank, qty: all }]
pricing: { mode: market | premium_pct: 5 | fixed_silver: 2 }
currency: silver # proceeds → employer bank (`10`)
7.2 Step types
| Step | Behavior |
|---|---|
travel |
Pathfind to target; time = distance / move_speed; stamina cost |
harvest |
Gather from world node (lumber, ore, herb); skill + tool modify tick time & yield |
withdraw |
Pull items from storage to worker inventory |
deposit |
Push items from worker inventory to storage |
craft |
Run recipe at device; uses worker skill for speed/failure |
enchant |
Run enchant ritual at altar; mana/stamina from worker pools; partial reagent loss on fail (17) |
broker_sell |
List or instant-sell at broker (10); proceeds to employer |
stall_sell |
Optional: player stall instead of broker |
rest_if_needed |
Branch: lodging if stamina/hunger thresholds |
wait |
Rare: wait for input stock (mill blocked until logs arrive) |
harvest_route |
Ordered harvest over specific node ids until carry threshold or nodes exhausted (compiled from route, see §7.3) |
7.3 Harvest loops — route block (implemented)
A high-level route on the job compiles server-side into the travel/harvest/deposit step cycle — this is what the gfx route editor saves:
job_id: route_oak_loop
mode: job_loop
route:
kind: harvest_loop
lodging_container_id: bed-1
outbound_waypoints: [{ x: 12.0, y: 10.0 }]
harvest_nodes: [oak-1, oak-2]
carry_return_ratio: 0.90 # head home when carry ≥ 90%
loop_wait_ticks: 90 # pause at home between loops
steps: [] # compiled from route
Compiled cycle: travel waypoints outbound → harvest_route over the listed nodes → travel waypoints reversed → travel to lodging bed → deposit all → rest_if_needed → wait → repeat.
Runtime reliability rules (harvest route):
- Drop-centric collection — after a harvest channel completes, the worker walks to each scattered loot pile itself and picks it up by drop id. Loot scatters up to ~1.2 m past the fixed harvest stand position, so chasing the drop (not the node) is what keeps collection reliable; far-side scatter can never stall the loop.
- Never abandon mid-collect — carry-full is only checked at node arrival and at pickup time (hard carry cap → head home to deposit); a node in progress is always finished and collected first.
- Path-failure skip — a node or waypoint with no viable path for ~3s is skipped with a
no path …worker error instead of stalling the route; leftover loot at a depleted node is re-collected on a later loop. - Rest rules — stamina only regens while idle, so the loop paces itself: a worker too tired to start a harvest channel rests in place and resumes the same node once recovered (never an
insufficient staminaretry spin);rest_if_neededat the bed tops stamina up to 90% so every loop starts rested; with no active job workers rest in place like any worker. - Carry capacity — route carry thresholds and encumbrance use the shared agent carry snapshot (same source as the sim's pickup/encumbrance gates), so heavy loads (e.g. oak logs) never fake a "full" reading after one node.
- Overburden redirect (≥ 95% carry) — a worker must not keep traveling to harvest / withdraw / pick up when already loaded. The job loop looks ahead for a step that reduces burden now (
deposit,craftthat shrinks mass with held recipe inputs even if a tool/station/stamina is blocking, orbroker_sellwith matching held items — not merely travel-to-broker). If one exists, the worker jumps to it and runs that step the same tick (sell/deposit/craft path themselves when out of range; craft surfaces tool/station blockers or rests for stamina instead of parking at bed). While Resting at lodging for a 90% bed top-up, an overburdened worker with a usable offload wakes at the mid-route recovery line (~40%) so they can saw/deposit/sell. If the plan has no usable offload action, the worker paths to their bed/lodging and surfaces statusoverburdened — holding …; no deposit/craft/sell step can lighten the pack.
7.4 Timing
tick_time(step) =
travel: path_distance / effective_move_speed(worker)
harvest: base_harvest_ticks / (1 + logging_skill × coeff) × qty
craft: recipe.craft_time_ticks / (1 + relevant_skill × coeff)
Travel time is first-class — distant forest + far mill = hire haulers or build closer storage.
7.5 Conditions & branching (Phase 6b+)
- step: withdraw
storage: storage_house_a
items: [{ template: oak_log, qty: 10 }]
on_fail: { wait_ticks: 60, retry: true } # mill idle until supply
8. Example factory line
Player owns residence B with lodging (2 beds), wood mill, links to storage A (near forest) and storage B (near residence).
| Worker | Job cycle |
|---|---|
| Ana | Forest → chop oak_log → deposit storage A → rest → repeat |
| Ben | Withdraw logs from A → mill at residence B → planks to storage B → repeat |
| Cara | Withdraw planks from B → travel to market C → broker sell for silver → bank proceeds to employer → repeat |
[Forest] ──Ana──► [Storage A] ──Ben──► [Mill @ Res B] ──► [Storage B] ──Cara──► [Broker @ Market C]
▲ │
└──────────── rest / food @ lodging B ◄─────────┘
Player stocks lodging pantry, pays one wage per world-clock day (base plus finished steps plus distance), outfits Ana with axe, maintains mill durability, and monitors profit = broker revenue − wages − training − food − fuel.
A level-1 crew that does this correctly is meant to come out ahead. One labor-day of a two-yield gather (about 80 units) sells to the matching merchant at full price, and that revenue clears the minimum wage with room for the walk. Milling or smelting pays about half again what selling the raw stack would, which covers the miller's wage. A second crew the same day hits the warm price band. The merchant's purse and those bands are what keep a large crew from emptying the town.
9. Outfitting
| Job type | Typical equipment |
|---|---|
| Lumber | axe, hands, backpack |
| Mining | pick, lantern, heavy pack |
| Hauling | large pack, cart (later) |
| Milling / forge | tongs, apron (recipe tool reqs) |
| Trading | light pack, market token |
Missing required tool → step fails / worker idles with error to employer the terminal client. Tools have durability — employer must repair or replace.
10. Economy integration
| Flow | Handling |
|---|---|
| Wages | Debit employer bank or residence treasury once per game day; one unpaid worked day becomes backpay, and further strike days do not add pay |
| Training | One-time fee to guild / trainer NPC |
| Broker sales | Proceeds to employer bank (config); physical coins not hauled unless withdraw_coins step |
| Currency | Copper, silver, gold, platinum (08 §8.5) |
| Taxes | Optional region sales tax on broker_sell (10) |
Workers do not need player online — sim runs on region worker while chunk is active (see §12).
Job-loop workers keep a workday. They harvest, craft, broker-sell, and list only during workers.work_phases (default: dawn through evening). Night sends them home to rest. At dawn each pool refills to labor_per_day + (level−1)×labor_per_level (default 40, plus 2 per level above 1). A finished harvest node spends labor_per_harvest; a finished craft batch spends labor_per_craft. An empty pool rests the same way as night. Below meal_need_ratio they do not start harvest or craft; they eat from pack or lodging, or idle at the lodge. Stamina does not regenerate during a harvest or craft channel. Players are not on this clock.
11. the terminal client / agent
flatland residence list
flatland residence link storage residence_b storage_house_a
flatland worker hire --residence residence_b --name Ana --wage 5_copper_per_100_ticks
flatland worker assign-bed worker_ana bed_2
flatland worker equip worker_ana --slot hands iron_axe
flatland worker train worker_ana --skill logging --fee 2_silver
flatland worker job set worker_ana --file jobs/ana_chop.yaml
flatland worker job enable worker_ana
flatland worker status worker_ana # step, stamina, location, errors
flatland factory status residence_b # all workers, storage levels, device queues
Agent JSON: full job state, storage snapshots, P&L estimate.
12. Simulation & region lifecycle
| Case | Behavior |
|---|---|
| Region active (players nearby or policy keeps hot) | Workers tick normally |
| Region cold / unloaded | Workers pause; state frozen; no wages accrue (config) or reduced accrual |
| Employer offline | Workers continue if region active |
Anti-exploit: cap workers per account; audit broker_sell for wash trading; residence must be in valid claimed territory.
13. Phasing
| Phase | Scope |
|---|---|
| 5 | Craft residences (building shell), plot prep, fixture anchors (20) |
| 6a | Hire 1 worker, simple job: harvest → deposit (1 storage) |
| 6b | Multi-step jobs, withdraw/craft/deposit, lodging + rest |
| 6c | Wages per tick, training, skills on job |
| 6d | Broker_sell step, factory dashboard the terminal client |
| 7 | Multi-worker lines, job conditions, carts, cross-storage wait |
15. Settlement workers (NPC towns)
Player-hired workers (§1–§14) and settlement workers share the same job engine (09, 18):
| Player workers | Settlement workers | |
|---|---|---|
| Owner | Player / guild | Authored settlement profile |
| Output | Any recipe player configures | Basic only — short/long sword, shield, leather armor, hardtack |
| Risk | PvP death, evil, wages |
No player-style permadeath; treasury-funded |
| Stock | Employer storage / broker | Shop shelf + food stand — depletes on purchase |
| Design | Player-built residence | World-build settlements/*.yaml (18 §6) |
Settlement job cycles run when the region is loaded; ops can seed initial stock at realm launch. Players compete with — and buy from — these shelves while building superior unique items via skill, quality rolls, and enchants.
16. Cross-references
| Topic | Doc |
|---|---|
| Recipes, devices, stations | 09 §7 |
| Storage chests | 08 §6 |
| Broker sell | 10 §4 |
| Attributes, stamina, skills | 11 |
| Settlement worker pools | 18 §6, 19 §9 |
| NPC definitions & AI | 19 |
| Buildings & schematics | 20 |
| Player housing / residence chests | 08 §6, 20 §9 |
Update 09 for device queue API; 10 for worker broker permissions.