I’ve been trying to understand how the growth mechanics work in Wicked, and whilst the main game has been where all my focus has been so far, there is still one other place where growth happens – the “Well Done” ending screen. This is what you see when you win the game, by beating all three stars in the final constellation, Sagittarius. Given how difficult the game is in later levels, few have ever seen it. Here it is in Zeusdaz’s unemulated playthrough (and even then he had to do a level skip cheat to see it*):
* I’m not judging, Darren – I can’t finish it without cheating either!
To see the winning “Well Done” ending screen in AiraForce, set $5B2 to 0008 and jump the Program Counter to $28A80
Over the past couple of weeks, I’ve been writing a simulator for Wicked to test out my understanding, and it’s got to the point where I can simulate growth “in game”. I’m using it to learn more about the different “intelligences” that the growths have, after reading about it many years ago in the Player’s Guides. Now that I’m able to simulate the growth, it’s time to turn my attention to another place where growth happens in the game – the final “Well Done” screen, where good portals and octagonal growth, the most “intelligent” of all growths, spell out the words “WELL DONE”.
Recently though, I’ve discovered that good growth is entirely random in its growth behaviour. It’s only evil growth of that type that shows any kind of pathfinding. Growth is not a separate “smarter” algorithm for both sides. The difference is that evil growth sometimes uses the pathfinding table, while good growth never does. Good growth always picks a random direction. Evil growth, on the other hand, first has a chance to use its stored pathfinding direction towards the nearest good portal, with a little randomness added on top. If that pathfinding check does not fire, evil growth also falls back to a random direction. So the “intelligence” of octagonal growth is really a matter of how often evil growth is “allowed” to follow its guided direction instead of growing randomly. In the octagonal case that chance is very high, which is why it looks like it has a purpose, where circular growth – the least intelligent – doesn’t.
The pathfinding check only fires when both of these gates pass:
1. The spreading portal must be evil
- Good growth never even enters the pathfinding branch.
- In the row loop, good portals jump straight to the pure-random direction picker.
2. A fresh random byte must be less than or equal to GrowthRateThreshold_530
- The Amiga test is
CMP.B GrowthRateThreshold_530,D1thenBHI LAB_PickRandomDirection_2E0C4
So:
- random > threshold –> no pathfinding, use random direction
- random <= threshold –> pathfinding fires
When pathfinding does fire, it still is not perfectly rigid. The game then:
- reads the base direction from the evil portal’s pathfinding table entry
- then adds a random offset of 1, 2, or 3
- then masks back into the 8-direction range
So even the “intelligent” branch is ‘guided’ rather than ‘exact’.
So, if the “Well Done” screen is using the same portal and growth machinery as the rest of the game, how is it so good at building the words “WELL DONE”?
The (first) wrong assumption

When I first added the ending screen into the simulation, the result was obviously wrong. Instead of recognisable words, the growth spread far too freely across the board. It looked like a mess, even though the portal positions themselves were correct and it was using octagonal growth. Clearly, something wasn’t right here and I needed to go back to the disassembly to trace the code execution. That was a useful clue, because I’d missed something. The disassembly for the “Well Done” ending initialisation routine at InitWellDoneWinEndingScreen_28776 does two important things:
1. It points ForbiddenCellBitmapPTR_4D2 at $33F6B – this was pointing to a new “forbidden cell” bitmap I had not discovered before. Because there was no label generated by the disassembler here, I’d assumed it was part of the same block as the in-game “forbidden cell” bitmap.
2. It then creates a fixed list of good portals from TBL_WellDonePortalLocations_33638
What the disassembly is really telling us
The bit that I’d missed was this line.
MOVE.L #$00033F6B,ForbiddenCellBitmapPTR_4D2
If you only look at that instruction in isolation, it is tempting to treat $33F6B as just “some address after the in-game bitmap”. But once I looked closely at the data layout around TBL_ForbiddenCellBitmap_InGame_33EEE, the arithmetic became very clear:
$33F6B – $33EEE = $7D
$7D = 125
$33FE8 – $33F6B = $7D
…again, 125!
That means the region from $33EEE to $33FE7 that I thought was a neat 250-byte block for the in-game “forbidden cell” bitmap, splits into two 125-byte slices:
$33EEE .. $33F6A— the in-game forbidden-cell bitmap$33F6B .. $33FE7— the ending-screen forbidden-cell bitmap
In other words, the “Well Done” screen is pointing at the second half of a ‘stencil’ or mask block, meaning that the growth was restricted to the ‘channels’ it was allowed to grow into. Once that was modelled correctly, the simulation stopped flooding the board and started behaving like the game. So we have:
- a fixed set of portal locations
- a forbidden-cell mask that blocks writes almost everywhere else
The growth then runs normally inside the remaining writable channels/paths. So the text is really formed by constrained growth moving through a mask or ‘stencil’. That is such a lovely design. It reuses the normal growth systems rather than introducing a separate one-off effect just for the ending. Very clever.
Why most of the letters stop at growth size 6

While comparing the simulation output to the Amiga version in Aira Force, I noticed another interesting detail. Most of the letters do not mature beyond growth stage 6. Only a few areas, especially around the `N`, seem to advance into the larger mature block forms. That turns out to be consistent with how the growth code works.
Sizes 1 to 6 are ordinary single-cell growth. Once growth gets beyond stage 5, the code does not continue increasing a single value forever. Instead, it switches to a new growth 2×2 maturity logic:
- size
7= top-left quarter - size
8= top-right quarter - size
9= bottom-left quarter - size
A= bottom-right quarter
For that ‘promotion’ to happen, the routine needs a legal 2×2 neighbourhood of same-type cells in the right stage range. If the stencil only leaves a one-cell-wide corridor, there is nowhere to place a full 2×2 block, so the growth effectively tops out at size 6.
That explains why so much of the Well Done text stays at that size. The mask deliberately creates narrow strokes. Around the “N”, the geometry happens to provide a few places where the 2×2 growth promotion test can succeed, so that part matures further. So the uneven growth across some of the letters is a direct consequence of the same growth rules used in gameplay.
What this changed in the simulation

The work ended up being part code fix, part disassembly clarification.
On the simulation side, the key changes were:
- implementing the ending front-end mode properly so the mode-8 init and body actually run
- making the ending init path load the real
$33F6Bforbidden-cell mask instead of treating it as empty data - making sure the ending portal list is only created once per visit, which matches the effective behaviour of the original tight loop
On the disassembly side, I also added a new label and banner commentary for TBL_ForbiddenCellBitmap_Ending_33F6B, because the raw data without a generated label did not previously make that obvious, and I’d been left wondering about how this routine worked for a while. It became one of those “Ah! Now I see!” things. This is one of those moments where disassembling stops feeling like cataloguing work and starts feeling like understanding the design decision.

Leave a Reply