Wiki: player-facing rewrite of every layer + add a scenario FAQ, linked from Home
This commit is contained in:
+55
-120
@@ -1,61 +1,40 @@
|
||||
# The Treatment Engine — shared rehabilitation
|
||||
|
||||
*`TreatmentProgram` + `TreatableConditionExtension`, in `Source/Core/TreatmentProgram.cs`.*
|
||||
*The shared maths behind every "fix a held pawn over time" system in the suite.*
|
||||
|
||||
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.
|
||||
Core carries one more thing every rehabilitation-style 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's nothing left to reduce a **recovery
|
||||
track** builds toward a state where the pawn can be discharged.
|
||||
|
||||
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.
|
||||
at different things — **Ward** treats the mental illness that got a pawn committed; **Justice**
|
||||
rehabilitates the disposition that got one imprisoned — and without a shared engine each would grow its
|
||||
own copy and drift apart. Core owns **only the maths**. Which interaction enrols a pawn, which
|
||||
conditions and moods carry the flavour, which jobs run the sessions, and which alert fires on discharge
|
||||
all live in the mod using it.
|
||||
|
||||
> 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 engine does something only when there's a real condition to work through, and does nothing
|
||||
> otherwise. A colony that never marks anything treatable never notices it exists.
|
||||
|
||||
---
|
||||
|
||||
## The two pieces
|
||||
## How treatment plays out
|
||||
|
||||
### `TreatableConditionExtension` — marking a condition
|
||||
A condition has to be **marked treatable** before a programme can touch it (Ward marks mental illness
|
||||
this way; a modder or player can mark anything — see the [Modder API](Modder-API.md) page). Once a
|
||||
condition is marked, treatment runs in sessions:
|
||||
|
||||
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` |
|
||||
1. **Each completed session removes a slice of the condition's severity.** The base amount is **0.12
|
||||
severity per session**, *before* it's scaled by the treating pawn's skill, the facility's quality,
|
||||
and how much of the session that patient actually gets. When a condition's severity reaches zero
|
||||
it's gone.
|
||||
2. **A full course is several sessions by design.** The programme has to be *sustained* — you can't
|
||||
fix a pawn in a single visit.
|
||||
3. **Once nothing is left to treat, continued care builds a recovery track** from 0 toward 1
|
||||
(discharge-ready). Fix the illness first, then stabilise.
|
||||
4. **The recovery track decays on its own if you stop.** Recovery you stop maintaining slips back down
|
||||
— which is what makes the whole thing a loop you keep up, not a one-time unlock.
|
||||
|
||||
---
|
||||
|
||||
@@ -63,96 +42,52 @@ A static, null-safe class. It holds no state of its own — it reads and mutates
|
||||
|
||||
### 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)
|
||||
```
|
||||
The room the treatment happens in scales every session between **0.5×** (grim) and **1.5×**
|
||||
(excellent):
|
||||
|
||||
| Room impressiveness | Factor |
|
||||
| Room | Factor |
|
||||
|---|---:|
|
||||
| 0 (bare) | `0.60` |
|
||||
| ~48 (decent) | `1.00` |
|
||||
| ≥108 (impressive) | `1.50` (capped) |
|
||||
| outdoors / none | `0.75` |
|
||||
| Bare (0 impressiveness) | 0.60 |
|
||||
| Decent (~48 impressiveness) | 1.00 |
|
||||
| Impressive (108+ impressiveness) | 1.50 (capped) |
|
||||
| Outdoors / no room | 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.
|
||||
The limits are deliberate: a grim, filthy, cramped facility heals worse and a calm clean one better,
|
||||
but a palace can't trivialise the work the programme costs (1.5× ceiling), and even treating a pawn out
|
||||
in the open is a poor makeshift room (0.75×), not a hard zero.
|
||||
|
||||
### Reducing a condition
|
||||
|
||||
```
|
||||
h.Severity -= reductionPerSession × strength // per marked hediff
|
||||
if h.Severity <= 0.001 → remove it
|
||||
```
|
||||
Each marked condition drops by **0.12 × the session's combined strength** per session, and vanishes
|
||||
when it hits zero. That combined strength is the treating pawn's skill × the facility quality above ×
|
||||
the patient's share of the session — so all three inputs matter, and a good therapist in a good room
|
||||
working one-on-one is worth many times a poor one splitting attention in a bad room.
|
||||
|
||||
`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.
|
||||
### Building recovery
|
||||
|
||||
### 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 recovery track is a plain 0-to-1 progress bar toward discharge. Continued care adds to it (capped
|
||||
at 1.0) and — crucially — it carries a slow decay, so it slips back down without sustained attention.
|
||||
The mod using the engine decides what reaching the top actually *unlocks* (Ward: a "ready for
|
||||
discharge" alert).
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
## Who uses it
|
||||
|
||||
- **[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
|
||||
mental-illness conditions treatable (Rim Disorders' depression, anxiety, PTSD, and OCD, when that mod
|
||||
is present), runs warden counselling sessions, and builds a recovery track toward a "ready for
|
||||
discharge" alert. The reference example.
|
||||
- **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.
|
||||
"Reduce the condition, *then* build recovery" is the shape Ward uses, but it isn't forced: a
|
||||
rehabilitation system with no clinical condition to clear (like Justice's reform) can build a recovery
|
||||
track from the very first session and read its level to gate a parole.
|
||||
|
||||
The point, exactly as with propensity: one engine, two uses, no drift.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user