Issue #1 · · Voyager #037

Mechanics Notes #1: How Level Spawns Are Built

Starting with level 1, derive 0.17q draw probabilities, budget deductions, and final-wave protection; calculate smooth lane weights and trace Soul selection and early-refresh conditions.

Restart the same level a few times, and a Conehead may appear where a group of Basic Zombies appeared before. Where does that difference come from? And when does the game decide which lane they will enter?

To answer those questions, we first need to understand how a wave is put together. We will start with a small example from level 1, then introduce authored spawns, lane selection, and refresh timing. You can follow from the beginning without knowing the level-file format; readers familiar with point pools may find the later exceptions useful. The rules here describe 0.17q's standard spawn system, checked against its level files and program logic. Zombies created by bosses, controllers, and preset entities need their own explanations.

Chance takes root: a three-pip die branches into one Conehead and three Basic Zombie faces.
Chance takes root: a three-pip die branches into one Conehead and three Basic Zombie faces.

Start with three points

Suppose the game has 3 points available to fill a wave. Its only choices are a Basic Zombie costing 1 point and a Conehead Zombie costing 3. Both are unlocked, and both have the same draw weight. We will call the available points the “budget” and the points needed to generate one zombie its “cost.”

Before calculating anything, consider what this wave could contain:

  • One Conehead Zombie.
  • Three Basic Zombies.
  • Either of the above.

If you chose the third answer, you have found the key to this example. But there is still something to explain: why can equal weights produce such different numbers?

Follow the two possibilities separately. If the first draw picks a Conehead, it spends all 3 points at once, leaving just that one zombie. If it picks a Basic, 2 points remain. A Conehead is now too expensive, so the next two draws can only pick Basics. The result is three Basic Zombies.

The same 3-point budget produces one Conehead above or three Basics below. Each dot represents 1 point. These are alternative outcomes, not simultaneous spawns. The teaching figures in this article are diagrams, not gameplay screenshots.
The same 3-point budget produces one Conehead above or three Basics below. Each dot represents 1 point. These are alternative outcomes, not simultaneous spawns. The teaching figures in this article are diagrams, not gameplay screenshots.

This is the situation on wave 4 of level 1 at MEDIUM difficulty. Neither outcome spends more points. The same allowance is simply spent on different zombies.

Equal weights do not mean equal counts. Weight affects the result of a draw; cost affects which candidates can take part afterward. Let us examine that rule more closely.

Three moments at which decisions are made

Read a run in three stages. Building the table at level start determines pool types, quantities, and initialization lanes. Spawning a wave reads its records and handles lane cooldowns, random lanes, and Soul lanes. Advancing between waves checks counters and the current wave's remaining aggregate to decide when to read the next set of records.

These stages connect, but answer different questions. A changed formation may affect Soul selection, and faster clearing may advance the next wave; neither implies that the pool chooses new types during combat. Likewise, an initialization result in lane 3 can still be redirected by runtime lane conditions. The budget, lane, and timing rules below each belong to one of these stages.

How the point pool spends its budget

Check the remaining points after every draw

The list of candidates in our example is the point pool, written as ZombiePoints.ZombieList in the level file. Each entry can set three main parameters:

  • Points: the points deducted when this entry is drawn once—its cost; default 1.
  • Weight: its relative weight in the current draw; default 100.
  • Waves: the first displayed wave that permits ordinary draws, counting from 1. The default 0 allows participation from wave 1.

Before a draw, the game checks which entries are unlocked and which it can afford with the remaining budget. Only candidates that pass both checks take part, using their respective weights. The chosen entry's cost is deducted, and the checks run again with the points left over.

Being drawn does not remove an entry from the pool. It can be selected again as long as the conditions still hold. Ordinary draws end when the budget runs out or no candidate remains eligible.

In our opening example, the Conehead and Basic compete with equal weight only on the first draw. After one Basic is chosen, the Conehead becomes too expensive to take part again. We cannot treat every draw as an even choice between the two. The Conehead is excluded for the current remaining budget, though; it has not been deleted from the level's pool.

Weights describe conditional chances, not wave quotas

Let R be the remaining budget and w the current wave. Keep entries whose unlock wave is no later than w and whose price is no greater than R; call this eligible set A. With normal nonnegative weights, an entry's theoretical chance on this draw is its weight divided by the sum of weights in A. The set is rebuilt after each draw, so that denominator can change. If its total effective weight is zero, ordinary drawing stops even with points left.

Keep the equally weighted 1-point Basic and 3-point Conehead, but raise the budget from 3 to 4. Under ideal weighted probabilities, the complete paths are:

  • Conehead first: probability 1/2; the remaining point buys one Basic.
  • Basic, then Conehead: probability 1/2 × 1/2 = 1/4; the budget is exhausted.
  • Two Basics first: probability 1/4; only two more Basics are affordable afterward.

Ignoring order, one Conehead plus one Basic has probability 3/4, while four Basics have probability 1/4. Expected counts are 0.75 Coneheads and 1.75 Basics, or 2.5 zombies total. Equal weights imply neither equal final counts nor an equal split of the wave's budget. Raising the allowance from 3 to 4 raises the chance of a Conehead from about 1/2 to about 3/4: the extra point permits a second draw while the Conehead is still affordable.

A type's chance of appearing anywhere in a wave is consequently not just its weight share. It combines all paths leading to that outcome, each with its own changing balance. The native integer draw takes a random number modulo the total weight, introducing a tiny modulo bias when the total does not divide the random-number range. The fractions above explain the ideal weighted model rather than count every possible seed exactly.

Some points can remain unspent

For another teaching pool, allow only a 3-point Conehead and give the wave 5 points. One draw leaves 2 points, with nothing affordable, so ordinary drawing stops. The game does not automatically add two Basics or buy another Conehead on credit. Unspent points do not carry into the next wave, which calculates its own budget.

Exhausting a positive integer balance requires suitable candidates, such as an unlocked 1-point entry with positive weight. Price controls expenditure, weight controls selection chance, and unlocking controls eligibility; changing any one can alter the wave's count distribution. The calculations here assume positive integer prices and nonnegative weights, not malformed configurations.

Where the budget comes from

We began by giving the game 3 points. How does it arrive at that allowance? An ordinary wave's default base budget is B = i / 3 + 1, where i is a wave index starting at 0. Use 0 for wave 1 and 3 for wave 4. Keep any fraction from the division for now.

Multiply the base budget by the difficulty multiplier M, then convert to integer points. For wave 4 of level 1 on MEDIUM:

  • Calculate the base budget: 3 / 3 + 1 = 2.
  • Apply the difficulty multiplier: 2 × 1.5 = 3.
  • The result is already an integer, leaving 3 points for the wave.

The five default multipliers are 1, 1.5, 2, 2.5, 3. An author can provide one shared Multiplier or a five-element array with a value for each difficulty. If ZombiePoints.Points is an array whose length exactly matches the total Waves, its entries replace the base budget for each wave. The difficulty multiplier still applies afterward.

The name Points can be confusing here. Inside a pool entry, it is the cost of one zombie. As a per-wave array under ZombiePoints, it supplies the base budgets. Check which level of the file you are reading first.

Spawn points are an internal allowance, separate from sun, Glory, and zombie HP. A Conehead costing 3 does not mean it has three times a Basic Zombie's durability.

One detail remains in the integer conversion. The program first adds a tiny 0.000001, then discards the fractional part; a positive budget above that epsilon but below 1 becomes 1 point. This method is enough for most hand calculations. A result very close to a boundary also requires attention to single-precision arithmetic.

Why a higher multiplier produces jumps

The budget becomes an integer only at the end, so increasing difficulty does not add zombies smoothly. A normal-wave base of 2.4 becomes 3.6 at a 1.5 multiplier, yielding 3 points; at a multiplier of 2 it becomes 4.8, yielding 4. That extra point can add a Basic, but can also keep a more expensive branch eligible for another draw.

A custom per-wave array is not the final budget either. An array value of 3 at a 1.5 multiplier still converts to 4 points. The array must have exactly as many entries as the configured wave count to activate this override; a shorter array does not mean “override the first few waves and use the default formula afterward.” Track the base, the multiplied integer budget, and the balance after special deductions separately.

Where the author's chosen zombies go

A point pool explains random additions, but consider another common arrangement: the author wants a Conehead in a particular wave and specifies lane 3. That record can go straight into the top-level ZombieList, without waiting for the pool to draw one.

We now have two lists with the same name. The top-level ZombieList stores authored records for each wave; ZombiePoints.ZombieList stores candidates for random additions. A level can use both. Set the random additions aside for a moment, and look at how the authored list becomes separate waves.

Splitting the list into waves

Suppose we write “Basic, Basic, wave separator, Conehead, end marker,” in that order. How many waves does that make? The two Basics belong to wave 1. After the separator, the Conehead belongs to wave 2.

In a level file, the wave separator is called NULLZOMBIE and the end marker ENDNULLZOMBIE. The game reads the list in order. Each ordinary record specifies one zombie; the first marker advances to the next wave, while the second ends the list.

Now put two separators next to each other. With no ordinary record between them, they leave a wave with no authored zombies. The figure compares these two arrangements:

Read from left to right. N stands for NULLZOMBIE and E for ENDNULLZOMBIE. Above, two Basics followed by N, a Conehead, and E make two waves. Below, adding a second N leaves wave 2 empty and moves the Conehead to wave 3. The empty wave has no authored records; the pool may still add zombies.
Read from left to right. N stands for NULLZOMBIE and E for ENDNULLZOMBIE. Above, two Basics followed by N, a Conehead, and E make two waves. Below, adding a second N leaves wave 2 empty and moves the Conehead to wave 3. The empty wave has no authored records; the pool may still add zombies.

A separator is therefore not a zombie, and an empty authored wave need not be empty in play. Also, two identical records of the same type and lane still mean two zombies. They do not merge into one. The site's x2 marker preserves that quantity.

Using one list across difficulties

Suppose the author wants our Conehead to appear only on HARD and above. They can add LowDif: 30. That 30 comes from the numeric difficulty values: EASY = 10, MEDIUM = 20, HARD = 30, IMPOSSIBLE = 40, and UNBALANCED = 50.

The comparison is straightforward. Keep the record if the current difficulty value is at least LowDif; otherwise, skip it. Omitting LowDif gives a threshold of 0, so all five difficulties pass this check.

What if we raise the threshold from 30 to 44? Can IMPOSSIBLE still include the zombie? Although 44 is closer to 40, it is not assigned to that tier. Since 40 < 44, only UNBALANCED's value of 50 passes.

Column headings 10, 20, 30, 40, and 50 represent the five difficulties. With a threshold of 30, the final three columns keep the Conehead. Raise it to 44, and only 50 keeps it. A dash means this record is filtered out, not that the whole wave is empty.
Column headings 10, 20, 30, 40, and 50 represent the five difficulties. With a threshold of 30, the final three columns keep the Conehead. Raise it to 44, and only 50 keeps it. A dash means this record is filtered out, not that the whole wave is empty.

LowDif compares numbers; it does not choose the nearest difficulty tier. The Dif rating in the level profile is a separate value and does not enter this comparison.

Repeating part of the table

The authored list can also specify a section to reuse. EndlessWave sets its starting point, again counting from 0. Level 3 has ten authored waves, and its EndlessWave: 7 points to wave 8.

After wave 10, reading returns to the records for wave 8. When the site expands Waves: 15, displayed waves 11–15 reuse authored waves 8, 9, 10, 8, and 9. The reading position returns to an earlier section, while the displayed wave number continues to increase.

Level 3's authored-wave expansion. The upper bracket marks source waves 8, 9, and 10. In each column below, the upper number is the displayed wave and the lower number is the authored wave it reuses. Waves 11–15 map to 8, 9, 10, 8, and 9. Only authored records repeat here; this does not mean the pool copies its earlier results.
Level 3's authored-wave expansion. The upper bracket marks source waves 8, 9, and 10. In each column below, the upper number is the displayed wave and the lower number is the authored wave it reuses. Waves 11–15 map to 8, 9, 10, 8, and 9. Only authored records repeat here; this does not mean the pool copies its earlier results.

Here, 15 only bounds the page's expansion. It does not establish that the looping level must end on wave 15 in play. That still depends on the game's runtime completion conditions.

Add three special rules

We now know how authored records are split into waves and how a pool spends its allowance. A few more rules let us follow the construction order: the game adds authored records, handles automatic flag groups, applies final-wave protection, deducts authored costs, and finally uses the remaining budget for ordinary draws.

This happens wave by wave when the level is entered. In particular, pool types, quantities, and initialization lanes are generated while building the table at level start. A wave that happens to be difficult for your formation is not evidence that the pool just inspected your plants and drew a counter. Soul lane selection does read plant state, as we will see later, but that is a separate step.

Large-wave budgets and flag groups

Large waves usually bring more company. The default budget formula makes a large-wave adjustment on every tenth wave and the final wave: multiply the base budget by 2.5, then calculate the extra Basic Zombie count N. To obtain N, discard the fraction from i × M / 3 and constrain the result to 2–8.

Including one Flag Zombie gives a group size of C = N + 1. If the enlarged base budget is at least 1.5 × C, subtract C before applying the difficulty multiplier and integer conversion. We can think of this as reserving points for the flag group.

Reserving points and actually creating a group need separate attention, however. Generating one Flag Zombie and N Basics also requires ZombiePoints.Flag: true, which is off by default. The reservation branch itself does not check Flag, so a deduction alone does not establish that an automatic group will appear.

A valid per-wave Points array overrides the base budget. There is another easy source of confusion: an author may write a single Flag Zombie into the authored list. That is an authored record and does not enable automatic groups. When we return to level 1, we will work through the large-wave numbers in full.

Why a large wave is not simply 2.5 times a normal wave

Large-wave processing combines multiplication, a conditional deduction, and truncation. It does not multiply an already rounded normal-wave budget by 2.5. Let B be the normal base, G = 2.5 × B the enlarged base, and C the automatic group size. Without a valid per-wave override, first check whether G is at least 1.5 × C. If so, use G − C before multiplying by M; otherwise use G. Integer conversion comes last.

For B = 4 and M = 1.5, G = 10 and C = 5, so (10 − 5) × 1.5 converts to 7 points. Calculating the normal integer budget as 6 and multiplying that by 2.5 incorrectly gives 15. Multiplying 10 by 1.5 and then subtracting 5 incorrectly gives 10. Both place an operation at the wrong stage.

A valid per-wave array replaces the base produced by this default calculation, while Flag controls insertion of the automatic group. An array value of 6 at M = 1.5 yields an integer budget of 9; do not apply the default large-wave reservation again to that 6. With Flag: true, the automatic group can still appear separately. WaveManager.Flag is a third concept: it controls the wait before a large wave, not the insertion of a Flag Zombie.

Authored records can consume the budget too

Suppose a wave has 5 points and the author has separately placed a Conehead in it. With no other special handling, the pool still has those 5 points to spend. Writing one authored zombie does not automatically remove one random addition.

To charge authored spawns to the budget, enable SubtractMode, which is off by default. If the Conehead record's deduction cost is 3, for example, 2 points remain for ordinary draws.

The cost has its own lookup order. Use an explicit Points value on the authored record first. Otherwise, look for the corresponding type's price in the pool; if none is available, use 0. Only authored records in this wave that pass the difficulty filter enter the deduction. The allowance left for random additions therefore depends on their costs, not simply on how many authored zombies there are.

The final wave can include an undrawn entry

Consider a different case. The pool has included a Conehead with nonzero weight throughout the level, but earlier draws happened never to pick it. Can it remain absent on the final wave? Protected, enabled by default, handles this situation.

It checks each pool entry's history, inserts each nonzero-weight entry with no previous pool generation once, and deducts its cost. For a small example, suppose 2 points remain at this check, the only entry needing protection is a 3-point Conehead, and all lanes are available. Despite being unaffordable, the Conehead is inserted, taking the budget to 2 - 3 = -1.

Final-wave protection checks this pool entry's generation history. Above, n = 0 means no earlier Conehead generation from this entry: protection adds one, deducts 3 from 2, and leaves −1. Below, n = 1 means it was generated earlier, so protection adds none and leaves 2 points. These are alternative cases, not consecutive steps.
Final-wave protection checks this pool entry's generation history. Above, n = 0 means no earlier Conehead generation from this entry: protection adds one, deducts 3 from 2, and leaves −1. Below, n = 1 means it was generated earlier, so protection adds none and leaves 2 points. These are alternative cases, not consecutive steps.

Why can an unaffordable zombie be inserted? Protection runs before ordinary unlock and budget checks, and before authored deductions. Neither a locked entry nor an insufficient budget rules out a protected insertion.

Pay particular attention to “from this pool entry.” If an earlier Conehead came from the authored list, it does not count as a pool draw. Conversely, an entry previously generated from the pool does not receive another protected spawn on the final wave. Protection tracks pool-entry history, not which zombies the player has seen on the lawn.

Put every source in the same ledger

Combine the rules in a hypothetical final wave. Its calculated integer budget is 7. It also has one authored Conehead, with SubtractMode enabled and a deduction cost of 3. A different positive-weight pool entry costs 5, has never been generated, and needs final-wave protection. Assume available lanes and no other protected entries.

  • The authored Conehead is already in the records; its 3-point deduction will be settled later.
  • Protection inserts the 5-point entry, reducing the balance from 7 to 2.
  • The authored deduction reduces 2 to −1.
  • Ordinary draws require a positive balance, so none occur. Both existing records remain.

The negative balance is not debt carried into the next wave, and it does not delete zombies already scheduled. Special arrangements have exceeded the random allowance under this ordering. The budget limits ordinary drawing; it is not a universal cap on every zombie in the wave.

Protection checks entries in pool order, potentially adding one of each eligible undrawn entry, and exhausting the budget does not stop that check. Two entries with the same type retain separate generation histories; drawing one does not satisfy the other's protection. Basics and Flags in an automatic group do not satisfy pool-entry history either.

This history records generation during initialization, not combat kills. Quickly defeating an earlier pool zombie cannot restore its protection eligibility. When reviewing a wave, distinguish authored records, automatic groups, protected insertions, and ordinary draws, then check their respective deductions.

Choosing an entrance lane

Fixed and random lanes

So far, we have asked which zombies appear. Now consider where they enter. Which lane does Row: 2 specify? Lane 3, because row numbers start at 0. On a typical five-lane lawn, the top lane is numbered 0 and the bottom 4.

If a record omits Row or uses Row: -1, the game waits until that zombie spawns to choose a lane. It randomly selects from currently available lanes that are not gated by a lane cooldown. If all available lanes are cooling down, it picks the one with the lowest cooldown.

Fixed lanes are not unconditional either. An invalid, unavailable, or cooldown-gated lane falls back to the same random path. A fixed-lane label tells us what the record specifies; the actual spawn must still pass runtime checks.

The level also has a top-level Row array describing lane states, where state 2 means unavailable. This differs from Row: 2 on a zombie record: one describes a lane's state, while the other specifies a destination for a zombie.

Why initialization lanes look more even

Watch several zombies generated by the pool, and their lanes may seem reasonably spread out. This comes from the smooth selector used during initialization. The pool and automatic flag groups track how many selections have passed since each lane's last two picks, then adjust weights to favor lanes picked less recently.

Think of it as a running record of lane choices. It is not cleared at the next wave, and authored fixed lanes update it too. Earlier records can therefore affect a later wave's lane distribution.

Smooth selection does not require every lane to take a turn before one can repeat. A lane picked just now can be chosen again, and five zombies need not occupy one lane each. Type draws and smooth lane draws also share the same level-local random stream, so changing earlier candidates or records can change later results.

Checking the smooth weights by hand

Normalize the raw weights of available lanes and call a lane's share p; with five equal available lanes, p = 0.2. Let a and b count selections since its most recent and second-most-recent picks. Ignoring single-precision rounding, the two corrections are:

  • Most recent pick: u = 2 × p × (a + 1) − 1.
  • Second-most-recent pick: v = p × (b + 1) − 1.
  • Combined, bounded correction: k = clamp(0.75 × u + 0.25 × v, 0.01, 100).
  • Weight for this draw: q = p × k. Normalize across all lane q values afterward; q alone is not the final probability.

Here clamp replaces values outside the bounds with the nearest bound. With five equal lanes, a lane with a = 4 and b = 9 has u = 1 and v = 1, giving q = 0.2. A recently picked lane with a = 0 and b = 5 has u = −0.6 and v = 0.2. Its combined value of −0.4 is raised to the lower bound of 0.01, giving q = 0.002. Its relative weight drops sharply but does not become zero.

This explains both the smoothing and the possibility of repeated lanes. Recent repeats receive low weight; longer gaps let it recover. History measures selections, not elapsed time or a lane's total zombie count. After a pick, lanes participating in history updates advance their counters; the selected lane moves its latest interval into the second history slot and resets the latest interval to zero. These histories persist across waves.

A type draw normally consumes another random value to select its lane before the next type draw. Adding an earlier zombie, changing a price, or enabling automatic groups can therefore change the purposes assigned to later random values, affecting many subsequent waves. A fixed seed makes an experiment repeatable, but changing the configuration does not guarantee that every unrelated random outcome stays fixed.

What Soul selection measures

Row: -2 is a different case. It follows ordinary random selection on EASY and MEDIUM; HARD, IMPOSSIBLE, and UNBALANCED enable Soul scoring. At the start of each wave, the game calculates a plant-layout snapshot, then selects the available lane with the lowest score. Ties go to the topmost lane.

Use an easy formation to calculate. All five lanes are available; lanes 1, 3, and 5 each contain one full-health Wall-nut; lanes 2 and 4 are empty, with no other plants anywhere. A Wall-nut contributes 5 × current HP / maximum HP using integer arithmetic, or 5 at full health. The five scores are therefore 5, 0, 5, 0, and 5.

Lanes 2 and 4 share the minimum. Which one wins? The topmost-tie rule selects lane 2.

Soul selection on HARD and above: lane numbers are on the left and scores on the right. Full-health Wall-nuts score 5 in lanes 1, 3, and 5; lanes 2 and 4 both score 0. The gold outline marks the selected lane 2, while the dashed outline marks the equally scored but lower lane 4.
Soul selection on HARD and above: lane numbers are on the left and scores on the right. Full-health Wall-nuts score 5 in lanes 1, 3, and 5; lanes 2 and 4 both score 0. The gold outline marks the selected lane 2, while the dashed outline marks the equally scored but lower lane 4.

Now change the situation slightly. A zombie from this wave has already entered lane 2. Does the next Soul record switch to lane 4? In this example, it does not. The score uses the plant snapshot from the start of the wave, and the new zombie has not changed that snapshot. Several Soul records can consequently choose the same lane in succession.

The full score also considers adjacent-lane support from the Dd gene of Peashooters and Peanuts, but it does not include every plant's damage, crowd control, sun production, and Active Skill options. A “weak Soul lane” only means the lane with the lowest score under this calculation. It need not be the lane you find hardest to defend.

Soul lanes also differ in their cooldown handling

On HARD and above, the Soul branch checks lane availability but does not apply the ordinary fixed-lane requirement that cooldown be at most zero. Once it finds the lowest-scoring available lane, it proceeds directly to creation. Do not apply the ordinary cooldown fallback to Soul selection. On lower difficulties, Row: -2 becomes the ordinary random path and uses its cooldown rules.

When every available lane is cooling down, ordinary random selection also resolves ties for the lowest cooldown in favor of the topmost lane. With no available lane at all, creation can fail. Initialization smoothing, runtime cooldown filtering, and Soul scoring are three distinct selection criteria.

Integer Wall-nut scoring also makes durability effects discontinuous. At 80% durability a Wall-nut contributes 4 points; at 79% it contributes 3; at 19% it already contributes zero. Equal lane scores still favor the upper lane, so a small durability improvement can affect ordering only when it crosses an integer boundary. Other plants do not automatically earn points for their combat value if the scoring rule does not include them.

Does faster clearing bring the next wave sooner?

We know what a wave contains and where its zombies enter. One question remains: when does the next wave arrive? WaveManager helps control this. InitTime sets the first wait, Counter sets the interval counter, and Factor helps calculate the early-refresh threshold. Its Flag subsection controls the interval leading into a large wave.

First, follow the early-refresh check. After a wave is generated, the game records an initial aggregate for its eligible zombies, then multiplies that value by Factor to obtain a threshold. Once more than 200 counter units have elapsed, with more than 100 remaining, reaching or falling below the threshold changes the remaining wait to 100.

We can use a purely numeric example. Suppose the initial aggregate is 100 and the factor is 0.25, giving a threshold of 25. A counter that started at 2500 has run for 300 units, leaving 2200. If the remaining aggregate is now 20, all three conditions hold, and the counter changes from 2200 to 100.

A numeric early-refresh example: 100 × 0.25 gives a threshold of 25. Elapsed units are 300, above 200; remaining units are 2200, above 100; and the remaining aggregate, 20, does not exceed 25. With all three conditions met, the remaining counter changes from 2200 to 100. The aggregate is not a zombie count, and counter units are not milliseconds.
A numeric early-refresh example: 100 × 0.25 gives a threshold of 25. Elapsed units are 300, above 200; remaining units are 2200, above 100; and the remaining aggregate, 20, does not exceed 25. With all three conditions met, the remaining counter changes from 2200 to 100. The aggregate is not a zombie count, and counter units are not milliseconds.

If only 150 units had elapsed, an aggregate of 20 would not trigger this branch at that moment. Early refresh depends on both clearing progress and counter conditions, not simply on the zombies left on screen.

The 0.17q defaults are an initial wait of 1800 logic-update units, an ordinary counter of 2500–3100 with factor 0.25, and a large-wave counter of 4000 with factor 0. Levels can override these: level 48, for example, sets both ordinary and large-wave factors to 0.5–0.65. These units cannot be read directly as milliseconds or rendered frames.

Two qualifications matter. First, the aggregate checks wave membership and entity state, so a count of every zombie on the lawn cannot replace it. Second, triggering the condition only shortens the remaining wait to 100; it does not immediately spawn the next wave. Large-wave warnings and additional counters can also affect the actual spawn time. The site does not currently simulate this live timing process.

All three early-refresh conditions must hold

Let H₀ be the initial aggregate, H its current value, F the selected factor, C₀ the initial counter, and C the remaining counter. The program converts H₀ × F to an integer threshold T. It then sets C to 100 when C > 100, C₀ − C > 200, and H ≤ T all hold.

The boundaries matter: exactly 200 elapsed units are insufficient, and exactly 100 remaining units do not trigger another reduction, but H equal to T does qualify. With H₀ = 101 and F = 0.25, the threshold is the integer 25, not 25.25. Counter and Factor ranges are sampled when this interval is set up, rather than resampled at every check.

A larger F generally allows a larger residual aggregate and makes early refresh easier. The default F = 0 before a large wave requires an aggregate at or below zero for this early branch. F = 0 neither stops the counter nor requires an empty lawn before the next wave can arrive. Even without early refresh, the normal counter advances and can permit the next wave once the other creation conditions also hold.

H is computed by filtering objects by wave membership, entity flags, and state, then adding values returned through an entity virtual method. It is neither a global headcount nor an established simple sum of every zombie's HP. A surviving zombie from an older wave therefore does not necessarily block the current wave's early refresh. Conversely, defeating a conspicuous zombie does not establish how much H fell merely from its appearance.

Why a large-wave warning adds another wait

The choice between ordinary and Flag parameters depends on the upcoming wave. After wave 9 spawns, if wave 10 is large, the interval already uses Flag settings; the game does not wait until wave 10 has spawned to select them. InitTime separately sets the first wait.

Before a large wave, reaching 5 on the main counter starts the warning and sets its counter to 810. While the warning counter exceeds 60, it gates further main-counter processing. At 60 it sets the main counter to 1, after which creation checks can continue. Spawning a wave also sets an additional creation-gate counter to 100, and the next spawn must check it too.

Setting the remaining main counter to 100 thus describes one state change, not a promise of a spawn exactly 100 units later. A large wave still involves the warning sequence. These values describe logic updates and should not be converted into unverified wall-clock seconds.

In play, concentrated damage may reach the threshold earlier and bring the next wave's pressure sooner. Keeping one zombie alive need not preserve a long wait: it might belong to an older wave, contribute too little to the aggregate, or remain alive as the normal counter expires. To explain overlapping waves, check membership, threshold, the main counter, and any large-wave warning together.

Return to level 1 and work it through

We now have enough rules to read a simple level. Return to level 1: it has ten waves, no top-level authored list, and automatic flag groups enabled. Basics and Coneheads cost 1 and 3 points, both have weight 4000, and Coneheads unlock on wave 2.

On MEDIUM, the multiplier is 1.5. What is the earliest wave on which a Conehead can participate in ordinary draws? Work out the first four budgets:

  • Wave 1: 1 × 1.5 converts to 1 point.
  • Wave 2: (1 / 3 + 1) × 1.5 gives 2 points.
  • Wave 3: the calculation gives 2.5, still 2 after discarding the fraction.
  • Wave 4: (3 / 3 + 1) × 1.5 = 3, finally reaching 3 points.
The first four waves of level 1 on MEDIUM. Each column shows the wave number above and its budget as dots: 1, 2, 2, and 3. Faded Coneheads with dashes are ineligible for ordinary draws. Only the outlined Conehead on wave 4 becomes eligible; the figure does not promise that the draw will select it.
The first four waves of level 1 on MEDIUM. Each column shows the wave number above and its budget as dots: 1, 2, 2, and 3. Faded Coneheads with dashes are ineligible for ordinary draws. Only the outlined Conehead on wave 4 becomes eligible; the figure does not promise that the draw will select it.

The answer is wave 4. Wave 2 unlocks the Conehead, but its 2 points cannot cover a cost of 3; wave 3 is still short. Unlocking permits a draw, while the budget must make it affordable. Even after both conditions hold, whether a Conehead appears still depends on the draw itself.

Now consider wave 10. With i = 9, the base budget is 9 / 3 + 1 = 4, enlarged to 10 for the large wave. The extra Basic count is 9 × 1.5 / 3 = 4.5, truncated to 4, giving five zombies including the Flag Zombie.

Since 10 ≥ 1.5 × 5, subtract 5 from the base budget, multiply by 1.5, and convert to 7 integer points. These 7 points are available for subsequent pool processing. The automatic group separately contains one Flag Zombie and four Basics. Keep the two parts separate so that neither the group nor its reservation gets counted incorrectly.

Open the level 1 MEDIUM seed example and expand the full table to check your calculation. In the site's current model, seed 123456 produces one Conehead in lane 3 on wave 4. On wave 10, the pool adds four Basics and one Conehead alongside the automatic group, spending exactly 7 points.

One small exercise remains: can wave 2 draw a Conehead on UNBALANCED? This level's multiplier array is 1, 1.5, 2, 2.5, 4, so the highest setting overrides the default 3. Try the calculation before comparing your answer below.

At four times the base budget, wave 2 has 5 points. The Conehead is both unlocked and affordable, so it can participate. Its eligibility moves from wave 4 to wave 2 because the higher multiplier meets its cost earlier, not because its unlock wave changed.

What to know when checking a wave table

Choose the difficulty first, then distinguish known counts, candidate types, and lanes chosen at spawn time. A question mark means the pool quantity has not yet been resolved by initialization simulation. “Eligible lanes 1/2/3/4/5” lists possible destinations for one record; it does not mean one zombie in every lane.

Enabling the simulated table uses the entered unsigned 32-bit integer to initialize the site's reconstructed MT19937. Under the same implementation, the same level, difficulty, and seed produce the same result. We can return to a draw and check its cost and the candidates left afterward. However, this seed serves a different purpose from the 12-character I, Zombie Endless share code, and the site does not reconstruct how the game derives its upstream seed. Entering a number therefore does not identify the roster from a particular gameplay session.

Two reconstruction differences remain. The original program leaves lane weights uninitialized before the first smooth draw; the site normalizes them to zero. Native code updates authored fixed-lane history before difficulty filtering, whereas the current simulation records only fixed lanes active at the selected difficulty. Levels mixing such records may produce different lanes. Spawn-time cooldowns, random selection, Soul snapshots, and wave timing are also outside this initialization simulation.

Official pages analyze only the base level{id}.json. Files such as level34_1.json are related sublevels or variants and cannot be merged into the base table; DIY Levels analyzes the currently selected sublevel. “No standard wave table” means there is no ordinary roster to expand. Controllers, bosses, and preset entities may still create zombies, requiring a look at the level's other arrangements.