# The Treatment Engine — shared rehabilitation
*`TreatmentProgram` + `TreatableConditionExtension`, in `Source/Core/TreatmentProgram.cs`.*
Core carries one more thing every "fix a held pawn over time" system needs and none should own alone:
the maths of a **treatment programme**. Sustained attention in a secured facility reduces a marked
condition, the room's quality helps or hurts, and once there is nothing left to reduce a **recovery
track** builds toward a dischargeable state.
It exists for the same reason the propensity engine does. Two systems want the identical loop pointed
at different states — **Ward** treats the mental illness that got a pawn committed; **Justice** wants
to rehabilitate the disposition that got one imprisoned — and without a shared engine each would grow
its own copy and drift. Core owns **only the maths**. Which interaction mode enrols a pawn, which
hediffs and thoughts carry the flavour, which jobs run the sessions, and which alert fires on
discharge all stay in the consuming mod.
> The engine does something concrete when there is a real condition to work through, and is a
> **no-op** otherwise. A colony that marks nothing treatable never notices it exists.
---
## The two pieces
### `TreatableConditionExtension` — marking a condition
A `DefModExtension` you attach to a `HediffDef` to declare it something a programme can reduce.
```xml
0.12
```
| Field | Default | Meaning |
|---|---:|---|
| `reductionPerSession` | `0.12` | Severity removed per **completed** session, *before* the caller's skill / facility / share scale it. |
A full course is several sessions by design — the programme has to be **sustained**, not run once. The
extension carries no flavour; it says only *how fast this condition yields*. Ward attaches it to
mental illness (via a soft, conditional patch on Rim Disorders' depression, anxiety, PTSD, OCD);
anything a mod or a player marks is treated identically, so opting a hediff in is a one-line patch.
### `TreatmentProgram` — the maths
A static, null-safe class. It holds no state of its own — it reads and mutates hediffs on the pawn.
| Call | Returns | What it does |
|---|---|---|
| `TreatableConditions(pawn)` | `List` | every marked hediff on the pawn that still has severity |
| `HasTreatableCondition(pawn)` | `bool` | is there any condition left to work through? |
| `ReduceConditions(pawn, strength)` | `void` | lower every marked condition by `reductionPerSession × strength`; remove any that reach ~0 |
| `FacilityQuality(pawn)` | `float 0.5..1.5` | how much the pawn's room helps or hurts |
| `AdvanceRecovery(pawn, recoveryDef, amount)` | `float` | advance (creating if absent) a recovery hediff, clamped to `1.0`; returns the new severity |
| `RecoveryLevel(pawn, recoveryDef)` | `float 0..1` | current level of that recovery track, or `0` |
---
## The numbers
### Facility quality
```
room == null OR psychologically outdoors → 0.75 (a poor makeshift facility, not zero)
otherwise → Clamp(0.6 + impressiveness / 120, 0.5, 1.5)
```
| Room impressiveness | Factor |
|---|---:|
| 0 (bare) | `0.60` |
| ~48 (decent) | `1.00` |
| ≥108 (impressive) | `1.50` (capped) |
| outdoors / none | `0.75` |
The clamp is deliberate: a grim, filthy, cramped facility heals worse, a calm clean one better, but a
palace can't trivialise the labour the programme costs (1.5× ceiling), and even nowhere is a poor
makeshift room, not a hard zero.
### Reducing a condition
```
h.Severity -= reductionPerSession × strength // per marked hediff
if h.Severity <= 0.001 → remove it
```
`strength` is the **caller's** combined factor — skill × facility quality × this pawn's share of the
session. The engine does not define it; the consumer does, so a one-on-one session at full skill in a
good room reduces far more than a distracted share in a squalid one.
### Advancing recovery
```
recovery = pawn's hediff of recoveryDef (created at 0.001 if absent)
recovery.Severity = min(1.0, recovery.Severity + amount)
```
The recovery track is a plain `0..1` severity the consumer supplies the def for (Ward's
`Ward_Recovery`). Core only advances it; the consumer decides what its top stage *unlocks* (Ward: a
"ready for discharge" alert) and — crucially — gives the hediff a **negative `severityPerDay`** so it
**decays without sustained attention**. Recovery you stop maintaining slips back; that decay is what
makes the programme a loop rather than a one-time unlock.
---
## The consumer contract
Core draws a hard line at "only the maths". A consumer owns everything with flavour:
| Core owns (the maths) | The consumer owns (the flavour) |
|---|---|
| `TreatableConditions` / `HasTreatableCondition` | which hediffs are marked treatable |
| `ReduceConditions` | the job/interaction that runs a session |
| `FacilityQuality` | the room role that makes a "facility" |
| `AdvanceRecovery` / `RecoveryLevel` | the recovery hediff def + what its stable stage unlocks |
| — | the discharge alert, the thoughts, the decay rate |
The idiomatic session, drawn from Ward's `JobDriver_PsychiatricCare` (the reference consumer):
```csharp
using Contraband;
float skill = 0.7f * social + 0.3f * medicine; // the consumer's own blend
float quality = TreatmentProgram.FacilityQuality(patient);
float strength = (0.5f + skill / 20f * 0.5f) * quality * share; // 1.0 share for the primary patient
// 1. Reduce the actual condition first.
TreatmentProgram.ReduceConditions(patient, strength);
// 2. Only once nothing is left to treat does recovery advance -- fix the illness, then stabilise.
if (!TreatmentProgram.HasTreatableCondition(patient))
{
TreatmentProgram.AdvanceRecovery(patient, MyDefOf.RecoveryHediff, 0.15f * quality * share);
}
```
"Reduce the condition, *then* build recovery" is the shape Ward uses, but it is a convention, not a
rule Core enforces — a rehabilitation consumer with no clinical condition to clear (Justice's reform)
can advance a recovery track from the first session and read `RecoveryLevel` to gate a parole.
---
## The two consumers
- **[Institution: Ward](https://git.onetick.ninja/flan/rimworld-ward)** — psychiatric care. Marks
mental-illness hediffs treatable, runs warden counselling sessions, builds `Ward_Recovery` toward a
"ready for discharge" alert. The reference implementation.
- **Institution: Justice** — rehabilitation. Its `reform` score is the disposition axis punishment
moves; the recovery track is the natural home for a *sustained rehabilitation programme* that gates
parole on the same shared engine, so the two systems agree on "getting better" instead of each
inventing it.
The point, exactly as with propensity: one engine, two states, no drift.
---
*Part of the **Institution** suite. AI disclosure: developed with substantial assistance from Claude (Anthropic).*