NPCs & Population

Every sector has a simulated population of real NPCs — not abstract numbers, but named individuals with jobs, homes, family ties, and schedules. The city has 10k–40k NPCs who get born, die, quit, emigrate, and witness what you do every day. Ignoring this system means losing control of your empire.


NPC Roles

From engine/internal/population/types.go:

Role Meaning
Owner One NPC per non-landmark building. Eigentümer / proprietor.
Staff Employees in commercial/industrial buildings. With wage.
Resident Lives in residential, no job. Birth pool for new owners/staff.
Unemployed Actively jobless (e.g. after quit, before replacement).

Phase-6+ specialties (server roadmap, partly reserved in pool): Auditor, Judge, Doctor, Teacher, Cop, CorpSec, Journalist, Lawyer, Guard.


NPC Attributes (0–100)

Each NPC has six psychological + economic values:

Attribute Meaning
Wealth 0–100+ (can exceed). Determines wealth tier (low/mid/high).
Corruption 0–100. Bribe susceptibility — high = easy to buy.
Fear 0–100. Reaction to intimidation. High fear = quits faster.
Loyalty 0–100. Loyalty to employer/family. < 20 = informant flag.
Observance 0–100. Witness clarity. < 20 = witnesses nothing.
Productivity 0–100. Job output modifier.

Schedule (StateAt)

Every NPC has a deterministic schedule as a pure function:

ShiftStart  = minute-of-day, default 540 (09:00)
ShiftEnd    = default 1020 (17:00)
Commute     = 10 (same sector) | 30 (adjacent) | 60 (far)

States: Home → CommutingOut → Working → CommutingIn → Home → OffDuty | Sick | Imprisoned | Grieving.

StateAt(tick) is O(1) — at any time-of-day you can ask “where is NPC X right now?”. Critical for the witness mechanic (below).


Witness System

NPCs at the crime scene observe events. Per NPC a ring buffer of 10 events:

WitnessEvent = {
  Day, EventType, ActorPlayerIdx, NodeID, SectorID,
  Fidelity (0-100, decay -10/day)
}

Gates:

Decay: −10 fidelity/day. At 0 → event pruned from buffer.

Fog-of-war: Other players see ActorPlayerIdx as −1 (unknown) — only you (or building owner) see who committed the crime.

Dedup: Same (EventType, Actor, Node) → existing entry refreshed to fidelity 100, no duplicate.

Player counter-actions against witnesses (full entries in Actions):


Informant Mechanic

If Staff.Loyalty ≤ 20:
  Staff.Informant = true (sticky — does not flip back on Loyalty recovery)

Informants leak witness events to the police — a primary path for your crimes ending up in investigations.

Reset: Only via Phase-3.F action. Otherwise: fire or replace NPC.

Visible: Building owner sees the informant flag in the exact-attribute view, others don’t.


Bribe Effect on NPCs

bribe-action on NPC:


Daily Lifecycle (End-of-Day)

Every tick runs the following population phases:

Mortality (age-driven death)

< 360 months (30 yrs)         → 0% chance
360-720 months (30-60 yrs)    → linear 0.001%/month-excess
> 720 months (60+ yrs)        → linear 0.003%/month-excess (3× multiplier)

Birth

Emigration

Quit (voluntary job loss for staff/owners)

Three independent channels:

Retirement (age-driven)

Replacement (death/quit → new NPC)

  1. Promotion: Local adult resident (20–40 yrs, matching wealth tier) → staff/owner
  2. Fresh spawn: If no candidate → fresh NPC with baseline-50 attributes

Immigration

Loyalty regen


Sector Aggregates

Each sector tracks 20+ counters (births, deaths-by-cause, quits, hires, etc.) as lifetime + today values plus 7-day rolling history (for UI sparklines).

Health Tier (demographic)

Tier Trigger
Thriving Births − Emigration > 5
Stable Default
Declining Emigration − Births > 5
Collapsing DeathsByViolence ≥ 10 OR (Emigration ≥ 10 AND Births/Emigration < 0.33)

Economy Tier (economic)

Tier Trigger
Booming WealthInflow ≥ 200 + Inflow/Outflow ≥ 3:1
Stable Default
Stagnating LaborSupply ≥ 5 + Supply/Demand ≥ 2:1
Recession Outflow ≥ 200 + Outflow/Inflow ≥ 3:1

The two tiers are independent — a sector can be Thriving (demographically) AND in Recession (economically) at the same time. “Brain drain” marker.


What you see as a player (fog-of-war)

Position Visible
Unscouted Sector Aggregates only (population, labor, migration, avg wealth). No individual NPCs.
Scouted Sector Owner/Staff lists with hinted attributes (“very_corrupt”, “very_loyal”). No exact values.
Own Building Staff with exact 0–100 values + informant flag + witness events (own crimes with ActorPlayerIdx, others’ as −1).
Admin No fog.

NPCDTO fields

From engine/internal/fixture/population.go:

NPCDTO {
  ID, Name, Surname, AgeYears
  Role                                // "owner" | "staff" | "resident" | "unemployed"
  HomeBuildingID, WorkBuildingID
  WealthTier                          // "low" | "mid" | "high"
  CorruptionHint, FearHint, LoyaltyHint   // hinted, categorical
  Wage, TenureDays
  State, CurrentNode, ShiftStart, ShiftEnd, NextTransition
  Exact?: {                           // owner/admin only
    Corruption, Fear, Loyalty, Observance, Productivity, Wealth
    Informant, BribedByRequester
    WitnessedEvents[]
  }
}

Sector Population DTO

SectorPopulationDTO {
  Total, Cap                          // Population + housing
  LaborDemand, LaborSupply, MigrationFlag  // +1 inflow / -1 outflow / 0 stable
  AvgWealth, AvgOwnerFear, AvgStaffLoyalty
  InformantCount                      // Count without identities
  AvgStaffProductivity
}

Strategic Implications

Deep dive: Once you start unionizing buildings, the Workforce & Strikes labor system applies — chronic-pattern detection, federal-heat penalties, crisis tiers, and bot adaptation all kick in.


Sources