Publish Foul Play wiki (source private)

flan
2026-07-16 03:13:22 +00:00
commit 4499672284
8 changed files with 1096 additions and 0 deletions
+114
@@ -0,0 +1,114 @@
# Drinking and Addiction
A thrown vessel is only half of what a fluid can do. **Every vessel is also ingestible** — any fluid is
drinkable, with wildly different consequences. Hooch is a buzz, piss is an illness, chemfuel is a
poisoning, milk just feeds you, and liquid luciferium is a death sentence. For several substances the
*drink* is the real weapon and the throw is only humiliation until then.
---
## Vessels are ingestible
Every vessel carries an `ingestible` block:
```xml
<ingestible>
<foodType>Fluid</foodType>
<preferability>NeverForNutrition</preferability> <!-- won't drink it unprompted -->
<baseIngestTicks>240</baseIngestTicks>
<ingestCommandString>Drink {0}</ingestCommandString>
</ingestible>
```
`NeverForNutrition` is the important flag: a pawn will **not** wander over and swig their own piss
grenade to fill their belly. Drinking is something you **order** (right-click → *Drink*), or something a
prisoner does with smuggled contraband, or a trick you play by leaving something drinkable where a
desperate pawn will take it. What swallowing does is decided at drink time from the **runtime contents**,
not the def — a "piss jar" that actually holds hooch gets you drunk.
---
## You swallow the whole blend
`PostIngested` walks the vessel's blend and applies **each constituent's** drink effect, scaled by its
**share** (see **Vessels and Substances**). A cocktail lands every ingredient at once:
For each substance at fraction *f*:
| Effect | Rule |
|---|---|
| **Body hediff** | `AdjustSeverity(drinkHediff, drinkHediffSeverity × f)` |
| **Memory** | gain `drinkThought` — but **only if `f ≥ 0.2`** (a single drop is not worth remembering) |
| **Nutrition** | `food += nutrition × f`, clamped to the food bar |
| **Addiction** | rolled — see below |
A drop of hooch in a jar of piss barely warms you; a jar that is mostly hooch gets you drunk *and*
sick, because you also swallowed the piss. Ratios decide the dose, in both directions.
### What each drink does (full potency, full jar)
| Drink | Effect | Notes |
|---|---|---|
| **milk** | +nutrition, no downside | the benign one — it just feeds you |
| **blood** | +nutrition, revulsion memory | food for a sanguophage, "drank something vile" for anyone else |
| **hooch / beer** | alcohol high (0.16) | a buzz that can, sometimes, become a habit |
| **wort** | alcohol high (0.05) | mild — it is unfermented beer |
| **fermented urine** | food poisoning (0.35) + revulsion | an illness and a memory you cannot rinse away |
| **vomit** | food poisoning (0.30) + revulsion | vile and easy to source |
| **chemfuel** | toxic buildup (0.20) + revulsion | a slow poisoning |
| **liquid luciferium** | luciferium high (0.30) + revulsion + near-certain addiction | catastrophic — see below |
| **water / earwax / toenails** | nothing (water) / a revulsion memory only | no body effect |
---
## The addiction roll, scaled by disposition
Every fluid *can* hook the drinker; the rarity is the point. The per-drink chance is:
```
chance = addictionRarity × fraction × Lerp(0.5, 4.0, disposition)
```
- **`addictionRarity`** is the substance's base hook chance (see **Substance Catalogue**). Hooch 0.03,
beer 0.025, wort 0.01, **luciferium 1.0**; most fluids 0 (they never hook anyone).
- **`fraction`** is the substance's share of what was drunk — a splash rolls at a splash's odds.
- **`disposition`** is the drinker's 0..1 propensity, and it swings the chance across an **8× range**: a
content pawn multiplies by 0.5, a despairing one by 4.0. **A despairing pawn addicts to what a content
one shrugs off** — the same merged propensity engine that decides who fills a vessel and who throws it.
If the roll wins and the drinker is not already addicted, the substance's `addictionChemical` is applied
via its real vanilla `addictionHediff` — so a hooch/beer habit *is* a vanilla Alcohol addiction, and
vanilla runs it from there.
### The odds in practice
| Drink | Content pawn (disp ≈ 0) | Despairing pawn (disp ≈ 1) |
|---|---:|---:|
| Full jar of **hooch** (0.03) | ~1.5% | ~12% |
| Full jar of **beer** (0.025) | ~1.25% | ~10% |
| Full jar of **wort** (0.01) | ~0.5% | ~4% |
| Full jar of **liquid luciferium** (1.0) | ~50% | **always** (chance ≥ 1) |
| A 20% splash of **luciferium** in a cocktail | ~10% | ~80% |
**Liquid luciferium is the extreme the model is built to express.** At rarity 1.0 the roll all but always
hooks a full jar, and even a minority share of it in a cocktail is a coin-flip-or-worse. Mapped to the
real Luciferium chemical, that becomes vanilla's permanent, lethal-to-stop dependency: slip a pawn a jar
and you have handed them a life sentence, which is exactly why it is the rarest, worst thing a vessel can
hold.
---
## Playing with the drink axis
- **Interrogation / persuasion:** a jar of hooch is a cheap way to buy a prisoner's mood — at a small,
disposition-scaled risk of creating an alcoholic you now have to manage.
- **Sabotage:** leave a jar of chemfuel or fermented urine where a raider or a wandering prisoner will
drink it. The poisoning and the food-poisoning land immediately; the memory sticks for days.
- **Cruelty made mechanical:** a jar of luciferium is the single nastiest thing you can do to a pawn
short of killing them — and unlike killing them, it keeps working.
- **Watch the merged disposition.** With **Institution: Contraband** installed, the disposition read is
the suite's full nature × nurture — so *how you treat a prisoner* directly changes how easily the
same drink hooks them. A mistreated, despairing captive is far more addictable than a well-kept one.
---
*Foul Play is part of the **Institution** suite — one install with a checkbox per layer (Core, Contraband, Policing, Corrections, Gangs, Ward) about what an institution does to the people inside it. It bridges to the Contraband layer when Institution is installed.*
+126
@@ -0,0 +1,126 @@
# Fermentation
Fermenting is what makes a vessel worth having. Fresh urine is nearly sterile and nearly harmless — it
is *weeks* of bacteria breaking urea into ammonia that make it caustic, make it burn eyes, and make it a
disease vector. Pruno is fruit, bread and time. Hooch is sugar and time. In every case the prisoner's
real ingredient is the one thing a cell gives them in abundance — **time** — and the institution's
counter is to take it away by finding the jar.
Fermentation is **prison chemistry, not a Piss Nuke quirk**, which is why it lives in the framework
(`CompFerment`) and not the flagship. Any substance flagged `ferments` gets it; in the shipped catalogue
that is **urine, hooch and wort**.
---
## Potency: age gives it, and age takes it away
`CompFerment` tracks one hidden number — **age**, in ticks — and turns it into **potency** (0..1), the
value every downstream system reads to know how strong the batch is. The defaults on the Piss Nuke
family:
| Property | Default | In days | Meaning |
|---|---:|---:|---|
| `freshPotency` | 0.30 | — | strength of a vessel sealed this instant |
| `ripeTicks` | 900,000 | **15** | ticks to climb from fresh to full |
| `burstAfterTicks` | 1,500,000 | **25** | past this, pressure has built too long → *overdue* |
| `burstMtbDays` | 6 | — | mean days between ruptures once overdue |
| `spoilTicks` | 0 → `ripeTicks×4` | **60** | when it starts turning to vinegar (0 defaults to long after ripe) |
| *(spoil end)* | `spoilStart + ripeTicks` | **75** | fully spoiled — inert sludge |
Potency is a three-phase curve:
```
age ≤ ripe (15d) → Lerp(0.30, 1.0, age/ripe) ripening
ripe < age ≤ 60d → 1.0 ripe and holding
60d < age ≤ 75d → Lerp(1.0, 0.1, t) going off (t across the spoil window)
```
So a batch climbs from 30% to full over its first ~15 days, plateaus at full strength for weeks, then —
if it survives that long — **decays** back down to a floor of 0.1 as it turns to vinegar and rot. A
vessel reads `spoiled` (inert, not worth throwing or drinking) once age passes the spoil end.
> **Why a piss carboy never spoils.** It goes *overdue* at 25 days and then ruptures on an MTB of 6 days
> — so it almost always lets go long before the 60-day spoil window opens. Spoiling is the fate of the
> *stable* ferments (a jar of hooch left in a cold corner and forgotten), not the pressurised ones.
---
## Temperature and seal drive the rate
Age does **not** accrue one tick per tick. It accrues at a temperature- and seal-scaled rate, exactly
like food rot — cold and a sealed jar are the difference between a season and a fortnight.
```
tempFactor = (temp ≤ 0°C) ? 0.05 : Clamp(temp / 20, 0.1, 2.0)
rate = tempFactor × (sealed ? 1.0 : 0.7)
```
| Condition | Rate | 15-day ripen becomes |
|---|---:|---|
| Freezer (≤ 0 °C) | 0.05 | ~300 days — nearly halted |
| Cold cell (10 °C) | 0.50 | ~30 days |
| Room temperature (20 °C) | 1.00 | ~15 days (the baseline) |
| Hot cell (≥ 40 °C) | 2.00 (capped) | ~7.5 days — a hot cell races it |
| Open vessel (×0.7) | — | slower: an open bucket breathes and loses to the air |
Two levers for the player fall straight out of this: **a freezer is a stasis vault** for confiscated
contraband (age it nowhere while you decide what to do), and **a warden who keeps cells cold slows every
batch in the block.** An open bucket ferments at 70% the rate of a sealed one, on top of any temperature
effect — one more reason the open vessels are the weak siblings.
---
## Dilution: topping up keeps a batch young
Fresh liquid poured into a fermenting vessel **pulls its average age down**. When the volume grows, age
is scaled by the ratio of old volume to new:
```
age ← age × (oldVolume / newVolume)
```
Pour an equal measure of fresh urine into a fully-aged half-jar and its effective age (and potency)
halves. The design consequence is sharp:
- **A jar filled once and hidden** ages undisturbed to full potency — the dangerous one.
- **A shared vat everyone keeps using** never gets old: every top-up resets it younger, so a
communal bucket stays a weak, watery batch no matter how long it has existed.
Which is realistic and which is *balance*: the batch you should fear is the one someone filled and left
alone, not the one the whole block keeps dipping into.
---
## Pressure: a sealed vessel ruptures on its own
A sealed vessel of fermenting anything builds pressure. Once it is **overdue** (age ≥ `burstAfterTicks`,
25 days by default), each rare tick rolls `MTBEventOccurs` against `burstMtbDays` (6). When it fires, the
vessel:
1. announces itself with a negative-event message,
2. is destroyed **first** (so it cannot be caught in its own blast and fire twice), and
3. hands off to its **burst worker** — the framework owns the pressure; *what comes out* is the owning
mod's business. A plain vessel just breaks and is gone; the Piss Nuke's carboy runs a **caustic
splash** at the vessel's current potency (see **The Piss Nuke**).
The lesson for a stockpile manager: **a sealed carboy is a bomb on a timer even if nobody throws it.**
Keep confiscated ones cold, thrown away, or drained — a shelf of aging piss nukes will eventually let go
in your warehouse.
The inspect pane shows the live state: `Fermentation: NN%`, plus `Overdue — building pressure` or
`Spoiled — turned to vinegar` as it reaches those phases.
---
## Fermentation and identity
The label reads the ferment state directly, and this is the mechanical root of the mod's central rule.
A fermenting vessel appends its progress (`piss nuke, fermenting 42%`); a spoiled one says so; and only a
vessel at **≥ 95% potency**, undiluted, and pure gets to wear its plain, full-strength name.
> **A "piss nuke" is only 100%-fermented, undiluted, pure urine in a carboy.** A fresh one, a
> half-fermented one, a diluted one, a spoiled one, or a cocktail is *not* — and the label refuses to
> pretend it is. See **The Piss Nuke** for what that identity buys you.
---
*Foul Play is part of the **Institution** suite — one install with a checkbox per layer (Core, Contraband, Policing, Corrections, Gangs, Ward) about what an institution does to the people inside it. It bridges to the Contraband layer when Institution is installed.*
+109
@@ -0,0 +1,109 @@
# Furniture Vats
A carryable vessel holds half a litre to a few litres. A cell, a brewery, or a bathhouse holds *bulk* —
and the bulk lives in furniture. Foul Play lets any liquid-holding fixture act as a large, fixed,
**blended vat** you cannot pick up or tip over: a place to ferment a batch too big for a jar, and a well
to dip jars out of. It is the same weighted-blend model `CompVessel` uses for carryables, applied to
buildings.
---
## What counts as a vat (a capability, not a mod list)
A building has no `CompVessel`, so its contents live in a map component keyed by the building. Foul Play
recognises a liquid-holding fixture the same way `CompVessel` recognises a container — by capability, so
the feature lights up with any hygiene or brewing mod and depends on none of them. `FermentSite`
counts a fixture as a vat if **any** of these hold:
1. It is vanilla's **`FermentingBarrel`** (the canonical case).
2. Its `thingClass` is a **`Building_Storage`** — vanilla shelves, LWM/Deep Storage drawers, modded
crates. A drawer has sides and seals well enough for prison chemistry.
3. Its defName or label contains a **liquid-container word**:
> toilet · latrine · outhouse · urinal · privy · bidet · barrel · keg · cask · vat · still · carboy ·
> fermenter · tub · bath · sink · basin · trough · cistern · tank · bucket · drawer · crate · chest ·
> locker · cabinet · cupboard · box · container
With no such furniture anywhere, hooch simply **cannot** be brewed in bulk — which is the correct answer,
not a crash. A bare cell with nothing that holds liquid gives a prisoner nowhere to run a batch.
Each vat holds a full blend, up to **30,000 ml (30 L)** — well beyond any carryable, so a cell can keep a
bulk batch of fermenting pruno and draw jars off it for a long time.
---
## The two moves: pour in, dip out
A pawn does exactly two things with a vat, and they are **not** symmetric — because you cannot tip a
bolted-down fixture the way you tip a jar.
| Move | Direction | Capped by | The only way to… |
|---|---|---|---|
| **Pour in** | carryable → vat | `min(amount, carryable.TotalVolume, vat.headroom)` | empty a jar into the vat |
| **Dip** | vat → carryable | `min(amount, vat.volume, carryable.headroom)` | get liquid **out** of a fixture |
**Dip is the whole reason the vat is usable at all.** A fixed drawer cannot be tipped, so the only way
liquid leaves it is a pawn dipping a carryable in and lifting a jar's worth out. Pour-in and dip together
let a cell run a bulk vat and decant it: keep 20 L of pruno fermenting in a crate, and dip a Piss Jar's
worth off it whenever you want to throw one.
Both directions transfer **in the vat's / carryable's current ratios**, and both **resolve reactions** on
arrival: pour water onto a vat of hooch and it douses (see **Mixing and Reactions**); dip from a mixed vat
and your jar reacts too. When a vat is dipped dry it is forgotten entirely.
### The float-menu UI
Carry a vessel and right-click a fixture: you are offered **"Pour X into Y"** and, for a fixture,
**"Dip X from Y."** Right-click another vessel on the ground and you get **"Pour X into Y"** only (you
dip from fixtures, not from loose jars). The job walks to the target (`Touch`), works for 120 ticks with
a progress bar, then does the transfer.
### Amount control
The transfer functions take an explicit **amount**, so the quantity is the pawn's choice in both
directions — any ratio the physics allows: dip a splash of one thing into a jar of another to mix, or
draw exactly a jar's worth off a bulk vat. The current ordered-job UI uses the two natural extremes —
**pour empties the carried vessel**, **dip fills it to the brim** — while the underlying API supports any
partial measure for finer mixing.
---
## Any pawn fills a vessel — openly
Filling is Foul Play's business, not the prison's. A disposed **free** pawn — a colonist, a visitor —
will fill a jar from their own body, openly, and keep it. **Disposition decides who bothers, not
imprisonment**, which is the suite's thesis at the mechanics level. Held pawns are excluded here: they
*conceal* what they make (the Contraband route), so the prison lens owns them.
The autonomous fill is **poll-based** (no Harmony) and deliberately rare:
| Gate | Value | Effect |
|---|---|---|
| Check interval | every 2,500 ticks (~1 in-game hour) | when the poll runs |
| Eligibility | free, awake, up, humanlike, has an inventory | held/downed/animal pawns skip |
| Disposition gate | **≥ 0.5** | only strongly foul pawns bother at all |
| Body cooldown | shared supply component | their body must have restocked |
| Trigger | `MTB = 8 × (1.2 − disposition)` days | fouler = a shorter fuse, but still now-and-then |
The jar they make is theirs; whether they ever *throw* it is the spree system's affair (see **The Piss
Nuke**).
---
## The autonomous cocktail: the foulest mix
An ordinary disposed pawn fills a plain jar of urine. The **foulest do not stop there** — above a
disposition of **0.7**, they **mix**, pouring a second vile substance in to make a cocktail:
```
SetContents(urine, capacity × 0.5) // half a jar of piss…
AddContent(feces, capacity) // …topped up with filth → a 50/50 piss-and-filth cocktail
```
(The second substance is feces if the pawn has any.) Note the **headroom rule** at work: the pawn
sets the jar to half-full of one substance *first*, then tops it up, so the result is a controlled 50/50
blend rather than an overflow that spills the excess (see **Mixing and Reactions**). Only the worst
bother — which is exactly why a cocktail jar, when you find one, tells you something about who made it.
---
*Foul Play is part of the **Institution** suite — one install with a checkbox per layer (Core, Contraband, Policing, Corrections, Gangs, Ward) about what an institution does to the people inside it. It bridges to the Contraband layer when Institution is installed.*
+113
@@ -0,0 +1,113 @@
# Foul Play
**Fill a container with something off a body, and throw it.**
Foul Play is a **liquid framework for RimWorld 1.6** — Noita's flasks, rebuilt in a colony sim.
Any container becomes a carryable vessel; any fluid becomes a substance you can pour, mix, ferment,
throw, or drink. What comes out the far end — a firebomb, a plague grenade, a caustic cloud, a jar of
humiliation, or an accidental cocktail that reacted with itself in transit — is decided entirely by
**what is in the vessel right now**, not by what item the def said it was.
The base game gives you neither half. RimWorld has **no carryable containers at all** — every barrel
and pot is a *building* — and no way to weaponise the filth a body produces. Foul Play adds both, and
ships them as a **framework** rather than a fixed list of items. Its flagship consumer, **Piss Nuke**,
is the proof that the framework works: a whole weapon family built on top with almost no code of its own.
---
## The two ideas everything derives from
Foul Play is built on exactly two data axes, kept deliberately separate:
| Axis | What it is | What it decides |
|---|---|---|
| **Vessel** (`CompVessel`) | a container — two numbers: **volume** and whether it is **sealed** | *delivery*: fill time, throw range, spill in transit, blast radius, splash density |
| **Substance** (`SubstanceDef`) | a fluid — pure data: `mlPerDay`, harm, disease, drink effect, addiction | *payload*: what it does when it lands, and what it does when you drink it |
A **filled vessel is a vessel-of-substance**: a Piss Jar is a *jar* (delivery) *of urine* (payload).
Swap the substance and the same jar is a firebomb; swap the container and the same urine is a carboy-
sized area weapon. Neither axis knows anything about the other, which is what makes "works with every
container and every fluid" honest — there is no per-item special-casing to get wrong.
The design law that makes this a *system* and not a novelty list: **harm inverts as volume falls.** A
body makes ~1.75 L of urine a day and a smear of earwax a year. The things a body makes least of do no
damage at all — so what they cost is **time**, and what they deliver is **humiliation**. A jar of
toenail clippings is a decade of sentence made physical, and possessing one tells you exactly how long
its owner has been caged.
---
## The flagship: the Piss Nuke
Foul Play ships **no weapons**. Piss Nuke is the flagship *consumer* — a four-vessel family of fermented
urine that exists only as data on top of the framework:
| Vessel | Volume | Sealed | Character |
|---|---|---|---|
| Piss Jar | 0.5 L | yes | fills in hours, throws far, palms easily, tight splash |
| Piss Bottle | 0.75 L | yes | ~half a day to fill, still throws clean |
| Piss Bucket | 8 L | **open** | days to fill, throws short, **sloshes over the carrier**, wide and thin |
| **Piss Nuke** | 5 L | yes | the flagship carboy — wide *and* dense |
Fermented urine is a **non-lethal disease weapon by design**: the splash barely blisters skin, but the
ammoniac infection it carries (piss rot) leaves the afflicted vomiting, half-blind and too shaky to
hold a rifle — the surest way to bring a raider home *breathing*. And an identity emerges only from
runtime state: **a carboy is a "piss nuke" only when it holds 100%-fermented, undiluted, pure urine.**
See **The Piss Nuke**.
---
## Wiki index
| Page | What it covers |
|---|---|
| **[Vessels and Substances](Vessels-and-Substances.md)** | `CompVessel` as a weighted **blend**, Capacity / Headroom / Fraction, the dominant substance, and how *every* consequence reads runtime contents and scales by share |
| **[Substance Catalogue](Substance-Catalogue.md)** | the full table of all 14 shipped substances — harm, disease, drink effect, addiction, fill rate |
| **[Mixing and Reactions](Mixing-and-Reactions.md)** | pouring substances together, the water-vs-incendiary 1:1 cancel, and the "headroom to receive" rule |
| **[Fermentation](Fermentation.md)** | temperature/seal-driven aging, dilution on top-up, spoiling past ripe, pressure ruptures |
| **[Drinking and Addiction](Drinking-and-Addiction.md)** | vessels are ingestible; per-fluid consequences; the addiction roll scaled by disposition |
| **[Furniture Vats](Furniture-Vats.md)** | sealed furniture as blended vats, dip vs pour physics, any-pawn filling, the autonomous cocktail |
| **[The Piss Nuke](The-Piss-Nuke.md)** | the flagship: what makes a carboy a nuke, throwing and the spree, the disposition-seeded thrower |
---
## Foul Play and the Institution suite
Foul Play plugs into the **Institution** suite — one install with a checkbox per layer (all on by
default) about what an institution does to the people inside it. The layers interlock around one thesis:
> **Every pawn has a criminal propensity on a spectrum — nature (traits) × nurture (circumstance,
> mood, treatment) — and the colony can police it.**
| Layer | What it is |
|---|---|
| **Core** | the propensity engine (nature × nurture), the criminal record, the treatment engine — the engine every layer agrees on |
| **Contraband** | prisoners conceal what they walked in with, whittle shivs from the cell, dig tunnels; wardens search the likeliest first, and a bent one looks away |
| **Policing** | your own colonists offend; witnesses and a constable name the culprit; a weighed arrest ends in a cell or a resisted breakout; order feeds back, riots when it collapses |
| **Corrections** | classification grades every prisoner by what they've done; discipline hardens or reforms; parole frees the reformed; regime gives recreation, yard time, and visits |
| **Gangs** | disposed prisoners band together and move contraband; rival gangs fight, inside the wire or out |
| **Ward** | commit a prisoner for psychiatric treatment instead of punishment — counselling reduces the disorder that broke them, on a recovery track toward discharge |
| **Foul Play** *(this mod)* | the vessel + substance + throw framework; the Piss Nuke flagship |
**Foul Play has zero hard dependencies** and patches nothing (no Harmony). It stands alone as a
craft-and-throw gross-weapon mod. The one seam it exposes is `Disposition` — "how disposed is this pawn
to foul behaviour?", a single 0..1 number that decides who fills a vessel, who swigs the vile stuff,
and who a drink hooks.
**When Institution's Contraband layer is enabled**, a small bridge assembly (`Bridge_Contraband/`,
loaded via `LoadFolders` *only* when Contraband is present) does three things:
1. **Merges the propensity engines.** Foul Play repoints its `Disposition.Source` at the suite's shared
**nature × nurture** engine — surfaced by Contraband, owned by **Institution: Core** — so the two
mods never disagree about the same person. Without Contraband, Foul Play keeps its own light local
read (mood + a couple of traits).
2. **Registers the piss vessels as brewable contraband** — a prisoner can brew a carboy from their own
body in a bare cell, conceal it (a jar palms; a 5 L carboy does not), and be searched for it.
3. **Preserves a vessel's contents through concealment**, so a hidden *jar of hooch* comes back holding
hooch, not whatever the jar's def defaulted to.
The throwing framework is never chained to the prison framework. See **The Piss Nuke** for the bridge
in full.
---
*Foul Play is part of the **Institution** suite — one install with a checkbox per layer (Core, Contraband, Policing, Corrections, Gangs, Ward) about what an institution does to the people inside it. It bridges to the Contraband layer when Institution is installed.*
+109
@@ -0,0 +1,109 @@
# Mixing and Reactions
This is the Noita layer. A vessel holds a **weighted blend**, and pouring one fluid into another does
not just stack them — some pairs **react**. Mixing is addition; reactions are chemistry on top of the
addition. Both resolve *in place, by volume*, so ratios decide the outcome.
If you have not read it yet, **Vessels and Substances** covers the blend model (Capacity, Headroom,
Fraction) this page builds on.
---
## Volumes add; the container decides the ceiling
Pour a measure of a substance into a vessel and the amounts add:
```
250 ml urine + pour in 250 ml hooch → { urine: 250, hooch: 250 } (a 50/50 jar)
```
Two rules govern the add:
1. **You cannot overfill.** Only up to the **headroom** is taken. Pour a full jar of hooch into a
half-full jar of piss and the jar ends up piss-and-hooch, filled to the brim and *no more* — the
excess never enters. A vessel with no headroom takes nothing at all until some is poured out.
2. **The blend re-balances, then reactions resolve.** Amounts add, shares shift, and *then* the reaction
pass runs on the new blend — so **what comes out may not be the sum of what went in.**
Because every consequence scales by share (see **Vessels and Substances**), changing the ratio changes
the weapon. A jar that is mostly piss with a splash of hooch barely burns; tip the ratio the other way
and it is a firebomb. Nobody re-tags the item — the blend simply *is* the weapon now.
---
## Pouring: the one action pawns take
The only thing a pawn does with vessels is **pour between containers**. It moves liquid from a source
into a target, capped three ways at once:
```
moved = min( requested, source.TotalVolume, target.Headroom )
```
Contents transfer **in their current ratios** — pour half of a 60/40 jar and the destination receives
60/40. The destination then reacts (a hooch jar poured into a water bucket is doused on arrival). The
UI (right-click a vessel-carrier onto another vessel or a liquid fixture) offers **"Pour X into Y"**; a
pour job walks to the target, works for 120 ticks with a progress bar, then empties the carried vessel.
> **The tipping rule.** You cannot pour *out of* a bolted-down furniture vat — you cannot tip a fixed
> drawer the way you tip a jar. To take liquid *out* of a fixture you **dip** a carryable into it instead.
> See **Furniture Vats**.
---
## The reaction: water douses fire, 1:1
The first and most intuitive reaction — and the anchor for the whole reaction layer — is **water versus
an incendiary.** An "incendiary" is any substance whose splash burns (its `damageDef` points at vanilla
`Flame`): in the shipped catalogue that is **hooch** and **chemfuel**.
When both water and one or more incendiaries share a vessel, they **cancel one another volume-for-volume
until one runs out**:
```
doused = min( water_ml, total_incendiary_ml )
```
- Each incendiary is reduced by its share of `doused`; any that hits zero is removed.
- The water is *spent* putting it out — reduced by the same `doused`; if it hits zero it is removed too.
- Whichever runs out first, the other survives with the remainder.
Ratios are everything:
| Blend before | Result |
|---|---|
| 100 ml water + 4900 ml chemfuel (carboy) | ~100 ml chemfuel neutralised — barely a dent; still a firebomb |
| 4000 ml water + 500 ml hooch (bucket) | hooch **gone**; ~3500 ml plain water left; inert |
| 250 ml water + 250 ml hooch | both cancel out exactly; an empty-of-either, doused vessel |
This is genuinely useful in play, not just flavour:
- **Defuse a firebomb** by pouring water into it before it is thrown.
- **Sabotage** a captured or looted incendiary in storage.
- **Botch a mix**: an autonomous mixer or a careless pour that lands water on hooch quietly destroys the
weapon — the vessel still *reads* full, but its bite is gone.
Reactions run **everywhere a blend can change**: on pour-in, on dip, and inside a furniture vat. The
resolver is a single local transform on the amount table, so new pairs (acid + base, oil feeding fire,
and so on) slot in beside `WaterDousesFire` without touching anything else.
---
## The headroom rule, restated
Every mixing interaction routes through the same gate: **a container needs headroom to receive.**
| Situation | What happens |
|---|---|
| Pour into a full vessel | nothing moves — no headroom |
| Pour more than the target can hold | only the headroom's worth transfers; the rest stays behind |
| Pour more than the source holds | capped at what the source actually has |
| Dip a carryable into a fixture | capped by the fixture's contents *and* the carryable's headroom |
The consequence for play: to build a *specific* cocktail you often have to **empty first, then mix**. The
autonomous mixers do exactly this — they set the vessel to half its capacity of one substance, *then*
top it up with a second, so the result is a controlled 50/50 rather than an overflow. (See **Furniture
Vats** for the autonomous cocktail.)
---
*Foul Play is part of the **Institution** suite — one install with a checkbox per layer (Core, Contraband, Policing, Corrections, Gangs, Ward) about what an institution does to the people inside it. It bridges to the Contraband layer when Institution is installed.*
+108
@@ -0,0 +1,108 @@
# Substance Catalogue
A **substance** (`SubstanceDef`) is pure data: what a fluid does when a vessel of it lands, and what it
does when someone drinks it. The framework ships the fluids below as neutral data — it attaches none of
them to a weapon itself (that is a *consumer's* job, like Piss Nuke). A vessel can hold any of them, and
any of them can be poured, mixed, fermented, thrown or drunk.
The organising law is **harm inverts as volume falls** (`mlPerDay`): a body makes a lot of some of these
and almost none of others, and the ones it makes least of do no damage at all. When harm goes to zero,
**time** becomes the weapon — a jar of toenail clippings took years to fill, and that *is* the point.
---
## The fields
| Field | Meaning |
|---|---|
| `mlPerDay` | how much a body (or the world) produces per day — sets **fill time**; default 1750 |
| `damageDef` | the splash's damage type; null → framework's generic `FP_SubstanceSplash` (a soft bruise) |
| `causticDamage` | splash damage at full potency; **0 = it only humiliates** (no blast, just filth + a memory) |
| `disease` / `diseaseSeverity` | infection applied *in code* so headgear can block it (peak severity at a bare face) |
| `burnsEyes` | concentrated ammonia can blind — only a ripe, fermenting substance |
| `hitThought` | the "someone threw this at me" memory — humiliation is the universal payload |
| `filth` | mess left on the ground; null → generic foul mess |
| `ferments` | does it age (and get worse, and build pressure)? see **Fermentation** |
| `nutrition` | food value if drunk |
| `drinkHediff` / `…Severity` | what swallowing it does to the body |
| `drinkThought` | how they feel about having drunk it |
| `addictionRarity` | base per-drink chance to form a dependency (scaled by the drinker's disposition) |
| `addictionChemical` | the real chemical the dependency maps to (its `addictionHediff` is applied) |
---
## The full catalogue (14 substances)
Sorted by production rate. **Harm falls as you go down the bodily list; time-to-fill rises.**
### Throw harm — what a splash does
| Substance | `mlPerDay` | Flammable? | Caustic | Disease (severity) | Burns eyes | Ferments | Throw memory (mood) |
|---|---:|:---:|---:|---|:---:|:---:|---|
| **milk** (`FP_Milk`) | 11000 | no | 0 | — | no | no | doused in milk (−3) |
| **water** (`FP_Water`) | 2000 | no | 0 | — | no | no | *none* (barely worth remembering) |
| **fermented urine** (`PN_Urine`) | 1750 | no | 6 | piss rot (0.35) | **yes** | **yes** | doused in piss (−14) |
| **chemfuel** (`FP_Chemfuel`) | 800 | **yes** | 26 | — | no | no | firebombed (−10) |
| **hooch** (`FP_Hooch`) | 500 | **yes** | 16 | — | no | **yes** | firebombed (−10) |
| **beer** (`FP_Beer`) | 500 | no | 0 | — | no | no | degraded (−16) |
| **wort** (`FP_Wort`) | 500 | no | 0 | — | no | **yes** | pelted with filth (−12) |
| **vomit** (`FP_Vomit`) | 250 | no | 0 | gut rot (0.25) | no | no | pelted with filth (−12) |
| **feces** (`FP_Feces`) | 150 | no | 0 | gut rot (0.45) | no | no | pelted with filth (−12) |
| **blood** (`FP_Blood`) | 60 | no | 0 | — | no | no | drenched in blood (−14) |
| **liquid luciferium** (`FP_Luciferium`) | 50 | no | 0 | — | no | no | degraded (−16) |
| **earwax** (`FP_Earwax`) | 0.05 | no | 0 | — | no | no | degraded (−16) |
| **toenail clippings** (`FP_Toenails`) | 0.02 | no | 0 | — | no | no | degraded (−16) |
### Drink payload — what swallowing it does
Any fluid is drinkable, and for several substances the drink is the *real* weight — thrown, they merely
humiliate, but slipped to a pawn in a drink they land their full effect. See **Drinking and Addiction**.
| Substance | Nutrition | Drink hediff (severity) | Drink memory | Addiction rarity → chemical |
|---|---:|---|---|---|
| **milk** | +0.05 | — | — | — |
| **blood** | +0.05 | — | drank something vile | — |
| **fermented urine** | 0 | food poisoning (0.35) | drank something vile | — |
| **vomit** | 0 | food poisoning (0.30) | drank something vile | — |
| **chemfuel** | 0 | toxic buildup (0.20) | drank something vile | — |
| **hooch** | 0 | alcohol high (0.16) | — | **0.03** → Alcohol |
| **beer** | 0 | alcohol high (0.16) | — | **0.025** → Alcohol |
| **wort** | 0 | alcohol high (0.05) | — | **0.01** → Alcohol |
| **liquid luciferium** | 0 | luciferium high (0.30) | drank something vile | **1.0** → Luciferium |
| water / earwax / toenails | 0 | — | — | — |
---
## Reading the catalogue
**The two flammables are the firebombs.** Chemfuel (26 caustic) and hooch (16) point their `damageDef`
at vanilla `Flame`, so their splash rides the framework's `GenExplosion` and **starts fires** with no
special-case code. Chemfuel is the industrial one — hotter and wider; a prisoner who reaches a fuel
stockpile is a serious problem. Hooch is the prison-brewed cousin, and it *ferments*: for hooch, age is
alcohol and alcohol is what burns, so it runs the harm axis the **other** way from the bodily fluids —
worse as it ages, not worse as volume falls.
**The two disease vectors are feces and vomit** (both carry gut rot, feces at the higher dose) and
**fermented urine** (piss rot). All three are applied *in code*, filtered through headgear — a sealed
helmet is near-total protection. All three infections are **non-lethal by design**: a wing of sick,
wretched, capturable prisoners, not corpses.
**The benign ones are the joke that makes the rest land.** Milk only annoys (−3, and no filth def exists
for it, so a splash leaves only a memory); a Kind pawn throwing milk is comedy. Water does *nothing* on
impact — it is the **anti-substance**, the key to the reaction layer: it douses fire and washes filth.
See **Mixing and Reactions**.
**The pure-humiliation tier is the thesis in miniature.** Earwax (0.05) and toenail
clippings (0.02) do zero damage. A jarful of any of them is worthless as a weapon and priceless as a
statement: it is only fillable by someone with *years* of idle time, so possessing one advertises exactly
how long its owner has been inside. All three share the harshest throw memory in the mod (**degraded,
−16**) precisely because there is nothing else to them.
**The drink specialists** carry almost nothing thrown but everything swallowed. Beer and wort are
smuggled/brewing alcohol; blood feeds a sanguophage and revolts everyone else. **Liquid luciferium is the
catastrophe**: thrown it is a monstrous waste, but drunk it applies vanilla's `LuciferiumHigh` and, at
`addictionRarity 1.0`, the roll all but always hooks — mapped to the real Luciferium chemical, so vanilla
then runs it as the permanent, lethal-to-stop dependency. Slip a pawn a jar and it is a life sentence.
---
*Foul Play is part of the **Institution** suite — one install with a checkbox per layer (Core, Contraband, Policing, Corrections, Gangs, Ward) about what an institution does to the people inside it. It bridges to the Contraband layer when Institution is installed.*
+275
@@ -0,0 +1,275 @@
# The Piss Nuke
The Piss Nuke is Foul Play's **flagship consumer** — a whole weapon family built on the framework with
almost no code of its own. Everything a piss nuke *is* comes from two data axes the framework already
provides: a **carboy** (a 5 L sealed vessel) holding **fermented urine** (a caustic, disease-carrying,
fermenting substance). The framework knows nothing about piss; the piss knows nothing about throwing.
That separation is the entire proof-of-concept.
> *"A contemptible weapon. It is also the surest way to bring a raider home breathing."*
---
## The vessel family
Four containers of the same fermented urine. Everything that separates them falls out of the two vessel
dials — **volume** and **seal** (see **Vessels and Substances**):
| Vessel | Volume | Sealed | Mass | Cooldown | Work | Cost | Character |
|---|---:|:---:|---:|---:|---:|---|---|
| **Piss Jar** | 500 ml | yes | 0.6 | 2.2 | 600 | 3 cloth | fills in ~7 h, throws far, palms easily, tight splash |
| **Piss Bottle** | 750 ml | yes | 0.9 | 2.6 | 900 | 5 cloth | ~10 h to fill, still throws clean |
| **Piss Bucket** | 8000 ml | **no** | 3.0 | 3.8 | 500 | 5 steel | days to fill, throws short, **sloshes over the carrier**, wide and thin |
| **Piss Nuke** | 5000 ml | yes | 2.2 | 3.2 | 3500 | 4 steel + 15 cloth | the flagship carboy — wide *and* dense |
All four throw as the framework's one projectile (`FP_Proj_Substance`), with a base verb range of **10.9**
and a **1.8 s** warm-up. The blast footprint each produces is derived from its two numbers, not authored:
| | Blast radius | Dose density | Filth |
|---|---:|---:|---:|
| Jar | ~2.1 | 1.0 | 2 |
| Bottle | ~2.4 | 1.0 | 2 |
| Bucket | ~7.1 | 0.55 (open) | 5 |
| Nuke | ~4.5 | 1.0 | 4 |
The bucket lands widest but thinnest and throws shortest; the carboy is the only one that is **both wide
and dense** — which is why it, and not the bucket, is the flagship.
---
## What makes a carboy a *nuke*
A carboy is not automatically a piss nuke. Identity is **emergent from runtime state**, enforced by the
contents-aware label (see **Fermentation**):
> **A "piss nuke" is only 100%-fermented (≥ 95% potency), undiluted, pure urine in a carboy.**
Any of the following demotes it, and the label refuses to pretend otherwise:
| State | Label | Why it is not a nuke |
|---|---|---|
| Fresh / mid-ferment | `piss nuke, fermenting 42%` | fresh urine is nearly sterile — potency is the weapon |
| Diluted (topped up) | lower potency | fresh liquid pulled the average age down |
| A cocktail | `piss nuke (urine 60%, feces 40%)` | it is a blend, and each part splashes at its own share |
| Spoiled (> ~75 days) | `piss nuke, spoiled` | it turned to inert vinegar |
Full strength is worth waiting for because **the harm scales with potency at every step** — the caustic
damage, the infection dose, and the eye burn all read it live at the moment of impact.
---
## Fermented urine, the substance
Urine (`PN_Urine`) is the harm profile the flagship attaches to its carboys — pure data on top of the
framework:
| Field | Value | Meaning |
|---|---|---|
| `mlPerDay` | 1750 | a jar fills in ~7 h, a carboy in ~3 days |
| `causticDamage` | 6 (via `PN_Caustic`) | the splash blisters skin — little more |
| `disease` / severity | piss rot / 0.35 | the real payload, applied in code, filtered by headgear |
| `burnsEyes` | true | concentrated ammonia can blind a bare face |
| `ferments` | true | fresh it is nearly harmless; weeks make it caustic |
| `drinkHediff` | food poisoning (0.35) | swallowing it is an illness and a memory |
Fresh urine is nearly sterile. It is **weeks of bacteria turning urea into ammonia** that make it
caustic, make it burn eyes, and make it a disease vector — which is why potency, not volume, is what you
are cultivating.
---
## Piss rot: non-lethal by design
The disease is the whole point, and it is deliberately **not a killer**. `PN_PissRot` is a real
immunizable infection built like vanilla flu, with one departure: `lethalSeverity = -1`, so however high
severity climbs, **it cannot kill**, and no stage is life-threatening.
| Stage | From severity | What it does |
|---|---:|---|
| **mild** | 0 | Moving/Manipulation/Sight −0.08, Breathing −0.04; occasional vomiting |
| **acute** | 0.35 | Moving/Manipulation/Sight −0.25, Eating −0.20, Consciousness −0.10, Breathing −0.12 |
| **wretched** | 0.70 | Moving/Manipulation −0.50, Sight −0.45, Eating −0.35, Breathing −0.22 — *the capture window* |
Even at `wretched`, breathing is held short of lethal on purpose: drive breathing to zero and the pawn
dies, which would quietly destroy the entire point of the weapon. The afflicted vomit, shake, go
half-blind and cannot hold a rifle straight — **capturable, not killable.**
The immunity race is what happens *afterward*: severity climbs fast but immunity outruns it (full
immunity in roughly **three days** for a healthy pawn), and tending flips severity from climbing to
falling. Two consequences worth knowing:
- **Tending and care genuinely matter** — a treated colonist shrugs it off in a day or two; an untreated
raider in the mud stays wretched for the better part of three days.
- **Immunity persists** (fading over ~10 days), so **piss-nuking the same faction twice in one week works
noticeably less well.** That is emergent, and it is a feature.
### Headgear is the counter
The infection route is the face (eyes, nose, mouth), so the single most effective thing a colonist can do
about any of this is **put a helmet on.** The dose is applied in C# precisely so it can read what a pawn
is wearing — something `DamageDef.additionalHediffs` cannot do:
| Worn on face | Protection |
|---|---:|
| Full-head covering (sealed helmet, gas mask) | **0.90** — near-total |
| Upper-head only (simple helmet) | 0.30 |
| Bare face | 0.00 |
On top of headgear, the pawn's Toxic Resistance further cuts the dose. A sealed helmet plus a constitution
of iron can shrug off a direct hit entirely.
### The eye burn
Only a *ripe, fermenting* substance burns corneas — a property of long fermentation. It requires potency
**≥ 0.75** and near-bare-face exposure (**≥ 0.9**); the chance scales with ripeness above that threshold
(`0.22 × (potency − 0.75) / 0.25`), and a hit takes 5–11 burn damage to an eye. A fresh carboy never does
it; a fully-ripe one thrown at an unhelmeted raider sometimes blinds.
---
## Throwing
When a pawn on a spree throws a carboy (`JobDriver_ThrowPissNuke`), the throw is deliberately *not* the
weapon's normal verb — the projectile is launched directly so the pawn never has to drop what they were
holding, and the carboy is **consumed** by the throw (it shatters, and having to brew another paces the
spree). The throw:
1. **Winds up** for 90 ticks.
2. **Reads potency** off the carboy's ferment comp — a vessel filled this morning is a bad smell; one
sitting since last season is a weapon.
3. **Hands the whole blend to the projectile** with per-substance shares, so a thrown cocktail lands every
constituent in its ratios (see **Vessels and Substances**).
4. **Scatters**: a psychotic throw is wild — it lands within ~2.6 cells of the aim point.
5. **Splashes back on the thrower**: you cannot heave an open-necked vessel of this without wearing some
of it. Self-splash chance is **0.18 for a sealed carboy, 0.54 for an open bucket** (×3), from whatever
substance they mostly slopped on themselves.
On impact the projectile runs the framework splash: the caustic blast (`6 × potency × doseDensity`), the
filth footprint, and the per-pawn infection dose with falloff toward the edge of the radius.
---
## Who throws it: the seeded disposition model
The mistake worth not making is treating imprisonment as the *cause*. It is not. Prisons hold thousands
and produce, every so often, **one** person notorious for this — notorious precisely because it is rare.
So the model is **disposition × circumstance, multiplied**, never a pile of added percentages
(`PissNukeSpreeUtility.WouldFoulPeople`):
- **Disposition** is a rare property of the person: `0.05` for the disinhibited (psychopath, bloodlust,
abrasive, cannibal), `0.004` for everyone else — effectively nobody.
- **Circumstance** decides whether a disposed person acts: tiers, not stacking bonuses.
| Circumstance | ×factor |
|---|---:|
| Free, well | 1.0 |
| Free, at the mood floor (< 0.20) | 3.0 |
| Prisoner, well kept | 2.5 |
| Prisoner, badly kept (mood < 0.35) | 6.0 |
| Prisoner, at the mood floor | 12.0 |
The resulting odds (capped at **60%**):
| Pawn | Chance |
|---|---:|
| Ordinary colonist | 0.4% |
| Ordinary colonist at the mood floor | 1.2% |
| Ordinary prisoner, well kept | 1.0% |
| Ordinary prisoner, badly kept | 2.4% |
| Ordinary prisoner, at the mood floor | 4.8% |
| Psychopath colonist | 5.0% |
| Psychopath prisoner, well kept | 12.5% |
| Psychopath prisoner, badly kept | 30.0% |
| Psychopath prisoner, at the mood floor | **60.0%** (capped) |
It therefore takes **both a rare individual and a badly run prison**. A well-run prison full of ordinary
captives essentially never sees this, which is exactly right.
**The roll is seeded on the pawn** (`thingIDNumber ^ 0x5E17`), so *"would they?"* is a fixed fact about
that person — the same pawn always answers the same way, which is what makes them a character the whole
block tells stories about rather than a dice roll re-thrown every tick.
### How the spree runs
The behaviour hangs off the existing psychotic/confused mental states via a think-tree patch — no new
mental break enters the roll table. A deranged pawn who *would* foul people:
1. **already carrying a carboy** → find any target in line of sight within ~22 cells and throw;
2. else **finds one lying about** within ~40 cells → fetch it (saves brewing);
3. else **brews one** — *if their body has anything left to give.*
That last limit is the **supply cooldown** (`MapComponent_PissNukeSupply`). Without it a spree brews and
throws on a ~4,500-tick cycle, which over 70k–90k ticks of psychotic wandering is sixteen to twenty
carboys — several dozen litres out of one person, a physiological impossibility. The body restocks on a
**25,000–35,000 tick** (~half-day) cooldown, so a spree yields two or three carboys, not twenty.
Note what the cooldown deliberately does **not** limit: throwing carboys **someone else made**. A pawn who
reaches a stockpile can empty it as fast as they can throw — a very good reason **not to keep the piss-nuke
stockpile near the people most likely to lose their minds.**
---
## Aftermath: residue and stink
The mess a carboy leaves is not just cosmetic.
**The residue is a fomite.** `MapComponent_PissResidue` spreads piss rot the way a contaminated person
really spreads it — by carrying it on themselves and leaving it on what they touch, **not** on the wind.
A pawn who wades through fouled ground is `contaminated` for ~half a day; while contaminated they have a
small chance each cycle to **track fresh filth** into wherever they walk (so the dining room becomes a
problem) and to **infect anyone adjacent** by direct contact. Nobody catches it from across the room —
but a fouled corridor walked into a mess hall is how these things move through a crowded building. Ground
residue reaches feet and hands, not eyes (kept below the eye-burn threshold on purpose).
**It reeks.** `ThoughtWorker_PissStink` gives a mood penalty for standing in or near fouled ground —
mild near a tile or two, and a distinct *"it's all I can smell"* penalty near six or more tiles of it
within a 4-cell radius. Cleaning up after a piss-nuke fight is not optional busywork; it is disease
control and mood management at once.
---
## Pressure: the carboy that goes off by itself
A sealed carboy of fermenting urine builds pressure. Once **overdue** (25 days) it rolls to rupture on an
MTB of 6 days, and when it does, `BurstWorker_Caustic` fires the same caustic splash at the carboy's
current potency — with nobody throwing it. A shelf of aging piss nukes is a rack of timed bombs. Keep
confiscated ones **cold** (a freezer nearly halts fermentation), drained, or destroyed. See
**Fermentation**.
---
## With Institution: Contraband — the prison layer
Foul Play stands alone as a craft-and-throw gross-weapon mod and patches nothing. When **Institution:
Contraband** is installed, a small bridge assembly (`Bridge_Contraband/`, loaded via `LoadFolders` *only*
when Contraband is present) turns the piss nuke into prison contraband — a prisoner brews a carboy from
their **own body** in a bare cell, conceals it, and gets searched for it. The bridge does three things:
1. **Registers the vessels as brewable contraband**, with concealability tracking size — a jar palms; a
five-litre carboy does not:
| Vessel | Concealability | Hides in |
|---|---:|---|
| Piss Jar | 0.70 | on body, in cell |
| Piss Bottle | 0.55 | on body, in cell |
| Piss Bucket | 0.20 | in cell only |
| Piss Nuke | 0.35 | in cell only |
Whether a prisoner *would* brew one uses the same `WouldFoulPeople` model above — a rare disposition
**and** a badly-run prison, multiplied. How you treat them decides how much of this you get.
2. **Merges the propensity engines.** The bridge repoints Foul Play's `Disposition.Source` at the suite's
full **nature × nurture** engine (surfaced by Contraband, owned by **Institution: Core**), flattened to
the 0..1 Foul Play wants: `Clamp01(nature × Clamp(nurture, 0.4, 3) × 0.6)`. From then on, *who fills a
vessel* and *who a drink hooks* read the same disposition Contraband uses for crime and policing — the
two mods never disagree about the same person. Without Contraband, Foul Play keeps its own local read.
3. **Preserves contents through concealment.** Contraband stores a blind content tag; the bridge gives it
meaning by wiring it to `CompVessel.SerializeContents` / `DeserializeContents`, so a hidden *jar of
hooch* comes back holding hooch, not whatever the jar's def defaulted to.
The throwing framework is never chained to the prison framework — the spree brews and throws on its own,
and concealment is a bonus the prison layer adds.
---
*Foul Play is part of the **Institution** suite — one install with a checkbox per layer (Core, Contraband, Policing, Corrections, Gangs, Ward) about what an institution does to the people inside it. It bridges to the Contraband layer when Institution is installed.*
+142
@@ -0,0 +1,142 @@
# Vessels and Substances
Foul Play splits every throwable into two axes that never touch:
- **The vessel** (`CompVessel`) is the *container* — how it is delivered.
- **The substance** (`SubstanceDef`) is the *fluid* — what it does when it lands.
A "piss jar" is the intersection: a jar (vessel) of urine (substance). This page is about how the two
combine at runtime, and the single most important fact about the whole framework: **a vessel holds a
weighted blend, and every consequence reads that blend, not the def.**
---
## A vessel is two numbers
RimWorld has no carryable containers of its own, so Foul Play ships a capability instead of a family.
Any `ThingDef` becomes a throwable vessel just by carrying `CompProperties_Vessel`, which declares two
things and lets everything else derive:
```xml
<li Class="FoulPlay.CompProperties_Vessel">
<volumeMl>500</volumeMl> <!-- capacity in millilitres -->
<sealed_>true</sealed_> <!-- corked/waxed, or open like a bucket -->
<substance>PN_Urine</substance> <!-- the default fill -->
</li>
```
Everything physical about the weapon is a function of those two numbers, derived once in `VesselProfile`
so the derivation is consistent across our vessels and any modded one. The reference point is a **5 L
carboy** (`RefVolumeMl = 5000`); `VolumeFraction = Clamp(volumeMl / 5000, 0.05, 4)`.
| Derived property | Formula | Sealed → | Open → | Consumed by |
|---|---|---|---|---|
| **Blast radius** | `4.5 × VolumeFraction^(1/3)` | ×1.0 | ×1.35 (slops wider) | the splash |
| **Dose density** | constant | 1.0 | 0.55 (lost some in transit) | splash damage + infection dose |
| **Filth count** | `max(2, round(4 × √VolumeFraction))` | — | — | how much mess it leaves |
| **Spill per cell** | constant | 0.0 | 0.06 | *(design model; see below)* |
| **Throw range factor** | `Lerp(1.3, 0.6, InverseLerp(0.1, 1.6, VF))` | ×1.0 | ×0.65 | *(design model; see below)* |
| **Fill ticks** | `round((volumeMl / mlPerDay) × 60000)` | — | — | how long a body takes to fill it |
Blast is a **cube-root** of volume because a splash is a volume spreading over an *area* — doubling the
litres does not double the radius. A sealed vessel bursts concentrated; an open one has already lost
liquid down the carrier's leg and spreads the rest thin.
> **Honesty note.** Blast radius, dose density and filth count are read live by the splash. Spill-per-cell
> and throw-range-factor are part of the same single-source derivation model but are not yet wired into
> a live per-cell spill or a range multiplier; the open vessel's "wears it on the way" character is
> currently expressed at throw time as a **tripled self-splash chance** (0.18 → 0.54). The model is
> the design contract; the splash is where it currently bites.
### The four starter vessels, derived
Concrete numbers for the Piss Nuke family, all falling straight out of the two dials:
| Vessel | Vol | Sealed | Blast radius | Dose density | Filth | Fill time (urine, 1750 ml/day) |
|---|---:|:---:|---:|---:|---:|---|
| Piss Jar | 500 ml | yes | ~2.1 | 1.0 | 2 | ~7 in-game hours |
| Piss Bottle | 750 ml | yes | ~2.4 | 1.0 | 2 | ~10 in-game hours |
| Piss Bucket | 8000 ml | **no** | ~7.1 | 0.55 | 5 | ~4.6 days |
| Piss Nuke | 5000 ml | yes | ~4.5 | 1.0 | 4 | ~2.9 days |
The bucket holds sixteen times the jar but throws *shorter*, lands *wider*, and arrives *thinner* — the
whole personality of an open container, none of it hand-authored.
---
## A vessel holds a *blend*, not a substance
Here is the part that turns four items into a system. `CompVessel` does not store "the substance." It
stores a **weighted blend** — a dictionary of *how much of each substance is present, by volume in ml*:
```
amounts = { FP_Urine: 250, FP_Feces: 250 } // a half-and-half cocktail in a 500 ml jar
```
A single substance is just a blend of one. A never-touched vessel reports `null` and behaves as a full
vessel of its def's substance until you pour something in — at which point the amounts materialise and
can be mutated.
### The four measurements
Every downstream system asks the blend the same handful of questions:
| Property | Meaning |
|---|---|
| **`Capacity`** | how much it holds full, in ml (= `volumeMl`) |
| **`TotalVolume`** | how much liquid is in it right now (a never-touched vessel = full of its def) |
| **`Headroom`** | `Capacity − TotalVolume` — room left to pour *more* in |
| **`FractionOf(sub)`** | that substance's **share** of the blend, `amount / total`, in 0..1 |
`IsFull` is `Headroom ≤ 0.001`. `Headroom` is the gatekeeper of mixing: **you cannot pour into a vessel
with no headroom.** (See **Mixing and Reactions**.)
### The dominant substance
`Substance` (singular) returns the biggest share — the substance a mostly-piss cocktail "is." It is used
for the label, for self-splash on a throw ("whatever they mostly slopped on themselves"), and anywhere a
single answer is needed. Setting it *replaces* the whole blend with a full vessel of that one substance.
---
## Everything scales by share
This is the payoff, and it is uniform across the entire mod. No consequence looks at the def's declared
substance; each looks at the runtime blend and **scales by each substance's fraction.** A drop of hooch
in a jar of piss barely warms you; a jar that is mostly hooch is a firebomb. Ratios decide the dose.
| System | How the share is applied |
|---|---|
| **Throwing / splash** | the projectile carries the whole blend; each constituent lands its own splash at `potency × fraction`. A thrown cocktail applies *every* substance in its ratios. |
| **Drinking** | `PostIngested` walks the blend and applies each substance's drink effect (hediff, thought, nutrition, addiction) scaled by its fraction. A memory below a **0.2** share is not even worth remembering. |
| **Addiction** | `addictionRarity × fraction × dispositionMultiplier` — a splash of luciferium in a jar rolls at a fraction of a full jar's odds. |
| **Reactions** | water douses fire volume-for-volume; a splash of water in a carboy of chemfuel barely dents it, a cup of hooch in a bucket of water is simply gone. |
| **Label** | a real cocktail relabels itself with the shares: `piss jar (urine 60%, hooch 40%)`. |
### Contents-aware labels
Because contents are runtime, a "piss jar" the def shipped may actually hold a vile cocktail. `CompVessel`
tells the truth in the label:
- A **cocktail** shows the shares, dominant first: `piss jar (feces 50%, urine 50%)`.
- A **single substance that is not the def's own**: `piss jar (hooch)`.
- A **fermenting or spoiled** vessel appends its state: `piss nuke, fermenting 42%` / `piss nuke, spoiled`.
Only a full-strength (≥95% potency), undiluted, pure vessel gets to wear its plain name — which is the
mechanical root of "a carboy is only a *piss nuke* when it is 100% ripe pure urine." (See **The Piss Nuke**.)
---
## For modders
Add a throwable container to any mod in three lines of XML: give a `ThingDef` a `CompProperties_Vessel`
with `volumeMl`, `sealed_`, and a default `substance`. You inherit correct fill time, blast, spill,
splash shape, mixing, fermentation-readiness, drink behaviour and contents labels for free — no
per-container code. Attach a new `SubstanceDef` (see **Substance Catalogue**) and any vessel can now hold
it. The two axes are orthogonal by construction: *N* vessels × *M* substances is *N×M* weapons from
*N+M* defs.
The contents blend is exposed as a flat string via `SerializeContents()` / `DeserializeContents()` so a
content-agnostic layer (like Contraband's concealment) can store a cocktail blind and hand it back whole.
---
*Foul Play is part of the **Institution** suite — one install with a checkbox per layer (Core, Contraband, Policing, Corrections, Gangs, Ward) about what an institution does to the people inside it. It bridges to the Contraband layer when Institution is installed.*