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.
7.0 KiB
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.
<HediffDef Name="SomeDisorder">
<modExtensions>
<li Class="Contraband.TreatableConditionExtension">
<reductionPerSession>0.12</reductionPerSession>
</li>
</modExtensions>
</HediffDef>
| 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<Hediff> |
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):
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 — psychiatric care. Marks
mental-illness hediffs treatable, runs warden counselling sessions, builds
Ward_Recoverytoward a "ready for discharge" alert. The reference implementation. - Institution: Justice — rehabilitation. Its
reformscore 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).