The organic growth is one the most important part of Wicked’s game mechanics, and the part of the game that fascinates me the most. Evil growth (blue) spreads from evil portals and seeks to wipe out good portals. The player wins the level by picking up and carrying new good spores, then dropping them onto existing good growth to place new good portals with fresh growth of their own. Good growth cannot grow over evil growth, it has to be shot first.
There are four “types” of growth in the game. They are defined in the level data, and when the level loads, the growth type value is copied into $518. The descriptions below are from the Player’s guide (The percentages are approximate as we’ll see later).

Circular growth ($518 = 0000)
Round shaped growth is the least intelligent. About 95% grows in random directions, with only the remaining 5% showing any intelligence.

Diamond shaped growth ($518 = 0001)
80% of growth is random, with 20% growing intelligently.

Cross shaped growth ($518 = 0002)
About 50% grows randomly, and the other 50% grows intelligently.

Octagonal growth ($518 = 0003)
This is the most intelligent. 90% grows intelligently whilst only 10% grows in random directions.
The Growth ‘Tick’
One thing that I missed at first is that growth does not update once per frame.
The game has two growth timers, both incremented from the VBL. One controls good growth, and the other controls evil growth. The main loop then calls SUB_GrowthTickController_2D7E4 three times in succession, followed by a pathfinding refresh. That triple call seems to be a way of letting the growth system catch up if the main loop has fallen behind the VBL for any reason.
Good growth is controlled by $538, which is compared against the threshold loaded from the level data. Evil growth is controlled separately by $536, which is compared against a constellation-specific rate table. In both of these cases, when the timer crosses the threshold, the threshold value is subtracted and the remainder carries forward. So growth does not drift over time. It grows at a steady average rate.
When a growth step fires, every eligible portal of the active type gets one pass through the spread routine.
Each portal also has a growth budget. This is the total amount of growth that portal can still produce. Once the budget reaches zero, that portal stops expanding, although it can still continue to spore. Evil portals start with a smaller budget than good ones, and duplicate portal entries in the level data effectively give a portal location multiple budgets and multiple spread opportunities.
LAB_02C0 positions the cursor to look at all the immediate squares on the board surrounding the position we are examining, then calls a function to calculate the growth in that square.

Good And Evil Growth Do Not Behave The Same Way
Good and evil portals do not use the same direction logic.
Good portals always spread in a completely random direction. The growth type has no effect on them. This is a hardcoded bypass in SUB_GrowthRowLoop_2E04A at $2E088.
Evil portals are the ones that use the intelligence system. So the different growth “types” are really telling us how intelligently evil growth behaves, not how good growth behaves.
Direction Selection
Even evil growth is not rethinking its direction every time it spreads.
Most of the time it simply keeps going the same way it was already going. There is a 7/8 chance that it continues in its current direction (AND #$0007 on the random sample, branch if non-zero at $2E080), and only about 1 tick in 8 triggers a direction re-evaluation. That is one of the reasons the growth feels organic. It creeps and pushes in one direction instead of making a fresh decision every single step.
For each evil portal, the code finds the nearest good portal using Manhattan Distance and stores a simple quadrant-style direction hint:
| Value | Quadrant |
|---|---|
| 0 | Up-right |
| 1 | Down-right |
| 2 | Down-left |
| 3 | Up-left |
When an evil portal needs a new direction, the algorithm at $2E092 draws a random byte and compares it to GrowthRateThreshold_530:
- Random byte > threshold → pure random direction (all 8 directions equally probable)
- Random byte ≤ threshold → intelligent direction — the pathfinding quadrant is looked up, a random small change of 1, 2, or 3 is added, and the result is masked to 0–7. This produces a 3-direction cone (
AND #$0007on the random sample, branch if non-zero at$2E080)
The threshold is loaded from TBL_GrowthRateLookupTable_3276A at $3276A at the start of each level using (GameBias × 4) + GrowthType as the index.
Growth Type, Difficulty, And Intelligence
The value at $518 selects the growth type, but the actual intelligence also depends on the game bias setting at $5DE.
GameBias_5DE works as follows:
- 0 = Tactical
- 1 = Standard Mix
- 2 = Arcade
The threshold is loaded from TBL_GrowthRateLookupTable_3276A using:
(GameBias × 4) + GrowthType
The table is:
| Circular | Diamond | Cross | Octagonal | |
|---|---|---|---|---|
| Tactical | $32 (50) | $78 (120) | $BE (190) | $EB (235) |
| Normal | $00 (0) | $50 (80) | $96 (150) | $C8 (200) |
| Arcade | $00 (0) | $28 (40) | $50 (80) | $78 (120) |
Because the code takes the intelligent branch when random <= threshold, the real probability is (threshold + 1) / 256, not just the rough percentages from the manuals.
That gives:
| Circular | Diamond | Cross | Octagonal | |
|---|---|---|---|---|
| Tactical | ~19.5% | ~46.9% | ~74.2% | ~91.8% |
| Normal | ~0.4%* | ~31.3% | ~58.6% | ~78.1% |
| Arcade | ~0.4%* | ~15.6% | ~31.3% | ~46.9% |
*Threshold $00: the comparison is random_byte > 0, so only the value 0 (1 in 256) takes the intelligent path — effectively always random.
So in Standard Mix, Circular growth is effectively random, while Octagonal growth heads towards good portals most of the time. Tactical pushes every type upwards, making the evil growth noticeably smarter. Arcade pulls them down again. This seems to fit with the Player’s Guides.
Shot Growth
Shot evil growth turned out to be one of the most interesting parts of the system.
When the player shoots evil growth, the game does not erase it outright. Instead, it marks the cell as “shot” by adding $90 to the value in GameBoardA, and $20 to the corresponding visual/type value in GameBoardB. The original stage is preserved in the low nibble.
What matters is that this shot state does not recover on a timer. Instead, the cell stays in that shot state until the growth spread routine reaches it again. When that happens, the original stage is recovered from the low nibble, incremented, and written back as normal growth. So shot growth reverts because spread reaches it, not because some hidden countdown timer expires.
That means the player’s opportunity to reclaim shot evil growth with good growth is not fixed. It depends on how quickly the surrounding spread reaches that cell.
2×2 Growth Blocks
Once growth gets mature enough, the game can replace clusters of smaller cells with larger 2×2 growth blocks. When a cell has been at growth stage 6 or higher and its three neighbours (right, below, diagonal) are also same-type cells in stages 6–9, a persistence counter increments each tick that this condition holds. After 12 consecutive qualifying ticks the simulation places a larger 2×2 block spanning stages 7/8/9/A across the four cells. The counter threshold and block placement logic live in LAB_Check2x2BlockReadiness_2E28C and LAB_PlaceGrowthBitmap_2E300.
This is why the larger growth patches tend to appear only once an area has become dense and stable. A single portal can do it eventually, but overlapping portals make it happen much more readily. That is especially true for player-created good portals, because each newly dropped portal comes with a generous fresh budget of its own. This will be important for later levels where there are double or triple portals placed on top of each other in the level data.
Player Interaction
The player collects good spores from good spore entities and carries one at a time. When the player is over existing good growth, carrying a spore and the fire button is pressed (SUB_PlayerFireRoutine_2AA3A at $2AA3A), the spore is dropped and SUB_CreatePortal_2DF60 creates a new good portal at that cell with a budget of 216–279 ((rand & $3F) + $D8). This is significantly larger than the initial portal budgets and is the primary mechanism for generating the dense growth needed to form 2×2 blocks over the course of a level.

Leave a Reply