Wiki: player-facing rewrite of every layer + add a scenario FAQ, linked from Home

This commit is contained in:
flan
2026-07-16 02:18:25 +00:00
parent ff703271ba
commit 8250dcb369
32 changed files with 1654 additions and 2510 deletions
+68 -80
View File
@@ -1,128 +1,116 @@
# Compatibility
*Contraband ships zero Harmony patches. It adds defs, subclasses a work-giver, mutates two duty
trees at startup, and polls. That is why it composes instead of colliding.*
*Contraband adds its own content and reads from the base game rather than rewriting it. That is why it
composes with other mods instead of colliding with them.*
## Requires: Institution: Core
Contraband declares a hard `modDependency` on **`flan.institution.core`** and loads after it. This
is not optional — after the split, the entire substrate Contraband reads lives in Core:
Contraband has a hard dependency on **Institution: Core** and loads after it. This is not optional —
after the split, everything Contraband reads lives in Core:
| Core provides | Contraband uses it for |
|---|---|
| `SecuredContext` / `SecuredContexts` / `CanConceal` / `IsHeld` | who counts as a concealer; who can be intaken, whittle, or dig |
| `Propensity.Would(pawn, base, salt)` | every disposition roll — intake (0.6), improvise (0.10), dig (0.08), all seeded and scaled by nature × nurture |
| `CriminalRecord` + `GameComponent_CriminalRecords` | `timesSearched`, `timesCaught`, `escapeAttempts`, `contrabandMade` — written by search and acquisition, read by priority |
| Which pawns count as "in custody," and who can hide things | who counts as a concealer; who can be intaken, whittle, or dig |
| A pawn's criminal propensity (nature × nurture) | every disposition roll — intake (0.6), improvise (0.10), dig (0.08), all scaled and settled per pawn |
| The criminal record | times searched, times caught, escape attempts, contraband made — written by search and acquisition, read by search priority |
Install Contraband without Core and it will not run. Everything else on this page is optional
interplay that degrades gracefully when the other mod is absent.
Install Contraband without Core and it will not run. Everything else on this page is optional interplay
that degrades gracefully when the other mod is absent.
## Zero Harmony patches
## It plays nicely with other prison mods
Post-split, the mod's one Harmony patch (the regime that forces Joy for prisoners) moved to
**Institution: Justice**, so Contraband is Harmony-free again. Instead of patching, it:
Contraband adds its own content rather than rewriting the base game's. It:
- **Adds a new `WorkGiver`** (`WorkGiver_Warden_Search`) rather than patching a vanilla one.
- **Subclasses `WorkGiver_Warden`**, inheriting its behaviour rather than overriding it.
- **Mutates two `DutyDef` think trees at startup** via `StaticConstructorOnStartup` (not Harmony) —
an XML patch on a duty think tree silently no-ops in 1.6, so it is done in C#, deterministically.
- **Polls** every held pawn from a `MapComponent` for intake, improvisation, and tunnels — no hook
on the capture event is needed because the tick already visits every held pawn.
- **Adds a new warden job** (search) rather than changing an existing one.
- **Reuses vanilla warden behaviour** rather than overriding it, so anything that adjusts warden
behaviour on the base class flows through to searches for free.
- **Extends two escape-related behaviours at startup** so prisoners arm themselves and use what they
are hiding when they break — inserted at a specific point, and it logs a warning if that anchor is
missing rather than failing silently.
- **Runs on a heartbeat** over held pawns for intake, improvisation, and tunnels — no hook on the
capture event is needed because the heartbeat already visits every held pawn.
The net effect: the surfaces other prison mods touch are mostly untouched here, so conflicts are the
exception, not the rule.
## Foul Play — the carboy bridge
**Foul Play** (the "Piss Nuke" mod) stays its own mod with its own front door, and yet its **carboy
is a first-class contraband item.** This is the flagship demonstration of Contraband's *"items are
defs, subsystems are classes, mods are audiences"* principle, and it works through two seams:
**Foul Play** (the "Piss Nuke" mod) stays its own mod with its own front door, and yet its **carboy is
a first-class contraband item.** This is the flagship demonstration of Contraband's *"items are
content, subsystems are shared, mods are audiences"* principle, and it works two ways:
1. **Cross-assembly worker resolution.** `CompProperties_Contraband`'s `useWorker` / `escapeWorker`
fields are plain `Type`s, and RimWorld resolves def `Type` fields with
`GenTypes.GetTypeInAnyAssembly` — searching **every loaded assembly**. So the carboy declares
`CompProperties_Contraband` and points `useWorker` at a class that lives in *Foul Play's* assembly
(e.g. a throw-the-carboy worker). Contraband never has to know that class exists.
2. **The opaque content tag.** A carboy is not just "a jar" — it is a jar *of* a fermented blend, and
that blend has to survive being concealed. Foul Play sets Contraband's two delegates:
```csharp
ContrabandUtility.ContentTagOf = thing => /* serialise the carboy's blend */;
ContrabandUtility.ApplyContent = (thing, tag) => /* pour that blend back in on redeem */;
```
When a carboy is intaken or smuggled, Contraband captures the tag blind; on redemption it hands
the tag back to Foul Play to restore the contents. **Contraband knows nothing about substances or
fermentation** — that framework lives entirely in Foul Play. If Foul Play is absent, both delegates
are null, no content is captured, and nothing breaks: a jar is just a jar. See
1. **The carboy brings its own behaviour.** The carboy simply declares itself as contraband and points
at the throw-the-carboy behaviour that lives in *Foul Play*. Contraband never has to know that
behaviour exists — it just runs whatever the item brought with it.
2. **A concealed carboy keeps its contents.** A carboy is not just "a jar" — it is a jar *of* a
fermented blend, and that blend has to survive being concealed. When a carboy is intaken or
smuggled, Contraband captures a label for its contents blindly; on redemption it hands the label
back to Foul Play to restore the blend. **Contraband knows nothing about substances or
fermentation** — that framework lives entirely in Foul Play. If Foul Play is absent, no content is
captured and nothing breaks: a jar is just a jar. See
[Concealment and Intake](Concealment-and-Intake.md).
The dependency runs one way only: Foul Play bridges *to* Contraband (and to Core) if they are
present; Contraband takes **no** dependency on Foul Play.
The dependency runs one way only: Foul Play bridges *to* Contraband (and to Core) if they are present;
Contraband takes **no** dependency on Foul Play.
## Institution: Justice — the record is the shared bus
Contraband and **Justice** never call each other. They meet on Core's `CriminalRecord`:
Contraband and **Justice** never call each other. They meet on Core's criminal record — Contraband
writes to it, Justice reads from it:
```
Contraband writes ──▶ CriminalRecord ──▶ Justice reads
timesSearched (in Core) Classification (security grade)
timesCaught Deterrence (colony-wide signal)
escapeAttempts Discipline / Parole (reform)
contrabandMade
```
| Contraband writes | Justice reads it into |
|---|---|
| times searched | Classification (security grade) |
| times caught | Deterrence (colony-wide signal) |
| escape attempts | Discipline / Parole (reform) |
| contraband made | |
- **Catching contraband feeds classification.** A prisoner repeatedly caught with shivs or foiled
mid-tunnel accrues `timesCaught` and `escapeAttempts`, which Justice's classification weighs into a
higher security grade.
- **And it feeds back.** Justice's deterrence signal flows *back* through Core's propensity seam
(`Nurture`), nudging every future intake / improvise / dig roll a Contraband pawn makes. A prison
that catches and disciplines becomes a prison where fewer prisoners bother trying — without either
mod referencing the other. Run Contraband alone and the deterrence factor is a neutral 1.0; the
record fields still route the warden.
mid-tunnel racks up catches and escape attempts, which Justice's classification weighs into a higher
security grade.
- **And it feeds back.** Justice's deterrence signal flows *back* through Core's propensity, nudging
every future intake / improvise / dig roll a Contraband pawn makes. A prison that catches and
disciplines becomes a prison where fewer prisoners bother trying — without either mod referencing the
other. Run Contraband alone and deterrence is a neutral 1.0; the record still routes the warden.
## Institution: Gangs — the contraband economy
**Gangs** depends on Core, **Contraband**, and Justice, because a gang *is* a contraband economy:
- Gang smuggling moves contraband through the same public `Conceal` door intake and corruption use.
- A gang's outside members are the natural caller for the **reach-in corruption** primitive
(`Corruption.Smuggle`) — paying a bent warden to make a delivery. That primitive is exposed in
Contraband but has no in-repo trigger; Gangs is what drives it. See [Corruption](Corruption.md).
- Gang fights route to Justice's crime record, which then raises search priority here. The loop
closes through Core again.
- Gang smuggling moves contraband through the same door intake and corruption use.
- A gang's outside members are the natural caller for the **reach-in corruption** — paying a bent
warden to make a delivery. That ability exists in Contraband but has no in-game trigger of its own;
Gangs is what drives it. See [Corruption](Corruption.md).
- Gang fights route to Justice's crime record, which then raises search priority here. The loop closes
through Core again.
## Prison mods the suite is tested against
| Mod | Interaction | Verdict |
|---|---|---|
| **Prison Commons** | postfixes `WorkGiver_Warden.ShouldSkip` on the **base** class; Contraband's search subclasses it and does not override, so searches respect prison-commons/allowed areas **for free** | works by inheritance |
| **Custom Prisoner Interactions** | patches only the *named* vanilla warden givers (`_Chat`, `_Convert`, `_Enslave`, `_ReleasePrisoner`); it cannot see a brand-new giver | no conflict |
| **Prisoner Realism** | its escapes are for "mood prisoners" mid-break; a tunnel breakout hands off to vanilla `PrisonBreakUtility.StartPrisonBreak`, which Prisoner Realism layers on. Tunnels **complement** it — they let ward patients and slaves who would never mood-break still, patiently, dig out | complementary |
| **Prison Labor** | prisoners working outside the cell are still held pawns and still tracked; Contraband adds no patches to labor jobs. A work assignment is simply another place a disposed prisoner might come by materials | no conflict |
| **Prisoner Recreation** | overlaps the *regime* feature — which now lives in **Institution: Justice**, not here, and is written to be idempotent with Prisoner Recreation | not Contraband's concern post-split |
| **Prison Commons** | it adjusts warden behaviour on the base class, and Contraband's search inherits that, so searches respect prison-commons/allowed areas **for free** | works by inheritance |
| **Custom Prisoner Interactions** | it only touches the *named* vanilla warden jobs (chat, convert, enslave, release); it cannot see a brand-new job | no conflict |
| **Prisoner Realism** | its escapes are for "mood prisoners" mid-break; a tunnel breakout hands off to the vanilla prison-break flow, which Prisoner Realism layers on. Tunnels **complement** it — they let ward patients and slaves who would never mood-break still, patiently, dig out | complementary |
| **Prison Labor** | prisoners working outside the cell are still held pawns and still tracked; Contraband adds nothing to labor jobs. A work assignment is simply another place a disposed prisoner might come by materials | no conflict |
| **Prisoner Recreation** | overlaps the *regime* feature — which now lives in **Institution: Justice**, not here, and is written to coexist with Prisoner Recreation | not Contraband's concern post-split |
## Load order
```
Ludeon.RimWorld
flan.institution.core ← required, loads before Contraband
flan.institution.contraband ← this mod
(Foul Play / Justice / Gangs — any order after Core; each bridges if present)
```
1. Base game
2. **Institution: Core** — required, loads before Contraband
3. **Institution: Contraband** — this mod
4. **Foul Play / Justice / Gangs** — any order after Core; each bridges if present
## The general rule
If a mod adds prisoner behaviour by **patching vanilla warden givers or the escape duty tree by
name**, it will not see Contraband's additions, and Contraband will not see its — they pass each
other. If a mod adds a *new* `WorkGiver` or duty node of its own, it stacks. The one place to watch is
another mod that *also* rewrites the same two duty think trees (`PrisonerEscape`,
`PrisonerAssaultColony`) wholesale; Contraband inserts its nodes at a specific anchor and logs a
warning if that anchor is missing, so a load-order or conflict problem is visible in the log rather
than silent.
If a mod adds prisoner behaviour by **changing vanilla warden jobs or the escape flow by name**, it
will not see Contraband's additions, and Contraband will not see its — they pass each other harmlessly.
If a mod adds a *new* warden job or escape behaviour of its own, it stacks. The one place to watch is
another mod that *also* rewrites the same two escape-related behaviours wholesale; Contraband inserts
its part at a specific point and logs a warning if that point is missing, so a load-order or conflict
problem is visible in the log rather than silent.
---
*Part of the **Institution** suite — Core · Contraband · Justice · Gangs, alongside Foul Play and
Ward. Each stands alone; together they interlock.*
**