Wiki/Home.md is the suite's front door; every layer's wiki now mirrors here under Wiki/<layer>/ (core, contraband, justice, gangs, ward), so the whole suite reads in one place with the index linking to the local pages. The layer repos stay canonical -- Tools/sync-wiki.sh refreshes the aggregated copy on demand. The README's main page points to it.
317 lines
16 KiB
Markdown
317 lines
16 KiB
Markdown
# Commitment
|
||
|
||
How involuntary psychiatric commitment actually works in play: how a colonist becomes a ward patient,
|
||
what the treatment station does, how a room turns into a ward, who does the counselling, what the
|
||
treatment buys, and what happens if you commit someone and then forget about them.
|
||
|
||
Every def and class name below is the real one from the mod source. The `Ward_` prefix marks a
|
||
def; the C# class names are the workers behind them.
|
||
|
||
---
|
||
|
||
## The loop in one paragraph
|
||
|
||
You **arrest** a colonist (or otherwise take a prisoner) and set their interaction mode to
|
||
**psychiatric care**. You build a **treatment station** in their cell, which turns the room into a
|
||
**psychiatric ward**. A warden walks over, sits, and **counsels** them; each session adds a little
|
||
`Ward_UnderTreatment` severity, which **lowers their mental-break threshold**. That severity
|
||
**decays** at 0.15/day, so the effect fades unless wardens keep attending. Counselling also gives a
|
||
small mood lift (`Ward_Counselled`). Neglect a committed patient — leave them with no active treatment
|
||
hediff — and once a day they gain `Ward_Neglected`, a mood *penalty* that drags them back toward the
|
||
break that got them committed. Treat them and they stabilise; forget them and they don't. That
|
||
feedback loop is the entire mod.
|
||
|
||
---
|
||
|
||
## Step 1 — Becoming a ward patient
|
||
|
||
Commitment reuses vanilla's arrest → prisoner transition. You don't invent a new pawn state; you take
|
||
a prisoner (arrest your own colonist, or a raider) and then flip on a **non-exclusive interaction
|
||
mode**.
|
||
|
||
### `Ward_PsychiatricCare` — the interaction mode
|
||
|
||
| Field | Value | Why |
|
||
|---|---|---|
|
||
| Def type | `PrisonerInteractionModeDef` | A Def, not the compiled `GuestStatus` enum — that's the whole point |
|
||
| `defName` | `Ward_PsychiatricCare` | |
|
||
| `label` | "psychiatric care" | Shown in the prisoner's interaction dropdown |
|
||
| `listOrder` | `150` | Sits between vanilla's `ReduceResistance` (100) and `Release` (200) |
|
||
| `isNonExclusiveInteraction` | `true` | **Stacks** with recruit/convert/work instead of stealing the radio button |
|
||
| `mustBeAwake` | `false` | You can flag a downed or sleeping patient for care; the *work giver* decides when to actually treat |
|
||
| `allowOnWildMan` | `false` | A wild man isn't a commitment case |
|
||
| `allowInClassicIdeoMode` | `true` | Available without Ideology's ideoligion system |
|
||
|
||
**Non-exclusive is load-bearing.** Vanilla's recruit/convert/enslave/release/execute modes are
|
||
mutually exclusive — you pick one from a radio group. Psychiatric care is modelled on vanilla's own
|
||
*Bloodfeed* and *Study* modes, which are toggles layered *on top* of the exclusive choice. So a
|
||
patient can be set to **recruit AND psychiatric care at once**: you counsel the sad colonist toward
|
||
stability while also chipping at their resistance. It also means Ward doesn't have to ship a
|
||
cross-product of `workAndPsychiatricCare` variants to coexist with *Prison Labor*'s work modes — both
|
||
just toggle on.
|
||
|
||
The harness proves this on a live pawn: after `ToggleNonExclusiveInteraction(Ward_PsychiatricCare,
|
||
true)` and then `SetExclusiveInteraction(AttemptRecruit)`, **both** modes report enabled
|
||
(`live.stacksWithRecruit = True`).
|
||
|
||
---
|
||
|
||
## Step 2 — The treatment station
|
||
|
||
Flagging a patient for care does nothing on its own. Treatment happens *at a station, in the
|
||
patient's own room*. Without one, a patient flagged for care in an ordinary cell simply goes
|
||
untreated — which is the point of the neglect thought (Step 6).
|
||
|
||
### `Ward_TreatmentStation` — the building
|
||
|
||
> *"A desk, a chair bolted to the floor, and a locked cabinet of sedatives. A warden set to
|
||
> psychiatric care will use it to counsel patients held in this room."*
|
||
|
||
| Field | Value | Why |
|
||
|---|---|---|
|
||
| `defName` | `Ward_TreatmentStation` | |
|
||
| Parent | `BuildingBase` | Ordinary passable furniture |
|
||
| Cost | **40 Steel + 2 Industrial medicine** | Deliberately cheap |
|
||
| `WorkToBuild` | `1600` | A quick build |
|
||
| `MaxHitPoints` | `120` | |
|
||
| `researchPrerequisites` | `MedicineProduction` | The one research gate |
|
||
| `size` | `(2,1)` | A two-tile desk |
|
||
| `graphicClass` | `Graphic_Single` | One texture, not a rotation set — nothing to keep in sync |
|
||
| `designationCategory` | `Misc` | |
|
||
| `passability` | `PassThroughOnly`, `pathCost 60` | Pawns squeeze past it; it doesn't wall a cell |
|
||
| `Flammability` | `1.0` | It burns |
|
||
|
||
**It's cheap on purpose.** The real cost of running a ward is not the 40 steel. It is the **warden
|
||
hours** you spend counselling and the **labour you give up** by not putting the patient to work. The
|
||
building is just the gate that says "this room is set up to treat people."
|
||
|
||
---
|
||
|
||
## Step 3 — The room becomes a ward
|
||
|
||
Once a treatment station stands in a room that already holds prisoner beds, the room's *role* changes
|
||
from prison cell to psychiatric ward.
|
||
|
||
### `Ward_PsychWard` — the room role
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Def type | `RoomRoleDef` (`workerClass` is a public field — no patch needed) |
|
||
| `defName` | `Ward_PsychWard` |
|
||
| `label` | "psychiatric ward" |
|
||
| `workerClass` | `Ward.RoomRoleWorker_PsychWard` |
|
||
| `relatedStats` | Impressiveness, Cleanliness, Space |
|
||
|
||
Vanilla already ships `PrisonCell`, `PrisonBarracks` and `Hospital` on exactly this rail; the ward is
|
||
the fourth sibling. The scoring worker, `RoomRoleWorker_PsychWard.GetScore`, is where the care goes:
|
||
|
||
```
|
||
score = 0 if stations == 0 OR prisonerBeds == 0
|
||
score = 1_000_000 × prisonerBeds otherwise
|
||
```
|
||
|
||
Two design decisions are baked into that formula:
|
||
|
||
- **Gated on a station.** The score is **zero** unless the room actually contains a
|
||
`Ward_TreatmentStation` *and* at least one prisoner bed. This is deliberate: without the gate, any
|
||
ordinary prison cell full of prisoner beds would start scoring as a ward and quietly steal the
|
||
`PrisonCell` role from vanilla — a compatibility bug dressed up as a feature. Build the station and
|
||
it's a ward; don't and your cells keep their vanilla role, untouched.
|
||
- **1e6, not a hard-coded constant.** Vanilla's room roles score in the `~1e5` range. The ward must
|
||
*outscore* `PrisonCell` for the same room or it would read as a cell block. Multiplying by
|
||
1,000,000 clears that range without pinning to a magic number a future RimWorld patch might move.
|
||
(The harness's `FakeDLC` fixture deliberately adds a greedy competing role at `1e5 × beds`, and the
|
||
ward still wins the room.)
|
||
|
||
**Crucially, it is still a prison cell.** Re-labelling the role does not release anyone. `Room.isPrisonCell`
|
||
is a cached field set only when the room's shape changes — never derived from the role — so a ward is
|
||
a prison cell *and* a ward simultaneously. Containment, food delivery, and prison breaks all keep
|
||
working. This is the pair of claims the harness holds together: `room.roleIsWard = True` **and**
|
||
`room.stillPrisonCellAsWard = True`.
|
||
|
||
---
|
||
|
||
## Step 4 — The warden does the work
|
||
|
||
### `Ward_WardenPsychiatricCare` — the work giver
|
||
|
||
| Field | Value | Why |
|
||
|---|---|---|
|
||
| `defName` | `Ward_WardenPsychiatricCare` | |
|
||
| `giverClass` | `Ward.WorkGiver_Warden_PsychiatricCare` | A **new** class extending `WorkGiver_Warden` |
|
||
| `workType` | `Warden` | Assigned like any other warden work |
|
||
| `verb` / `gerund` | "treat" / "treating" | |
|
||
| `priorityInType` | `70` | Above chat (60), below feeding — an untreated patient deteriorates, a bored one doesn't |
|
||
| `requiredCapacities` | Talking, Hearing | A mute or deaf warden can't counsel |
|
||
|
||
The class extends `WorkGiver_Warden` and its `JobOnThing` refuses the job unless **all** of these
|
||
hold:
|
||
|
||
1. The pawn is a prisoner of the colony being taken care of (`ShouldTakeCareOfPrisoner`).
|
||
2. `IsInteractionEnabled(Ward_PsychiatricCare)` — asked, not "is this *the* mode," because the mode is
|
||
non-exclusive and the patient may also be set to recruit or forced labour.
|
||
3. The patient is **awake, not in a mental state, and not downed** — counselling someone mid-break or
|
||
unconscious isn't counselling.
|
||
4. The warden can reserve the patient.
|
||
5. A `Ward_TreatmentStation` exists **in the patient's own room** (not `PsychologicallyOutdoors`), is
|
||
reservable, and isn't forbidden. You can't treat someone through a wall from the station two
|
||
blocks over.
|
||
|
||
**Being a new class is the entire compatibility story** (see The Compat Harness for the proof):
|
||
|
||
- *Custom Prisoner Interactions* prefixes/postfixes the **named** vanilla warden givers (`_Chat`,
|
||
`_Convert`, `_Enslave`, `_ReleasePrisoner`). It literally cannot see `WorkGiver_Warden_PsychiatricCare`,
|
||
so it can't break it.
|
||
- *Prison Commons* postfixes `WorkGiver_Warden.ShouldSkip` on the **base** class. Ward's giver
|
||
inherits that method and doesn't override it, so Ward respects prison-commons areas **for free**,
|
||
without Ward knowing Prison Commons exists.
|
||
|
||
### `Ward_ProvidePsychiatricCare` — the job
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| `defName` | `Ward_ProvidePsychiatricCare` |
|
||
| `driverClass` | `Ward.JobDriver_PsychiatricCare` |
|
||
| `casualInterruptible` | `false` |
|
||
|
||
> Note: the `JobDef` and the `PrisonerInteractionModeDef` deliberately have **different** defNames.
|
||
> `[DefOf]` binds fields to defs by name, so two defs sharing one name couldn't both be reached from
|
||
> the `WardDefOf` class.
|
||
|
||
The driver, `JobDriver_PsychiatricCare`, walks the warden to the patient and runs a counselling toil:
|
||
|
||
- **Session length:** `SessionTicks = 1200` — about **20 in-game minutes**.
|
||
- The wait toil uses `activeSkill = Social` and shows a progress bar; it fails out if the patient
|
||
despawns, is forbidden, falls asleep, or enters a mental state partway through.
|
||
- On completion it applies treatment, grants the counselled mood memory, fires a `DeepTalk` social
|
||
interaction (so the relationship builds and the *next* session lands harder), and awards **60 Social
|
||
XP** to the warden.
|
||
|
||
---
|
||
|
||
## Step 5 — What treatment buys: `Ward_UnderTreatment`
|
||
|
||
Each completed session adds severity to a single hediff. The severity is **skill-scaled**:
|
||
|
||
```
|
||
gain = 0.20 + (wardenSocialLevel / 20) × 0.30 → range 0.20 .. 0.50 per session
|
||
```
|
||
|
||
| Warden Social skill | Severity gained per session |
|
||
|---|---|
|
||
| 0 | 0.20 |
|
||
| 5 | 0.275 |
|
||
| 10 | 0.35 |
|
||
| 15 | 0.425 |
|
||
| 20 | 0.50 |
|
||
|
||
The floor is deliberate: even an unskilled warden buys **0.20** per session. A bad ward is *neglect*,
|
||
not *zero* — a clumsy counsellor is still worth something. Severity is capped at `maxSeverity = 1.0`.
|
||
|
||
### The hediff
|
||
|
||
| Field | Value | Why |
|
||
|---|---|---|
|
||
| `defName` | `Ward_UnderTreatment` | |
|
||
| `hediffClass` | `HediffWithComps` | |
|
||
| `label` | "under psychiatric care" | |
|
||
| `isBad` | `false` | It's a good hediff; won't be treated as an injury |
|
||
| `scenarioCanAdd` | `false` | Can't be granted by scenario editor |
|
||
| `maxSeverity` | `1.0` | |
|
||
| **Decay** | `severityPerDay = −0.15` | Roughly a week from a full course back to nothing, unattended |
|
||
| **Effect** | `MentalBreakThreshold −0.10` (stage 0) | A *negative* offset means the pawn breaks at a **lower** mood — i.e. **breaks less often** |
|
||
|
||
**Decay is the mechanic.** Because severity bleeds off at 0.15/day, a patient treated once and then
|
||
ignored slides right back. Sustained treatment keeps the hediff topped up and the break threshold
|
||
suppressed; stopping lets it fade. Treatment is a *programme*, not a one-time cure. (The
|
||
`MentalBreakThreshold −0.10` value is a first-guess, not yet playtested — see the "unplaytested"
|
||
caveats in the README.)
|
||
|
||
---
|
||
|
||
## Step 6 — The other half: neglect
|
||
|
||
A ward you don't staff is not a neutral place to keep someone. It is a *worse* one. Without a cost,
|
||
"arrest the sad colonist and park them" would be a free way to remove a problem pawn from play. It
|
||
isn't free.
|
||
|
||
### `MapComponent_WardNeglect`
|
||
|
||
Once per **in-game day** (`CheckIntervalTicks = 60000`), this component scans every spawned prisoner
|
||
of the colony. For each prisoner flagged for `Ward_PsychiatricCare` who does **not** currently have a
|
||
`Ward_UnderTreatment` hediff, it grants the `Ward_Neglected` thought.
|
||
|
||
The absence of the treatment hediff is the signal *by design*: because the hediff decays on its own,
|
||
its absence means **no warden has been near this patient in days** — not merely that they aren't being
|
||
counselled at this exact instant.
|
||
|
||
### The two thoughts
|
||
|
||
| Thought | Mood | Duration | Stack | Meaning |
|
||
|---|---|---|---|---|
|
||
| `Ward_Counselled` | **+6** | 2 days | up to 3 | "Someone sat with me and listened. It helped, a little." |
|
||
| `Ward_Neglected` | **−8** | 3 days | up to 4 | "They locked me in here for my own good and then forgot about me." |
|
||
|
||
Neglect is asymmetric — a −8 penalty stacking four deep (−32) badly outweighs three counselling lifts
|
||
(+18). That's intentional: a neglected patient's mood falls, which raises their break risk, which is
|
||
exactly the crisis you committed them to avoid. The ward can *manufacture* the break it was built to
|
||
prevent. Staff it, or don't build it.
|
||
|
||
> **Known rough edge (from the README's "Open" list):** neglect currently keys off "no
|
||
> `Ward_UnderTreatment` hediff." A patient treated once a week technically dodges the neglect thought
|
||
> on the single day the hediff expires. A real last-treated timestamp would be cleaner. Documented,
|
||
> not yet fixed.
|
||
|
||
---
|
||
|
||
## How it stacks with recruitment (and everything else)
|
||
|
||
Because `Ward_PsychiatricCare` is non-exclusive, it layers onto whatever else you've set:
|
||
|
||
| You want to… | Set | Result |
|
||
|---|---|---|
|
||
| Just stabilise a broken colonist | Psychiatric care | Wardens counsel; break threshold drops |
|
||
| Talk a captured raider down *and* recruit them | Psychiatric care **+** Attempt recruit | Both run — counselling lifts mood while resistance is chipped |
|
||
| Convert *and* treat | Psychiatric care **+** convert | Both toggle on |
|
||
| Work a patient *and* treat them | Psychiatric care **+** Prison Labor's work mode | Both apply. Working a fragile patient is bleak — and it's your call to make |
|
||
|
||
The last row is the darkest option the mod exposes, and it exposes it on purpose: Ward doesn't
|
||
forbid working a patient, it just makes the trade-off visible.
|
||
|
||
Because a ward patient is a genuine vanilla prisoner, everything the wider Institution suite does to
|
||
prisoners applies to them unchanged — a committed patient can be classified, disciplined, paroled,
|
||
searched, and can conceal or improvise contraband. Ward writes no integration code for any of that;
|
||
the patient satisfies "held pawn" and the rest follows. See **Home** for the suite map and **The
|
||
Compat Harness** for how all of it is verified in one running game.
|
||
|
||
---
|
||
|
||
## Quick reference — every Ward def
|
||
|
||
| defName | Type | Class (if any) | Key numbers |
|
||
|---|---|---|---|
|
||
| `Ward_PsychiatricCare` | PrisonerInteractionModeDef | — | non-exclusive; listOrder 150 |
|
||
| `Ward_TreatmentStation` | ThingDef | `Building` | 40 steel + 2 medicine; WorkToBuild 1600; MedicineProduction research |
|
||
| `Ward_PsychWard` | RoomRoleDef | `RoomRoleWorker_PsychWard` | score = 1e6 × prisonerBeds (station-gated) |
|
||
| `Ward_WardenPsychiatricCare` | WorkGiverDef | `WorkGiver_Warden_PsychiatricCare` | priority 70; Talking + Hearing |
|
||
| `Ward_ProvidePsychiatricCare` | JobDef | `JobDriver_PsychiatricCare` | 1200-tick session; +60 Social XP |
|
||
| `Ward_UnderTreatment` | HediffDef | `HediffWithComps` | +0.20–0.50/session; −0.15/day decay; −0.10 break threshold |
|
||
| `Ward_Counselled` | ThoughtDef | `Thought_Memory` | +6 mood, 2 days, stack 3 |
|
||
| `Ward_Neglected` | ThoughtDef | `Thought_Memory` | −8 mood, 3 days, stack 4 |
|
||
| — | MapComponent | `MapComponent_WardNeglect` | daily scan (60000 ticks) |
|
||
|
||
---
|
||
|
||
## Part of the Institution suite
|
||
|
||
Institution: Ward is one mod in the **Institution** suite of RimWorld 1.6 mods — Ward, plus
|
||
**Institution: Core**, **Institution: Contraband**, **Institution: Justice**, **Institution: Gangs**,
|
||
and **Foul Play**. Each stands alone; together they interlock. A committed patient rides the same
|
||
prisoner rail the rest of the suite polices, so a psychiatric ward is also a secure context where a
|
||
patient can conceal and improvise contraband exactly as a prisoner can.
|
||
|
||
## AI disclosure
|
||
|
||
This mod was developed with substantial assistance from Claude (Anthropic), including the
|
||
compatibility analysis, the def and C# implementation, and the test harness.
|