Choosing the zombie roster
Index sampling, weighted filling, and final-wave inclusion.
3 min read
The budget determines what a wave can spend. Two different selection rules determine what it buys: an index-based choice of types, followed by repeated weighted draws among those that remain affordable.
01 / THE CAST
Choose the types first
Start with the world's basic zombie and configured pool . The generator selects pool entries without replacement, using a bounded integer draw at each step. Weight does not participate in this choice.11Pool selection by indexThe builder adds the stage basic type, then chooses ZombieTypeCount entries from the configured pool. Each selected vector entry is removed before the next bounded draw. The baseline count is 4. Weight is not read by this selection pass.0x101ab6840
Removing the vector entry prevents that pool entry from being picked twice. A type with a large Weight has no larger interval in this initial draw: each remaining pool entry contributes one index.
The selected types, together with , become available to the ordinary filler from the first wave. The pool choice and the eventual frequency of a type are therefore separate questions.
For , an additional rule checks whether a selected type costs at least 1500 points. If none does, the last pool choice is replaced by a randomly chosen remaining type meeting that cost threshold. This is a Wave test, not a test for the Gargantuar class.22The high-cost replacementAbove BigZombieSureExistLevel, baseline 50, the helper checks for a selected type whose WavePointCost is at least 1500. If absent, it draws from qualifying remaining pool entries and replaces the last pool selection. The predicate concerns cost, not a particular runtime zombie class.0x101ab6d78
02 / THE DRAW
Cost admits. Weight selects
Let be the active types. For each type , write for Wave and for Weight. With points remaining, the positive-weight candidates form
Each candidate owns an integer interval of length in a bag of size . For the chosen ordering, let be the cumulative weight before . A draw selects the unique interval containing :33The weighted integer bagThe ordinary filler drops candidates whose WavePointCost exceeds the remaining budget, draws through the integer weighted bag, appends the chosen type, and subtracts its cost. FirstWave and the separate Cost property are not inputs to these helpers. Bounded integer draws use modulo reduction; bag shares describe interval lengths, not a claim of perfectly uniform RNG residues.0x101ce7f080x100366650
The nominal share of the bag is . The bag is rebuilt as affordability changes; a type can disappear from consideration while still having a large weight. Filling ends when no positive-weight candidate fits, so the budget can leave a remainder.
Neither First nor the separate property named Cost is used by this filler. An entry's declared first wave is therefore not an additional gate on this path.
The cast: the basic type and four pool choices, with cost and weight
- Mummy100 · 1000
- Camel300 · 3000
- Pharaoh450 · 3000
- Endless Gargantuar1500 · 3000
- Conehead Mummy200 · 3000
- 1,825d = 11848 of 13000Conehead Mummyd = 11848 of 13000
- 1,625d = 10487 of 13000Conehead Mummyd = 10487 of 13000
- 1,425d = 2301 of 10000Cameld = 2301 of 10000
- 1,125d = 3896 of 10000Cameld = 3896 of 10000
- 825d = 8710 of 10000Conehead Mummyd = 8710 of 10000
- 625d = 8331 of 10000Conehead Mummyd = 8331 of 10000
- 425d = 2442 of 7000Cameld = 2442 of 7000
- 125d = 515 of 1000Mummyd = 515 of 1000
25 points left: no type fits, so filling ends.
03 / THE LAST WAVE
One last inclusion attempt
The materializer tracks which selected types have appeared in earlier instructions. Before filling the final wave normally, it visits the remaining unseen types in the active set’s order. It attempts to insert them in order, subtracting each admitted cost from the remaining budget. This pass uses a strict inequality:44Strict final-wave reservationBefore normal final-wave filling, the materializer visits selected types not yet seen. A type is appended only when its cost is strictly less than the current remaining budget. The budget is reduced after each insertion, so ordering and earlier insertions affect later eligibility.0x101ce8598
An exact cost match can be accepted by ordinary filling and rejected by the reservation pass. Skipping a reservation does not remove that type from the later weighted bag. Earlier accepted reservations also reduce the balance for later ones.
For an ordered unseen pair costing 200 and 400 with 600 points left, the first insertion leaves an exact match for the second, which the reservation skips. Reversing the order changes which type receives the reservation. The filler can still draw an affordable skipped type afterward.
Reservation pass: cost < points left
- Conehead Mummy200 < 600reserved→ 400
- Buckethead Mummy400 < 400skipped
Weighted filling: cost ≤ points left, seed 3
- Buckethead Mummy400 ≤ 400drawn→ 0
The budget, spent in insertion order
Instructions:Conehead Mummy · Buckethead Mummy
04 / THE RESULT
The roster is still a starting point
The ordering of a weighted bag affects its draw-to-type mapping. The native set is ordered by type pointers; equal costs and weights therefore do not make an arbitrary replacement order reproduce the same seeded sequence.55Ordering and the component exampleThe native ordered-set comparator compares type-pointer values. The website uses selected display order and reconstructed integer draws. The isolated filler demonstrates budget spending; the construction and music views generate preceding waves, final reservation, per-instruction levels, and the level-wide leader attempt.0x100c03c8c
From level 4 onward, generation makes an extra wealth-entry attempt and an extra leader-entry attempt for the level, then assigns a successful entry to a chosen wave. This is not a fresh 0.4 leader roll on every wave. The baseline leader probability is 0.4; its type is selected by weight from types whose cost is strictly greater than 100.
The baseline wealth probability is zero, but its chance draw is still consumed. If both features are enabled and succeed, another draw suppresses one. A surviving extra entry is appended after ordinary filling without deducting its cost from the ordinary budget. World processing can then replace it, including clearing a removed leader’s marker when Jam constructs its replacement.66Extra leader entriesThe materializer attempts extra entries from displayed level 4 onward. The shared baseline declares LeaderProbability = 0.4 and LeaderMinWaveCost = 100. Leader eligibility uses a strict cost-greater-than test, followed by weighted selection. Successful entries are appended outside the ordinary filler budget. Wealth probability is zero in this baseline, but its chance draw is still consumed.0x101ce8a540x101ab6840
Together with the wave plan, these rules explain how a point allowance becomes an ordered list of ordinary spawn instructions. Placement, strength, and timing operate on that result later.
05 / RANDOM STATE
Why one seed is not the whole level
The bag equations use the inspected integer stream: MT-style state, a 31-bit result, then modulo reduction for bounded draws. A zero seed becomes 4357. Different parts of generation own different stream states:77Separate random-state consumersFresh DangerRoom initialization constructs designer state, materializes waves, runs world postprocessing, installs runtime actions and loot tags, then reseeds the WaveManager. Jam uses the global RNG; Modern queue shuffling calls imported C++ machinery. The website uses reconstructed integer draws with explicit input seeds and independent scenario state.0x101d476240x101c79bec0x101ce66dc0x100121044
GetSeed(1) reads time(NULL), but the timestamp alone does not specify every stream’s state or earlier consumption. Rejected duplicate choices, zero-probability attempts, and computed values that are later discarded can still advance a stream. The component controls expose their own input seeds so the individual rules remain reproducible.
Notes
The evidence behind each claim: the code path, and the native addresses where it was traced.
- 1
Pool selection by index
The builder adds the stage basic type, then chooses ZombieTypeCount entries from the configured pool. Each selected vector entry is removed before the next bounded draw. The baseline count is 4. Weight is not read by this selection pass.
0x101ab6840 - 2
The high-cost replacement
Above BigZombieSureExistLevel, baseline 50, the helper checks for a selected type whose WavePointCost is at least 1500. If absent, it draws from qualifying remaining pool entries and replaces the last pool selection. The predicate concerns cost, not a particular runtime zombie class.
0x101ab6d78 - 3
The weighted integer bag
The ordinary filler drops candidates whose WavePointCost exceeds the remaining budget, draws through the integer weighted bag, appends the chosen type, and subtracts its cost. FirstWave and the separate Cost property are not inputs to these helpers. Bounded integer draws use modulo reduction; bag shares describe interval lengths, not a claim of perfectly uniform RNG residues.
0x101ce7f080x100366650 - 4
Strict final-wave reservation
Before normal final-wave filling, the materializer visits selected types not yet seen. A type is appended only when its cost is strictly less than the current remaining budget. The budget is reduced after each insertion, so ordering and earlier insertions affect later eligibility.
0x101ce8598 - 5
Ordering and the component example
The native ordered-set comparator compares type-pointer values. The website uses selected display order and reconstructed integer draws. The isolated filler demonstrates budget spending; the construction and music views generate preceding waves, final reservation, per-instruction levels, and the level-wide leader attempt.
0x100c03c8c - 6
Extra leader entries
The materializer attempts extra entries from displayed level 4 onward. The shared baseline declares LeaderProbability = 0.4 and LeaderMinWaveCost = 100. Leader eligibility uses a strict cost-greater-than test, followed by weighted selection. Successful entries are appended outside the ordinary filler budget. Wealth probability is zero in this baseline, but its chance draw is still consumed.
0x101ce8a540x101ab6840 - 7
Separate random-state consumers
Fresh DangerRoom initialization constructs designer state, materializes waves, runs world postprocessing, installs runtime actions and loot tags, then reseeds the WaveManager. Jam uses the global RNG; Modern queue shuffling calls imported C++ machinery. The website uses reconstructed integer draws with explicit input seeds and independent scenario state.
0x101d476240x101c79bec0x101ce66dc0x100121044