26 September to 3 October 2025
Here's my disassembly diary for this part of my project to document The Sentinel on the BBC Micro. You can click on the following links to jump to a specific day in the diary:
- 26 September 2025 - Document GetTilesAtAltitude, identify xObject, yObjectHi and zObject
- 30 September 2025 - Split out SpawnPlayer, SpawnTrees and CheckSecretCode, document SpawnObjectOnTile, work out data packing in tileData, rename xObject, yObjectHi and zObject, work out object types 3 and 6
- 1 October 2025 - Realise y-coordinate is 16-bit so we have yObjectHi and yObjectLo, revamp terminology to talk about altitude rather than height, identify SpawnObjectBelow, finish documenting SpawnPlayer
- 2 October 2025 - Document SpawnTrees, split off CheckSecretCode parts 1 and 2, start documenting CheckSecretCode, identify GetNextSeedAsBCD and FinishLandscape
- 3 October 2025 - Finish documenting CheckSecretCode, reach 25% progress, document PreviewLandscape, starting adding "???" to unknowns
Please note that this diary is a dump of my thoughts as I disassembled and documented The Sentinel, and as such it contains lots of mistakes and dead ends and misinterpretations. This diary is all about the journey, rather than the destination; for the latter, see the finished product.
26 September 2025
=================
See all the GitHub commits and diffs for 26 September 2025.
sub_C158D gets a list of tile blocks that are at a specific height, so rename to GetTilesAtHeight and document.
Rename CreateEnemies -> AddEnemiesToTiles as that's what it does ("create" is a bit vague, especially as we also have a SpawnEnemies routine already).
Added labels to tile object coordinates from L0900 onwards:
- L0900 -> xTileObject
- L9040 -> yTileObject
- L0980 -> zTileObject
30 September 2025
=================
See all the GitHub commits and diffs for 30 September 2025.
SpawnPlayerTrees: split into SpawnPlayer, SpawnTrees and CheckSecretCode.
Continue working through AddEnemiesToTiles, the next subroutine to check is sub_C1EFF, which adds object to tile (so call it PlaceObjectOnTile).
When the object in slot X gets placed on a tile:
- X-th entry in (xTileObject, yTileObject, zTileObject) = tile 3D coordinate where yTileObject is the tile height
- X-th entry in objectFlags = 0, so bit 7 is clear to indicate that slot X contains an object
- X-th entry in L0A00 = &E0
- X-th entry in L0140 = &F5
- X-th entry in L09C0 = random number, multiple of 8
- tileData for the tile is set to the slot number in X in bits 0 to 5, and bits 6 and 7 are set
So! Because tile height is in the range 0 to 11, this means we have two types of data in tileData, one for empty tiles (where bits 6 and 7 are not both set), and one for tiles containing objects (where bits 6 and 7 are set).
First one contains tile slope and height, second one contains object slot number.
Clever packing of data here.
Also, objectFlags can contain an object slot number, if objects are stacked. We can only stack objects on object types 3 and 6, so one of these is presumably the boulder. The other is probably the Sentinel's tower?
So xTileObject etc. seem to be object 3D coordinates in space, rather than tiles, but obviously objects are on tiles so there is overlap.
But (xObject, yObject, zObject) is clearer, so rename variables.
During first pass of AddEnemiesToTiles, and looking back at PlaceObjectOnTile, it turns out we add the Sentinel after adding an object of type 6, so 6 must be the tower and 3 must be the boulder. We already identified the Sentinel as type 5, so we're getting there. Comments amended!
1 October 2025
==============
See all the GitHub commits and diffs for 1 October 2025.
Penny dropped, y-axis must have fractional heights as boulders are not as tall as a single tile block, so presumably L0A00 = yObjectLo, and yObject must really be yObjectHi.
Update all uses of yObject to talk about the two-byte value.
Picking up the analysis of AddEnemiesToTiles, next subroutine is sub_C196A, not sure what that is so skip it to finish the first pass.
Big revamp of terminology: we need to talk about altitudes for y-coordinates instead of heights.
"Object altitude" is its y-coordinate.
"Object height" is how tall the object is.
Boulders, for example, have a height of 0.5 coordinates, while the Sentinel's tower has a height of 1.0 coordinates, but they can be at any altitude.
Big manual search and replace to sort this out - it's worth it in the end for clarity's sake.
Expand the final set of calculated labels so the only ones in the form Lxxxx = Lyyyy + z are code modification labels.
e.g. convert any remaining bits like this:
L49A0 = &49A0 L49A1 = &49A1 L49AB = &49AB L49AC = &49AC L49B6 = &49B6 L49C1 = &49C1
into proper labels and headers.
Roll back up the hierarchy to PreviewLandscape, next up is SpawnPlayer.
This calls sub_C1224, which places the player below a specified height, so call it PlaceObjectBelow.
Finish off comments in SpawnPlayer.
2 October 2025
==============
See all the GitHub commits and diffs for 2 October 2025.
Next up is SpawnTrees, which is easy to document, but it contains some weird code at the end that isn't to do with trees.
It's to do with the showCodeError flag, which controls whether we return to the title screen or progress, so it looks like the first half of the routine that checks the secret code (the other half is after landscapeColour3, and we already identified it as related to the secret code).
So split them off into CheckSecretCode (Part 1 of 2) and CheckSecretCode (Part 2 of 2).
CheckSecretCode (Part 1 of 2) calls sub_C3364 which returns a random number in BCD format, so name it GetRandomNumberBCD.
Rename showCodeError flag -> doNotPlayLandscape, because we don't always show the secret code error when this is set (it's also set in another routine, sub_C2147, which affects how we return from the call to GenerateLandscape in sub_C1A7E).
sub_C1A7E is the only routine that prints the landscape code (it draws it in 3D) and it seems to add to the current landscape number, so tentatively rename this to FinishLandscape.
CheckSecretCode is complicated and designed not to be understood! So slow progress here...
3 October 2025
==============
See all the GitHub commits and diffs for 3 October 2025.
CheckSecretCode is a beast, but I finally understand it.
It uses various hacks, including obfuscation of the return address, checking the code a second time during gameplay, and never storing the generated secret code, but instead only storing the results of comparisons between the generated code and entered code.
Also using objectFlags (the Sentinel's flags) as a constant %01111111.
Very tricky stuff! Glad that's done.
>>> I have now broken through the 25% barrier <<<
>>> THIS IS COOL! The first non-numerical milestone of "one quarter". A big event... <<<
Document PreviewLandscape, which is where all this jumping around ends up if the codes don't match.
Add "???" to all the variables that need documenting properly, so we can revisit them easily.