https://lander.bbcelite.com/ Skip to navigation [?] [?] V Lander on the Acorn Archimedes --------------------------------------------------------------------- Lander on the Acorn Archimedes My software archaeology sites Mark Moxon's Software Archaeology Elite on the BBC Micro and NES Aviator on the BBC Micro Revs on the BBC Micro Lander on the Acorn Archimedes * My writing sites Mark Moxon's Travel Writing Walking Land's End to John o'Groats Tubewalker: The Tube, on Foot Contact details and more Mark Moxon's Homepage Fully documented source code for Lander on the Acorn Archimedes Flying over the treetops in Acorn Archimedes Lander This site contains reconstructed source code for Lander, David Braben's epic game for the Acorn Archimedes, with every single line documented and (for the most part) explained. Lander was the very first game to be released for the ARM processor, and it is both a milestone and a masterpiece. My hope is that this site will be useful for those who want to learn more about Lander and what makes it tick. It is provided on an educational and non-profit basis, with the aim of helping people appreciate the second classic game from this legend of 3D coding (the first classic being Elite, of course). Note that the code on this site is not David Braben's original source code, as that hasn't been released. Instead, it is a fully buildable source that's been lovingly reconstructed from a disassembly of the original game binaries, and which produces 100% identical game files. All of the variable and routine names are my own invention, but the code itself matches the original source. Suggestions for your visit -------------------------- To start your journey into the secrets of Lander, you might like to try the following: * See the quick start guide to find out how to use this site. * Read more about this project and how it came to be. * Check out the deep dive articles for lots of details about how Lander works under the hood. * Dive straight into the source code, though you might want to read these notes first, which explain some of the terminology used in the commentary. * Jump straight to a random routine from the source code - who knows where you might end up? You can also click the [?] at the top of the page to keep jumping through the source code; it's a good way to explore. If you prefer a darker theme for your Lander explorations, you can change the site's colour scheme by clicking the icons in the top-right corner. If you want to play with the code --------------------------------- If you are interested in building a working copy of Lander from the source, then you'll enjoy exploring the accompanying GitHub repository, which contains fully commented and buildable source code for Lander. This repository can be assembled on modern computers to produce a working game disc that can be loaded into an Acorn Archimedes or an emulator. If you want to experiment with the code, this is the place to go. Similar projects ---------------- And finally, you may also be interested in my other software archaeology projects: * Fully documented source code for Elite on the BBC Micro and NES * Fully documented source code for Revs on the BBC Micro * Fully documented source code for Aviator on the BBC Micro Right on, Commanders! Mark Moxon Lander, written by David Braben, (c) D.J.Braben 1987 Commentary (c) Mark Moxon 2021 All Rights Reserved Home page * Using this site * Home page Start at the very beginning * Quick start guide All you need to know to start exploring this site * All about this project Project history, building the source and more + All about this project + About this project The story of how this project came to be + Terminology used in this commentary Read this before you explore the source code + Building Lander from the source How to build your own working copy of Lander + Useful links A collection of links to pages I've found useful during this project + Acknowledgements The giants on whose shoulders this project stands + Site history A short history of this site's development + Site map A top-level map of this website + To-do list Code that could benefit from a bit more analysis * Understanding the source code * Deep dive articles Over 20 articles on how Lander weaves its magic + Index + Index of all deep dive articlesDiscover how Lander works under the hood + Deep dives + Program structure Memory maps and the main game loop o Program structure o The Lander memory map Memory usage and squeezing Lander into the unexpanded Archimedes 305 o The main game loop Details of the tasks that Lander performs every iteration around the main loop + Landscape How the luscious 3D landscape is created o Landscape o The camera and the landscape offset An explanation of two fundamental aspects of the Lander drawing routines o Generating the landscape Using Fourier synthesis to generate a 3D landscape using simple trigonometry o Drawing the landscape Converting a set of altitudes into an undulating landscape of coloured tiles + 3D objects and particles Drawing 3D objects and simulating particle physics o 3D objects and particles o Object blueprints Storing 3D object definitions using vertices, faces and normals o Drawing 3D objects Drawing 3D objects using object blueprints and rotation matrices o Placing objects on the map Details of Lander's object types and the object map o Particles and particle clouds The particles that make up sparks, splashes, explosions and exhaust plumes + Flight The challenges of travelling by mouse o Flight o Flying by mouse Flying the ship in Lander using polar coordinates and thrust vectors o Collisions and bullets Detecting when the player has crashed or shot down an object + Drawing on the screen How Lander's graphics make it onto the screen o Drawing on the screen o Depth-sorting with the graphics buffers The clever bin-sorting hack that correctly displays objects behind one another o Drawing triangles Building a landscape and 3D objects out of nothing but triangles o Projecting onto the screen How Lander converts 3D world coordinates into 2D screen coordinates o Screen memory in the Archimedes Understanding VIDC colours and bank-switching on the Archimedes + Miscellaneous Exploring this important piece of coding history o Miscellaneous o Random numbers Lander uses a random-number algorithm from the ARM Evaluation System o In David Braben's own words A code analysis of the Lander author's own article from The Micro User o Comparing Lander to Zarch How Lander's big brother compares to its predecessor o Unused code in Lander Memory might be tight, but even Lander contains some hidden subroutines o Lander's origins on the ARM1 How the creation of Lander on the ARM1 influenced the code o Hacking the landscape Hacking the Lander source to create huge landscapes on faster machines * Exploring the source code * Lander source code Annotated source of Lander + Version information + About the version of Lander on this siteDetails of the different versions of Lander + Lander source code by file + Map of the source code An overview of how the source code for Lander is structured + Annotated source files The fully commented source files o Lander source files o Workspaces and configuration The main variable workspaces used in Lander o Lander A source Part 1 of the main game code o Lander B source Part 2 of the main game code o Lander C source Part 3 of the main game code o Lander D source Part 4 of the main game code o !RunImage source The !RunImage source for RISC OS + Lander source code by category + 3D objects 3D objects such as trees, buildings and ships o Subroutines o DrawObject (Part 1 of 5) * Draw a 3D object and its shadow o DrawObject (Part 2 of 5) Process the object's vertices o DrawObject (Part 3 of 5) Calculate the visibility of each of the object's faces o DrawObject (Part 4 of 5) Draw the shadow for each of the object's faces o DrawObject (Part 5 of 5) Draw each of the object's faces o DrawObjects (Part 1 of 3) * Draw all the objects in the visible portion of the object map, starting by working our way through the map looking for objects o DrawObjects (Part 2 of 3) Draw the object that we have found on the object map o DrawObjects (Part 3 of 3) Draw a destroyed object that we have found on the object map o PlaceObjectsOnMap * Randomly place a number of objects on the map, avoiding the sea and the launchpad o Variables o objectBuilding Object blueprint for the building o objectFirTree Object blueprint for the fir tree o objectGazebo Object blueprint for the gazebo o objectPlayer Object blueprint for the player's ship o objectPlayerAddr The address of the object blueprint for the player's ship o objectPyramid Object blueprint for a pyramid o objectRock Object blueprint for a rock o objectRockAddr The address of the object blueprint for a rock o objectRocket Object blueprint for the rocket o objectSmallLeafyTree Object blueprint for the small leafy tree o objectSmokingBuilding Object blueprint for the smoking remains of a building o objectSmokingGazebo Object blueprint for the smoking remains of a gazebo o objectSmokingRemainsLeft Object blueprint for the smoking remains that bend to the left o objectSmokingRemainsRight Object blueprint for the smoking remains that bend to the right o objectTallLeafyTree Object blueprint for the tall leafy tree o objectTypes A table that maps object types to object blueprints + Copy protection Hiding the Lander code from prying eyes o Subroutines o DecryptGameBinary (!RunImage) Placeholder routine to decrypt game code to &8000 so it can be run o RunImageEntry (!RunImage) Entry point for the !RunImage Absolute file o Variables o absoluteAddr (!RunImage) The address of the start of the Absolute file o gameCode (!RunImage) The unencrypted game code o gameCodeAddr (!RunImage) The address of the game code o gameCodeEndAddr (!RunImage) The address of the end of the game code + Drawing lines The core horizontal line-drawing routines o Subroutines o DrawHorizontalLine Draw a horizontal line o DrawLineSegment Draw a horizontal line of between 0 and 17 pixels by jumping to the relevant entry point o Variables o lineJump Jump table for drawing a horizontal line of between 0 and 17 pixels using the relevant entry point in DrawLineSegment + Drawing the screen Smooth animation using screen switching o Subroutines o SwitchScreenBank Switch screen banks and clear the newly hidden screen bank to black o Variables o greyColourWords An unused table of grey four-pixel colour words o greyColourWordsAddr The unused address of the unused table of grey four-pixel colour words o screenAddr The screen address for the start of the 17th pixel line in the current bank (i.e. the line just below the two rows of text) o screenBank1Addr The screen address for the start of the 17th pixel line in screen bank 1 (i.e. the line just below the two rows of text) o screenBank2Addr The screen address for the start of the 17th pixel line in screen bank 0 (i.e. the line just below the two rows of text) o screenBankNumber The number of the current screen bank (0 or 1) + Drawing triangles The main building block of the 3D world o Subroutines o DrawQuadrilateral Draw a quadrilateral (i.e. two triangles) o DrawTriangle (Part 1 of 11) Draw a triangle, starting by ordering the coordinates and jumping to the relevant part of the routine o DrawTriangle (Part 2 of 11) Calculate the slope of (x1, y1) to (x2, y2) o DrawTriangle (Part 3 of 11) Calculate the slope of (x1, y1) to (x3, y3) o DrawTriangle (Part 4 of 11) Draw a triangle that isn't clipped and has a sloping first side o DrawTriangle (Part 5 of 11) Draw a triangle with a horizontal edge between (x1, y1) and (x2, y2) o DrawTriangle (Part 6 of 11) Draw a clipped triangle that's partly off-screen o DrawTriangle (Part 7 of 11) Calculate the slopes of (x1, y1) to (x2, y2) and (x1, y1) to (x3, y3) for a clipped triangle o DrawTriangle (Part 8 of 11) Draw the bottom part of a clipped triangle o DrawTriangle (Part 9 of 11) Draw the top part of a clipped triangle o DrawTriangle (Part 10 of 11) Draw a clipped triangle with a horizontal edge between (x1, y1) and (x2, y2) o DrawTriangle (Part 11 of 11) Draw a triangle, clipping it to the screen as we go o DrawTriangleFromBuffer Process the "draw triangle" command from the graphics buffer o DrawTriangleShadowToBuffer Draw a triangle shadow into the correct graphics buffer, according to its distance o DrawTriangleToBuffer Draw a coloured triangle into a slightly nearer graphics buffer, according to its distance + Graphics buffers How Lander draws objects in distance order o Subroutines o AddTerminatorsToBuffers Add terminators to the ends of the graphics buffers so we know when to stop drawing o DrawGraphicsBuffer * Draw the contents of the specified graphics buffer o Variables o bufferJump The jump table for drawing commands that we store in the graphics buffers o graphicsBuffEndAddr2 The addresses of the tables containing the graphics buffer addresses (same as graphicsBufferEndAddr and graphicsBufferAddr) o graphicsBufferAddr The address of the table containing the addresses of the graphics buffers o graphicsBufferEndAddr The address of the table containing the end addresses of the graphics buffers o graphicsBuffers The addresses of each of the graphics buffers (these values do not change) o graphicsBuffersEnd The end addresses of each of the graphics buffers (these values get updated as objects are drawn into the buffers) + Landscape The secrets of Lander's undulating landscape o Subroutines o DrawLandscapeAndBuffers (Part 1 of 4) * Draw the landscape and the contents of the graphics buffers, from the back of the screen to the front o DrawLandscapeAndBuffers (Part 2 of 4) Draw a row of landscape tiles o DrawLandscapeAndBuffers (Part 3 of 4) Draw the objects in the graphics buffers for two rows behind the current corner row o DrawLandscapeAndBuffers (Part 4 of 4) Draw the remaining graphics buffers o GetLandscapeAltitude * Calculate the altitude of the landscape for a given coordinate o GetLandscapeBelowVertex Calculate the landscape altitude directly below an object's vertex o GetLandscapeTileColour Calculate the colour of the landscape tile currently being drawn o Variables o landscapeConfig The configuration data for each tile row in the landscape o landscapeConfigAddr The address of the landscapeConfig table o landscapeOffset The offset we apply to the on-screen landscape to push it away from us and to the left, so the visible tiles fit nicely on-screen o landscapeOffsetAddr The address of the landscape offset + Main loop The core game loop that runs Lander o Subroutines o EndGame Finish the game o GameOver Print a Game Over message and start a new game o LoseLife * Display a crash animation when we lose a life and end the game if this is our last life o LoseLifeFromParticleLoop Lose a life when a crash is detected in the particle processing loop o MainLoop * The main game loop o StartNewGame Start a brand new game with a full set of lives and a newly generated set of objects + Maths (Arithmetic) Division, square roots and random numbers o Subroutines o GetRandomNumbers * Generate pseudo-random numbers from the random number seeds o Variables o divisionTable Division lookup tables o divisionTableAddr The address of the division lookup table o randomSeed1 The first random seed for the random number generator o randomSeed2 The second random seed for the random number generator o squareRootTable Square root lookup table o squareRootTableAddr The address of the square root lookup table + Maths (Geometry) Trigonometry, vectors and rotation matrices o Subroutines o AddVectors An unused routine that adds two vectors and uses self-modifying code to store the results in a specified location o AddVectorsWithFeedback An unused routine that adds a delta vector to a coordinate and updates the delta with feedback from the coordinate value o AddVectorToVertices Add a vector to the rotated vertex coordinates to get the vertex coordinates in 3D space o CalculateRotationMatrix * Calculate the rotation matrix o GetDotProduct Calculate the dot product of two 3D vectors o GetMouseInPolarCoordinates (Part 1 of 2) Convert the mouse x- and y-coordinates into polar coordinates, starting by calculating the polar angle o GetMouseInPolarCoordinates (Part 2 of 2) Calculate the polar distance o MultiplyVectorByConstant An unused routine that multiplies a vector by a constant value o MultiplyVectorByMatrix Multiply a 3D vector by the rotation matrix in rotationMatrix, if the object is a rotating object o ProjectParticleOntoScreen Project a 3D particle coordinate onto the screen o ProjectVertexOntoScreen Project a vertex coordinate from a 3D object onto the screen o TransposeRotationMatrix An unused routine that transposes the rotation matrix o Variables o arctanTable Arctan lookup table o arctanTableAddr The address of the arctan lookup table o sinTable Sine/cosine lookup table o sinTableAddr The address of the sine/cosine lookup table + Particles Explosions, splashes, sparks and falling rocks o Subroutines o AddBulletParticleToBuffer Add a bullet particle to the particle data buffer o AddDebrisParticleToBuffer Add a debris particle to the particle data buffer, which is a purple-brownish-green particle that bounces out of an explosion o AddExhaustParticleToBuffer Add one of the moving particles in the exhaust plume to the particle data buffer o AddExplosionToBuffer Create a big explosion of particles and add it to the particle data buffer o AddMovingParticleToBuffer Add a moving particle to the particle data buffer, adding a random element to its velocity and lifespan counter o AddRisingParticleToBuffer Add a particle to the particle data buffer that initially drifts up, with a random element to its velocity and lifespan counter o AddShipExplosionToBuffer An unused routine that adds a 50-cluster explosion cloud to the particle data buffer, just front of the player's ship o AddSmallExplosionToBuffer Add a small explosion to the particle data buffer o AddSmokeParticleToBuffer Add a smoke particle to the particle data buffer o AddSparkCloudToBuffer An unused routine that adds a cloud of 150 spark particles to the particle data buffer, just in front of the player's ship o AddSparkParticleToBuffer Add a spark particle to the particle data buffer that fades from white-hot to red over time o AddSprayParticleToBuffer Add a spray particle to the particle data buffer o AddStaticParticleToBuffer Add a particle to the particle data buffer that starts off static, adding a random element to its velocity and lifespan counter o BounceParticle Bounce a particle off the ground o DeleteParticleData Delete a particle from the particle data buffer and move the last particle's data down to take its place o Draw1x1ParticleFromBuffer Process the "draw 1x1-pixel specified" command from the graphics buffer o Draw2x1ParticleFromBuffer Process the "draw 2x1-pixel particle" command from the graphics buffer o Draw2x2ParticleFromBuffer Process the "draw 2x2-pixel particle" command from the graphics buffer o Draw3x1ParticleFromBuffer Process the "draw 3x1-pixel particle" command from the graphics buffer o Draw3x2ParticleFromBuffer Process the "draw 3x2-pixel particle" command from the graphics buffer o DrawParticleShadowToBuffer Draw a small black particle into the correct graphics buffer, according to its distance o DrawParticleToBuffer Draw a large coloured particle into a slightly nearer graphics, buffer according to its distance o DropARockFromTheSky Drop a rock from the specified coordinates by spawning it as a particle, albeit a very big particle with an associated 3D object o DropRocksFromTheSky If the score is 800 or more, then randomly drop rocks from the sky by spawning them as particles o MoveAndDrawParticles (Part 1 of 4) Process particle movement and draw the particles into the graphics buffers, starting with the movement of particles o MoveAndDrawParticles (Part 2 of 4) Draw particles (including rocks) into the graphics buffers o MoveAndDrawParticles (Part 3 of 4) Process rocks by checking for collisions and drawing them as 3D objects o MoveAndDrawParticles (Part 4 of 4) Draw particles into the graphics buffers o ProcessObjectDestruction If this particle has hit an object, destroy the object and the particle in an explosion, scoring points if it's a bullet o SetParticleColourToFade Set the flags for a particle whose colour fades from white to red over time, to give a white-hot explosion particle that cools down o SpawnRock An unused routine that spawns a rock in the sky, at half the altitude of the rocks in the DropRocksFromTheSky routine o SplashParticleIntoSea Splash a particle into the sea, creating a spray particle o StoreParticleData Store the data for a new particle in the particle data buffer + Player Moving the player using unique mouse-based controls o Subroutines o LandOnLaunchpad Check to see if the player has landed on the launchpad o MoveAndDrawPlayer (Part 1 of 5) * Process player movement and draw the player's ship into the graphics buffers, starting with reading the mouse position o MoveAndDrawPlayer (Part 2 of 5) Update the player's velocity and coordinates o MoveAndDrawPlayer (Part 3 of 5) Check for collisions and draw the ship o MoveAndDrawPlayer (Part 4 of 5) Spawn the particles in the exhaust plume if the engine is engaged o MoveAndDrawPlayer (Part 5 of 5) Spawn a bullet particle if the fire button is being pressed o PlacePlayerOnLaunchpad The main entry point for the game o ResetMousePosition Reset the mouse position to (511, 511), ready for the game o Variables o mouseParameters The parameters for OS_Word 21,3 for resetting the mouse position o mouseParametersAddr The address of the OS_Word block for resetting the mouse position + Score bar Updating the score at the top of screen o Subroutines o DrawFuelLevel Draw the bar at the top of the screen showing the current fuel level o PrintCurrentScore Print the current score at the left end of the score bar o PrintHexDigit An unused routine that prints a single digit hexadecimal number in the score bar o PrintHexNumber An unused routine that prints an 8-digit hexadecimal number on the second character row of the screen o PrintScoreInBothBanks Print a number at a specified text column in the score bar o Variables o fuelBarColour A four-pixel colour word for the colour of the fuel bar o initialFuelLevel The fuel level at the start of each new game o initialHighScore The high score when we first load the game o initialScore The score at the start of each game + Start and end Initialising the game and shutting it down o Subroutines o AbortWithMemoryError Show a memory error and abort the game o Entry * The main entry point for the game o InitialiseParticleData Initialise the particle data buffer and associated variables o ReturnToDesktop Return to the desktop o Variables o memoryTestAddr The memory location to check to ensure we have enough memory for the game o stackAddr The address of the game's stack o stackPointerOnEntry Stores the stack pointer from when the game was run o workspaceAddr The address of the game's variable workspace * Show me a Random Routine Or click [?] above to jump into the source code... * Indexes and code analyses * Indexes to the source code A-Z indexes, code usage analysis and more + A-Z indexes + A-Z index of the source code An index of every subroutine, entry point and variable in the source code + Source code cross-references Every label and variable in the source code and where they are used + Indexes by category + List of all subroutines by category Subroutines in Lander + List of all variables by category Variables in Lander * Code statistics for Lander Instruction counts and other source code stats * My software archaeology sites * Mark Moxon's Software Archaeology * Elite on the BBC Micro and NES * Aviator on the BBC Micro * Revs on the BBC Micro * Lander on the Acorn Archimedes * My writing sites * Mark Moxon's Travel Writing * Walking Land's End to John o'Groats * Tubewalker: The Tube, on Foot * Contact details and more * Mark Moxon's Homepage