A seed looks like one die. It's thirteen. StS1 derives every random decision in a run from a single number, but it doesn't roll them all on one stream — it splits the work across named streams so that shuffling your deck doesn't shift which event appears next floor.
Thirteen streams, thirteen owners
Exactly 13 streams exist. Twelve are created directly from the run seed, each starting at counter 0; the map stream is created once per act, with an act-specific offset. Each owns one slice:
| Stream | Owns |
|---|---|
| monsterRng | encounter table rolls, boss list shuffle |
| eventRng | ? room substitution, event/shrine selection, event outcomes |
| merchantRng | shop stock tier, price jitter, sale card |
| cardRng | card reward rarity rolls, colorless rarity, curse picks |
| treasureRng | chest size/rewards, gold amounts, elite relic tier |
| relicRng | relic tier rolls, relic pool shuffles |
| potionRng | drop chance, potion rarity, key pick |
| monsterHpRng | HP range rolls (reseeded per floor) |
| aiRng | monster AI decisions (reseeded per floor) |
| shuffleRng | draw pile shuffles (reseeded per floor) |
| cardRandomRng | truly-random card generation (reseeded per floor) |
| miscRng | boss gold variance, scene randomization (reseeded per floor) |
| mapRng | map paths + room distribution |
Five of them (monsterHp, ai, shuffle, cardRandom, misc) reseed every floor
transition to seed + floorNum — in-combat churn can't drift the strategic
layer. The PRNG underneath is libGDX's RandomXS128 (xorshift128+), and saves
persist each stream as a (seed, counter) pair: reload and the game
fast-forwards counters to replay state exactly.
What knowing the seed buys (and doesn't)
With the seed you can precompute the full map of every act — path layout,
room distribution — before picking a starting bonus, plus encounter order,
event sequence, and shop stock. What you cannot precompute is anything
downstream of decisions: card rewards consume cardRng only when you take
them, shops only when visited. Seed knowledge is a map and a schedule, not a
playthrough.
The encoding itself: base-34 over the alphabet
0123456789ABCDEFGHIJKLMNPQRSTUVWXYZ — letter O omitted, typed O normalizes
to 0 — with an unoffensive-seed filter that rerolls any string the bad-word
checker flags.
The act-transition card-RNG clamp quirk
Crossing into a new act, dungeonTransitionSetup() fast-forwards cardRng
into fixed bands:
if (cardRng.counter > 0 && cardRng.counter < 250) cardRng.setCounter(250);
else if (counter > 250 && < 500) setCounter(500);
else if (counter > 500 && < 750) setCounter(750);
Quoted verbatim from the extraction. Read as design: however many card rewards you took in act N — heavy drafting or none — act N+1 begins with the card-RNG counter pushed past the nearest 250 boundary. Card luck doesn't carry cleanly across acts, and two players who drafted wildly differently converge on comparable reward streams next act. The bands cap at 750; a counter already beyond stays put.
Neow's untouchable stream
Neow's blessing roll constructs its own generator on the spot:
rng = new Random(Settings.seed) inside NeowEvent.blessing() — a fresh
stream from the raw seed, shared with nothing. Your Neow offer is fully
determined by the seed alone, independent of everything before and after.
That's why opening blessings can be tabulated
exactly, and why the offer shape is stable: 19 reward types across 4 offer
categories with 5 drawbacks, the boss-relic option gated alone in
category 3. The screen itself lives in
StS2 too — Neow still sells power for drawbacks there,
under a different RNG regime entirely.
StS2's registry diverges
The sequel threw out the fixed 13-stream board. Its architecture:
- Run streams (shared): UpFront generates everything at run start — monsters, events, relics offered; Shuffle handles draw pile; UnknownMapPoint rolls unknown map points; TreasureRoomRelics arbitrates contested loot; Combat* streams split in-combat randomness five ways; MonsterAi, Niche, CombatOrbs fill the rest.
- Player streams (per player): Rewards (cards, potions, relic rarity), Shops, Transformations.
Two structural differences from StS1. First, UpFront moves the biggest
decisions earlier: knowing a StS2 seed reveals the entire encounter and
event schedule up front, where StS1's streams burn down as you play. Second,
reward dice are personal — each player's Rewards stream seeds independently
in co-op, so your draft isn't perturbed by anyone else's pickups. Seeds hash
through a djb2 variant (GetDeterministicHashCode) rather than StS1's base-34
parse, and named streams derive as runSeed + hash(streamName). Odds state
is data now too: card-rarity pity starts at −0.05 offset, potion chance at
0.4, both serialized alongside the counters.
Honest variance: designers spent randomness where listed
Both registries read like budgets. StS1 quarantined cosmetic noise onto an
unseeded global (MathUtils.random: shop chatter, chest-opening angles,
VFX — explicitly outside the deterministic streams), reseeded combat churn
per floor, and clamped the card stream at act borders. StS2 spent its
registry on fairness instead: per-player reward streams, upfront schedule
generation, dedicated arbitration for contested treasure. Neither game hides
a die under the table — the variance lives exactly where these files say it
does. Where it matters most is ascension, whose scaling sits on top of both
registries (ascension scaling); tools that
exploit seed determinism live in the site's tool set (see
tools).