Wiki: player-facing rewrite of every layer + add a scenario FAQ, linked from Home

This commit is contained in:
flan
2026-07-16 02:18:25 +00:00
parent ff703271ba
commit 8250dcb369
32 changed files with 1654 additions and 2510 deletions
+53 -90
View File
@@ -2,22 +2,22 @@
*The connection that turns the pipeline into a cycle.*
This is the module that makes policing **govern** rather than merely clean up. Everything else in
Justice reacts to one pawn: this reactor's *state* is the whole colony, and it feeds **back** into
every pawn's disposition. Crime that goes unanswered emboldens everyone a little; visible justice
deters everyone a little. The reason to punish is not just this prisoner — it is the message it sends
the rest, and here that message is a number they all read.
This is the part that makes policing **govern** rather than merely clean up. Everything else in Justice
reacts to one pawn: this reacts to the *whole colony*, and it feeds **back** into every pawn's
disposition. Crime that goes unanswered emboldens everyone a little; visible justice deters everyone a
little. The reason to punish is not just this prisoner — it is the message it sends the rest, and here
that message is a number they all read.
---
## The climate of order
Every map carries a `MapComponent_Deterrence` holding one value:
Every colony carries one order value:
| | |
|---|---|
| **Range** | `0.0` (lawless) … `1.0` (iron) |
| **Baseline** | `0.5` — an ordinary colony |
| **Range** | 0.0 (lawless) … 1.0 (iron) |
| **Baseline** | 0.5 — an ordinary colony |
| **Below baseline** | crime pays; dispositions run **hot** |
| **Above baseline** | order holds; dispositions run **cool** |
@@ -25,50 +25,40 @@ It is nudged by two events and, left alone, forgets.
### The nudges
| Event | Source | Nudge | Written by |
|---|---|---|---|
| A crime, unanswered | `Justice.RecordCrime(perp)` | **−0.08** | Justice, Gangs (fights) |
| Visible justice done | `Justice.RecordPunishment(map)` | **+0.12** | Justice (`Discipline.Punish`) |
| Event | Nudge |
|---|---|
| A crime, unanswered | **−0.08** |
| Visible justice done (a punishment) | **+0.12** |
Both clamp the result to `[0, 1]`. Note the asymmetry: **punishment (+0.12) outweighs crime (−0.08)
Both stay clamped to the 0–1 range. Note the asymmetry: **punishment (+0.12) outweighs crime (−0.08)
by 1.5×.** A colony that answers every offence does not merely break even — it ratchets *above*
baseline into "order holds" territory. This is the deterrence dividend, and it is deliberate: justice
seen to be done buys more order than the crime cost.
`RecordCrime` also writes the record — it increments `crimesCommitted` and stamps `lastCrimeTick` on
the perpetrator — so the same event that moves the climate is the event classification and parole
later see. `RecordPunishment` moves only the climate; the *record* side of punishment (the reform
shift) is [Discipline](Discipline-and-Reform.md)'s job.
The same crime that moves the climate also marks the culprit's record — the offence that shifts the
colony's mood is the one classification and parole will remember later. A punishment moves only the
climate; the reform side of a punishment — how the offender themselves changes — is
[Discipline](Discipline-and-Reform.md)'s job.
### The drift
```
every 2500 ticks: level = MoveTowards(level, 0.5, 0.0015)
```
Memory fades. With nothing happening, the climate creeps back toward ordinary at about **0.0015 every
in-game while (roughly one nudge every 2500 ticks)** — which works out to:
Memory fades. With nothing happening, the climate creeps back toward ordinary at **0.0015 per step,
one step every 2500 ticks** — which works out to:
**drift per in-game day ≈ 0.036**
```
drift per in-game day = (60000 / 2500) * 0.0015 = 24 * 0.0015 = 0.036 / day
```
So a single unanswered crime (`−0.08`) takes roughly `0.08 / 0.036 ≈ 2.2 days` to heal on its own —
or one punishment (`+0.12`) to over-answer instantly. An iron colony you stop maintaining slides back
to baseline over about two weeks; it does not stay stern for free.
So a single unanswered crime (−0.08) takes roughly `0.08 / 0.036 ≈ 2.2 days` to heal on its own — or
one punishment (+0.12) to over-answer instantly. An iron colony you stop maintaining slides back to
baseline over about two weeks; it does not stay stern for free.
---
## The feedback — how it reaches every pawn
This is the loop. The climate is read back into `Propensity.Nurture` (in Core) as a multiplier:
This is the loop. The climate is read back into every colonist's upbringing as a multiplier on their
propensity:
```
DeterrenceFactor(pawn) = Lerp(1.3, 0.7, level) // = 1.3 - 0.6 * level
Nurture(pawn) = ... * DeterrenceFactor(pawn)
```
| `level` | Factor | Effect on every pawn's disposition |
| Order level | Factor | Effect on every pawn's disposition |
|---|---|---|
| 0.00 (lawless) | **1.300** | +30% hotter — crime pays, everyone feels it |
| 0.30 | 1.120 | +12% |
@@ -79,55 +69,42 @@ Nurture(pawn) = ... * DeterrenceFactor(pawn)
Two things to notice:
- **Baseline is the neutral point, by design.** A default colony sits at `0.5`, which is a factor of
exactly `1.0` — ordinary order neither inflames nor calms. That symmetry is deliberate. If baseline
ran hot (as an earlier tuning did), ordinary order would nudge propensity up, breed a little more
crime, drop order, and feed a slow runaway. Neutral-at-baseline means only a colony that lets order
*slide below* ordinary earns the hot multiplier, and only one that pushes *above* it earns the calm.
- **The swing is `0.7×` to `1.3×`, symmetric around `1.0`** — a `±30%` spread applied to *everyone's*
nurture at once. This is the multiplier that makes catching one pawn matter to the disposition of
- **Baseline is the neutral point, by design.** A default colony sits at 0.5, which is a factor of
exactly 1.0 — ordinary order neither inflames nor calms. That symmetry is deliberate. If baseline
ran hot, ordinary order would nudge propensity up, breed a little more crime, drop order, and feed a
slow runaway. Neutral-at-baseline means only a colony that lets order *slide below* ordinary earns
the hot multiplier, and only one that pushes *above* it earns the calm.
- **The swing is 0.7× to 1.3×, symmetric around 1.0** — a ±30% spread applied to *everyone's*
disposition at once. This is the multiplier that makes catching one pawn matter to the disposition of
the rest.
### PolicingBootstrap — reconnecting the loop across the mod boundary
### When it applies
Core keeps `Propensity.DeterrenceFactor` as a neutral seam — a `Func<Pawn,float>` that returns `1f`
until something fills it. Core alone never has to know Justice exists; that one seam is what lets Core
stay a dependency-free leaf while the deterrence loop runs *through* it.
At startup, `PolicingBootstrap` fills the seam:
```csharp
Propensity.DeterrenceFactor = pawn => {
var d = pawn?.Map?.GetComponent<MapComponent_Deterrence>();
return d != null ? Mathf.Lerp(1.3f, 0.7f, d.Level) : 1f; // neutral (1.0) at baseline 0.5
};
```
So **only when Justice is installed** does the climate bend disposition; without it, Core reads a flat
`1.0` and pawns are indifferent to order. This is the deterrence feedback loop, reconnected across the
mod boundary without Core ever depending on the justice layer. (If the pawn is off-map — caravan, in
transit — there is no map component, and the factor falls back to a neutral `1.0`.)
This bending of behaviour only happens while **Policing is installed**. Core on its own reads a flat,
neutral 1.0 — colonists are indifferent to order — and only Policing wires the climate into their
disposition. A colonist who is off the map (in a caravan, in transit) has no local climate to read, so
they fall back to neutral too.
---
## Worked example — a day at the institution
The colony starts at baseline `0.5` (factor `1.05`). Over one day:
The colony starts at baseline 0.5 (factor 1.05). Over one day:
| Step | Event | `level` | Factor |
| Step | Event | Order level | Factor |
|---|---|---|---|
| start | — | 0.50 | 1.050 |
| 1 | Prisoner A shanks a guard (crime, unanswered) | 0.42 | 1.106 |
| 2 | Prisoner B foments trouble (crime, unanswered) | 0.34 | 1.162 |
| 3 | Warden punishes A (`RecordPunishment`) | 0.46 | 1.078 |
| 4 | Warden punishes B (`RecordPunishment`) | 0.58 | 0.994 |
| 3 | Warden punishes A | 0.46 | 1.078 |
| 4 | Warden punishes B | 0.58 | 0.994 |
| overnight | nothing happens, drift ≈ −0.036 toward 0.5 | 0.544 | 1.019 |
Two crimes cost `−0.16`; two punishments returned `+0.24`. The colony ends the day at `0.58` —
**above** where it started — because punishment out-answers crime. Every pawn's disposition dipped
hotter as the crimes landed (`1.05 → 1.16`) and then cooled below neutral once order was reasserted
(`0.994`). By morning the drift has begun erasing the gain, and if nothing keeps the pressure on, the
colony sinks back to its slightly-hot baseline over the next couple of weeks.
Two crimes cost −0.16; two punishments returned +0.24. The colony ends the day at 0.58 — **above**
where it started — because punishment out-answers crime. Every pawn's disposition dipped hotter as the
crimes landed (1.05 → 1.16) and then cooled below neutral once order was reasserted (0.994). By morning
the drift has begun erasing the gain, and if nothing keeps the pressure on, the colony sinks back to its
slightly-hot baseline over the next couple of weeks.
That arc — hot when crime pays, cool when justice is seen, forgetful when neither happens — is the
whole reason discipline is not inert. You are not punishing a pawn; you are setting the temperature of
@@ -140,27 +117,13 @@ the room.
- **Answer crime, visibly and promptly.** Each punishment is worth 1.5 crimes of order. A colony that
reliably punishes climbs *above* baseline and cools everyone; a colony that lets offences slide
sinks below and heats everyone — a spiral, because hotter pawns commit more crime.
- **Don't coast on a past crackdown.** The climate drifts back to baseline at `0.036/day`. Order is a
- **Don't coast on a past crackdown.** The climate drifts back to baseline at 0.036/day. Order is a
maintenance cost, not a one-time purchase.
- **Push past baseline if you want calm.** Neutral disposition needs `level ≈ 0.571`; ordinary
(`0.5`) still runs 5% hot. A steady rhythm of caught-and-punished offences is what holds you there.
- **A lawless spell is self-feeding.** At `level 0.3` every pawn is `1.19×` more disposed; more crime
follows, driving the level lower still. Break the cycle with punishments, not patience.
---
## For modders
```csharp
Justice.RecordCrime(perpetrator); // -0.08 climate, +1 crime, stamps lastCrimeTick
Justice.RecordPunishment(map); // +0.12 climate
float level = map.GetComponent<MapComponent_Deterrence>().Level; // raw 0..1
```
`RecordCrime` is the writer any module calls when a pawn does something the colony would police —
Institution: Gangs calls it on rival fights, for instance. `RecordPunishment` is called by
`Discipline.Punish`. The component and statics live in the `Contraband` namespace (shared across the
suite since Justice's extraction from Contraband).
- **Push past baseline if you want calm.** Neutral disposition needs an order level of about 0.571;
ordinary (0.5) still runs 5% hot. A steady rhythm of caught-and-punished offences is what holds you
there.
- **A lawless spell is self-feeding.** At an order level of 0.3 every pawn is 1.19× more disposed; more
crime follows, driving the level lower still. Break the cycle with punishments, not patience.
---