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
+27 -51
View File
@@ -3,48 +3,33 @@
*Gangs grow out of who pawns **already are** — and the counter-play is to keep the wrong pawns apart.*
A gang in this mod is never invented from nowhere. It crystallises along the bonds a colony already
contains: shared faction, shared faith, or real friendship. This page covers the formation rule — what
`SharesAffiliation` checks and why the *same room* requirement matters — and then the segregation
counter-play that turns those same bonds against the network.
contains: shared faction, shared faith, or real friendship. This page covers the formation rule — which
bonds count and why the *same room* requirement matters — and then the segregation counter-play that
turns those same bonds against the network.
## The formation rule
On each 5000-tick check, the gang component walks the eligible `crew` (every spawned humanlike that
currently meets the `Nature × Nurture ≥ 0.9` join bar) and tries to pair each unaffiliated member with
a mate:
```
mate = a pawn q in crew such that:
q != p
AND q.GetRoom() == p.GetRoom() -- same room, right now
AND SharesAffiliation(p, q) -- a bond they already have
if mate exists: Enlist(p, mate)
```
On each 5000-tick pass, the game walks everyone currently over the join bar (Nature × Nurture ≥ 0.9)
and tries to pair each unaffiliated pawn with a mate. A pawn pairs up with someone who is, at that
moment, **in the same room** *and* someone they **already share a bond with**.
Two conditions, both required: they must be **in the same room** at the moment of the check, **and**
they must **share an affiliation**. A disposed pawn does not fall in with a stranger across the map; it
falls in with someone it is standing next to *and* already connected to.
`Enlist` then binds them: if either already runs with a gang, the other joins that gang; otherwise a
fresh gang id is minted. So gangs accrete — a new member pairing with an existing member is absorbed
Pairing binds them together: if either already runs with a gang, the other joins that gang; otherwise a
fresh gang is founded. So gangs accrete — a new member pairing with an existing member is absorbed
into the existing crew rather than starting a rival one.
### What counts as an affiliation
```
SharesAffiliation(a, b) is true if ANY of:
a.Faction != null AND a.Faction == b.Faction -- same faction
Ideology active AND a.Ideo == b.Ideo (both non-null) -- same ideoligion
a.relations.OpinionOf(b) >= 20 -- a genuine friendship
```
| Bond | Condition | Notes |
|---|---|---|
| **Same faction** | `a.Faction == b.Faction` (non-null) | your colonists share one; captured raiders share theirs |
| **Same ideoligion** | `a.Ideo == b.Ideo`, only if the Ideology DLC is active | guarded by `ModsConfig.IdeologyActive` |
| **Friendship** | `OpinionOf(b) >= 20` | a real positive relationship, not mere acquaintance |
| **Same faction** | both belong to the same (non-empty) faction | your colonists share one; captured raiders share theirs |
| **Same ideoligion** | both follow the same ideoligion, only if the Ideology DLC is active | needs Ideology enabled |
| **Friendship** | an opinion of at least **+20** of each other | a real positive relationship, not mere acquaintance |
The design intent, from the source:
The design intent:
> Gangs grow out of who pawns ALREADY are, not out of nowhere — so a prisoner's gang on the outside is
> their old faction/friends, and rival factions run as rival gangs.
@@ -57,9 +42,9 @@ random groupings over the top.
Follow the rule to its conclusion. Two captured raiders from **different** hostile factions each share
an affiliation with *their own* side but not with each other. Housed in the same wing, each pairs up
along its own faction line — and now you have **two gangs**. By the definition on the
[Rivalry and Fights](Rivalry-and-Fights.md) page, members of two different gangs are automatically
**rivals**, and rival-gang violence between them is booked as a crime.
along its own faction line — and now you have **two gangs**. As the
[Rivalry and Fights](Rivalry-and-Fights.md) page explains, members of two different gangs are
automatically **rivals**, and rival-gang violence between them is booked as a crime.
So the affiliation rule and the rivalry rule are two ends of one idea: **who bands together** and **who
is opposed** both derive from pre-existing loyalties. Mix hostile factions or clashing ideoligions in
@@ -70,39 +55,31 @@ them. This is a housing decision with mechanical teeth.
Here is where the formation rule and the network rule meet, and where the rest of the suite earns its
keep. A gang can only *do* anything — resupply itself — if its members can **reach** each other.
`MoveWithin` requires `SameGang` **and**, for two co-located pawns, a walkable path
(`CanReach(..., Touch, Danger.Deadly)`). Break the path and you break the network:
Passing contraband requires two things: the pawns must be in the same gang, **and** two pawns both on
the map must have a walkable path between them. Break the path and you break the network.
```
MoveWithin(from, to):
...
if from.Spawned && to.Spawned && !from.CanReach(to, Touch, Deadly):
return false -- kept apart: the segregation counter-play
```
The source calls this out as the intended answer to the whole mod:
The design calls this out as the intended answer to the whole mod:
> The counter-play is the rest of the suite: Classification SEGREGATES rivals into different wings, and
> a network whose members cannot REACH each other is starved.
**Classification** lives in **Institution: Justice**. It grades pawns by risk and lets you sort them
into separate, walled wings. Two gangmates graded into different wings, with no walkable route between
them, fail the reach gate on every network pass. The gang still *exists* on the membership map — they
are still the same crew, still rivals of the other crew — but it can no longer pass a shiv from a
holder to a have-not. **A network that cannot reach itself is a network that cannot supply itself.**
them, fail the reach test on every network pass. The gang still *exists* — they are still the same crew,
still rivals of the other crew — but it can no longer pass a shiv from a holder to a have-not. **A
network that cannot reach itself is a network that cannot supply itself.**
This is the elegant part of the design: the very bonds that formed the gang (`SharesAffiliation`) tell
you *who to keep apart*, and the reach requirement (`CanReach`) makes keeping them apart actually
starve the supply chain. You do not disband a gang; you **partition the graph** until its edges carry
nothing.
This is the elegant part of the design: the very bonds that formed the gang tell you *who to keep
apart*, and the reach requirement makes keeping them apart actually starve the supply chain. You do not
disband a gang; you **cut it off from itself** until nothing can move along it.
## How to play it
- **Read affiliations before you house pawns.** Same-faction and same-ideoligion prisoners will band
together; hostile factions in one wing will form *rival* gangs and fight. Sort deliberately.
- **Segregate by Classification, not by hope.** Putting rivals in "different areas" is not enough — the
reach test cares about a *walkable path*. A shared corridor is a supply line. Use genuinely separate,
walled wings.
- **Segregate by Classification, not by hope.** Putting rivals in "different areas" is not enough —
resupply only needs a *walkable path* between two gangmates. A shared corridor is a supply line. Use
genuinely separate, walled wings.
- **Starve, don't chase.** You will rarely delete a gang outright. The durable win is to keep its
members unable to reach one another so the network dries up, while keeping mood and deterrence high so
few pawns cross the join bar in the first place (see [Joining](Joining.md)).
@@ -112,4 +89,3 @@ nothing.
---
*Part of the **Institution** suite — Core · Contraband · Justice · Gangs (this). Each mod stands alone; together they are one system.*
**
+20 -21
View File
@@ -23,7 +23,7 @@ If you run **Prisoner Realism**, its *Ringleader* system already models a domina
unrest and mood contagion through a wing. That system is good, and Gangs does not touch it. Ringleader
owns *influence and mood*.
Gangs owns the thing Ringleader has no equivalent for: **the network as a logistics graph.** Contraband
Gangs owns the thing Ringleader has no equivalent for: **the network as a supply chain.** Contraband
physically changes hands along social lines. A stash on one pawn is a stash available to the whole
gang. The two systems are complementary — run both. Ringleader tells you *who stirs the pot*; Gangs
tells you *how the shivs get around*.
@@ -36,7 +36,7 @@ dependencies:
| It asks... | ...and the answer comes from |
|---|---|
| *Who is disposed enough to join?* | **Institution: Core** — `Nature × Nurture`, the shared propensity engine |
| *Who is disposed enough to join?* | **Institution: Core** — the propensity engine that scores each pawn's Nature and Nurture |
| *What do they move?* | **Institution: Contraband** — concealment, stashes, search, and the bent-warden supply route |
| *Where does a fight get booked, and how are rivals kept apart?* | **Institution: Justice** — the crime/deterrence loop, and Classification's segregation |
@@ -45,10 +45,11 @@ Contraband's stashes, and Justice's policing all cash out at once.
## A healthy colony grows few gangs — or none
This is the thesis, and it is enforced in the numbers, not just the flavour. Membership is gated at
`Nature × Nurture ≥ 0.9` — a high bar on purpose. A disposed pawn who is **well-kept and
well-policed** does not band up: their nurture multiplier stays low, and deterrence pulls it lower
still. It takes a foul streak (nature) *and* a badly-run situation (nurture) at the same time.
This is the thesis, and it is enforced in the numbers, not just the flavour. Membership is gated at a
Nature × Nurture score of **0.9 or higher** — a high bar on purpose. A disposed pawn who is
**well-kept and well-policed** does not band up: their nurture multiplier stays low, and deterrence
pulls it lower still. It takes a foul streak (nature) *and* a badly-run situation (nurture) at the
same time.
So a gang problem is a **symptom**. It is the game telling you that a wing is mistreated, under-policed,
or both. The fix is never "fight the gang system" — it is to run a better prison. Feed them, give them
@@ -58,32 +59,30 @@ recreation, keep deterrence high, segregate rivals, and the networks starve on t
## The pages
- **[Joining](Joining.md)** — `WouldJoin = Nature × Nurture ≥ 0.9`: why the bar is high, why good
treatment and deterrence keep pawns *out*, and how the 5000-tick check works for every kind of pawn.
- **[Networks and Smuggling](Networks-and-Smuggling.md)** — `MoveWithin`: how a holder resupplies a
needy gangmate, the *same-gang + can-reach* rule, why this defeats a single search, and how a bent
warden refills a starved network from outside.
- **[Rivalry and Fights](Rivalry-and-Fights.md)** — `AreRivals` and `RecordFight`: how a gang fight is
booked as a crime through Justice, why inside-the-wire and out-on-the-street are the same offence,
and how it feeds deterrence.
- **[Affiliations and Segregation](Affiliations-and-Segregation.md)** — `SharesAffiliation` plus
*same room* as the formation rule, why rival factions become rival gangs, and how Classification's
segregation is the counter-play that starves a network which cannot reach itself.
- **[Joining](Joining.md)** — why the join bar (Nature × Nurture ≥ 0.9) is high, why good treatment and
deterrence keep pawns *out*, and how membership is re-checked for every kind of pawn.
- **[Networks and Smuggling](Networks-and-Smuggling.md)** — how a holder resupplies a needy gangmate,
the *same-gang-and-can-reach* rule, why this defeats a single search, and how a bent warden refills a
starved network from outside.
- **[Rivalry and Fights](Rivalry-and-Fights.md)** — how a gang fight is booked as a crime through
Justice, why inside-the-wire and out-on-the-street are the same offence, and how it feeds deterrence.
- **[Affiliations and Segregation](Affiliations-and-Segregation.md)** — shared faction, faith, or
friendship plus *same room* as the formation rule, why rival factions become rival gangs, and how
Classification's segregation is the counter-play that starves a network which cannot reach itself.
## The suite
Part of the **Institution** suite of RimWorld 1.6 mods:
- **Institution: Core** — the propensity engine (`Nature × Nurture`), criminal records, secured context.
- **Institution: Core** — the propensity engine (Nature × Nurture), criminal records, secured context.
- **Institution: Contraband** — concealment, improvised shivs, tunnels, warden search and corruption.
- **Institution: Justice** — Classification, Deterrence, Discipline, Parole, Regime.
- **Institution: Gangs** — this mod: joining, networks/smuggling, rivalry/fights.
Sibling projects: **Foul Play** (the vessel/substance framework and the "Piss Nuke") and **Ward** (the
test harness and a ward/treatment prison mode).
Sibling projects: **Foul Play** (the vessel/substance framework and the "Piss Nuke") and **Ward** (a
ward/treatment prison mode).
Each mod stands alone as an install; together they form one system.
---
*Part of the **Institution** suite — Core · Contraband · Justice · Gangs (this). Each mod stands alone; together they are one system.*
**
+34 -55
View File
@@ -3,48 +3,39 @@
*How Gangs decides who runs with a crew — and why a well-run colony keeps almost everyone out.*
Membership is not random, and it is not a mood event. A pawn joins a gang only when their **disposition
and their circumstances line up at once** — the same `Nature × Nurture` engine that drives every other
behaviour in the Institution suite. This page covers the exact test, why the bar is set where it is,
and how you keep pawns on the right side of it.
and their circumstances line up at once** — the same Nature × Nurture propensity that drives every
other behaviour in the Institution suite. This page covers the exact test, why the bar is set where it
is, and how you keep pawns on the right side of it.
## The rule
```
WouldJoin(pawn) == Propensity.Nature(pawn) * Propensity.Nurture(pawn) >= JoinThreshold
JoinThreshold = 0.9
```
A pawn joins when their **Nature multiplied by their Nurture reaches 0.9 or higher**. Only humanlike
pawns are ever eligible — animals and mechs never join.
Two gates before the maths even runs:
| Guard | Effect |
|---|---|
| `pawn == null` | never joins |
| not `RaceProps.Humanlike` | never joins — animals and mechs are out |
Then it is one line: multiply the pawn's **Nature** by their **Nurture** and compare to **0.9**. There
is no dice roll here. `WouldJoin` is a deterministic threshold on the two propensity scores, so the
same pawn in the same situation always gives the same answer — join, or don't. (This is different from
Core's `Propensity.Would(...)`, which *is* a seeded random roll used for one-off acts like a piss
spree. Gang membership is a standing condition, so it uses the raw product.)
Beyond that it is one line of arithmetic: multiply the pawn's **Nature** by their **Nurture** and
compare to **0.9**. There is no dice roll here. The same pawn in the same situation always gives the
same answer — join, or don't. (That makes membership different from one-off acts like a piss spree,
which *do* roll the dice each time. Gang membership is a standing condition, so it uses the raw product
with no randomness.)
### The two halves
Both terms come from **Institution: Core** — see Core's own documentation for the full tables — but you
need the shape of them to understand the bar:
- **Nature** (`0..1`) is *who the pawn is*: a base of `0.05`, plus trait weights, clamped to `[0, 1]`.
Psychopath `+0.45`, Bloodlust `+0.35`, Kleptomaniac `+0.40`, Greedy `+0.25`, Abrasive `+0.15`;
and it goes **down** for Kind `−0.30` or Ascetic `−0.15`. This is fixed at pawn creation and barely
moves.
- **Nurture** (a multiplier, `~≥ 0.4`, base `1.0`) is *the situation you put them in*: a floored mood
multiplies it up hard (roughly `×2.5` under 0.20 mood, `×1.6` under 0.35), being held while
miserable adds more (`×1.4`), a hardened record (negative reform) raises it, and — critically —
**deterrence pulls it down** (`×Lerp(1.3, 0.7, deterrence)`, neutral `1.0` at baseline order, so a
high-deterrence colony scales nurture toward `0.7`). This is the half you control.
- **Nature** (`0` to `1`) is *who the pawn is*: a base of `0.05`, plus trait weights, floored at `0`
and capped at `1`. Psychopath `+0.45`, Bloodlust `+0.35`, Kleptomaniac `+0.40`, Greedy `+0.25`,
Abrasive `+0.15`; and it goes **down** for Kind `−0.30` or Ascetic `−0.15`. This is fixed at pawn
creation and barely moves.
- **Nurture** (a multiplier, roughly `0.4` at the floor, `1.0` at baseline) is *the situation you put
them in*: a floored mood multiplies it up hard (roughly `×2.5` under 0.20 mood, `×1.6` under 0.35),
being held while miserable adds more (`×1.4`), a hardened record (negative reform) raises it, and —
critically — **deterrence pulls it down** (toward about `0.7` in a high-deterrence colony; a neutral,
baseline order sits at `1.0`). This is the half you control.
## Why the bar is high
`0.9` is a deliberately steep threshold. From the source, in its own words:
`0.9` is a deliberately steep threshold. In the design's own words:
> A high bar, on purpose: gangs are a symptom of a badly-run colony, not furniture. A healthy Rimworld
> — content pawns, an orderly colony — grows few gangs, if any.
@@ -63,7 +54,7 @@ the shape of the decision.
| Pawn | Nature | Situation → Nurture | Product | Joins? |
|---|---|---|---|---|
| **Kind colonist**, ordinary life | `0.05 − 0.30 → 0.00` (clamped) | content, `≈ 1.0` | `0.00` | **No** — nature floors it |
| **Kind colonist**, ordinary life | `0.05 − 0.30`, floored at `0.00` | content, `≈ 1.0` | `0.00` | **No** — nature floors it |
| **Greedy prisoner**, content, policed | `0.30` | fed & high deterrence, `≈ 0.7` | `≈ 0.21` | **No** |
| **Greedy prisoner**, starved & neglected | `0.30` | mood floored + held, `≈ 3.5` | `≈ 1.05` | **Yes** |
| ...same pawn, but you raise deterrence | `0.30` | `× ≈ 0.7` → `≈ 2.45` | `≈ 0.74` | **No** — deterrence tipped them out |
@@ -74,44 +65,33 @@ you run the wing. The Kind colonist and the near-maxed psychopath are the fixed
cannot join, the other essentially always will if you neglect them. Everyone in between is a policy
choice.
The mod's own integration test asserts exactly these poles: a psychopath-plus-bloodlust pawn with a
floored mood returns `WouldJoin == true`, and a Kind colonist in ordinary circumstance returns
`WouldJoin == false`.
## It works for every pawn, everywhere
There is no "prisoners only" special case. The comment is explicit:
There is no "prisoners only" special case: any pawn — colonist, prisoner, slave — can run with a crew,
wherever they are.
> Any pawn — colonist, prisoner, slave — can, wherever they are.
`WouldJoin` reads nothing about a pawn's secured status. A disposed **free colonist** can run with a
Membership pays no attention to a pawn's secured status. A disposed **free colonist** can run with a
crew on the outside; a **prisoner** can run with theirs on the inside; a **slave** likewise. This is
what lets a gang span the wall — an outside member and an inside member of the same crew (see
[Networks and Smuggling](Networks-and-Smuggling.md)). Being held raises nurture (misery), but it is not
a requirement.
## The cadence: the 5000-tick check
## The cadence: every 5000 ticks
Membership is re-evaluated on a fixed interval by the gang map component:
Gang membership is re-evaluated on a fixed interval — every **5000 ticks**, which is about **2 in-game
hours** (a RimWorld day is 60,000 ticks), or roughly **80 seconds** of real time at normal (1×) speed.
On each pass, the game:
```
CheckInterval = 5000 ticks
MapComponentTick: run only when TicksGame % 5000 == 0
```
**5000 ticks** is about **2 in-game hours** (a RimWorld day is 60,000 ticks), or roughly **80 seconds**
of real time at normal (1×) speed. On each fire, the component:
1. Gathers `crew` — every spawned humanlike on the map for whom `WouldJoin` is currently true.
2. Pairs up unaffiliated members of `crew` who **share a room and a bond** into gangs (see
1. Gathers everyone on the map who currently meets the Nature × Nurture ≥ 0.9 join bar.
2. Pairs up unaffiliated members who **share a room and a bond** into gangs (see
[Affiliations and Segregation](Affiliations-and-Segregation.md)).
3. Runs one round of network resupply inside each gang (see
[Networks and Smuggling](Networks-and-Smuggling.md)).
Because the check re-reads `WouldJoin` every time, membership is *live*: a pawn whose situation improves
past the point where the product drops back under `0.9` simply stops being eligible to form new bonds.
The bar is not a one-time gate at recruitment — it is a standing condition the colony is continuously
graded against.
Because the join bar is re-checked from scratch every pass, membership is *live*: a pawn whose situation
improves until the product drops back under `0.9` simply stops being eligible to form new bonds. The
bar is not a one-time gate at recruitment — it is a standing condition the colony is continuously graded
against.
## How to keep pawns out
@@ -131,4 +111,3 @@ You do not fight the gang system. You lower nurture, which lowers the product, w
---
*Part of the **Institution** suite — Core · Contraband · Justice · Gangs (this). Each mod stands alone; together they are one system.*
**
+43 -58
View File
@@ -3,40 +3,33 @@
*The one thing nothing else models: contraband that flows **between** pawns. A gang is a supply chain.*
This is the core of the mod. Everything else — who joins, who fights, who is kept apart — exists to
serve or to break the network described here. A gang is not a mood aura; it is a **logistics graph**,
and its edges carry contraband.
serve or to break the network described here. A gang is not a mood aura; it is a **supply chain**, and
contraband flows along it.
## The move
The heart of it is one method, `MoveWithin(from, to)`: a gangmate who is holding a stash passes a piece
of it to a gangmate who has none. It returns `true` if something actually moved.
The heart of it is a single transfer: a gangmate who is holding a stash passes one piece of it to a
gangmate who has none. Here is everything that has to be true for a piece to move:
```
MoveWithin(from, to):
1. both non-null, and SameGang(from, to) -- else false
2. if both are Spawned: from must CanReach(to, -- the reach gate
PathEndMode.Touch, Danger.Deadly) -- else false
3. a Contraband tracker must exist on the map -- else false
4. 'from' must have at least one concealed item -- else false
5. take stash[0]:
tracker.Confiscate(from, item.def) -- leaves the supplier's hands
tracker.Conceal(to, item.def) -- arrives, hidden, in the customer's
return true
```
- both pawns are in the **same gang**;
- if both are on the map, the supplier has a **walkable path** to the customer (touch range, willing to
cross deadly danger to get there);
- there is contraband in play on the map at all;
- the supplier is actually holding at least one concealed item.
When all of that holds, the supplier's first concealed item leaves their hands and arrives — still
hidden — on the customer.
A few things worth reading carefully:
- **One item per move.** It takes `stash[0]` — the first concealed item on the supplier — and moves
exactly that. It is a redistribution, not a duplication: the item leaves `from` (`Confiscate`) and
arrives concealed on `to` (`Conceal`). The gang's total stash is unchanged; only *who holds it*
changes.
- **Same gang, always.** `SameGang` requires both pawns to hold the same non-zero gang id. There is no
smuggling to a stranger — the network only moves along membership.
- **The reach gate only applies to co-located pawns.** The `CanReach` check is guarded by
`from.Spawned && to.Spawned`. Two pawns both physically on the map must have a walkable path
(`Touch` range, willing to cross `Deadly` danger) between them. If a member is not spawned, the
reach check is skipped — which is what allows a gang to reach across the wall to a member who is off
the active map.
- **One item per move.** It moves the first concealed item on the supplier, and exactly that. It is a
redistribution, not a duplication: the item leaves the supplier and arrives concealed on the customer.
The gang's total stash is unchanged; only *who holds it* changes.
- **Same gang, always.** Both pawns must belong to the same gang. There is no smuggling to a stranger —
the network only moves along membership.
- **The reach requirement only applies to pawns both on the map.** Two pawns physically present must
have a walkable path between them. If a member is off the active map, the reach check is skipped —
which is what allows a gang to reach across the wall to a member who is not on the map right now.
## Why this defeats a single search
@@ -45,61 +38,54 @@ tick a box: *cell searched, no contraband.* But the shiv was on Prisoner C the w
next 5000-tick network pass it will move to whoever is out. Search C tomorrow and it may already be on
A again.
From the source comment, plainly:
Put plainly:
> A gangmate holding a stash supplies one who has none, so a search that turns up nothing on one
> prisoner has not cleaned out the wing.
A single search is a snapshot of one node in a graph that reshuffles itself. This is the whole reason
A single search is a snapshot of one pawn in a network that reshuffles itself. This is the whole reason
contraband-as-a-network is worth modelling: **the unit of contraband is the wing, not the pawn.** To
clean it out you have to either search faster than it moves, or — far better — break the graph.
clean it out you have to either search faster than it moves, or — far better — break the network.
## The automatic resupply pass
You do not call `MoveWithin` by hand; the gang component does it on the 5000-tick check. After forming
gangs for the pass, it runs one resupply round **per gang**:
```
for each gang among the eligible crew:
holder = first member who IS hiding contraband
needy = first member who is NOT hiding contraband
if holder and needy both exist:
MoveWithin(holder, needy)
```
You never trigger a transfer by hand; the game runs it automatically on the 5000-tick pass. After
forming gangs for the pass, it runs one resupply round **per gang**: it finds the first member who *is*
hiding contraband and the first member who is *not*, and if both exist, moves one item from the holder
to the empty-handed member.
So on each interval, every gang that has both a haves-member and a have-not-member performs **one**
transfer, moving a single item from a holder to someone empty-handed. Over several ticks the effect is
transfer, moving a single item from a holder to someone empty-handed. Over several passes the effect is
that a gang tends to keep its members supplied and to spread a stash out — which is exactly what makes
a scattershot search miss it. (Only members who currently meet the join bar participate in this
automatic pass; the resupply loop draws from the same `crew` used for formation.)
a scattershot search miss it. (Only members who currently meet the join bar take part in this automatic
pass.)
## The cross-wall move
Because `WouldJoin` and `SameGang` care nothing about a pawn's secured status, a gang can have a
Because neither the join bar nor gang membership cares about a pawn's secured status, a gang can have a
**free** member and a **held** member. If the free member is holding the stash, the network resupplies
*into* the prison — the outside man passes to the inside man. The mod's integration test builds exactly
this: a free psychopath colonist and a prisoner in one gang, the stash on the free member, and
`MoveWithin(free, prisoner)` succeeds — after which the prisoner is hiding contraband and the free
colonist is not. Your prison's contraband problem is not sealed inside your prison.
*into* the prison — the outside man passes to the inside man. A free colonist and a prisoner can be in
one gang with the stash on the free member; the transfer succeeds, and afterwards the prisoner is hiding
contraband and the colonist is not. Your prison's contraband problem is not sealed inside your prison.
## Resupply from outside: the bent warden
`MoveWithin` only *redistributes* what a gang already has. So what happens when you finally search the
whole wing on the same day and strip every member clean — the graph has no more edges to carry? The
The transfer only *redistributes* what a gang already has. So what happens when you finally search the
whole wing on the same day and strip every member clean — there is nothing left to pass around? The
gang is starved. It stays starved until contraband **re-enters** from outside.
That external source is not part of Gangs; it is **Institution: Contraband's** corruption route. A
warden's honesty varies by personality (a Greedy warden has a price), and a bent warden can *smuggle
contraband in to a prisoner* — `Corruption.Smuggle(warden, prisoner, tracker)` plants a concealed item
directly. That single seeded item is then all the network needs: one holder, and the 5000-tick pass
spreads it back out across everyone who can reach.
contraband in to a prisoner*, planting a concealed item directly. That single planted item is then all
the network needs: one holder, and the next 5000-tick pass spreads it back out across everyone who can
reach.
So the two halves of the supply picture are:
| Mechanism | Owner | What it does |
|---|---|---|
| `MoveWithin` | **Gangs** | moves existing contraband *between* gangmates who can reach each other |
| `Corruption.Smuggle` | **Contraband** | injects *new* contraband from outside via a corruptible warden |
| Passing contraband between gangmates | **Gangs** | moves existing contraband *between* gangmates who can reach each other |
| Warden smuggling | **Contraband** | injects *new* contraband from outside via a corruptible warden |
Cut both and a gang genuinely dries up. Cut only the redistribution and a bent warden re-seeds it; cut
only the warden and any stash you missed keeps circulating.
@@ -109,12 +95,11 @@ only the warden and any stash you missed keeps circulating.
- **Search the whole wing at once**, not one pawn at a time. A partial sweep is a snapshot the network
routes around.
- **Segregate rivals into different, unreachable wings** (Classification, in Institution: Justice). The
reach gate is the lever — a network whose members cannot walk to each other cannot pass anything.
This is the primary counter-play; see
reach requirement is the lever — a network whose members cannot walk to each other cannot pass
anything. This is the primary counter-play; see
[Affiliations and Segregation](Affiliations-and-Segregation.md).
- **Clean up your wardens.** If searches never seem to finish the job, you may have a Greedy warden
re-seeding the wing. Corruption is the resupply valve; personality is the fix.
---
*Part of the **Institution** suite — Core · Contraband · Justice · Gangs (this). Each mod stands alone; together they are one system.*
**
+31 -49
View File
@@ -9,27 +9,22 @@ suite can *see* and *police*.
## Who is a rival
```
AreRivals(a, b):
ga = GangOf(a); gb = GangOf(b)
return ga != 0 && gb != 0 && ga != gb
```
The definition is exactly as blunt as it reads: **two pawns in two different gangs are rivals.** Both
must actually be in a gang (a non-zero id), and the ids must differ. From the source:
The rule is exactly as blunt as it sounds: **two pawns in two different gangs are rivals.** Both must
actually be in a gang, and it must be a *different* gang for each. As the design puts it:
> Two pawns of DIFFERENT gangs are rivals — inside the wire or out on the street.
Note what is *not* required. There is no separate "hostility" flag, no rival-declaration event, no
threshold to cross. The moment two crews exist, their members are rivals of one another. Rivalry is a
structural fact about the membership map, not a mood or a relationship value.
structural fact about who is in which gang, not a mood or a relationship value.
Two consequences fall straight out of that:
- **Non-members are nobody's rival.** A pawn with gang id `0` — everyone in a healthy colony — is never
a rival to anyone, because `AreRivals` requires both ids non-zero. No gangs, no rivalry.
- **Same gang, never rivals.** Members of one crew fail the `ga != gb` test. Within a gang there is no
rivalry to book; there is the network (see [Networks and Smuggling](Networks-and-Smuggling.md)).
- **Non-members are nobody's rival.** A pawn in no gang — everyone in a healthy colony — is never a
rival to anyone, because rivalry needs *both* pawns to be in a gang. No gangs, no rivalry.
- **Same gang, never rivals.** Members of one crew are in the *same* gang, so they are not rivals.
Within a gang there is no rivalry to book; there is the network (see
[Networks and Smuggling](Networks-and-Smuggling.md)).
Where do two *different* gangs come from in the first place? From the affiliations pawns already have —
rival factions and rival ideoligions form into separate crews. That is the subject of
@@ -38,44 +33,33 @@ with the colony's existing social fault lines, so **rival factions run as rival
## A fight is a crime
The payoff of tracking rivalry is `RecordFight`. When a rival-gang attack happens, it is not treated as
generic brawling — it is booked as a crime through the same Justice pipeline as any other offence.
The payoff of tracking rivalry is what happens when rivals fight. When a rival-gang attack happens, it
is not treated as generic brawling — it is booked as a crime through the same Justice pipeline as any
other offence.
```
RecordFight(attacker, victim):
if attacker == null || victim == null: return
if !AreRivals(attacker, victim): return -- only rival-gang violence counts
Justice.RecordCrime(attacker)
```
Only rival-gang violence counts: the two pawns must be in different gangs for anything to be recorded.
A scuffle between gangmates, or between two non-members, is not a *gang* fight and is not booked. When
it *is* rival-gang violence, the whole event is recorded as a crime against the **attacker**, and that
does three things at once (they live in Institution: Justice, but this is what Gangs is leaning on):
So the guard is precise: the two pawns must be **rivals** (different gangs) for anything to be recorded.
A scuffle between gangmates, or between two non-members, is not a *gang* fight and is not booked here.
When it *is* rival-gang violence, the whole event routes through one call — `Justice.RecordCrime`,
against the **attacker** — and that single call does three things at once (it lives in Institution:
Justice, but this is what Gangs is leaning on):
| Effect of `Justice.RecordCrime(attacker)` | Owner |
| Effect of booking a gang fight | Where it lands |
|---|---|
| `crimesCommitted` on the attacker's record goes up | Core's `CriminalRecord` |
| `lastCrimeTick` is stamped to now | Core's `CriminalRecord` |
| the colony's **deterrence** nudges **down** (a crime happened; order slipped) | Justice's `MapComponent_Deterrence` |
The mod's integration test confirms the loop end to end: it builds two rival gangs, records a fight,
and asserts both that the attacker and victim *are* rivals and that the attacker's `crimesCommitted`
went up as a result.
| the attacker's crime count goes up | their criminal record (Core) |
| the time of the crime is stamped to now | their criminal record (Core) |
| the colony's **deterrence** nudges **down** (a crime happened; order slipped) | Justice's deterrence system |
## Inside the wire and out on the street are the same offence
This is the design point the source is emphatic about:
This is the design point the mod is emphatic about:
> A gang fight is a CRIME — it goes on the attacker's record and moves the colony's climate through
> the same Justice loop as any other, so it can be investigated, attributed and policed. Rival-gang
> violence inside a prison and out on the street are the same offence.
There is no separate code path for a prison-yard shanking versus a colonists' brawl in the dining
room. `RecordFight` reads only `AreRivals` and calls `Justice.RecordCrime`. A free colonist who is a
gang member attacking a rival is booked identically to a prisoner doing the same in a cell block. The
gang system does not care which side of the wall the violence is on — only that it was between rivals.
There is no separate rule for a prison-yard shanking versus a colonists' brawl in the dining room. A
fight is booked purely on whether the two pawns are rivals. A free colonist who is a gang member
attacking a rival is booked identically to a prisoner doing the same in a cell block. The gang system
does not care which side of the wall the violence is on — only that it was between rivals.
This is what makes gang violence *legible* to the rest of the suite. A fight is not a one-off flavour
event that scrolls past in the log; it is a record entry with an attributed perpetrator and a timestamp,
@@ -85,19 +69,18 @@ which means it can be investigated, blamed on a specific pawn, and answered.
Here is the loop that closes the whole suite:
1. A rival-gang fight fires `RecordFight` → `Justice.RecordCrime(attacker)`.
1. A rival-gang fight is booked as a crime against the attacker.
2. That nudges the colony's **deterrence down**. Order has visibly slipped.
3. Lower deterrence *raises* the nurture multiplier for **every** disposed pawn on the map
(deterrence scales nurture via `×Lerp(1.3, 0.7, deterrence)` — less deterrence, bigger multiplier).
4. Higher nurture pushes more pawns over the `Nature × Nurture ≥ 0.9` join bar (see
3. Lower deterrence *raises* the nurture multiplier for **every** disposed pawn on the map (less
deterrence means a bigger multiplier).
4. Higher nurture pushes more pawns over the Nature × Nurture ≥ 0.9 join bar (see
[Joining](Joining.md)).
5. More members → more rivals → more fights available to be booked.
Left unanswered, gang violence is self-reinforcing: each booked fight makes the next one likelier. The
brake is the other half of Justice — **punishment raises deterrence back up** (`RecordPunishment`
nudges it up), which lowers nurture, which drops borderline pawns back under the bar. The integration
test checks exactly this seesaw: a punishment raises the deterrence level, and a subsequent crime
lowers it again.
brake is the other half of Justice — **punishment raises deterrence back up**, which lowers nurture,
which drops borderline pawns back under the bar. The seesaw works both ways: punishing a pawn raises the
deterrence level, and a fresh crime lowers it again.
## How to play it
@@ -113,4 +96,3 @@ lowers it again.
---
*Part of the **Institution** suite — Core · Contraband · Justice · Gangs (this). Each mod stands alone; together they are one system.*
**