Aggregate the whole suite wiki onto the Institution page
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.
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
# 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
|
||||
<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):
|
||||
|
||||
```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).*
|
||||
Reference in New Issue
Block a user