Plant food and other drops
How planned quotas and loot schedules become pickups.
5 min read
Two allocation systems feed the later loot event. Plant food begins as a per-wave quota and requests carriers in instruction order. General loot begins as a saved per-entry schedule and assigns tags by individual wave cost. Neither a planned count nor an accepted marker is already a collected reward.
What “eligible setup row” means
A setup row is eligible when its MinLevel is at most the displayed level . The generator chooses one row from all eligible Flag rows. Its Flag gives the number of plant-food count draws, not the number or spacing of waves in the newer wave-layout formula.
The separate Plantfood supplies the draw bounds. Its bundled rows are:
For eligible food rows , both bounds are reduced with a minimum operation:
With equal to the selected Flag, total planned count is
The rows declaring 2 do not displace the earlier row declaring 1. Both effective bounds remain 1 until the level-55 row makes them zero. At level 49, four eligible flag rows request one draw and one row requests two, so is 1 or 2 depending on the chosen row.
Allocation visits regular flag boundaries in order, giving each one unit while any remain. Only afterward does it place remaining units on randomly chosen waves, with repeats possible. A short final wave is not inserted into the regular-boundary pass merely because it is final. At level 49, the 9-wave plan has only one regular boundary, wave 5: the first unit goes there, and a possible second goes to a randomly chosen wave. The final wave 9 receives no priority in this allocation.
Each wave’s allocation is copied to its ordinary action’s Additional. This is an action quota; the independent flag-zombie action has its own default-zero quota. The generator leaves Dynamic and Spawn empty.11Plant-food count constructionThe builder samples all eligible FlagWaveSetupList rows for a FlagCount. It reduces eligible PlantfoodSetupList minima and maxima using a minimum operation for each bound, then allocates the resulting count to waves. Materialization copies each wave's count into AdditionalPlantfood. The generated ordinary action leaves DynamicPlantfood and SpawnPlantName empty.0x101ab68400x101ce8a54
A request can consume quota and still fail
The creator scans the ordinary instructions in order. While quota remains, CanSpawn consumes one unit and requests a carrier marker on the new entity. A false property skips the instruction without consuming a unit. There is no extra random carrier-selection pass.
The marker then applies its profile and mode gates. In DangerRoom, IsA(Zombie rejects a true request, including subclasses. This is a runtime class test, distinct from the high-cost test in roster selection. The request was already consumed; the caller has no success result, refund, or retry branch.22A consumed request can be rejectedThe ordered creation loop decrements quota before calling the entity marker. CanSpawnPlantFood false skips consumption; true consumes a unit. The marker separately checks profile/mode gates and rejects IsA(ZombieGargantuar) in DangerRoom. It returns no success result, and the caller has no refund or retry branch. These property and runtime-class tests are separate.0x1014c40c00x1014c43240x1019af834
Jam replacement precedes this scan. It keeps the numeric quota but changes the types and order that receive requests; no pre-Jam entity marker exists to preserve. A quota left after the action ends is not transferred by this loop to another action. Portal children use a separate emitter.
Requests also precede placement hooks. A King or Fisherman rejected there may already have an accepted marker. Both rejection routes can reach ordinary loot handling, despite their different death/removal behavior.
The later event requests the pickup
The base Zombie loot method emits its Board event before setting the processed-loot flag. The listener requires an unprocessed event, m_can, the hasplantfood condition, and the applicable mode permissions.
For the ordinary empty-Spawn branch, the listener clears the carrier condition and requests a plantfood pickup. A nonempty name takes a packet branch instead. Base removal also reaches the loot dispatcher; removal is not intrinsically a no-loot operation.33From carrier condition to pickup factoryBase loot dispatch emits the Board event before setting its processed-loot flag. The listener checks that flag, m_canDropLoot, hasplantfood, and mode guards. Its ordinary empty-name branch clears the carrier condition and invokes the pickup factory. The base removal callback also reaches loot dispatch; removal is not inherently a no-loot operation.0x1019a5dac0x10158157c0x101588a24
The carrier view separates the property check, consumed request, accepted marker, and pickup event. Reordering the same two instructions changes the result without changing the original quota.
Order 1
- eighties_gargantuar_danger重金属巨人僵尸(无尽)
1 left
false
skipped, no unit used
- eighties摇滚僵尸
1 left
true
consumes one: 1 → 0
accepted
carrier marker set
plantfood
pickup requested
Order 2
- cowboy_gargantuar_danger西部巨人僵尸(无尽)
1 left
true
consumes one: 1 → 0
rejected
the unit stays spent
- cowboy牛仔僵尸
none left
property not read
true
Order 3
- cowboy牛仔僵尸
1 left
true
consumes one: 1 → 0
accepted
carrier marker set
plantfood
pickup requested
- cowboy_gargantuar_danger西部巨人僵尸(无尽)
none left
property not read
true
General loot advances saved per-entry schedules
Wave installation runs the general-loot pass after world postprocessing and before the runtime WaveManager reseed. Its configuration must exist, be enabled, and have a positive collected total wave cost. With Level, it estimates a planning length from installed waves:
The arithmetic uses float32 before widening to double. An explicit Level can replace that estimate. These are planning units, not time spent fighting.
Eligible loot-table rows must pass their World and Enabled checks. The world tag comes from an exact world-map level-node lookup, not simply the stage’s world name. The inspected map set has no matching DangerRoom node, leaving an empty tag; world-restricted rows do not match it. The seven unrestricted fallback rows still require tutorial4 progress:
Each eligible row owns a saved record keyed by Unique. Two gold rows therefore keep separate histories even when their type and period agree. Write for Level, for Next, and for Next. A fresh record starts at , , , where denotes the no-pending-drop sentinel.
For each planning call:
- Add to .
- If , draw an inclusive count from
Min–Max, append that many loot codes, and reset to the sentinel. - If , choose a phase inside
Period, set to the old plus that phase, then addPeriodto . - Repeat the drop/schedule processing while another scheduling pass was needed.
Both comparisons are strict. A newly scheduled drop can already be due within the same planning call and is handled on the next pass. Equality waits for later accumulated length. Phase/count draws consume the global RNG, and the manager requests saving the updated records.44Saved per-entry scheduling stateThe installer invokes general-loot planning after world postprocessing and before the runtime WaveManager reseed. Eligible table rows retain separate UniqueId histories. The planner advances LevelLengthsPlayed, handles strictly due drops and schedules, and requests saving the records. Count and phase draws consume the global RNG. World/profile eligibility and effective table overrides are additional inputs.0x101ce66dc0x101a8b5e80x101a8b124
This is why the current level and one generation seed cannot determine the planned list: effective table entries, profile eligibility, saved histories, and earlier global draws all participate.
Cost weights individual instructions
The pass gathers type vectors from ordinary and independent flag spawners and creates parallel, initially zero-filled loot arrays. Portal children do not yet exist in these spawner vectors and are not entries in this pass.
For each nonzero loot code, an untagged instruction with cost occupies the following nominal share of the bag:
where is the remaining untagged set. A cumulative-cost draw selects one instruction, assigns its tag, and removes its cost from later draws. Assignment is without replacement and stops when no remaining candidate can be selected. It uses Wave, not Weight, HP, entity level, or leader health.55Individual-cost weighting without replacementThe pass collects ZombieSpawnerAction type vectors and creates parallel loot arrays. Nonzero loot codes are assigned by cumulative resolved WavePointCost; each tagged instruction and its cost leave subsequent draws. The tags do not reorder instructions or alter their level, row, leader, or plant-food fields. Entity creation later copies the annotation to the entity's stored loot code.0x101ce66dc0x1014c513c0x1019afe38
Because the pass follows Jam, it uses replacement costs. The annotation array leaves instruction order, row, level, leader fields, and plant-food quota unchanged. During creation, the tag at each instruction’s index is copied to its entity.
The base loot dispatcher later maps stored codes to requested pickup aliases, subject to its loot/state guards:
Codes 4–13 create no pickup in this dispatcher. The code-3 enum name therefore cannot be used by itself to infer either the spawned alias or eventual inventory credit.66Enum labels versus dispatched aliasesRegistration names codes 1, 2, and 3 SilverCoin, GoldCoin, and Diamond. The inspected base dispatcher requests coin_silver for 1 and coin_gold for both 2 and 3. Codes 4–13 create no pickup through this dispatcher. These are requested pickup aliases; inventory credit is not inferred from the enum label.0x101a899940x1019a5dac0x101a8b78c
Notes
The evidence behind each claim: the code path, and the native addresses where it was traced.
- 1
Plant-food count construction
The builder samples all eligible FlagWaveSetupList rows for a FlagCount. It reduces eligible PlantfoodSetupList minima and maxima using a minimum operation for each bound, then allocates the resulting count to waves. Materialization copies each wave's count into AdditionalPlantfood. The generated ordinary action leaves DynamicPlantfood and SpawnPlantName empty.
0x101ab68400x101ce8a54 - 2
A consumed request can be rejected
The ordered creation loop decrements quota before calling the entity marker. CanSpawnPlantFood false skips consumption; true consumes a unit. The marker separately checks profile/mode gates and rejects IsA(ZombieGargantuar) in DangerRoom. It returns no success result, and the caller has no refund or retry branch. These property and runtime-class tests are separate.
0x1014c40c00x1014c43240x1019af834 - 3
From carrier condition to pickup factory
Base loot dispatch emits the Board event before setting its processed-loot flag. The listener checks that flag, m_canDropLoot, hasplantfood, and mode guards. Its ordinary empty-name branch clears the carrier condition and invokes the pickup factory. The base removal callback also reaches loot dispatch; removal is not inherently a no-loot operation.
0x1019a5dac0x10158157c0x101588a24 - 4
Saved per-entry scheduling state
The installer invokes general-loot planning after world postprocessing and before the runtime WaveManager reseed. Eligible table rows retain separate UniqueId histories. The planner advances LevelLengthsPlayed, handles strictly due drops and schedules, and requests saving the records. Count and phase draws consume the global RNG. World/profile eligibility and effective table overrides are additional inputs.
0x101ce66dc0x101a8b5e80x101a8b124 - 5
Individual-cost weighting without replacement
The pass collects ZombieSpawnerAction type vectors and creates parallel loot arrays. Nonzero loot codes are assigned by cumulative resolved WavePointCost; each tagged instruction and its cost leave subsequent draws. The tags do not reorder instructions or alter their level, row, leader, or plant-food fields. Entity creation later copies the annotation to the entity's stored loot code.
0x101ce66dc0x1014c513c0x1019afe38 - 6
Enum labels versus dispatched aliases
Registration names codes 1, 2, and 3 SilverCoin, GoldCoin, and Diamond. The inspected base dispatcher requests coin_silver for 1 and coin_gold for both 2 and 3. Codes 4–13 create no pickup through this dispatcher. These are requested pickup aliases; inventory credit is not inferred from the enum label.
0x101a899940x1019a5dac0x101a8b78c